Skip to content

Commit

Permalink
take 2: switch to boost::thread
Browse files Browse the repository at this point in the history
Summary:
boost::thread lets us choose the stack size
Now working on gcc 4.9!

Reviewed By: int3

Differential Revision: D6780803

fbshipit-source-id: 73349d00fbc2f256d1680a254ecdeecbb98809d3
  • Loading branch information
Justin Hendrick authored and facebook-github-bot committed Jan 26, 2018
1 parent a32424c commit 223a562
Show file tree
Hide file tree
Showing 9 changed files with 197 additions and 42 deletions.
9 changes: 6 additions & 3 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ libredex_la_LIBADD = \
$(BOOST_SYSTEM_LIB) \
$(BOOST_REGEX_LIB) \
$(BOOST_IOSTREAMS_LIB) \
-lpthread
-lpthread \
-lboost_thread

#
# redex-all: the main executable
Expand Down Expand Up @@ -234,7 +235,8 @@ redex_all_LDADD = \
$(BOOST_SYSTEM_LIB) \
$(BOOST_REGEX_LIB) \
$(BOOST_PROGRAM_OPTIONS_LIB) \
-lpthread
-lpthread \
-lboost_thread

redex_all_LDFLAGS = \
-rdynamic # function names in stack traces
Expand All @@ -251,7 +253,8 @@ redexdump_LDADD = \
$(BOOST_FILESYSTEM_LIB) \
$(BOOST_SYSTEM_LIB) \
$(BOOST_REGEX_LIB) \
-lpthread
-lpthread \
-lboost_thread

#
# redex: Python driver script
Expand Down
4 changes: 2 additions & 2 deletions cmake_modules/Commons.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ macro(set_common_cxx_flags_for_redex)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /MT")
set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /MT")
set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /MT")
else ()
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -Wall")
set(COMMON_CXX_FLAGS_NODBG, "-O3")
Expand All @@ -25,7 +25,7 @@ macro(set_common_cxx_flags_for_redex)
endmacro()

macro(add_dependent_packages_for_redex)
find_package(Boost 1.56.0 REQUIRED COMPONENTS regex filesystem program_options iostreams)
find_package(Boost 1.56.0 REQUIRED COMPONENTS regex filesystem program_options iostreams thread)
print_dirs("${Boost_INCLUDE_DIRS}" "Boost_INCLUDE_DIRS")
print_dirs("${Boost_LIBRARIES}" "Boost_LIBRARIES")

Expand Down
1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ AX_BOOST_SYSTEM
AX_BOOST_REGEX
AX_BOOST_PROGRAM_OPTIONS
AX_BOOST_IOSTREAMS
AX_BOOST_THREAD
AC_CHECK_LIB([z], [adler32], [], [AC_MSG_ERROR([Please install zlib])])
AC_CHECK_LIB([jsoncpp], [main], [], [AC_MSG_ERROR([Please install jsoncpp])])

Expand Down
2 changes: 1 addition & 1 deletion get_boost.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ set -e
wget https://dl.bintray.com/boostorg/release/1.64.0/source/boost_1_64_0.tar.bz2
tar --bzip2 -xf boost_1_64_0.tar.bz2
cd boost_1_64_0
./bootstrap.sh --with-libraries=filesystem,iostreams,program_options,regex,system
./bootstrap.sh --with-libraries=filesystem,iostreams,program_options,regex,system,thread
./b2 -d0 install
17 changes: 1 addition & 16 deletions libredex/WeakTopologicalOrdering.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
#include <iterator>
#include <limits>
#include <stack>
#include <thread>
#include <vector>
#include <unordered_map>

Expand Down Expand Up @@ -206,7 +205,6 @@ class WeakTopologicalOrdering final {
}

private:
constexpr size_t max_depth() { return 1000; }

// We keep the notations used by Bourdoncle in the paper to describe the
// algorithm.
Expand All @@ -219,20 +217,7 @@ class WeakTopologicalOrdering final {
uint32_t succ_dfn = get_dfn(succ);
uint32_t min;
if (succ_dfn == 0) {
if (depth < max_depth()) {
min = visit(succ, partition, depth + 1);
} else {
// If the depth-first search dives too deep into the graph, we fork
// the computation into a new thread, which eases pressure on the
// stack (a new thread gets its own stack space).
std::packaged_task<uint32_t()> task(
[=] { return visit(succ, partition, 0); });
std::future<uint32_t> f = task.get_future();
std::thread t(std::move(task));
f.wait();
min = f.get();
t.join();
}
min = visit(succ, partition, depth + 1);
} else {
min = succ_dfn;
};
Expand Down
23 changes: 13 additions & 10 deletions libredex/WorkQueue.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
#include "Debug.h"

#include <algorithm>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <chrono>
#include <mutex>
#include <numeric>
#include <queue>
#include <random>
#include <thread>

namespace workqueue_impl {

Expand All @@ -44,14 +44,14 @@ inline std::vector<int> create_permutation(int num, unsigned int thread_idx) {
template <class Input, class Data, class Output>
struct WorkerState {
std::queue<Input> queue;
std::mutex queue_mtx;
boost::mutex queue_mtx;
Data data;
Output result;

WorkerState(const Data& initial) : data(initial) {}

bool pop_task(Input& task) {
std::lock_guard<std::mutex> guard(queue_mtx);
boost::lock_guard<boost::mutex> guard(queue_mtx);
if (!queue.empty()) {
task = std::move(queue.front());
queue.pop();
Expand Down Expand Up @@ -122,7 +122,7 @@ template <class Input>
WorkQueue<Input, std::nullptr_t /*Data*/, std::nullptr_t /*Output*/>
workqueue_foreach(const std::function<void(Input)>& func,
unsigned int num_threads =
std::max(1u, std::thread::hardware_concurrency())) {
std::max(1u, boost::thread::hardware_concurrency())) {
using Data = std::nullptr_t;
using Output = std::nullptr_t;
return WorkQueue<Input, Data, Output>(
Expand All @@ -143,8 +143,8 @@ template <class Input, class Output>
WorkQueue<Input, std::nullptr_t /*Data*/, Output> workqueue_mapreduce(
const std::function<Output(Input)>& mapper,
const std::function<Output(Output, Output)>& reducer,
unsigned int num_threads = std::max(1u,
std::thread::hardware_concurrency())) {
unsigned int num_threads =
std::max(1u, boost::thread::hardware_concurrency())) {
using Data = std::nullptr_t;
return WorkQueue<Input, Data, Output>(
[mapper](Data&, Input a) -> Output { return mapper(a); },
Expand All @@ -157,7 +157,7 @@ template <class Input, class Data, class Output>
void WorkQueue<Input, Data, Output>::add_item(Input task) {
if (m_currently_running) {
auto insert_idx = rand() % m_num_threads;
std::lock_guard<std::mutex> guard(m_states[insert_idx]->queue_mtx);
boost::lock_guard<boost::mutex> guard(m_states[insert_idx]->queue_mtx);
m_states[insert_idx]->queue.push(task);
} else {
m_insert_idx = (m_insert_idx + 1) % m_num_threads;
Expand All @@ -172,7 +172,7 @@ void WorkQueue<Input, Data, Output>::add_item(Input task) {
template <class Input, class Data, class Output>
Output WorkQueue<Input, Data, Output>::run_all(const Output& init_output) {
m_currently_running = true;
std::vector<std::thread> all_threads;
std::vector<boost::thread> all_threads;
auto worker = [&](WorkerState<Input, Data, Output>* state, size_t state_idx) {
state->result = init_output;
auto attempts =
Expand All @@ -195,7 +195,10 @@ Output WorkQueue<Input, Data, Output>::run_all(const Output& init_output) {
};

for (size_t i = 0; i < m_num_threads; ++i) {
all_threads.emplace_back(worker, m_states[i].get(), i);
boost::thread::attributes attrs;
attrs.set_stack_size(8 * 1024 * 1024);
all_threads.emplace_back(attrs,
boost::bind<void>(worker, m_states[i].get(), i));
}

for (auto& thread : all_threads) {
Expand Down
163 changes: 163 additions & 0 deletions m4/ax_boost_thread.m4
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_boost_thread.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_BOOST_THREAD
#
# DESCRIPTION
#
# Test for Thread library from the Boost C++ libraries. The macro requires
# a preceding call to AX_BOOST_BASE. Further documentation is available at
# <http://randspringer.de/boost/index.html>.
#
# This macro calls:
#
# AC_SUBST(BOOST_THREAD_LIB)
#
# And sets:
#
# HAVE_BOOST_THREAD
#
# LICENSE
#
# Copyright (c) 2009 Thomas Porschberg <[email protected]>
# Copyright (c) 2009 Michael Tindal
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.

#serial 31

AC_DEFUN([AX_BOOST_THREAD],
[
AC_ARG_WITH([boost-thread],
AS_HELP_STRING([--with-boost-thread@<:@=special-lib@:>@],
[use the Thread library from boost -
it is possible to specify a certain library for the linker
e.g. --with-boost-thread=boost_thread-gcc-mt ]),
[
if test "$withval" = "yes"; then
want_boost="yes"
ax_boost_user_thread_lib=""
else
want_boost="yes"
ax_boost_user_thread_lib="$withval"
fi
],
[want_boost="yes"]
)
if test "x$want_boost" = "xyes"; then
AC_REQUIRE([AC_PROG_CC])
AC_REQUIRE([AC_CANONICAL_BUILD])
CPPFLAGS_SAVED="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
export CPPFLAGS
LDFLAGS_SAVED="$LDFLAGS"
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
export LDFLAGS
AC_CACHE_CHECK(whether the Boost::Thread library is available,
ax_cv_boost_thread,
[AC_LANG_PUSH([C++])
CXXFLAGS_SAVE=$CXXFLAGS
if test "x$host_os" = "xsolaris" ; then
CXXFLAGS="-pthreads $CXXFLAGS"
elif test "x$host_os" = "xmingw32" ; then
CXXFLAGS="-mthreads $CXXFLAGS"
else
CXXFLAGS="-pthread $CXXFLAGS"
fi
AC_COMPILE_IFELSE([
AC_LANG_PROGRAM(
[[@%:@include <boost/thread/thread.hpp>]],
[[boost::thread_group thrds;
return 0;]])],
ax_cv_boost_thread=yes, ax_cv_boost_thread=no)
CXXFLAGS=$CXXFLAGS_SAVE
AC_LANG_POP([C++])
])
if test "x$ax_cv_boost_thread" = "xyes"; then
if test "x$host_os" = "xsolaris" ; then
BOOST_CPPFLAGS="-pthreads $BOOST_CPPFLAGS"
elif test "x$host_os" = "xmingw32" ; then
BOOST_CPPFLAGS="-mthreads $BOOST_CPPFLAGS"
else
BOOST_CPPFLAGS="-pthread $BOOST_CPPFLAGS"
fi
AC_SUBST(BOOST_CPPFLAGS)
AC_DEFINE(HAVE_BOOST_THREAD,,
[define if the Boost::Thread library is available])
BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
LDFLAGS_SAVE=$LDFLAGS
case "x$host_os" in
*bsd* )
LDFLAGS="-pthread $LDFLAGS"
break;
;;
esac
if test "x$ax_boost_user_thread_lib" = "x"; then
for libextension in `ls -r $BOOSTLIBDIR/libboost_thread* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'`; do
ax_lib=${libextension}
AC_CHECK_LIB($ax_lib, exit,
[link_thread="yes"; break],
[link_thread="no"])
done
if test "x$link_thread" != "xyes"; then
for libextension in `ls -r $BOOSTLIBDIR/boost_thread* 2>/dev/null | sed 's,.*/,,' | sed 's,\..*,,'`; do
ax_lib=${libextension}
AC_CHECK_LIB($ax_lib, exit,
[link_thread="yes"; break],
[link_thread="no"])
done
fi
else
for ax_lib in $ax_boost_user_thread_lib boost_thread-$ax_boost_user_thread_lib; do
AC_CHECK_LIB($ax_lib, exit,
[link_thread="yes"; break],
[link_thread="no"])
done
fi
if test "x$ax_lib" = "x"; then
AC_MSG_ERROR(Could not find a version of the library!)
fi
if test "x$link_thread" = "xno"; then
AC_MSG_ERROR(Could not link against $ax_lib !)
else
BOOST_THREAD_LIB="-l$ax_lib"
case "x$host_os" in
*bsd* )
BOOST_LDFLAGS="-pthread $BOOST_LDFLAGS"
break;
;;
xsolaris )
BOOST_THREAD_LIB="$BOOST_THREAD_LIB -lpthread"
break;
;;
xmingw32 )
break;
;;
* )
BOOST_THREAD_LIB="$BOOST_THREAD_LIB -lpthread"
break;
;;
esac
AC_SUBST(BOOST_THREAD_LIB)
fi
fi
CPPFLAGS="$CPPFLAGS_SAVED"
LDFLAGS="$LDFLAGS_SAVED"
fi
])
14 changes: 7 additions & 7 deletions test/unit/TraceMultithreadingTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*/

#include <gtest/gtest.h>
#include <thread>
#include <boost/thread/thread.hpp>
#include <vector>

#include "Trace.h"
Expand All @@ -21,20 +21,20 @@ TEST(TraceMultithreadingTest, singleThread) {
}

TEST(TraceMultithreadingTest, multipleThreadsOnePrint) {
std::vector<std::thread> threads;
std::vector<boost::thread> threads;
for (size_t idx = 0; idx < NUM_THREADS; ++idx) {
threads.emplace_back(
std::thread([]() { TRACE(TIME, 1, "Test output!\n"); }));
boost::thread([]() { TRACE(TIME, 1, "Test output!\n"); }));
}
for (auto& thread : threads) {
thread.join();
}
}

TEST(TraceMultithreadingTest, multipleThreadsMultiplePrints) {
std::vector<std::thread> threads;
std::vector<boost::thread> threads;
for (size_t idx = 0; idx < NUM_THREADS; ++idx) {
threads.emplace_back(std::thread([]() {
threads.emplace_back(boost::thread([]() {
for (int j = 0; j < NUM_ITERS; ++j) {
TRACE(TIME, 1, "Test output count %d\n", j);
}
Expand All @@ -46,9 +46,9 @@ TEST(TraceMultithreadingTest, multipleThreadsMultiplePrints) {
}

TEST(TraceMultithreadingTest, localThreadContext) {
std::vector<std::thread> threads;
std::vector<boost::thread> threads;
for (size_t idx = 0; idx < NUM_THREADS; ++idx) {
threads.emplace_back(std::thread([]() {
threads.emplace_back(boost::thread([]() {
for (int j = 0; j < NUM_ITERS; ++j) {
TraceContext context("thread context");
TRACE(TIME, 1, "Test output count %d\n", j);
Expand Down
Loading

0 comments on commit 223a562

Please sign in to comment.