// -*- coding: utf-8 -*- // Copyright (C) 2019, 2020 Laboratoire de Recherche et // Developpement de l'Epita // // This file is part of Spot, a model checking library. // // Spot is free software; you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // // Spot is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public // License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include namespace spot { template static SPOT_API ec_stats instanciate(kripke_ptr sys, spot::twacube_ptr prop = nullptr, bool trace = false) { // FIXME ensure that algo_name contains all methods spot::timer_map tm; std::atomic stop(false); unsigned nbth = sys->get_threads(); typename algo_name::shared_map map; std::vector swarmed(nbth); // The shared structure requires sometime one instance per thread using struct_name = typename algo_name::shared_struct; std::vector ss(nbth); tm.start("Initialisation"); for (unsigned i = 0; i < nbth; ++i) { ss[i] = algo_name::make_shared_structure(map, i); swarmed[i] = new algo_name(*sys, prop, map, ss[i], i, stop); } tm.stop("Initialisation"); // Spawn Threads std::mutex iomutex; std::atomic barrier(true); std::vector threads(nbth); for (unsigned i = 0; i < nbth; ++i) { threads[i] = std::thread ([&swarmed, &iomutex, i, &barrier] { #if defined(unix) || defined(__unix__) || defined(__unix) { std::lock_guard iolock(iomutex); std::cout << "Thread #" << i << ": on CPU " << sched_getcpu() << '\n'; } #endif // Wait all threads to be instanciated. while (barrier) continue; swarmed[i]->run(); }); #if defined(unix) || defined(__unix__) || defined(__unix) // Pins threads to a dedicated core. cpu_set_t cpuset; CPU_ZERO(&cpuset); CPU_SET(i, &cpuset); int rc = pthread_setaffinity_np(threads[i].native_handle(), sizeof(cpu_set_t), &cpuset); if (rc != 0) { std::lock_guard iolock(iomutex); std::cerr << "Error calling pthread_setaffinity_np: " << rc << '\n'; } #endif } tm.start("Run"); barrier.store(false); for (auto& t: threads) t.join(); tm.stop("Run"); // Build the result ec_stats result; for (unsigned i = 0; i < nbth; ++i) { result.name.emplace_back(swarmed[i]->name()); result.walltime.emplace_back(swarmed[i]->walltime()); result.states.emplace_back(swarmed[i]->states()); result.transitions.emplace_back(swarmed[i]->transitions()); result.sccs.emplace_back(swarmed[i]->sccs()); result.value.emplace_back(swarmed[i]->result()); } if (trace) { bool go_on = true; for (unsigned i = 0; i < nbth && go_on; ++i) { // Enumerate cases where a trace can be extraced // Here we use a switch so that adding new algortihm // with new return status will trigger an error that // should the be fixed here. switch (result.value[i]) { // A (partial?) trace has been computed case mc_rvalue::DEADLOCK: case mc_rvalue::NOT_EMPTY: result.trace = swarmed[i]->trace(); go_on = false; break; // Nothing to do here. case mc_rvalue::NO_DEADLOCK: case mc_rvalue::EMPTY: case mc_rvalue::SUCCESS: case mc_rvalue::FAILURE: break; } } } for (unsigned i = 0; i < nbth; ++i) { delete swarmed[i]; delete ss[i]; } return result; } template static ec_stats ec_instanciator(const mc_algorithm algo, kripke_ptr sys, spot::twacube_ptr prop = nullptr, bool trace = false) { if (algo == mc_algorithm::BLOEMEN_EC || algo == mc_algorithm::CNDFS || algo == mc_algorithm::SWARMING) { SPOT_ASSERT(prop != nullptr); SPOT_ASSERT(sys->ap().size() == prop->ap().size()); for (unsigned int i = 0; i < sys->ap().size(); ++i) SPOT_ASSERT(sys->ap()[i].compare(prop->ap()[i]) == 0); } switch (algo) { case mc_algorithm::BLOEMEN_SCC: return instanciate, kripke_ptr, State, Iterator, Hash, Equal> (sys, prop, trace); case mc_algorithm::BLOEMEN_EC: return instanciate, kripke_ptr, State, Iterator, Hash, Equal> (sys, prop, trace); case mc_algorithm::CNDFS: return instanciate, kripke_ptr, State, Iterator, Hash, Equal> (sys, prop, trace); case mc_algorithm::DEADLOCK: return instanciate, kripke_ptr, State, Iterator, Hash, Equal> (sys, prop, trace); case mc_algorithm::SWARMING: return instanciate, kripke_ptr, State, Iterator, Hash, Equal> (sys, prop, trace); } } }