Import Geant4 11.1.0.beta source tree
This commit is contained in:
+123
@@ -0,0 +1,123 @@
|
||||
# -------------------------------------------------------------------------------------- #
|
||||
# General
|
||||
# -------------------------------------------------------------------------------------- #
|
||||
# Locate sources and headers for this project - headers are included so they will show up
|
||||
# in IDEs
|
||||
file(GLOB_RECURSE ptl_headers ${PROJECT_SOURCE_DIR}/include/PTL/*.hh
|
||||
${PROJECT_SOURCE_DIR}/include/PTL/*.icc)
|
||||
file(GLOB_RECURSE ptl_sources ${CMAKE_CURRENT_LIST_DIR}/*.cc)
|
||||
|
||||
# -------------------------------------------------------------------------------------- #
|
||||
# Config, Version
|
||||
# -------------------------------------------------------------------------------------- #
|
||||
|
||||
configure_file(${PROJECT_SOURCE_DIR}/cmake/Templates/Config.hh.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/PTL/Config.hh @ONLY)
|
||||
|
||||
list(APPEND ptl_headers ${CMAKE_CURRENT_BINARY_DIR}/PTL/Config.hh)
|
||||
|
||||
configure_file(${PROJECT_SOURCE_DIR}/cmake/Templates/Version.hh.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/PTL/Version.hh @ONLY)
|
||||
|
||||
list(APPEND ptl_headers ${CMAKE_CURRENT_BINARY_DIR}/PTL/Version.hh)
|
||||
|
||||
# -------------------------------------------------------------------------------------- #
|
||||
# PTL Library
|
||||
# -------------------------------------------------------------------------------------- #
|
||||
|
||||
if(BUILD_OBJECT_LIBS)
|
||||
|
||||
ptl_build_library(
|
||||
TYPE OBJECT
|
||||
TARGET_NAME ptl-object
|
||||
OUTPUT_NAME G4ptl-object
|
||||
SOURCES ${ptl_headers} ${ptl_sources})
|
||||
|
||||
target_link_libraries(ptl-object PUBLIC Threads::Threads)
|
||||
if(PTL_USE_TBB)
|
||||
target_link_libraries(ptl-object PUBLIC TBB::tbb)
|
||||
endif()
|
||||
|
||||
target_include_directories(
|
||||
ptl-object PUBLIC $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/source>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>)
|
||||
endif()
|
||||
|
||||
if(BUILD_SHARED_LIBS)
|
||||
|
||||
ptl_build_library(
|
||||
TYPE SHARED
|
||||
TARGET_NAME ptl-shared
|
||||
OUTPUT_NAME G4ptl
|
||||
SOURCES ${ptl_headers} ${ptl_sources})
|
||||
|
||||
target_link_libraries(ptl-shared PUBLIC Threads::Threads)
|
||||
if(PTL_USE_TBB)
|
||||
target_link_libraries(ptl-shared PUBLIC TBB::tbb)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(ptl-shared PUBLIC PTL_BUILD_DLL)
|
||||
|
||||
target_include_directories(
|
||||
ptl-shared
|
||||
PUBLIC $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
|
||||
$<INSTALL_INTERFACE:${PTL_INSTALL_INCLUDEDIR}>)
|
||||
|
||||
if(PTL_USE_SANITIZER AND NOT ("${PTL_SANITIZER_TYPE}" STREQUAL "leak"))
|
||||
string(REPLACE " " ";" _sanitize_args "${ptl_sanitize_args}")
|
||||
set_target_properties(ptl-shared PROPERTIES INTERFACE_LINK_OPTIONS
|
||||
"${_sanitize_args}")
|
||||
endif()
|
||||
|
||||
export(
|
||||
TARGETS ptl-shared
|
||||
NAMESPACE PTL::
|
||||
FILE ${PROJECT_BINARY_DIR}/ptl-shared.cmake)
|
||||
endif()
|
||||
|
||||
if(BUILD_STATIC_LIBS)
|
||||
|
||||
ptl_build_library(
|
||||
TYPE STATIC
|
||||
TARGET_NAME ptl-static
|
||||
OUTPUT_NAME $<IF:$<PLATFORM_ID:Windows>,G4ptl-static,G4ptl>
|
||||
SOURCES ${ptl_headers} ${ptl_sources})
|
||||
|
||||
target_link_libraries(ptl-static PUBLIC Threads::Threads)
|
||||
if(PTL_USE_TBB)
|
||||
target_link_libraries(ptl-static PUBLIC TBB::tbb)
|
||||
endif()
|
||||
|
||||
target_include_directories(
|
||||
ptl-static
|
||||
PUBLIC $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
|
||||
$<INSTALL_INTERFACE:${PTL_INSTALL_INCLUDEDIR}>)
|
||||
|
||||
export(
|
||||
TARGETS ptl-static
|
||||
NAMESPACE PTL::
|
||||
FILE ${PROJECT_BINARY_DIR}/ptl-static.cmake)
|
||||
endif()
|
||||
|
||||
# -------------------------------------------------------------------------------------- #
|
||||
# Installation
|
||||
# -------------------------------------------------------------------------------------- #
|
||||
|
||||
if(PTL_INSTALL_CONFIG)
|
||||
# install export
|
||||
install(
|
||||
EXPORT ${PROJECT_NAME}Targets
|
||||
NAMESPACE PTL::
|
||||
DESTINATION ${PTL_INSTALL_CMAKEDIR}
|
||||
COMPONENT Development)
|
||||
endif()
|
||||
|
||||
if(PTL_INSTALL_HEADERS)
|
||||
# headers
|
||||
install(
|
||||
FILES ${ptl_headers}
|
||||
DESTINATION ${PTL_INSTALL_INCLUDEDIR}/PTL
|
||||
COMPONENT Development)
|
||||
endif()
|
||||
+7
-2
@@ -52,8 +52,13 @@ task_group_counter()
|
||||
ThreadPool*
|
||||
get_default_threadpool()
|
||||
{
|
||||
if(TaskRunManager::GetMasterRunManager())
|
||||
return TaskRunManager::GetMasterRunManager()->GetThreadPool();
|
||||
auto* mrm = TaskRunManager::GetMasterRunManager();
|
||||
if(mrm)
|
||||
{
|
||||
if(!mrm->GetThreadPool())
|
||||
mrm->Initialize();
|
||||
return mrm->GetThreadPool();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
+27
-8
@@ -36,11 +36,24 @@ using namespace PTL;
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
TaskRunManager::pointer&
|
||||
TaskRunManager::GetPrivateMasterRunManager()
|
||||
{
|
||||
static pointer _instance = nullptr;
|
||||
return _instance;
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
TaskRunManager::pointer&
|
||||
TaskRunManager::GetPrivateMasterRunManager(bool init, bool useTBB)
|
||||
{
|
||||
static pointer _instance = (init) ? new TaskRunManager(useTBB) : nullptr;
|
||||
return _instance;
|
||||
auto& _v = GetPrivateMasterRunManager();
|
||||
if(!init)
|
||||
return _v;
|
||||
if(!_v)
|
||||
_v = new TaskRunManager(useTBB);
|
||||
return _v;
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
@@ -48,8 +61,8 @@ TaskRunManager::GetPrivateMasterRunManager(bool init, bool useTBB)
|
||||
TaskRunManager*
|
||||
TaskRunManager::GetMasterRunManager(bool useTBB)
|
||||
{
|
||||
static pointer& _instance = GetPrivateMasterRunManager(true, useTBB);
|
||||
return _instance;
|
||||
auto& _v = GetPrivateMasterRunManager(true, useTBB);
|
||||
return _v;
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
@@ -65,10 +78,8 @@ TaskRunManager::GetInstance(bool useTBB)
|
||||
TaskRunManager::TaskRunManager(bool useTBB)
|
||||
: m_workers(std::thread::hardware_concurrency())
|
||||
{
|
||||
if(!GetPrivateMasterRunManager(false))
|
||||
{
|
||||
GetPrivateMasterRunManager(false) = this;
|
||||
}
|
||||
if(!GetPrivateMasterRunManager())
|
||||
GetPrivateMasterRunManager() = this;
|
||||
|
||||
#if defined(PTL_USE_TBB)
|
||||
auto _useTBB = GetEnv<bool>("PTL_FORCE_TBB", GetEnv<bool>("FORCE_TBB", useTBB));
|
||||
@@ -83,6 +94,14 @@ TaskRunManager::TaskRunManager(bool useTBB)
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
TaskRunManager::~TaskRunManager()
|
||||
{
|
||||
if(GetPrivateMasterRunManager() == this)
|
||||
GetPrivateMasterRunManager() = nullptr;
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
void
|
||||
TaskRunManager::Initialize(uint64_t n)
|
||||
{
|
||||
|
||||
+282
-65
@@ -31,27 +31,18 @@
|
||||
#include "PTL/ThreadPool.hh"
|
||||
#include "PTL/Globals.hh"
|
||||
#include "PTL/ThreadData.hh"
|
||||
#include "PTL/Threading.hh"
|
||||
#include "PTL/UserTaskQueue.hh"
|
||||
#include "PTL/Utility.hh"
|
||||
#include "PTL/VUserTaskQueue.hh"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <thread>
|
||||
|
||||
using namespace PTL;
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
inline intmax_t
|
||||
ncores()
|
||||
{
|
||||
return static_cast<intmax_t>(Thread::hardware_concurrency());
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
ThreadPool::thread_id_map_t ThreadPool::f_thread_ids;
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
namespace
|
||||
{
|
||||
ThreadData*&
|
||||
@@ -63,7 +54,58 @@ thread_data()
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
bool ThreadPool::f_use_tbb = false;
|
||||
ThreadPool::thread_id_map_t&
|
||||
ThreadPool::f_thread_ids()
|
||||
{
|
||||
static auto _v = thread_id_map_t{};
|
||||
return _v;
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
bool&
|
||||
ThreadPool::f_use_tbb()
|
||||
{
|
||||
static bool _v = GetEnv<bool>("PTL_USE_TBB", false);
|
||||
return _v;
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
bool&
|
||||
ThreadPool::f_use_cpu_affinity()
|
||||
{
|
||||
static bool _v = GetEnv<bool>("PTL_CPU_AFFINITY", false);
|
||||
return _v;
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
int&
|
||||
ThreadPool::f_thread_priority()
|
||||
{
|
||||
static int _v = GetEnv<int>("PTL_THREAD_PRIORITY", 0);
|
||||
return _v;
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
int&
|
||||
ThreadPool::f_verbose()
|
||||
{
|
||||
static int _v = GetEnv<int>("PTL_VERBOSE", 0);
|
||||
return _v;
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
ThreadPool::size_type&
|
||||
ThreadPool::f_default_pool_size()
|
||||
{
|
||||
static size_type _v =
|
||||
GetEnv<size_type>("PTL_NUM_THREADS", Thread::hardware_concurrency());
|
||||
return _v;
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
// static member function that calls the member function we want the thread to
|
||||
@@ -71,14 +113,20 @@ bool ThreadPool::f_use_tbb = false;
|
||||
void
|
||||
ThreadPool::start_thread(ThreadPool* tp, thread_data_t* _data, intmax_t _idx)
|
||||
{
|
||||
if(tp->get_verbose() > 0)
|
||||
{
|
||||
AutoLock lock(TypeMutex<decltype(std::cerr)>());
|
||||
std::cerr << "[PTL::ThreadPool] Starting thread " << _idx << "..." << std::endl;
|
||||
}
|
||||
|
||||
auto _thr_data = std::make_shared<ThreadData>(tp);
|
||||
{
|
||||
AutoLock lock(TypeMutex<ThreadPool>(), std::defer_lock);
|
||||
if(!lock.owns_lock())
|
||||
lock.lock();
|
||||
if(_idx < 0)
|
||||
_idx = f_thread_ids.size();
|
||||
f_thread_ids[std::this_thread::get_id()] = _idx;
|
||||
_idx = f_thread_ids().size();
|
||||
f_thread_ids()[std::this_thread::get_id()] = _idx;
|
||||
Threading::SetThreadId(_idx);
|
||||
_data->emplace_back(_thr_data);
|
||||
}
|
||||
@@ -86,6 +134,13 @@ ThreadPool::start_thread(ThreadPool* tp, thread_data_t* _data, intmax_t _idx)
|
||||
tp->record_entry();
|
||||
tp->execute_thread(thread_data()->current_queue);
|
||||
tp->record_exit();
|
||||
|
||||
if(tp->get_verbose() > 0)
|
||||
{
|
||||
AutoLock lock(TypeMutex<decltype(std::cerr)>());
|
||||
std::cerr << "[PTL::ThreadPool] Thread " << _idx << " terminating..."
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
@@ -93,7 +148,7 @@ ThreadPool::start_thread(ThreadPool* tp, thread_data_t* _data, intmax_t _idx)
|
||||
bool
|
||||
ThreadPool::using_tbb()
|
||||
{
|
||||
return f_use_tbb;
|
||||
return f_use_tbb();
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
@@ -102,7 +157,19 @@ void
|
||||
ThreadPool::set_use_tbb(bool enable)
|
||||
{
|
||||
#if defined(PTL_USE_TBB)
|
||||
f_use_tbb = enable;
|
||||
f_use_tbb() = enable;
|
||||
#else
|
||||
ConsumeParameters<bool>(enable);
|
||||
#endif
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
// static member function that initialized tbb library
|
||||
void
|
||||
ThreadPool::set_default_use_cpu_affinity(bool enable)
|
||||
{
|
||||
#if defined(PTL_USE_TBB)
|
||||
f_use_cpu_affinity() = enable;
|
||||
#else
|
||||
ConsumeParameters<bool>(enable);
|
||||
#endif
|
||||
@@ -113,7 +180,31 @@ ThreadPool::set_use_tbb(bool enable)
|
||||
const ThreadPool::thread_id_map_t&
|
||||
ThreadPool::get_thread_ids()
|
||||
{
|
||||
return f_thread_ids;
|
||||
return f_thread_ids();
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
uintmax_t
|
||||
ThreadPool::get_thread_id(ThreadId _tid)
|
||||
{
|
||||
uintmax_t _idx = 0;
|
||||
{
|
||||
AutoLock lock(TypeMutex<ThreadPool>(), std::defer_lock);
|
||||
if(!lock.owns_lock())
|
||||
lock.lock();
|
||||
auto itr = f_thread_ids().find(_tid);
|
||||
if(itr == f_thread_ids().end())
|
||||
{
|
||||
_idx = f_thread_ids().size();
|
||||
f_thread_ids()[_tid] = _idx;
|
||||
}
|
||||
else
|
||||
{
|
||||
_idx = itr->second;
|
||||
}
|
||||
}
|
||||
return _idx;
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
@@ -121,42 +212,90 @@ ThreadPool::get_thread_ids()
|
||||
uintmax_t
|
||||
ThreadPool::get_this_thread_id()
|
||||
{
|
||||
auto _tid = ThisThread::get_id();
|
||||
{
|
||||
AutoLock lock(TypeMutex<ThreadPool>(), std::defer_lock);
|
||||
if(!lock.owns_lock())
|
||||
lock.lock();
|
||||
if(f_thread_ids.find(_tid) == f_thread_ids.end())
|
||||
{
|
||||
auto _idx = f_thread_ids.size();
|
||||
f_thread_ids[_tid] = _idx;
|
||||
}
|
||||
}
|
||||
return f_thread_ids[_tid];
|
||||
return get_thread_id(ThisThread::get_id());
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
ThreadPool::ThreadPool(const size_type& pool_size, VUserTaskQueue* task_queue,
|
||||
bool _use_affinity, affinity_func_t _affinity_func)
|
||||
: m_use_affinity(_use_affinity)
|
||||
, m_pool_state(std::make_shared<std::atomic_short>(thread_pool::state::NONINIT))
|
||||
, m_task_queue(task_queue)
|
||||
, m_affinity_func(std::move(_affinity_func))
|
||||
uintmax_t
|
||||
ThreadPool::add_thread_id(ThreadId _tid)
|
||||
{
|
||||
AutoLock lock(TypeMutex<ThreadPool>(), std::defer_lock);
|
||||
if(!lock.owns_lock())
|
||||
lock.lock();
|
||||
if(f_thread_ids().find(_tid) == f_thread_ids().end())
|
||||
{
|
||||
auto _idx = f_thread_ids().size();
|
||||
f_thread_ids()[_tid] = _idx;
|
||||
Threading::SetThreadId(_idx);
|
||||
}
|
||||
return f_thread_ids().at(_tid);
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
ThreadPool::Config::Config(bool _init, bool _use_tbb, bool _use_affinity, int _verbose,
|
||||
int _prio, size_type _size, VUserTaskQueue* _task_queue,
|
||||
affinity_func_t _affinity_func, initialize_func_t _init_func,
|
||||
finalize_func_t _fini_func)
|
||||
: init{ _init }
|
||||
, use_tbb{ _use_tbb }
|
||||
, use_affinity{ _use_affinity }
|
||||
, verbose{ _verbose }
|
||||
, priority{ _prio }
|
||||
, pool_size{ _size }
|
||||
, task_queue{ _task_queue }
|
||||
, set_affinity{ std::move(_affinity_func) }
|
||||
, initializer{ std::move(_init_func) }
|
||||
, finalizer{ std::move(_fini_func) }
|
||||
{}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
ThreadPool::ThreadPool(const Config& _cfg)
|
||||
: m_use_affinity{ _cfg.use_affinity }
|
||||
, m_tbb_tp{ _cfg.use_tbb }
|
||||
, m_verbose{ _cfg.verbose }
|
||||
, m_priority{ _cfg.priority }
|
||||
, m_pool_state{ std::make_shared<std::atomic_short>(thread_pool::state::NONINIT) }
|
||||
, m_task_queue{ _cfg.task_queue }
|
||||
, m_init_func{ _cfg.initializer }
|
||||
, m_fini_func{ _cfg.finalizer }
|
||||
, m_affinity_func{ _cfg.set_affinity }
|
||||
{
|
||||
auto master_id = get_this_thread_id();
|
||||
if(master_id != 0 && m_verbose > 1)
|
||||
std::cerr << "ThreadPool created on non-master slave" << std::endl;
|
||||
{
|
||||
AutoLock lock(TypeMutex<decltype(std::cerr)>());
|
||||
std::cerr << "[PTL::ThreadPool] ThreadPool created on worker thread" << std::endl;
|
||||
}
|
||||
|
||||
thread_data() = new ThreadData(this);
|
||||
|
||||
// initialize after get_this_thread_id so master is zero
|
||||
this->initialize_threadpool(pool_size);
|
||||
|
||||
if(!m_task_queue)
|
||||
m_task_queue = new UserTaskQueue(m_pool_size);
|
||||
if(_cfg.init)
|
||||
this->initialize_threadpool(_cfg.pool_size);
|
||||
}
|
||||
|
||||
ThreadPool::ThreadPool(const size_type& _pool_size, VUserTaskQueue* _task_queue,
|
||||
bool _use_affinity, affinity_func_t _affinity_func,
|
||||
initialize_func_t _init_func, finalize_func_t _fini_func)
|
||||
: ThreadPool{ Config{ true, f_use_tbb(), _use_affinity, f_verbose(), f_thread_priority(),
|
||||
_pool_size, _task_queue, std::move(_affinity_func),
|
||||
std::move(_init_func), std::move(_fini_func) } }
|
||||
{}
|
||||
|
||||
ThreadPool::ThreadPool(const size_type& pool_size, initialize_func_t _init_func,
|
||||
finalize_func_t _fini_func, bool _use_affinity,
|
||||
affinity_func_t _affinity_func, VUserTaskQueue* task_queue)
|
||||
: ThreadPool{ pool_size,
|
||||
task_queue,
|
||||
_use_affinity,
|
||||
std::move(_affinity_func),
|
||||
std::move(_init_func),
|
||||
std::move(_fini_func) }
|
||||
{}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
ThreadPool::~ThreadPool()
|
||||
@@ -188,7 +327,25 @@ ThreadPool::is_initialized() const
|
||||
//======================================================================================//
|
||||
|
||||
void
|
||||
ThreadPool::set_affinity(intmax_t i, Thread& _thread)
|
||||
ThreadPool::record_entry()
|
||||
{
|
||||
if(m_thread_active)
|
||||
++(*m_thread_active);
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
void
|
||||
ThreadPool::record_exit()
|
||||
{
|
||||
if(m_thread_active)
|
||||
--(*m_thread_active);
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
void
|
||||
ThreadPool::set_affinity(intmax_t i, Thread& _thread) const
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -196,14 +353,39 @@ ThreadPool::set_affinity(intmax_t i, Thread& _thread)
|
||||
intmax_t _pin = m_affinity_func(i);
|
||||
if(m_verbose > 0)
|
||||
{
|
||||
std::cout << "Setting pin affinity for thread " << _thread.get_id() << " to "
|
||||
<< _pin << std::endl;
|
||||
AutoLock lock(TypeMutex<decltype(std::cerr)>());
|
||||
std::cerr << "[PTL::ThreadPool] Setting pin affinity for thread "
|
||||
<< get_thread_id(_thread.get_id()) << " to " << _pin << std::endl;
|
||||
}
|
||||
Threading::SetPinAffinity(_pin, native_thread);
|
||||
} catch(std::runtime_error& e)
|
||||
{
|
||||
std::cout << "Error setting pin affinity" << std::endl;
|
||||
std::cerr << e.what() << std::endl; // issue assigning affinity
|
||||
std::cerr << "[PTL::ThreadPool] Error setting pin affinity: " << e.what()
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
void
|
||||
ThreadPool::set_priority(int _prio, Thread& _thread) const
|
||||
{
|
||||
try
|
||||
{
|
||||
NativeThread native_thread = _thread.native_handle();
|
||||
if(m_verbose > 0)
|
||||
{
|
||||
AutoLock lock(TypeMutex<decltype(std::cerr)>());
|
||||
std::cerr << "[PTL::ThreadPool] Setting thread "
|
||||
<< get_thread_id(_thread.get_id()) << " priority to " << _prio
|
||||
<< std::endl;
|
||||
}
|
||||
Threading::SetThreadPriority(_prio, native_thread);
|
||||
} catch(std::runtime_error& e)
|
||||
{
|
||||
AutoLock lock(TypeMutex<decltype(std::cerr)>());
|
||||
std::cerr << "[PTL::ThreadPool] Error setting thread priority: " << e.what()
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,7 +407,7 @@ ThreadPool::initialize_threadpool(size_type proposed_size)
|
||||
#if defined(PTL_USE_TBB)
|
||||
//--------------------------------------------------------------------//
|
||||
// handle tbb task scheduler
|
||||
if(f_use_tbb || m_tbb_tp)
|
||||
if(m_tbb_tp)
|
||||
{
|
||||
m_tbb_tp = true;
|
||||
m_pool_size = proposed_size;
|
||||
@@ -243,14 +425,19 @@ ThreadPool::initialize_threadpool(size_type proposed_size)
|
||||
tbb::global_control::max_allowed_parallelism, proposed_size + 1);
|
||||
if(m_verbose > 0)
|
||||
{
|
||||
std::cout << "ThreadPool [TBB] initialized with " << m_pool_size
|
||||
<< " threads." << std::endl;
|
||||
AutoLock lock(TypeMutex<decltype(std::cerr)>());
|
||||
std::cerr << "[PTL::ThreadPool] ThreadPool [TBB] initialized with "
|
||||
<< m_pool_size << " threads." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// create task group (used for async)
|
||||
if(!m_tbb_task_group)
|
||||
m_tbb_task_group = new tbb_task_group_t();
|
||||
{
|
||||
m_tbb_task_group = new tbb_task_group_t{};
|
||||
execute_on_all_threads([this]() { m_init_func(); });
|
||||
}
|
||||
|
||||
return m_pool_size;
|
||||
}
|
||||
#endif
|
||||
@@ -267,21 +454,27 @@ ThreadPool::initialize_threadpool(size_type proposed_size)
|
||||
;
|
||||
if(m_verbose > 0)
|
||||
{
|
||||
std::cout << "ThreadPool initialized with " << m_pool_size << " threads."
|
||||
<< std::endl;
|
||||
AutoLock lock(TypeMutex<decltype(std::cerr)>());
|
||||
std::cerr << "[PTL::ThreadPool] ThreadPool initialized with "
|
||||
<< m_pool_size << " threads." << std::endl;
|
||||
}
|
||||
if(!m_task_queue)
|
||||
{
|
||||
m_delete_task_queue = true;
|
||||
m_task_queue = new UserTaskQueue(m_pool_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_task_queue->resize(m_pool_size);
|
||||
}
|
||||
return m_pool_size;
|
||||
}
|
||||
else if(m_pool_size == proposed_size) // NOLINT
|
||||
{
|
||||
if(m_verbose > 0)
|
||||
{
|
||||
std::cout << "ThreadPool initialized with " << m_pool_size << " threads."
|
||||
AutoLock lock(TypeMutex<decltype(std::cerr)>());
|
||||
std::cerr << "ThreadPool initialized with " << m_pool_size << " threads."
|
||||
<< std::endl;
|
||||
}
|
||||
if(!m_task_queue)
|
||||
@@ -301,7 +494,10 @@ ThreadPool::initialize_threadpool(size_type proposed_size)
|
||||
}
|
||||
|
||||
if(!m_task_queue)
|
||||
m_task_queue = new UserTaskQueue(proposed_size);
|
||||
{
|
||||
m_delete_task_queue = true;
|
||||
m_task_queue = new UserTaskQueue(proposed_size);
|
||||
}
|
||||
|
||||
auto this_tid = get_this_thread_id();
|
||||
for(size_type i = m_pool_size; i < proposed_size; ++i)
|
||||
@@ -321,15 +517,19 @@ ThreadPool::initialize_threadpool(size_type proposed_size)
|
||||
// set the affinity
|
||||
if(m_use_affinity)
|
||||
set_affinity(i, thr);
|
||||
set_priority(m_priority, thr);
|
||||
// store
|
||||
m_threads.emplace_back(std::move(thr));
|
||||
} catch(std::runtime_error& e)
|
||||
{
|
||||
std::cerr << e.what() << std::endl; // issue creating thread
|
||||
AutoLock lock(TypeMutex<decltype(std::cerr)>());
|
||||
std::cerr << "[PTL::ThreadPool] " << e.what()
|
||||
<< std::endl; // issue creating thread
|
||||
continue;
|
||||
} catch(std::bad_alloc& e)
|
||||
{
|
||||
std::cerr << e.what() << std::endl;
|
||||
AutoLock lock(TypeMutex<decltype(std::cerr)>());
|
||||
std::cerr << "[PTL::ThreadPool] " << e.what() << std::endl;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -351,8 +551,9 @@ ThreadPool::initialize_threadpool(size_type proposed_size)
|
||||
|
||||
if(m_verbose > 0)
|
||||
{
|
||||
std::cout << "ThreadPool initialized with " << m_pool_size << " threads."
|
||||
<< std::endl;
|
||||
AutoLock lock(TypeMutex<decltype(std::cerr)>());
|
||||
std::cerr << "[PTL::ThreadPool] ThreadPool initialized with " << m_pool_size
|
||||
<< " threads." << std::endl;
|
||||
}
|
||||
|
||||
return m_main_threads.size();
|
||||
@@ -375,6 +576,7 @@ ThreadPool::destroy_threadpool()
|
||||
#if defined(PTL_USE_TBB)
|
||||
if(m_tbb_task_group)
|
||||
{
|
||||
execute_on_all_threads([this]() { m_fini_func(); });
|
||||
auto _func = [&]() { m_tbb_task_group->wait(); };
|
||||
if(m_tbb_task_arena)
|
||||
m_tbb_task_arena->execute(_func);
|
||||
@@ -394,7 +596,11 @@ ThreadPool::destroy_threadpool()
|
||||
delete _global_control;
|
||||
_global_control = nullptr;
|
||||
m_tbb_tp = false;
|
||||
std::cout << "ThreadPool [TBB] destroyed" << std::endl;
|
||||
AutoLock lock(TypeMutex<decltype(std::cerr)>());
|
||||
if(m_verbose > 0)
|
||||
{
|
||||
std::cerr << "[PTL::ThreadPool] ThreadPool [TBB] destroyed" << std::endl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -441,8 +647,8 @@ ThreadPool::destroy_threadpool()
|
||||
|
||||
//--------------------------------------------------------------------//
|
||||
// erase thread from thread ID list
|
||||
if(f_thread_ids.find(_tid) != f_thread_ids.end())
|
||||
f_thread_ids.erase(f_thread_ids.find(_tid));
|
||||
if(f_thread_ids().find(_tid) != f_thread_ids().end())
|
||||
f_thread_ids().erase(f_thread_ids().find(_tid));
|
||||
|
||||
//--------------------------------------------------------------------//
|
||||
// it's joined
|
||||
@@ -453,6 +659,7 @@ ThreadPool::destroy_threadpool()
|
||||
m_threads.clear();
|
||||
m_main_threads.clear();
|
||||
m_is_joined.clear();
|
||||
|
||||
m_alive_flag->store(false);
|
||||
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
@@ -466,15 +673,17 @@ ThreadPool::destroy_threadpool()
|
||||
|
||||
auto _active = m_thread_active->load();
|
||||
|
||||
if(get_verbose() >= 0)
|
||||
if(get_verbose() > 0)
|
||||
{
|
||||
if(_active == 0)
|
||||
{
|
||||
std::cout << "ThreadPool destroyed" << std::endl;
|
||||
AutoLock lock(TypeMutex<decltype(std::cerr)>());
|
||||
std::cerr << "[PTL::ThreadPool] ThreadPool destroyed" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "ThreadPool destroyed but " << _active
|
||||
AutoLock lock(TypeMutex<decltype(std::cerr)>());
|
||||
std::cerr << "[PTL::ThreadPool] ThreadPool destroyed but " << _active
|
||||
<< " threads might still be active (and cause a termination error)"
|
||||
<< std::endl;
|
||||
}
|
||||
@@ -497,6 +706,8 @@ ThreadPool::stop_thread()
|
||||
if(!m_alive_flag->load() || m_pool_size == 0)
|
||||
return 0;
|
||||
|
||||
m_pool_state->store(thread_pool::state::PARTIAL);
|
||||
|
||||
//------------------------------------------------------------------------//
|
||||
// notify all threads we are shutting down
|
||||
m_task_lock->lock();
|
||||
@@ -505,6 +716,9 @@ ThreadPool::stop_thread()
|
||||
m_task_lock->unlock();
|
||||
//------------------------------------------------------------------------//
|
||||
|
||||
while(!m_is_stopped.empty() && m_stop_threads.empty())
|
||||
;
|
||||
|
||||
// lock up the task queue
|
||||
AutoLock _task_lock(*m_task_lock);
|
||||
|
||||
@@ -526,6 +740,8 @@ ThreadPool::stop_thread()
|
||||
m_is_joined.pop_back();
|
||||
}
|
||||
|
||||
m_pool_state->store(thread_pool::state::STARTED);
|
||||
|
||||
m_pool_size = m_main_threads.size();
|
||||
return m_main_threads.size();
|
||||
}
|
||||
@@ -539,7 +755,6 @@ ThreadPool::get_valid_queue(task_queue_t*& _queue) const
|
||||
_queue = new UserTaskQueue{ static_cast<intmax_t>(m_pool_size) };
|
||||
return _queue;
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
void
|
||||
@@ -552,6 +767,8 @@ ThreadPool::execute_thread(VUserTaskQueue* _task_queue)
|
||||
|
||||
// initialization function
|
||||
m_init_func();
|
||||
// finalization function (executed when scope is destroyed)
|
||||
ScopeDestructor _fini{ [this]() { m_fini_func(); } };
|
||||
|
||||
ThreadId tid = ThisThread::get_id();
|
||||
ThreadData* data = thread_data();
|
||||
|
||||
+106
-9
@@ -25,15 +25,24 @@
|
||||
#include "PTL/Threading.hh"
|
||||
#include "PTL/AutoLock.hh"
|
||||
#include "PTL/Globals.hh"
|
||||
#include "PTL/Types.hh"
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
|
||||
#if defined(PTL_WINDOWS)
|
||||
# include <Windows.h>
|
||||
#else
|
||||
#elif defined(PTL_UNIX)
|
||||
# include <sys/syscall.h>
|
||||
# include <sys/types.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined(PTL_MACOS)
|
||||
# include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#if defined(PTL_LINUX)
|
||||
# include <fstream>
|
||||
#endif
|
||||
|
||||
#include <atomic>
|
||||
|
||||
using namespace PTL;
|
||||
@@ -43,6 +52,7 @@ using namespace PTL;
|
||||
namespace
|
||||
{
|
||||
thread_local int ThreadID = Threading::MASTER_ID;
|
||||
|
||||
} // namespace
|
||||
|
||||
//======================================================================================//
|
||||
@@ -64,6 +74,50 @@ Threading::GetNumberOfCores()
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
unsigned
|
||||
Threading::GetNumberOfPhysicalCpus()
|
||||
{
|
||||
#if defined(PTL_MACOS)
|
||||
int count;
|
||||
size_t count_len = sizeof(count);
|
||||
sysctlbyname("hw.physicalcpu", &count, &count_len, nullptr, 0);
|
||||
return static_cast<unsigned>(count);
|
||||
#elif defined(PTL_LINUX)
|
||||
unsigned core_id_count = 0;
|
||||
std::ifstream ifs("/proc/cpuinfo");
|
||||
if(ifs)
|
||||
{
|
||||
std::set<std::string> core_ids;
|
||||
while(true)
|
||||
{
|
||||
std::string line = {};
|
||||
getline(ifs, line);
|
||||
if(!ifs.good())
|
||||
break;
|
||||
if(line.find("core id") != std::string::npos)
|
||||
{
|
||||
for(std::string itr : { "core id", ":", " ", "\t" })
|
||||
{
|
||||
static auto _npos = std::string::npos;
|
||||
auto _pos = _npos;
|
||||
while((_pos = line.find(itr)) != _npos)
|
||||
line = line.replace(_pos, itr.length(), "");
|
||||
}
|
||||
core_ids.insert(line);
|
||||
}
|
||||
}
|
||||
core_id_count = static_cast<unsigned>(core_ids.size());
|
||||
if(core_id_count > 0)
|
||||
return core_id_count;
|
||||
}
|
||||
return GetNumberOfCores();
|
||||
#else
|
||||
return GetNumberOfCores();
|
||||
#endif
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
void
|
||||
Threading::SetThreadId(int value)
|
||||
{
|
||||
@@ -79,16 +133,59 @@ Threading::GetThreadId()
|
||||
//======================================================================================//
|
||||
|
||||
bool
|
||||
Threading::SetPinAffinity(int cpu, NativeThread& aT)
|
||||
Threading::SetPinAffinity(int _cpu)
|
||||
{
|
||||
#if defined(__linux__) || defined(_AIX)
|
||||
cpu_set_t* aset = new cpu_set_t;
|
||||
CPU_ZERO(aset);
|
||||
CPU_SET(cpu, aset);
|
||||
pthread_t& _aT = static_cast<pthread_t&>(aT);
|
||||
return (pthread_setaffinity_np(_aT, sizeof(cpu_set_t), aset) == 0);
|
||||
cpu_set_t _cpu_set{};
|
||||
CPU_ZERO(&_cpu_set);
|
||||
if(_cpu >= 0)
|
||||
CPU_SET(_cpu, &_cpu_set);
|
||||
return (pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &_cpu_set) == 0);
|
||||
#else // Not available for Mac, WIN,...
|
||||
ConsumeParameters(cpu, aT);
|
||||
ConsumeParameters(_cpu);
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
bool
|
||||
Threading::SetThreadPriority(int _prio)
|
||||
{
|
||||
#if defined(__linux__) || defined(_AIX)
|
||||
return (pthread_setschedprio(pthread_self(), _prio) == 0);
|
||||
#else // Not available for Mac, WIN,...
|
||||
ConsumeParameters(_prio);
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
bool
|
||||
Threading::SetPinAffinity(int _cpu, NativeThread& _t)
|
||||
{
|
||||
#if defined(__linux__) || defined(_AIX)
|
||||
cpu_set_t _cpu_set{};
|
||||
CPU_ZERO(&_cpu_set);
|
||||
CPU_SET(_cpu, &_cpu_set);
|
||||
return (pthread_setaffinity_np(static_cast<pthread_t>(_t), sizeof(cpu_set_t),
|
||||
&_cpu_set) == 0);
|
||||
#else // Not available for Mac, WIN,...
|
||||
ConsumeParameters(_cpu, _t);
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
bool
|
||||
Threading::SetThreadPriority(int _prio, NativeThread& _t)
|
||||
{
|
||||
#if defined(__linux__) || defined(_AIX)
|
||||
return (pthread_setschedprio(static_cast<pthread_t>(_t), _prio) == 0);
|
||||
#else
|
||||
ConsumeParameters(_prio, _t);
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
Vendored
+137
@@ -0,0 +1,137 @@
|
||||
//
|
||||
// MIT License
|
||||
// Copyright (c) 2019 Jonathan R. Madsen
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
|
||||
// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// ----------------------------------------------------------------------
|
||||
// class Timer
|
||||
//
|
||||
// Implementation
|
||||
// 29.04.97 G.Cosmo Added timings for Windows systems
|
||||
|
||||
#include "PTL/Timer.hh"
|
||||
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
using namespace PTL;
|
||||
|
||||
#if defined(IRIX6_2)
|
||||
# if defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE_EXTENDED == 1)
|
||||
# define __vfork vfork
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
|
||||
# include <sys/types.h>
|
||||
# include <windows.h>
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
// extract milliseconds time unit
|
||||
int
|
||||
sysconf(int a)
|
||||
{
|
||||
if(a == _SC_CLK_TCK)
|
||||
return 1000;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
static clock_t
|
||||
filetime2msec(FILETIME* t)
|
||||
{
|
||||
return (clock_t)((((float) t->dwHighDateTime) * 429496.7296) +
|
||||
(((float) t->dwLowDateTime) * .0001));
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
clock_t
|
||||
times(struct tms* t)
|
||||
{
|
||||
FILETIME ct = { 0, 0 }, et = { 0, 0 }, st = { 0, 0 }, ut = { 0, 0 }, rt = { 0, 0 };
|
||||
SYSTEMTIME realtime;
|
||||
|
||||
GetSystemTime(&realtime);
|
||||
SystemTimeToFileTime(&realtime, &rt); // get real time in 10^-9 sec
|
||||
if(t != 0)
|
||||
{
|
||||
GetProcessTimes(GetCurrentProcess(), &ct, &et, &st,
|
||||
&ut); // get process time in 10^-9 sec
|
||||
t->tms_utime = t->tms_cutime = filetime2msec(&ut);
|
||||
t->tms_stime = t->tms_cstime = filetime2msec(&st);
|
||||
}
|
||||
return filetime2msec(&rt);
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
#endif /* WIN32 */
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
Timer::Timer()
|
||||
: fValidTimes(false)
|
||||
{}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
double
|
||||
Timer::GetRealElapsed() const
|
||||
{
|
||||
if(!fValidTimes)
|
||||
{
|
||||
throw std::runtime_error("Timer::GetRealElapsed() - "
|
||||
"Timer not stopped or times not recorded!");
|
||||
}
|
||||
std::chrono::duration<double> diff = fEndRealTime - fStartRealTime;
|
||||
return diff.count();
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
double
|
||||
Timer::GetSystemElapsed() const
|
||||
{
|
||||
if(!fValidTimes)
|
||||
{
|
||||
throw std::runtime_error("Timer::GetSystemElapsed() - "
|
||||
"Timer not stopped or times not recorded!");
|
||||
}
|
||||
double diff = fEndTimes.tms_stime - fStartTimes.tms_stime;
|
||||
return diff / sysconf(_SC_CLK_TCK);
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
double
|
||||
Timer::GetUserElapsed() const
|
||||
{
|
||||
if(!fValidTimes)
|
||||
{
|
||||
throw std::runtime_error("Timer::GetUserElapsed() - "
|
||||
"Timer not stopped or times not recorded!");
|
||||
}
|
||||
double diff = fEndTimes.tms_utime - fStartTimes.tms_utime;
|
||||
return diff / sysconf(_SC_CLK_TCK);
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
+7
-1
@@ -27,8 +27,10 @@
|
||||
#include "PTL/Task.hh"
|
||||
#include "PTL/TaskGroup.hh"
|
||||
#include "PTL/ThreadPool.hh"
|
||||
#include "PTL/Utility.hh"
|
||||
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
|
||||
using namespace PTL;
|
||||
|
||||
@@ -41,6 +43,7 @@ UserTaskQueue::UserTaskQueue(intmax_t nworkers, UserTaskQueue* parent)
|
||||
, m_insert_bin((parent) ? (ThreadPool::get_this_thread_id() % (nworkers + 1)) : 0)
|
||||
, m_hold((parent) ? parent->m_hold : new std::atomic_bool(false))
|
||||
, m_ntasks((parent) ? parent->m_ntasks : new std::atomic_uintmax_t(0))
|
||||
, m_mutex((parent) ? parent->m_mutex : new Mutex{})
|
||||
, m_subqueues((parent) ? parent->m_subqueues : new TaskSubQueueContainer())
|
||||
{
|
||||
// create nthreads + 1 subqueues so there is always a subqueue available
|
||||
@@ -85,6 +88,7 @@ UserTaskQueue::~UserTaskQueue()
|
||||
m_subqueues->clear();
|
||||
delete m_hold;
|
||||
delete m_ntasks;
|
||||
delete m_mutex;
|
||||
delete m_subqueues;
|
||||
}
|
||||
}
|
||||
@@ -94,7 +98,9 @@ UserTaskQueue::~UserTaskQueue()
|
||||
void
|
||||
UserTaskQueue::resize(intmax_t n)
|
||||
{
|
||||
AutoLock l(m_mutex);
|
||||
if(!m_mutex)
|
||||
throw std::runtime_error("nullptr to mutex");
|
||||
AutoLock lk(m_mutex);
|
||||
if(m_workers < n)
|
||||
{
|
||||
while(m_workers < n)
|
||||
|
||||
Reference in New Issue
Block a user