Add a --enable-pthread option to activate experimental threading code
* NEWS, README, doc/org/compile.org: Mention the option and its effect on compilation requirements. * configure.ac: Add the --enable-pthread option, and ENABLE_PTHREAD macro. * doc/org/g++wrap.in, spot/Makefile.am, spot/libspot.pc.in: Compile with -pthread conditionally. * spot/graph/graph.hh, spot/twa/twagraph.cc: Adjust the code to not use thread-local variables, and let the pthread code be optional. * .gitlab-ci.yml: Activate --enable-pthread in two configurations.
This commit is contained in:
parent
721d5695ec
commit
23908f3d2f
10 changed files with 79 additions and 32 deletions
|
|
@ -1,5 +1,5 @@
|
|||
## -*- coding: utf-8 -*-
|
||||
## Copyright (C) 2009, 2010, 2012, 2013, 2014, 2015, 2016, 2017, 2020
|
||||
## Copyright (C) 2009, 2010, 2012, 2013, 2014, 2015, 2016, 2017, 2020, 2022
|
||||
## Laboratoire de Recherche et Développement de l'Epita (LRDE).
|
||||
## Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||
## département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
||||
|
|
@ -35,7 +35,7 @@ SUBDIRS = misc priv tl graph twa twacube twaalgos ta taalgos kripke \
|
|||
|
||||
lib_LTLIBRARIES = libspot.la
|
||||
libspot_la_SOURCES =
|
||||
libspot_la_LDFLAGS = $(BUDDY_LDFLAGS) -no-undefined -pthread $(SYMBOLIC_LDFLAGS)
|
||||
libspot_la_LDFLAGS = $(BUDDY_LDFLAGS) -no-undefined @LIBSPOT_PTHREAD@ $(SYMBOLIC_LDFLAGS)
|
||||
libspot_la_LIBADD = \
|
||||
kripke/libkripke.la \
|
||||
misc/libmisc.la \
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <spot/misc/common.hh>
|
||||
#include <spot/misc/_config.h>
|
||||
#include <vector>
|
||||
#include <type_traits>
|
||||
#include <tuple>
|
||||
|
|
@ -28,7 +29,9 @@
|
|||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#ifdef SPOT_ENABLE_PTHREAD
|
||||
# include <thread>
|
||||
#endif // SPOT_ENABLE_PTHREAD
|
||||
|
||||
namespace spot
|
||||
{
|
||||
|
|
@ -1242,8 +1245,6 @@ namespace spot
|
|||
//std::cerr << "\nbefore\n";
|
||||
//dump_storage(std::cerr);
|
||||
const auto N = num_states();
|
||||
// Read threads once
|
||||
const unsigned nthreads = get_nthreads();
|
||||
|
||||
auto idx_list = std::vector<unsigned>(N+1);
|
||||
auto new_edges = edge_vector_t();
|
||||
|
|
@ -1265,13 +1266,17 @@ namespace spot
|
|||
// If we have few edge or only one threads
|
||||
// Benchmark few?
|
||||
auto bne = new_edges.begin();
|
||||
#ifdef SPOT_ENABLE_PTHREAD
|
||||
const unsigned nthreads = get_nthreads();
|
||||
if (nthreads == 1 || edges_.size() < 1000)
|
||||
#endif
|
||||
{
|
||||
for (auto s = 0u; s < N; ++s)
|
||||
std::stable_sort(bne + idx_list[s],
|
||||
bne + idx_list[s+1],
|
||||
p);
|
||||
}
|
||||
#ifdef SPOT_ENABLE_PTHREAD
|
||||
else
|
||||
{
|
||||
static auto tv = std::vector<std::thread>();
|
||||
|
|
@ -1291,7 +1296,7 @@ namespace spot
|
|||
t.join();
|
||||
tv.clear();
|
||||
}
|
||||
// Done
|
||||
#endif
|
||||
std::swap(edges_, new_edges);
|
||||
// Like after normal sort_edges, they need to be chained before usage
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,5 +8,5 @@ Description: A library of LTL and omega-automata algorithms for model checking
|
|||
URL: https://spot.lrde.epita.fr/
|
||||
Version: @PACKAGE_VERSION@
|
||||
Cflags: -I${includedir}
|
||||
Libs: -L${libdir} -lspot
|
||||
Libs: -L${libdir} -lspot @LIBSPOT_PTHREAD@
|
||||
Requires: libbddx
|
||||
|
|
|
|||
|
|
@ -372,7 +372,11 @@ namespace spot
|
|||
throw std::runtime_error(
|
||||
"twa_graph::merge_states() does not work on alternating automata");
|
||||
|
||||
#ifdef ENABLE_PTHREAD
|
||||
const unsigned nthreads = get_nthreads();
|
||||
#else
|
||||
constexpr unsigned nthreads = 1;
|
||||
#endif
|
||||
|
||||
typedef graph_t::edge_storage_t tr_t;
|
||||
g_.sort_edges_srcfirst_([](const tr_t& lhs, const tr_t& rhs)
|
||||
|
|
@ -511,9 +515,12 @@ namespace spot
|
|||
// << ((env_map.size()+player_map.size())/((float)n_states))
|
||||
// << '\n';
|
||||
|
||||
|
||||
// Check whether we can merge two states
|
||||
// and takes into account the self-loops
|
||||
auto state_equal = [&](unsigned s1, unsigned s2)
|
||||
auto state_equal = [&e_vec, &e_chain, &e_idx](unsigned s1, unsigned s2,
|
||||
std::vector<char>& checked1,
|
||||
std::vector<char>& checked2)
|
||||
{
|
||||
auto edge_data_comp = [](const auto& lhs,
|
||||
const auto& rhs)
|
||||
|
|
@ -528,10 +535,6 @@ namespace spot
|
|||
return false;
|
||||
};
|
||||
|
||||
|
||||
thread_local auto checked1 = std::vector<char>();
|
||||
thread_local auto checked2 = std::vector<char>();
|
||||
|
||||
auto [i1, nsl1, sl1, e1] = e_idx[s1];
|
||||
auto [i2, nsl2, sl2, e2] = e_idx[s2];
|
||||
|
||||
|
|
@ -612,10 +615,10 @@ namespace spot
|
|||
std::vector<unsigned> remap(nb_states, -1U);
|
||||
|
||||
// Check each hash
|
||||
auto check_ix = [&](unsigned ix)
|
||||
auto check_ix = [&](unsigned ix, std::vector<unsigned>& v,
|
||||
std::vector<char>& checked1,
|
||||
std::vector<char>& checked2)
|
||||
{
|
||||
// Reduce cache miss
|
||||
thread_local auto v = std::vector<unsigned>();
|
||||
v.clear();
|
||||
for (auto i = ix; i != -1U; i = hash_linked_list[i])
|
||||
v.push_back(i);
|
||||
|
|
@ -627,7 +630,7 @@ namespace spot
|
|||
for (unsigned jdx = 0; jdx < idx; ++jdx)
|
||||
{
|
||||
auto j = v[jdx];
|
||||
if (state_equal(j, i))
|
||||
if (state_equal(j, i, checked1, checked2))
|
||||
{
|
||||
remap[i] = (remap[j] != -1U) ? remap[j] : j;
|
||||
|
||||
|
|
@ -675,13 +678,19 @@ namespace spot
|
|||
|
||||
auto worker = [&upd, check_ix, nthreads](unsigned pid, auto begp, auto endp,
|
||||
auto bege, auto ende)
|
||||
{
|
||||
upd(begp, endp, pid);
|
||||
upd(bege, ende, pid);
|
||||
for (; begp != endp; upd(begp, endp, nthreads))
|
||||
check_ix(begp->second.first);
|
||||
for (; bege != ende; upd(bege, ende, nthreads))
|
||||
check_ix(bege->second.first);
|
||||
{
|
||||
// Temporary storage for list of edges to reduce cache misses
|
||||
std::vector<unsigned> v;
|
||||
// Vector reused by all invocations of state_equal to mark edges
|
||||
// that have been matched already.
|
||||
std::vector<char> checked1;
|
||||
std::vector<char> checked2;
|
||||
upd(begp, endp, pid);
|
||||
upd(bege, ende, pid);
|
||||
for (; begp != endp; upd(begp, endp, nthreads))
|
||||
check_ix(begp->second.first, v, checked1, checked2);
|
||||
for (; bege != ende; upd(bege, ende, nthreads))
|
||||
check_ix(bege->second.first, v, checked1, checked2);
|
||||
};
|
||||
|
||||
{
|
||||
|
|
@ -690,10 +699,12 @@ namespace spot
|
|||
auto bege = env_map.begin();
|
||||
auto ende = env_map.end();
|
||||
|
||||
|
||||
#ifdef ENABLE_PTHREAD
|
||||
if ((nthreads == 1) & (num_states() > 1000)) // Bound?
|
||||
{
|
||||
#endif // ENABLE_PTHREAD
|
||||
worker(0, begp, endp, bege, ende);
|
||||
#ifdef ENABLE_PTHREAD
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -711,6 +722,7 @@ namespace spot
|
|||
t.join();
|
||||
tv.clear();
|
||||
}
|
||||
#endif // ENABLE_PTHREAD
|
||||
}
|
||||
|
||||
for (auto& e: edges())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue