diff --git a/CMakeLists.txt b/CMakeLists.txt index f11cb076b140cfc115a6725bff79905019e9de7b..4636699fe4808f4a55ece8b37ae333d2eeb0a4ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ project(pmc-sog C CXX) # compiler flags if(CMAKE_COMPILER_IS_GNUCC) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive -g3") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive -g3 -std=c++17") endif() # add pn parser diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f8861e386b05948d48f75819e19a85b910a7e609..cbf7ecbe4c2dff51b7fd521589cd4de86c59af78 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -63,6 +63,10 @@ add_executable(mc-sog main.cpp SogKripkeIteratorTh.h ModelCheckerTh.cpp ModelCheckerTh.h + stacksafe.cpp + stacksafe.h + ModelCheckerThV2.cpp + ModelCheckerThV2.h MCHybridSOG.cpp MCHybridSOG.h HybridKripke.cpp diff --git a/src/ModelCheckerTh.h b/src/ModelCheckerTh.h index 58bce47f2fc6dc1782fcbb111118b87f82001af9..ae0ff73da642e964bc754a754d1a9c39770cbefe 100644 --- a/src/ModelCheckerTh.h +++ b/src/ModelCheckerTh.h @@ -30,7 +30,7 @@ private: pthread_barrier_t m_barrier_builder; unsigned int m_gc=0; // - bool m_finish=false; + volatile bool m_finish=false; bool m_finish_initial=false; pthread_mutex_t m_mutex_stack[128]; pthread_t m_list_thread[128]; diff --git a/src/ModelCheckerThV2.cpp b/src/ModelCheckerThV2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f1f9c3d7918de075a11d76baab544737164cb9aa --- /dev/null +++ b/src/ModelCheckerThV2.cpp @@ -0,0 +1,282 @@ +#include "ModelCheckerThV2.h" +#include "sylvan.h" +#include "sylvan_seq.h" +#include <sylvan_sog.h> +#include <sylvan_int.h> + +using namespace sylvan; +using namespace std; + +ModelCheckerThV2::ModelCheckerThV2 ( const NewNet &R, int nbThread ) : + ModelCheckBaseMT ( R, nbThread ) +{ +} +size_t +getMaxMemoryV3() +{ + long pages = sysconf ( _SC_PHYS_PAGES ); + long page_size = sysconf ( _SC_PAGE_SIZE ); + return pages * page_size; +} +void ModelCheckerThV2::preConfigure() +{ + + lace_init ( 1, 0 ); + lace_startup ( 0, NULL, NULL ); + size_t max = 16LL<<30; + if ( max > getMaxMemoryV3() ) { + max = getMaxMemoryV3() /10*9; + } + sylvan_set_limits ( max, 8, 0 ); + + sylvan_init_package(); + sylvan_init_ldd(); + displayMDDTableInfo(); + + vector<Place>::const_iterator it_places; + + init_gc_seq(); + + + transitions = m_net->transitions; + m_observable = m_net->Observable; + m_place_proposition = m_net->m_formula_place; + m_nonObservable = m_net->NonObservable; + + m_transitionName = m_net->transitionName; + m_placeName = m_net->m_placePosName; + + InterfaceTrans = m_net->InterfaceTrans; + + cout << "Nombre de places : " << m_nbPlaces << endl; + cout << "Derniere place : " << m_net->places[m_nbPlaces - 1].name << endl; + + uint32_t *liste_marques = new uint32_t[m_net->places.size()]; + uint32_t i; + for ( i = 0, it_places = m_net->places.begin(); it_places != m_net->places.end(); i++, it_places++ ) { + liste_marques[i] = it_places->marking; + } + + m_initialMarking = lddmc_cube ( liste_marques, m_net->places.size() ); + ldd_refs_push ( m_initialMarking ); + uint32_t *prec = new uint32_t[m_nbPlaces]; + uint32_t *postc = new uint32_t[m_nbPlaces]; + // Transition relation + for ( vector<Transition>::const_iterator t = m_net->transitions.begin(); t != m_net->transitions.end(); t++ ) { + // Initialisation + for ( i = 0; i < m_nbPlaces; i++ ) { + prec[i] = 0; + postc[i] = 0; + } + // Calculer les places adjacentes a la transition t + set<int> adjacentPlace; + for ( vector<pair<int, int> >::const_iterator it = t->pre.begin(); it != t->pre.end(); it++ ) { + adjacentPlace.insert ( it->first ); + prec[it->first] = prec[it->first] + it->second; + //printf("It first %d \n",it->first); + //printf("In prec %d \n",prec[it->first]); + } + // arcs post + for ( vector<pair<int, int> >::const_iterator it = t->post.begin(); it != t->post.end(); it++ ) { + adjacentPlace.insert ( it->first ); + postc[it->first] = postc[it->first] + it->second; + + } + for ( set<int>::const_iterator it = adjacentPlace.begin(); it != adjacentPlace.end(); it++ ) { + MDD Precond = lddmc_true; + Precond = Precond & ( ( *it ) >= prec[*it] ); + } + + MDD _minus = lddmc_cube ( prec, m_nbPlaces ); + ldd_refs_push ( _minus ); + MDD _plus = lddmc_cube ( postc, m_nbPlaces ); + ldd_refs_push ( _plus ); + m_tb_relation.push_back ( TransSylvan ( _minus, _plus ) ); + } + delete[] prec; + delete[] postc; + ComputeTh_Succ(); + +} + +LDDState* ModelCheckerThV2::getInitialMetaState() +{ + while ( !m_finish_initial ) ; + LDDState *initial_metastate = m_graph->getInitialState(); + if ( !initial_metastate->isVisited() ) { + initial_metastate->setVisited(); + while ( !initial_metastate->isCompletedSucc() ) + ; + } + return initial_metastate; +} + +void ModelCheckerThV2::buildSucc ( LDDState *agregate ) +{ + if ( !agregate->isVisited() ) { + agregate->setVisited(); + while ( !agregate->isCompletedSucc() ) + ; + } +} + +void ModelCheckerThV2::Compute_successors() +{ + int id_thread; + { + std::scoped_lock guard ( m_mutex ); + id_thread = m_id_thread++; + } + //cout<<" I'm here thread id " <<m_id_thread<<endl; + Set fire; + int min_charge = 0; + m_started=false; + if ( id_thread == 0 ) { + LDDState *c = new LDDState; + MDD Complete_meta_state=Accessible_epsilon ( m_initialMarking ); + ldd_refs_push ( Complete_meta_state ); + + fire = firable_obs ( Complete_meta_state ); + c->m_lddstate = Complete_meta_state; + c->setDeadLock ( Set_Bloc ( Complete_meta_state ) ); + c->setDiv ( Set_Div ( Complete_meta_state ) ); + m_common_stack.push ( Pair ( couple ( c, Complete_meta_state ), fire ) ); + m_started=true; + m_graph->setInitialState ( c ); + m_graph->insert ( c ); + m_finish_initial = true; + + } + + LDDState *reached_class; + //pthread_barrier_wait ( &m_barrier_builder ); + do { + Pair e; + while ( !m_common_stack.empty() && !m_finish ) { + m_terminaison++; + bool advance=true; + try { + m_common_stack.pop ( e ); + } catch ( ... ) { + advance=false; + } + + if ( advance ) { + while ( !e.second.empty() && !m_finish ) { + int t = *e.second.begin(); + e.second.erase ( t ); + if ( id_thread ) { + std::scoped_lock supervise ( m_supervise_gc_mutex ); + m_gc++; + if ( m_gc == 1 ) { + m_gc_mutex.lock(); + } + } + + //MDD reduced_meta = Complete_meta_state; //Canonize(Complete_meta_state,0); + /*ldd_refs_push(reduced_meta);*/ + if ( id_thread == 0 ) { + std::scoped_lock guard ( m_gc_mutex ); + // #ifdef DEBUG_GC + //displayMDDTableInfo(); + // #endif // DEBUG_GC + sylvan_gc_seq(); + // #ifdef DEBUG_GC + //displayMDDTableInfo(); + // #endif // DEBUG_GC + } + + //pthread_spin_lock(&m_accessible); + + MDD reduced_meta = Accessible_epsilon ( get_successor ( e.first.second, t ) ); + ldd_refs_push ( reduced_meta ); + reached_class = new LDDState(); + reached_class->m_lddstate = reduced_meta; + m_graph_mutex.lock(); + LDDState *pos = m_graph->find ( reached_class ); + if ( !pos ) { + // cout<<"not found"<<endl; + + m_graph->addArc(); + m_graph->insert ( reached_class ); + m_graph_mutex.unlock(); + //reached_class->setDiv(Set_Div(reduced_meta)); + //reached_class->setDeadLock(Set_Bloc(reduced_meta)); + fire = firable_obs ( reduced_meta ); + reached_class->setDeadLock ( Set_Bloc ( reduced_meta ) ); + reached_class->setDiv ( Set_Div ( reduced_meta ) ); + + + m_common_stack.push ( Pair ( couple ( reached_class, reduced_meta ), fire ) ); + + e.first.first->Successors.insert ( e.first.first->Successors.begin(), LDDEdge ( reached_class, t ) ); + reached_class->Predecessors.insert ( reached_class->Predecessors.begin(), LDDEdge ( e.first.first, t ) ); + + //pthread_mutex_lock(&m_mutex); + + + } else { + m_graph->addArc(); + m_graph_mutex.unlock(); + e.first.first->Successors.insert ( e.first.first->Successors.begin(), LDDEdge ( pos, t ) ); + pos->Predecessors.insert ( pos->Predecessors.begin(), LDDEdge ( e.first.first, t ) ); + delete reached_class; + } + if ( id_thread ) { + std::scoped_lock guard ( m_supervise_gc_mutex ); + m_gc--; + if ( m_gc == 0 ) { + m_gc_mutex.unlock(); + } + + } + } + e.first.first->setCompletedSucc(); + } //end advance + m_terminaison--; + } + + } while ( !m_finish ); + pthread_barrier_wait ( &m_barrier_builder ); + +} + +void ModelCheckerThV2::threadHandler ( void *context ) +{ + ( ( ModelCheckerThV2* ) context )->Compute_successors(); +} + +void ModelCheckerThV2::ComputeTh_Succ() +{ + + m_id_thread = 0; + + + + /* pthread_barrier_init(&m_barrier_threads, NULL, m_nb_thread+1);*/ + pthread_barrier_init ( &m_barrier_builder, NULL, m_nb_thread + 1 ); + + + m_gc=0; + m_terminaison=0; + m_finish=false; + for ( int i = 0; i < m_nb_thread; i++ ) { + int rc; + m_list_thread[i]= new thread ( threadHandler,this ); + if ( m_list_thread==nullptr ) { + cout << "error: pthread_create, rc: " << rc << endl; + } + } +} + +ModelCheckerThV2::~ModelCheckerThV2() +{ + m_finish = true; + pthread_barrier_wait ( &m_barrier_builder ); + for ( int i = 0; i < m_nb_thread; i++ ) { + m_list_thread[i]->join(); + delete m_list_thread[i]; + } + +} + diff --git a/src/ModelCheckerThV2.h b/src/ModelCheckerThV2.h new file mode 100644 index 0000000000000000000000000000000000000000..987b7de6839b784acd23b2f352655a6dae8fda60 --- /dev/null +++ b/src/ModelCheckerThV2.h @@ -0,0 +1,37 @@ +#ifndef MODELCHECKERTHV2_H +#define MODELCHECKERTHV2_H +#include "ModelCheckBaseMT.h" +#include "stacksafe.h" +#include <atomic> +#include <thread> +#include <mutex> +typedef pair<LDDState *, int> couple_th; +typedef stack<pair<LDDState *,int>> pile_t; + +class ModelCheckerThV2 : public ModelCheckBaseMT +{ +public: + ModelCheckerThV2(const NewNet &R,int nbThread); + ~ModelCheckerThV2(); + LDDState * getInitialMetaState(); + void buildSucc(LDDState *agregate); + static void threadHandler(void *context); + void Compute_successors(); + void ComputeTh_Succ(); +private: + void preConfigure(); + + + StackSafe<Pair> m_common_stack; + bool m_started=false; + + int m_id_thread; + std::mutex m_mutex,m_graph_mutex,m_gc_mutex,m_supervise_gc_mutex; + pthread_barrier_t m_barrier_builder; + atomic<uint32_t> m_gc,m_terminaison; // + volatile bool m_finish=false; + bool m_finish_initial=false; + pthread_mutex_t m_mutex_stack[128]; + thread* m_list_thread[128]; +}; +#endif diff --git a/src/main.cpp b/src/main.cpp index 0f773efc82f9ba2c159f83413559b7dde77423bd..aa3f8247b37efade5a5cef9fc755b584d2602164 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,6 +13,7 @@ #include "LDDGraph.h" #include "ModelCheckLace.h" #include "ModelCheckerTh.h" +#include "ModelCheckerThV2.h" #include <spot/misc/version.hh> #include <spot/twaalgos/dot.hh> @@ -118,12 +119,14 @@ int main(int argc, char **argv) { MPI_Comm_rank(MPI_COMM_WORLD, &task_id); if (n_tasks == 1) { - if (n_tasks == 1 && (!strcmp(argv[1], "otfL") || !strcmp(argv[1], "otfP"))) { + if (n_tasks == 1 && (!strcmp(argv[1], "otfL") || !strcmp(argv[1], "otfC") || !strcmp(argv[1], "otfP"))) { cout << "Performing on the fly Model checking..." << endl; if (!strcmp(argv[1], "otfP")) cout << "Multi-threaded algorithm based on Pthread library!" << endl; - else + else if (!strcmp(argv[1], "otfL")) cout << "Multi-threaded algorithm based on Lace framework!" << endl; + else + cout << "Multi-threaded algorithm based on C++ Thread library!" << endl; cout << "Building automata for not(formula)\n"; auto d = spot::make_bdd_dict(); @@ -144,8 +147,10 @@ int main(int argc, char **argv) { ModelCheckBaseMT *mcl; if (!strcmp(argv[1], "otfL")) mcl = new ModelCheckLace(Rnewnet, nb_th); - else + else if (!strcmp(argv[1], "otfP")) mcl = new ModelCheckerTh(Rnewnet, nb_th); + else + mcl = new ModelCheckerThV2(Rnewnet, nb_th); mcl->loadNet(); auto k = std::make_shared<SogKripkeTh>(d, mcl, Rnewnet.getListTransitionAP(), Rnewnet.getListPlaceAP()); cout << "Performing on the fly Modelchecking" << endl; diff --git a/src/stacksafe.cpp b/src/stacksafe.cpp new file mode 100644 index 0000000000000000000000000000000000000000..de7f260f0ef86460ca808ac1f0e59367fd703f3f --- /dev/null +++ b/src/stacksafe.cpp @@ -0,0 +1,64 @@ +/* + * Copyright 2020 chiheb <email> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "stacksafe.h" + +template<typename T> +StackSafe<T>::StackSafe() {} + +template<typename T> +StackSafe<T>::StackSafe ( const StackSafe& other) +{ + std::scoped_lock lock ( other.m_mutex ); + m_data=other.m_data; +} + +template<typename T> +void StackSafe<T>::push ( T new_value ){ + std::scoped_lock lock ( m_mutex ); + m_data.push ( std::move ( new_value ) ); +} +template<typename T> +std::shared_ptr<T> StackSafe<T>::pop() +{ + std::scoped_lock lock(m_mutex); + if(m_data.empty()) throw empty_stack(); + std::shared_ptr<T> const res(std::make_shared<T>(m_data.top())); + m_data.pop(); + return res; +} +template<typename T> +void StackSafe<T>::pop(T& value) +{ + std::scoped_lock lock(m_mutex); + if(m_data.empty()) throw empty_stack(); + value=m_data.top(); + m_data.pop(); +} + +template<typename T> +bool StackSafe<T>::empty() const +{ + std::scoped_lock lock(m_mutex); + return m_data.empty(); +} + + + template class StackSafe<Pair>; + + + + diff --git a/src/stacksafe.h b/src/stacksafe.h new file mode 100644 index 0000000000000000000000000000000000000000..af33910ec32b554ffb4e7b048a53562c5e6e1af8 --- /dev/null +++ b/src/stacksafe.h @@ -0,0 +1,49 @@ +/* + * Copyright 2020 chiheb <email> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef STACKSAFE_H +#define STACKSAFE_H +#include <mutex> +/** + * @todo A thread safe stack + */ +#include "LDDState.h" +#include <exception> +#include <memory> +#include <stack> +#include <exception> +typedef pair<LDDState *, MDD> couple; +typedef pair<couple, Set> Pair; +struct empty_stack: std::exception { + ~empty_stack() {}; + const char* what() const noexcept {return "heloo";} + + }; +template<typename T> class StackSafe { + private: + std::stack<T> m_data; + mutable std::mutex m_mutex; + public: + explicit StackSafe(); + ~StackSafe() {}; + StackSafe ( const StackSafe& other); + StackSafe& operator= ( const StackSafe& ) = delete; + void push ( T new_value ); + std::shared_ptr<T> pop(); + void pop ( T& value ); + bool empty() const; + }; +#endif // STACKSAFE_H