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
|
|
@ -22,9 +22,9 @@ debian-stable-gcc:
|
||||||
image: gitlab-registry.lrde.epita.fr/spot/buildenv/debian:stable
|
image: gitlab-registry.lrde.epita.fr/spot/buildenv/debian:stable
|
||||||
script:
|
script:
|
||||||
- autoreconf -vfi
|
- autoreconf -vfi
|
||||||
- ./configure --enable-max-accsets=256
|
- ./configure --enable-max-accsets=256 --enable-pthread
|
||||||
- make
|
- make
|
||||||
- make distcheck
|
- make distcheck DISTCHECK_CONFIGURE_FLAGS='--enable-max-accsets=256 --enable-pthread'
|
||||||
artifacts:
|
artifacts:
|
||||||
when: always
|
when: always
|
||||||
paths:
|
paths:
|
||||||
|
|
@ -111,7 +111,7 @@ alpine-gcc:
|
||||||
- autoreconf -vfi
|
- autoreconf -vfi
|
||||||
- ./configure
|
- ./configure
|
||||||
- make
|
- make
|
||||||
- make distcheck || { chmod -R u+w ./spot-*; false; }
|
- make distcheck DISTCHECK_CONFIGURE_FLAGS='--enable-pthread' || { chmod -R u+w ./spot-*; false; }
|
||||||
artifacts:
|
artifacts:
|
||||||
when: always
|
when: always
|
||||||
paths:
|
paths:
|
||||||
|
|
|
||||||
12
NEWS
12
NEWS
|
|
@ -1,5 +1,17 @@
|
||||||
New in spot 2.10.6.dev (not yet released)
|
New in spot 2.10.6.dev (not yet released)
|
||||||
|
|
||||||
|
Build:
|
||||||
|
|
||||||
|
- A new configure option --enable-pthread enable the compilation of
|
||||||
|
Spot with -pthread, and activate the parallel version of some
|
||||||
|
algorithms. If Spot is compiled with -pthread enabled, any user
|
||||||
|
linking with Spot should also link with the pthread library. In
|
||||||
|
order to not break existing build setups using Spot, this option
|
||||||
|
is currently disabled by default in this release. We plan to turn
|
||||||
|
it on by default in some future release. Third-party project
|
||||||
|
using Spot may want to start linking with -pthread in prevision
|
||||||
|
for this change.
|
||||||
|
|
||||||
Command-line tools:
|
Command-line tools:
|
||||||
|
|
||||||
- autfilt has a new options --aliases=drop|keep to specify
|
- autfilt has a new options --aliases=drop|keep to specify
|
||||||
|
|
|
||||||
6
README
6
README
|
|
@ -173,6 +173,12 @@ flags specific to Spot:
|
||||||
client code should be compiled with -D_GLIBCXX_DEBUG as well. This
|
client code should be compiled with -D_GLIBCXX_DEBUG as well. This
|
||||||
options should normally only be useful to run Spot's test-suite.
|
options should normally only be useful to run Spot's test-suite.
|
||||||
|
|
||||||
|
--enable-pthread
|
||||||
|
Build and link with the -pthread option, and activate a few
|
||||||
|
parallel variants of the algorithms. This is currently disabled
|
||||||
|
by default, as it require all third-party tools using Spot to
|
||||||
|
build with -pthread as well.
|
||||||
|
|
||||||
--enable-c++20
|
--enable-c++20
|
||||||
Build everything in C++20 mode. We use that in our build farm to
|
Build everything in C++20 mode. We use that in our build farm to
|
||||||
ensure that Spot can be used in C++20 projects as well.
|
ensure that Spot can be used in C++20 projects as well.
|
||||||
|
|
|
||||||
11
configure.ac
11
configure.ac
|
|
@ -53,6 +53,15 @@ AC_ARG_ENABLE([c++20],
|
||||||
[Compile in C++20 mode.])],
|
[Compile in C++20 mode.])],
|
||||||
[enable_20=$enableval], [enable_20=no])
|
[enable_20=$enableval], [enable_20=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE([pthread],
|
||||||
|
[AS_HELP_STRING([--enable-pthread],
|
||||||
|
[Allow libspot to use POSIX threads.])],
|
||||||
|
[enable_pthread=$enableval], [enable_pthread=no])
|
||||||
|
if test "$enable_pthread" = yes; then
|
||||||
|
AC_DEFINE([ENABLE_PTHREAD], [1], [Whether Spot is compiled with -pthread.])
|
||||||
|
AC_SUBST([LIBSPOT_PTHREAD], [-pthread])
|
||||||
|
fi
|
||||||
|
|
||||||
AC_ARG_ENABLE([doxygen],
|
AC_ARG_ENABLE([doxygen],
|
||||||
[AS_HELP_STRING([--enable-doxygen],
|
[AS_HELP_STRING([--enable-doxygen],
|
||||||
[enable generation of Doxygen documentation (requires Doxygen)])],
|
[enable generation of Doxygen documentation (requires Doxygen)])],
|
||||||
|
|
@ -150,7 +159,7 @@ AX_CHECK_BUDDY
|
||||||
AC_CHECK_FUNCS([times kill alarm sigaction sched_getcpu])
|
AC_CHECK_FUNCS([times kill alarm sigaction sched_getcpu])
|
||||||
|
|
||||||
oLIBS=$LIBS
|
oLIBS=$LIBS
|
||||||
LIBS="$LIBS -lpthread"
|
LIBS="$LIBS -pthread"
|
||||||
AC_CHECK_FUNCS([pthread_setaffinity_np])
|
AC_CHECK_FUNCS([pthread_setaffinity_np])
|
||||||
LIBS=$oLIBS
|
LIBS=$oLIBS
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -210,11 +210,14 @@ one library requiring another, you will need to link with the =bddx=
|
||||||
library. This should be as simple as adding =-lbddx= after =-lspot=
|
library. This should be as simple as adding =-lbddx= after =-lspot=
|
||||||
in the first three cases.
|
in the first three cases.
|
||||||
|
|
||||||
|
Similarly, if Spot has been configured with =--enable-pthread=, you
|
||||||
|
will need to add =-pthread= to the compiler flags.
|
||||||
|
|
||||||
In the fourth case where =libtool= is used to link against
|
In the fourth case where =libtool= is used to link against
|
||||||
=libspot.la= linking against =libbddx.la= should not be necessary because
|
=libspot.la= linking against =libbddx.la= should not be necessary because
|
||||||
Libtool already handles such dependencies. However the version of =libtool=
|
Libtool already handles such dependencies. However the version of =libtool=
|
||||||
distributed with Debian is patched to ignore those dependencies, so in this
|
distributed with Debian is patched to ignore those dependencies, so in this
|
||||||
case you 2
|
case you have to list all dependencies.
|
||||||
|
|
||||||
* Additional suggestions
|
* Additional suggestions
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# This is a wrapper around the compiler, to ensure that the code
|
# This is a wrapper around the compiler, to ensure that the code
|
||||||
# example run from the org-mode file are all linked with Spot.
|
# examples run from org-mode files are all linked with Spot.
|
||||||
#
|
#
|
||||||
# Also we save errors to org.errors, so that we can detect issues
|
# Also we save errors to org.errors, so that we can detect issues
|
||||||
# after org-mode has exported everything. Otherwise these errors
|
# after org-mode has exported everything. Otherwise these errors
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
@top_builddir@/libtool link @CXX@ @CXXFLAGS@ @CPPFLAGS@ -Wall -Werror \
|
@top_builddir@/libtool link @CXX@ @CXXFLAGS@ @CPPFLAGS@ -Wall -Werror \
|
||||||
-I@abs_top_builddir@ -I@abs_top_srcdir@ -I@abs_top_srcdir@/buddy/src \
|
-I@abs_top_builddir@ -I@abs_top_srcdir@ -I@abs_top_srcdir@/buddy/src \
|
||||||
"$@" @abs_top_builddir@/spot/libspot.la \
|
"$@" @abs_top_builddir@/spot/libspot.la \
|
||||||
@abs_top_builddir@/buddy/src/libbddx.la 2> errors.$$
|
@abs_top_builddir@/buddy/src/libbddx.la @LIBSPOT_PTHREAD@ 2> errors.$$
|
||||||
code=$?
|
code=$?
|
||||||
if test $code -ne 0 && test -s errors.$$; then
|
if test $code -ne 0 && test -s errors.$$; then
|
||||||
cat errors.$$ >>org.errors
|
cat errors.$$ >>org.errors
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
## -*- coding: utf-8 -*-
|
## -*- 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).
|
## Laboratoire de Recherche et Développement de l'Epita (LRDE).
|
||||||
## Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
|
## Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||||
## département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
## 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
|
lib_LTLIBRARIES = libspot.la
|
||||||
libspot_la_SOURCES =
|
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 = \
|
libspot_la_LIBADD = \
|
||||||
kripke/libkripke.la \
|
kripke/libkripke.la \
|
||||||
misc/libmisc.la \
|
misc/libmisc.la \
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <spot/misc/common.hh>
|
#include <spot/misc/common.hh>
|
||||||
|
#include <spot/misc/_config.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
@ -28,7 +29,9 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <thread>
|
#ifdef SPOT_ENABLE_PTHREAD
|
||||||
|
# include <thread>
|
||||||
|
#endif // SPOT_ENABLE_PTHREAD
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
|
|
@ -1242,8 +1245,6 @@ namespace spot
|
||||||
//std::cerr << "\nbefore\n";
|
//std::cerr << "\nbefore\n";
|
||||||
//dump_storage(std::cerr);
|
//dump_storage(std::cerr);
|
||||||
const auto N = num_states();
|
const auto N = num_states();
|
||||||
// Read threads once
|
|
||||||
const unsigned nthreads = get_nthreads();
|
|
||||||
|
|
||||||
auto idx_list = std::vector<unsigned>(N+1);
|
auto idx_list = std::vector<unsigned>(N+1);
|
||||||
auto new_edges = edge_vector_t();
|
auto new_edges = edge_vector_t();
|
||||||
|
|
@ -1265,13 +1266,17 @@ namespace spot
|
||||||
// If we have few edge or only one threads
|
// If we have few edge or only one threads
|
||||||
// Benchmark few?
|
// Benchmark few?
|
||||||
auto bne = new_edges.begin();
|
auto bne = new_edges.begin();
|
||||||
|
#ifdef SPOT_ENABLE_PTHREAD
|
||||||
|
const unsigned nthreads = get_nthreads();
|
||||||
if (nthreads == 1 || edges_.size() < 1000)
|
if (nthreads == 1 || edges_.size() < 1000)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
for (auto s = 0u; s < N; ++s)
|
for (auto s = 0u; s < N; ++s)
|
||||||
std::stable_sort(bne + idx_list[s],
|
std::stable_sort(bne + idx_list[s],
|
||||||
bne + idx_list[s+1],
|
bne + idx_list[s+1],
|
||||||
p);
|
p);
|
||||||
}
|
}
|
||||||
|
#ifdef SPOT_ENABLE_PTHREAD
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
static auto tv = std::vector<std::thread>();
|
static auto tv = std::vector<std::thread>();
|
||||||
|
|
@ -1291,7 +1296,7 @@ namespace spot
|
||||||
t.join();
|
t.join();
|
||||||
tv.clear();
|
tv.clear();
|
||||||
}
|
}
|
||||||
// Done
|
#endif
|
||||||
std::swap(edges_, new_edges);
|
std::swap(edges_, new_edges);
|
||||||
// Like after normal sort_edges, they need to be chained before usage
|
// 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/
|
URL: https://spot.lrde.epita.fr/
|
||||||
Version: @PACKAGE_VERSION@
|
Version: @PACKAGE_VERSION@
|
||||||
Cflags: -I${includedir}
|
Cflags: -I${includedir}
|
||||||
Libs: -L${libdir} -lspot
|
Libs: -L${libdir} -lspot @LIBSPOT_PTHREAD@
|
||||||
Requires: libbddx
|
Requires: libbddx
|
||||||
|
|
|
||||||
|
|
@ -372,7 +372,11 @@ namespace spot
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"twa_graph::merge_states() does not work on alternating automata");
|
"twa_graph::merge_states() does not work on alternating automata");
|
||||||
|
|
||||||
|
#ifdef ENABLE_PTHREAD
|
||||||
const unsigned nthreads = get_nthreads();
|
const unsigned nthreads = get_nthreads();
|
||||||
|
#else
|
||||||
|
constexpr unsigned nthreads = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef graph_t::edge_storage_t tr_t;
|
typedef graph_t::edge_storage_t tr_t;
|
||||||
g_.sort_edges_srcfirst_([](const tr_t& lhs, const tr_t& rhs)
|
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))
|
// << ((env_map.size()+player_map.size())/((float)n_states))
|
||||||
// << '\n';
|
// << '\n';
|
||||||
|
|
||||||
|
|
||||||
// Check whether we can merge two states
|
// Check whether we can merge two states
|
||||||
// and takes into account the self-loops
|
// 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,
|
auto edge_data_comp = [](const auto& lhs,
|
||||||
const auto& rhs)
|
const auto& rhs)
|
||||||
|
|
@ -528,10 +535,6 @@ namespace spot
|
||||||
return false;
|
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 [i1, nsl1, sl1, e1] = e_idx[s1];
|
||||||
auto [i2, nsl2, sl2, e2] = e_idx[s2];
|
auto [i2, nsl2, sl2, e2] = e_idx[s2];
|
||||||
|
|
||||||
|
|
@ -612,10 +615,10 @@ namespace spot
|
||||||
std::vector<unsigned> remap(nb_states, -1U);
|
std::vector<unsigned> remap(nb_states, -1U);
|
||||||
|
|
||||||
// Check each hash
|
// 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();
|
v.clear();
|
||||||
for (auto i = ix; i != -1U; i = hash_linked_list[i])
|
for (auto i = ix; i != -1U; i = hash_linked_list[i])
|
||||||
v.push_back(i);
|
v.push_back(i);
|
||||||
|
|
@ -627,7 +630,7 @@ namespace spot
|
||||||
for (unsigned jdx = 0; jdx < idx; ++jdx)
|
for (unsigned jdx = 0; jdx < idx; ++jdx)
|
||||||
{
|
{
|
||||||
auto j = v[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;
|
remap[i] = (remap[j] != -1U) ? remap[j] : j;
|
||||||
|
|
||||||
|
|
@ -676,12 +679,18 @@ namespace spot
|
||||||
auto worker = [&upd, check_ix, nthreads](unsigned pid, auto begp, auto endp,
|
auto worker = [&upd, check_ix, nthreads](unsigned pid, auto begp, auto endp,
|
||||||
auto bege, auto ende)
|
auto bege, auto ende)
|
||||||
{
|
{
|
||||||
|
// 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(begp, endp, pid);
|
||||||
upd(bege, ende, pid);
|
upd(bege, ende, pid);
|
||||||
for (; begp != endp; upd(begp, endp, nthreads))
|
for (; begp != endp; upd(begp, endp, nthreads))
|
||||||
check_ix(begp->second.first);
|
check_ix(begp->second.first, v, checked1, checked2);
|
||||||
for (; bege != ende; upd(bege, ende, nthreads))
|
for (; bege != ende; upd(bege, ende, nthreads))
|
||||||
check_ix(bege->second.first);
|
check_ix(bege->second.first, v, checked1, checked2);
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
@ -690,10 +699,12 @@ namespace spot
|
||||||
auto bege = env_map.begin();
|
auto bege = env_map.begin();
|
||||||
auto ende = env_map.end();
|
auto ende = env_map.end();
|
||||||
|
|
||||||
|
#ifdef ENABLE_PTHREAD
|
||||||
if ((nthreads == 1) & (num_states() > 1000)) // Bound?
|
if ((nthreads == 1) & (num_states() > 1000)) // Bound?
|
||||||
{
|
{
|
||||||
|
#endif // ENABLE_PTHREAD
|
||||||
worker(0, begp, endp, bege, ende);
|
worker(0, begp, endp, bege, ende);
|
||||||
|
#ifdef ENABLE_PTHREAD
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -711,6 +722,7 @@ namespace spot
|
||||||
t.join();
|
t.join();
|
||||||
tv.clear();
|
tv.clear();
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_PTHREAD
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& e: edges())
|
for (auto& e: edges())
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue