Import Geant4 11.0.0.beta source tree

This commit is contained in:
Gabriele Cosmo
2021-06-25 16:12:29 +02:00
parent c968e26a39
commit 6399a014b6
4200 changed files with 207479 additions and 237366 deletions
-129
View File
@@ -1,129 +0,0 @@
//
// MIT License
// Copyright (c) 2020 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.
//
// ---------------------------------------------------------------
// Tasking class implementation
//
#include <iomanip>
#include "PTL/TaskAllocator.hh"
#include "PTL/TaskAllocatorList.hh"
using namespace PTL;
//======================================================================================//
TaskAllocatorList*&
TaskAllocatorList::fAllocatorList()
{
static thread_local TaskAllocatorList* _instance = nullptr;
return _instance;
}
//======================================================================================//
TaskAllocatorList*
TaskAllocatorList::GetAllocatorList()
{
if(!fAllocatorList())
{
fAllocatorList() = new TaskAllocatorList;
}
return fAllocatorList();
}
//======================================================================================//
TaskAllocatorList*
TaskAllocatorList::GetAllocatorListIfExist()
{
return fAllocatorList();
}
//======================================================================================//
TaskAllocatorList::TaskAllocatorList() {}
//======================================================================================//
TaskAllocatorList::~TaskAllocatorList() { fAllocatorList() = nullptr; }
//======================================================================================//
void
TaskAllocatorList::Register(TaskAllocatorBase* alloc)
{
fList.push_back(alloc);
}
//======================================================================================//
void
TaskAllocatorList::Destroy(int nStat, int verboseLevel)
{
int i = 0, j = 0;
double tmem = 0;
if(verboseLevel > 0)
{
std::cout << "================== Deleting memory pools ==================="
<< std::endl;
}
for(auto& itr : fList)
{
double mem = itr->GetAllocatedSize();
if(i < nStat)
{
i++;
tmem += mem;
itr->ResetStorage();
continue;
}
j++;
tmem += mem;
if(verboseLevel > 1)
{
std::cout << "Pool ID '" << itr->GetPoolType()
<< "', size : " << std::setprecision(3) << mem / 1048576
<< std::setprecision(6) << " MB" << std::endl;
}
itr->ResetStorage();
// delete *itr;
}
if(verboseLevel > 0)
{
std::cout << "Number of memory pools allocated: " << Size()
<< "; of which, static: " << i << std::endl;
std::cout << "Dynamic pools deleted: " << j
<< " / Total memory freed: " << std::setprecision(2) << tmem / 1048576
<< std::setprecision(6) << " MB" << std::endl;
std::cout << "============================================================"
<< std::endl;
}
fList.clear();
}
//======================================================================================//
int
TaskAllocatorList::Size() const
{
return fList.size();
}
//======================================================================================//
-124
View File
@@ -1,124 +0,0 @@
//
// MIT License
// Copyright (c) 2020 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.
//
// ---------------------------------------------------------------
// Tasking class implementation
//
// TaskAllocatorPool
//
// Implementation file
//
// Author: G.Cosmo, November 2000
//
#include "PTL/TaskAllocatorPool.hh"
using namespace PTL;
// ************************************************************
// TaskAllocatorPool constructor
// ************************************************************
//
TaskAllocatorPool::TaskAllocatorPool(unsigned int sz)
: esize((sz < sizeof(PoolLink)) ? sizeof(PoolLink) : sz)
, csize((sz < 1024 / 2 - 16) ? (1024 - 16) : (sz * 10 - 16))
, chunks(nullptr)
, head(nullptr)
, nchunks(0)
{}
// ************************************************************
// TaskAllocatorPool copy constructor
// ************************************************************
//
TaskAllocatorPool::TaskAllocatorPool(const TaskAllocatorPool& right)
: esize(right.esize)
, csize(right.csize)
, chunks(right.chunks)
, head(right.head)
, nchunks(right.nchunks)
{}
// ************************************************************
// TaskAllocatorPool operator=
// ************************************************************
//
TaskAllocatorPool&
TaskAllocatorPool::operator=(const TaskAllocatorPool& right)
{
if(&right == this)
return *this;
chunks = right.chunks;
head = right.head;
nchunks = right.nchunks;
return *this;
}
// ************************************************************
// TaskAllocatorPool destructor
// ************************************************************
//
TaskAllocatorPool::~TaskAllocatorPool() { Reset(); }
// ************************************************************
// Reset
// ************************************************************
//
void
TaskAllocatorPool::Reset()
{
// Free all chunks
//
PoolChunk* n = chunks;
PoolChunk* p = nullptr;
while(n)
{
p = n;
n = n->next;
delete p;
}
head = nullptr;
chunks = nullptr;
nchunks = 0;
}
// ************************************************************
// Grow
// ************************************************************
//
void
TaskAllocatorPool::Grow()
{
// Allocate new chunk, organize it as a linked list of
// elements of size 'esize'
//
PoolChunk* n = new PoolChunk(csize);
n->next = chunks;
chunks = n;
nchunks++;
const int nelem = csize / esize;
char* start = n->mem;
char* last = &start[(nelem - 1) * esize];
for(char* p = start; p < last; p += esize)
{
reinterpret_cast<PoolLink*>(p)->next = reinterpret_cast<PoolLink*>(p + esize);
}
reinterpret_cast<PoolLink*>(last)->next = nullptr;
head = reinterpret_cast<PoolLink*>(start);
}
@@ -19,22 +19,50 @@
// ---------------------------------------------------------------
// Tasking class implementation
//
// Class Description:
//
// This file creates an abstract base class for the grouping the thread-pool
// tasking system into independently joinable units
//
// ---------------------------------------------------------------
// Author: Jonathan Madsen (Feb 13th 2018)
// ---------------------------------------------------------------
#include "PTL/TaskAllocator.hh"
#include "PTL/TaskAllocatorList.hh"
using namespace PTL;
#include "PTL/TaskGroup.hh"
#include "PTL/Globals.hh"
#include "PTL/Task.hh"
#include "PTL/TaskRunManager.hh"
#include "PTL/ThreadData.hh"
#include "PTL/ThreadPool.hh"
#include "PTL/VTask.hh"
//======================================================================================//
TaskAllocatorBase::TaskAllocatorBase()
namespace PTL
{
TaskAllocatorList::GetAllocatorList()->Register(this);
namespace internal
{
std::atomic_uintmax_t&
task_group_counter()
{
static std::atomic_uintmax_t _instance(0);
return _instance;
}
//======================================================================================//
ThreadPool*
get_default_threadpool()
{
if(TaskRunManager::GetMasterRunManager())
return TaskRunManager::GetMasterRunManager()->GetThreadPool();
return nullptr;
}
TaskAllocatorBase::~TaskAllocatorBase() {}
intmax_t
get_task_depth()
{
return (ThreadData::GetInstance()) ? ThreadData::GetInstance()->task_depth : 0;
}
} // namespace internal
} // namespace PTL
//======================================================================================//
+5 -13
View File
@@ -63,20 +63,15 @@ TaskRunManager::GetInstance(bool useTBB)
//======================================================================================//
TaskRunManager::TaskRunManager(bool useTBB)
: m_is_initialized(false)
, m_verbose(0)
, m_workers(std::thread::hardware_concurrency())
, m_task_queue(nullptr)
, m_thread_pool(nullptr)
, m_task_manager(nullptr)
: m_workers(std::thread::hardware_concurrency())
{
if(!GetPrivateMasterRunManager(false))
{
GetPrivateMasterRunManager(false) = this;
}
#ifdef PTL_USE_TBB
auto _useTBB = GetEnv<bool>("FORCE_TBB", useTBB);
#if defined(PTL_USE_TBB)
auto _useTBB = GetEnv<bool>("PTL_FORCE_TBB", GetEnv<bool>("FORCE_TBB", useTBB));
if(_useTBB)
useTBB = true;
#endif
@@ -88,10 +83,6 @@ TaskRunManager::TaskRunManager(bool useTBB)
//======================================================================================//
TaskRunManager::~TaskRunManager() {}
//======================================================================================//
void
TaskRunManager::Initialize(uint64_t n)
{
@@ -142,7 +133,8 @@ void
TaskRunManager::Terminate()
{
m_is_initialized = false;
m_thread_pool->destroy_threadpool();
if(m_thread_pool)
m_thread_pool->destroy_threadpool();
delete m_task_manager;
delete m_thread_pool;
m_task_manager = nullptr;
+4 -8
View File
@@ -41,11 +41,9 @@ ThreadData::GetInstance()
//======================================================================================//
ThreadData::ThreadData(ThreadPool* tp)
: is_master(tp->is_master())
, within_task(false)
, task_depth(0)
: is_main((tp) ? tp->is_main() : false)
, thread_pool(tp)
, current_queue(tp->get_queue())
, current_queue((tp) ? tp->get_queue() : nullptr)
, queue_stack({ current_queue })
{}
@@ -54,12 +52,10 @@ ThreadData::ThreadData(ThreadPool* tp)
void
ThreadData::update()
{
if(!thread_pool)
return;
current_queue = thread_pool->get_queue();
queue_stack.push_back(current_queue);
}
//======================================================================================//
ThreadData::~ThreadData() {}
//======================================================================================//
+71 -49
View File
@@ -69,8 +69,9 @@ bool ThreadPool::f_use_tbb = false;
// static member function that calls the member function we want the thread to
// run
void
ThreadPool::start_thread(ThreadPool* tp, intmax_t _idx)
ThreadPool::start_thread(ThreadPool* tp, thread_data_t* _data, intmax_t _idx)
{
auto _thr_data = std::make_shared<ThreadData>(tp);
{
AutoLock lock(TypeMutex<ThreadPool>(), std::defer_lock);
if(!lock.owns_lock())
@@ -78,9 +79,10 @@ ThreadPool::start_thread(ThreadPool* tp, intmax_t _idx)
if(_idx < 0)
_idx = f_thread_ids.size();
f_thread_ids[std::this_thread::get_id()] = _idx;
Threading::SetThreadId(_idx);
_data->emplace_back(_thr_data);
}
static thread_local std::unique_ptr<ThreadData> _unique_data(new ThreadData(tp));
thread_data() = _unique_data.get();
thread_data() = _thr_data.get();
tp->record_entry();
tp->execute_thread(thread_data()->current_queue);
tp->record_exit();
@@ -91,7 +93,7 @@ ThreadPool::start_thread(ThreadPool* tp, intmax_t _idx)
bool
ThreadPool::using_tbb()
{
return f_use_tbb;
return f_use_tbb;
}
//======================================================================================//
@@ -111,7 +113,7 @@ ThreadPool::set_use_tbb(bool enable)
const ThreadPool::thread_id_map_t&
ThreadPool::get_thread_ids()
{
return f_thread_ids;
return f_thread_ids;
}
//======================================================================================//
@@ -136,24 +138,12 @@ ThreadPool::get_this_thread_id()
//======================================================================================//
ThreadPool::ThreadPool(const size_type& pool_size, VUserTaskQueue* task_queue,
bool _use_affinity, const affinity_func_t& _affinity_func)
bool _use_affinity, affinity_func_t _affinity_func)
: m_use_affinity(_use_affinity)
, m_tbb_tp(false)
, m_verbose(0)
, m_pool_size(0)
, m_master_tid(ThisThread::get_id())
, m_alive_flag(std::make_shared<std::atomic_bool>(false))
, m_pool_state(std::make_shared<std::atomic_short>(thread_pool::state::NONINIT))
, m_thread_awake(std::make_shared<std::atomic_uintmax_t>(0))
, m_task_lock(std::make_shared<Mutex>())
, m_task_cond(std::make_shared<Condition>())
, m_task_queue(task_queue)
, m_tbb_task_group(nullptr)
, m_init_func([]() { return; })
, m_affinity_func(_affinity_func)
, m_affinity_func(std::move(_affinity_func))
{
m_verbose = GetEnv<int>("PTL_VERBOSE", m_verbose);
auto master_id = get_this_thread_id();
if(master_id != 0 && m_verbose > 1)
std::cerr << "ThreadPool created on non-master slave" << std::endl;
@@ -179,7 +169,7 @@ ThreadPool::~ThreadPool()
<< std::endl;
m_pool_state->store(thread_pool::state::STOPPED);
m_task_lock->lock();
CONDITIONBROADCAST(m_task_cond.get());
m_task_cond->notify_all();
m_task_lock->unlock();
for(auto& itr : m_threads)
itr.join();
@@ -232,10 +222,10 @@ ThreadPool::initialize_threadpool(size_type proposed_size)
if(!m_alive_flag->load())
m_pool_state->store(thread_pool::state::STARTED);
//--------------------------------------------------------------------//
// handle tbb task scheduler
#ifdef PTL_USE_TBB
if(f_use_tbb)
#if defined(PTL_USE_TBB)
//--------------------------------------------------------------------//
// handle tbb task scheduler
if(f_use_tbb || m_tbb_tp)
{
m_tbb_tp = true;
m_pool_size = proposed_size;
@@ -281,7 +271,10 @@ ThreadPool::initialize_threadpool(size_type proposed_size)
<< std::endl;
}
if(!m_task_queue)
m_task_queue = new UserTaskQueue(m_pool_size);
{
m_delete_task_queue = true;
m_task_queue = new UserTaskQueue(m_pool_size);
}
return m_pool_size;
}
else if(m_pool_size == proposed_size) // NOLINT
@@ -292,7 +285,10 @@ ThreadPool::initialize_threadpool(size_type proposed_size)
<< std::endl;
}
if(!m_task_queue)
m_task_queue = new UserTaskQueue(m_pool_size);
{
m_delete_task_queue = true;
m_task_queue = new UserTaskQueue(m_pool_size);
}
return m_pool_size;
}
}
@@ -304,13 +300,18 @@ ThreadPool::initialize_threadpool(size_type proposed_size)
m_is_joined.reserve(proposed_size);
}
if(!m_task_queue)
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)
{
// add the threads
try
{
Thread thr(ThreadPool::start_thread, this, this_tid + i + 1);
// create thread
Thread thr{ ThreadPool::start_thread, this, &m_thread_data,
this_tid + i + 1 };
// only reaches here if successful creation of thread
++m_pool_size;
// store thread
@@ -354,9 +355,6 @@ ThreadPool::initialize_threadpool(size_type proposed_size)
<< std::endl;
}
if(!m_task_queue)
m_task_queue = new UserTaskQueue(m_main_threads.size());
return m_main_threads.size();
}
@@ -374,13 +372,22 @@ ThreadPool::destroy_threadpool()
//--------------------------------------------------------------------//
// handle tbb task scheduler
#ifdef PTL_USE_TBB
#if defined(PTL_USE_TBB)
if(m_tbb_task_group)
{
m_tbb_task_group->wait();
auto _func = [&]() { m_tbb_task_group->wait(); };
if(m_tbb_task_arena)
m_tbb_task_arena->execute(_func);
else
_func();
delete m_tbb_task_group;
m_tbb_task_group = nullptr;
}
if(m_tbb_task_arena)
{
delete m_tbb_task_arena;
m_tbb_task_arena = nullptr;
}
if(m_tbb_tp && tbb_global_control())
{
tbb_global_control_t*& _global_control = tbb_global_control();
@@ -397,7 +404,7 @@ ThreadPool::destroy_threadpool()
//------------------------------------------------------------------------//
// notify all threads we are shutting down
m_task_lock->lock();
CONDITIONBROADCAST(m_task_cond.get());
m_task_cond->notify_all();
m_task_lock->unlock();
//------------------------------------------------------------------------//
@@ -440,13 +447,9 @@ ThreadPool::destroy_threadpool()
//--------------------------------------------------------------------//
// it's joined
m_is_joined.at(i) = true;
//--------------------------------------------------------------------//
// try waking up a bunch of threads that are still waiting
CONDITIONBROADCAST(m_task_cond.get());
//--------------------------------------------------------------------//
}
m_thread_data.clear();
m_threads.clear();
m_main_threads.clear();
m_is_joined.clear();
@@ -463,12 +466,25 @@ ThreadPool::destroy_threadpool()
auto _active = m_thread_active->load();
if(_active == 0)
std::cout << "ThreadPool destroyed" << std::endl;
else
std::cout << "ThreadPool destroyed but " << _active
<< " threads might still be active (and cause a termination error)"
<< std::endl;
if(get_verbose() >= 0)
{
if(_active == 0)
{
std::cout << "ThreadPool destroyed" << std::endl;
}
else
{
std::cout << "ThreadPool destroyed but " << _active
<< " threads might still be active (and cause a termination error)"
<< std::endl;
}
}
if(m_delete_task_queue)
{
delete m_task_queue;
m_task_queue = nullptr;
}
return 0;
}
@@ -485,7 +501,7 @@ ThreadPool::stop_thread()
// notify all threads we are shutting down
m_task_lock->lock();
m_is_stopped.push_back(true);
CONDITIONNOTIFY(m_task_cond.get());
m_task_cond->notify_one();
m_task_lock->unlock();
//------------------------------------------------------------------------//
@@ -516,6 +532,16 @@ ThreadPool::stop_thread()
//======================================================================================//
ThreadPool::task_queue_t*&
ThreadPool::get_valid_queue(task_queue_t*& _queue) const
{
if(!_queue)
_queue = new UserTaskQueue{ static_cast<intmax_t>(m_pool_size) };
return _queue;
}
//======================================================================================//
void
ThreadPool::execute_thread(VUserTaskQueue* _task_queue)
{
@@ -559,8 +585,6 @@ ThreadPool::execute_thread(VUserTaskQueue* _task_queue)
if(_task)
{
(*_task)();
if(!_task->group())
delete _task;
}
data->within_task = false;
}
@@ -674,8 +698,6 @@ ThreadPool::execute_thread(VUserTaskQueue* _task_queue)
if(_task)
{
(*_task)();
if(!_task->group())
delete _task;
}
}
//----------------------------------------------------------------//
+1 -32
View File
@@ -21,9 +21,6 @@
//
// Threading.cc
//
// ---------------------------------------------------------------
// Author: Andrea Dotti (15 Feb 2013): First Implementation
// ---------------------------------------------------------------
#include "PTL/Threading.hh"
#include "PTL/AutoLock.hh"
@@ -46,7 +43,6 @@ using namespace PTL;
namespace
{
thread_local int ThreadID = Threading::MASTER_ID;
std::atomic_int numActThreads(0);
} // namespace
//======================================================================================//
@@ -73,21 +69,12 @@ Threading::SetThreadId(int value)
{
ThreadID = value;
}
int
Threading::GetThreadId()
{
return ThreadID;
}
bool
Threading::IsWorkerThread()
{
return (ThreadID >= 0);
}
bool
Threading::IsMasterThread()
{
return (ThreadID == MASTER_ID);
}
//======================================================================================//
@@ -107,21 +94,3 @@ Threading::SetPinAffinity(int cpu, NativeThread& aT)
}
//======================================================================================//
int
Threading::WorkerThreadLeavesPool()
{
return numActThreads--;
}
int
Threading::WorkerThreadJoinsPool()
{
return numActThreads++;
}
int
Threading::GetNumberOfRunningWorkerThreads()
{
return numActThreads.load();
}
//======================================================================================//
+32 -47
View File
@@ -47,13 +47,13 @@ UserTaskQueue::UserTaskQueue(intmax_t nworkers, UserTaskQueue* parent)
if(!parent)
{
for(intmax_t i = 0; i < nworkers + 1; ++i)
m_subqueues->push_back(new TaskSubQueue(m_ntasks));
m_subqueues->emplace_back(new TaskSubQueue(m_ntasks));
}
#if defined(DEBUG)
if(GetEnv<int>("PTL_VERBOSE", 0) > 3)
{
RecursiveAutoLock l(TypeRecursiveMutex<decltype(std::cout)>());
RecursiveAutoLock l(TypeMutex<decltype(std::cout), RecursiveMutex>());
std::stringstream ss;
ss << ThreadPool::get_this_thread_id() << "> " << ThisThread::get_id() << " ["
<< __FUNCTION__ << ":" << __LINE__ << "] "
@@ -79,7 +79,7 @@ UserTaskQueue::~UserTaskQueue()
{
for(auto& itr : *m_subqueues)
{
assert(itr->size() == 0);
assert(itr->empty());
delete itr;
}
m_subqueues->clear();
@@ -99,7 +99,7 @@ UserTaskQueue::resize(intmax_t n)
{
while(m_workers < n)
{
m_subqueues->push_back(new TaskSubQueue(m_ntasks));
m_subqueues->emplace_back(new TaskSubQueue(m_ntasks));
++m_workers;
}
}
@@ -235,9 +235,9 @@ UserTaskQueue::GetTask(intmax_t subq, intmax_t nitr)
//======================================================================================//
intmax_t
UserTaskQueue::InsertTask(task_pointer task, ThreadData* data, intmax_t subq)
UserTaskQueue::InsertTask(task_pointer&& task, ThreadData* data, intmax_t subq)
{
// skip increment here (handled externally)
// increment number of tasks
++(*m_ntasks);
bool spin = m_hold->load(std::memory_order_relaxed);
@@ -267,7 +267,7 @@ UserTaskQueue::InsertTask(task_pointer task, ThreadData* data, intmax_t subq)
if(task_subq->AcquireClaim())
{
// push the task into the bin
task_subq->PushTask(task);
task_subq->PushTask(std::move(task));
// release the claim on the bin
task_subq->ReleaseClaim();
// return success
@@ -304,8 +304,8 @@ UserTaskQueue::InsertTask(task_pointer task, ThreadData* data, intmax_t subq)
void
UserTaskQueue::ExecuteOnAllThreads(ThreadPool* tp, function_type func)
{
typedef TaskGroup<int, int> task_group_type;
typedef std::map<int64_t, bool> thread_execute_map_t;
using task_group_type = TaskGroup<int, int>;
using thread_execute_map_t = std::map<int64_t, bool>;
if(!tp->is_alive())
{
@@ -313,18 +313,16 @@ UserTaskQueue::ExecuteOnAllThreads(ThreadPool* tp, function_type func)
return;
}
auto join_func = [=](int& ref, int i) {
ref += i;
return ref;
};
task_group_type* tg = new task_group_type(join_func, tp);
task_group_type tg{ [](int& ref, int i) { return (ref += i); }, tp };
// wait for all threads to finish any work
// NOTE: will cause deadlock if called from a task
while(tp->get_active_threads_count() > 0)
ThisThread::sleep_for(std::chrono::milliseconds(10));
thread_execute_map_t* thread_execute_map = new thread_execute_map_t();
thread_execute_map_t thread_execute_map{};
std::vector<std::shared_ptr<VTask>> _tasks{};
_tasks.reserve(m_workers + 1);
AcquireHold();
for(int i = 0; i < (m_workers + 1); ++i)
@@ -334,9 +332,10 @@ UserTaskQueue::ExecuteOnAllThreads(ThreadPool* tp, function_type func)
//--------------------------------------------------------------------//
auto thread_specific_func = [&]() {
static Mutex _mtx;
ScopeDestructor _dtor = tg.get_scope_destructor();
static Mutex _mtx;
_mtx.lock();
bool& _executed = (*thread_execute_map)[GetThreadBin()];
bool& _executed = thread_execute_map[GetThreadBin()];
_mtx.unlock();
if(!_executed)
{
@@ -348,25 +347,18 @@ UserTaskQueue::ExecuteOnAllThreads(ThreadPool* tp, function_type func)
};
//--------------------------------------------------------------------//
auto _task = tg->wrap(thread_specific_func);
//++(*m_ntasks);
// TaskSubQueue* task_subq = (*m_subqueues)[i];
// task_subq->PushTask(_task);
InsertTask(_task, ThreadData::GetInstance(), i);
InsertTask(tg.wrap(thread_specific_func), ThreadData::GetInstance(), i);
}
tp->notify_all();
int nexecuted = tg->join();
int nexecuted = tg.join();
if(nexecuted != m_workers)
{
std::stringstream msg;
msg << "Failure executing routine on all threads! Only " << nexecuted
<< " threads executed function out of " << m_workers;
<< " threads executed function out of " << m_workers << " workers";
std::cerr << msg.str() << std::endl;
// Exception("UserTaskQueue::ExecuteOnAllThreads", "TaskQueue0000",
// JustWarning, msg);
}
delete thread_execute_map;
ReleaseHold();
}
@@ -376,14 +368,10 @@ void
UserTaskQueue::ExecuteOnSpecificThreads(ThreadIdSet tid_set, ThreadPool* tp,
function_type func)
{
typedef TaskGroup<int, int> task_group_type;
typedef std::map<int64_t, bool> thread_execute_map_t;
using task_group_type = TaskGroup<int, int>;
using thread_execute_map_t = std::map<int64_t, bool>;
auto join_func = [=](int& ref, int i) {
ref += i;
return ref;
};
task_group_type* tg = new task_group_type(join_func, tp);
task_group_type tg{ [](int& ref, int i) { return (ref += i); }, tp };
// wait for all threads to finish any work
// NOTE: will cause deadlock if called from a task
@@ -396,15 +384,16 @@ UserTaskQueue::ExecuteOnSpecificThreads(ThreadIdSet tid_set, ThreadPool* tp,
return;
}
thread_execute_map_t* thread_execute_map = new thread_execute_map_t();
thread_execute_map_t thread_execute_map{};
//========================================================================//
// wrap the function so that it will only be executed if the thread
// has an ID in the set
auto thread_specific_func = [=]() {
static Mutex _mtx;
auto thread_specific_func = [&]() {
ScopeDestructor _dtor = tg.get_scope_destructor();
static Mutex _mtx;
_mtx.lock();
bool& _executed = (*thread_execute_map)[GetThreadBin()];
bool& _executed = thread_execute_map[GetThreadBin()];
_mtx.unlock();
if(!_executed && tid_set.count(ThisThread::get_id()) > 0)
{
@@ -425,21 +414,17 @@ UserTaskQueue::ExecuteOnSpecificThreads(ThreadIdSet tid_set, ThreadPool* tp,
if(i == GetThreadBin())
continue;
auto _task = tg->wrap(thread_specific_func);
InsertTask(_task, ThreadData::GetInstance(), i);
InsertTask(tg.wrap(thread_specific_func), ThreadData::GetInstance(), i);
}
tp->notify_all();
int nexecuted = tg->join();
if(nexecuted != m_workers)
decltype(tid_set.size()) nexecuted = tg.join();
if(nexecuted != tid_set.size())
{
std::stringstream msg;
msg << "Failure executing routine on all threads! Only " << nexecuted
<< " threads executed function out of " << tid_set.size();
msg << "Failure executing routine on specific threads! Only " << nexecuted
<< " threads executed function out of " << tid_set.size() << " workers";
std::cerr << msg.str() << std::endl;
// Exception("UserTaskQueue::ExecuteOnSpecificThreads", "TaskQueue0001",
// JustWarning, msg);
}
delete thread_execute_map;
ReleaseHold();
}
+5 -67
View File
@@ -31,78 +31,16 @@
#include "PTL/VTask.hh"
#include "PTL/ThreadData.hh"
#include "PTL/ThreadPool.hh"
#include "PTL/VTaskGroup.hh"
#include <cassert>
using namespace PTL;
//======================================================================================//
VTask::VTask()
: m_depth(0)
, m_group(nullptr)
, m_pool(nullptr)
VTask::VTask(bool _is_native, intmax_t _depth)
: m_is_native{ _is_native }
, m_depth{ _depth }
{}
//======================================================================================//
VTask::VTask(VTaskGroup* task_group)
: m_depth(0)
, m_group(task_group)
, m_pool((m_group) ? task_group->pool() : nullptr)
{}
//======================================================================================//
VTask::VTask(ThreadPool* tp)
: m_depth(0)
, m_group(nullptr)
, m_pool(tp)
{}
//======================================================================================//
VTask::~VTask() {}
//======================================================================================//
void
VTask::operator--()
{
if(m_group)
{
intmax_t _count = --(*m_group);
if(_count < 2)
{
try
{
m_group->task_cond()->notify_all();
} catch(std::system_error& e)
{
auto tid = ThreadPool::get_this_thread_id();
AutoLock l(TypeMutex<decltype(std::cerr)>(), std::defer_lock);
if(!l.owns_lock())
l.lock();
std::cerr << "[" << tid << "] Caught system error: " << e.what()
<< std::endl;
}
}
}
}
//======================================================================================//
bool
VTask::is_native_task() const
{
return (m_group) ? m_group->is_native_task_group() : false;
}
//======================================================================================//
ThreadPool*
VTask::pool() const
{
return (!m_pool && m_group) ? m_group->pool() : m_pool;
}
//======================================================================================//
-220
View File
@@ -1,220 +0,0 @@
//
// MIT License
// Copyright (c) 2020 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.
//
// ---------------------------------------------------------------
// Tasking class implementation
//
// Class Description:
//
// This file creates an abstract base class for the grouping the thread-pool
// tasking system into independently joinable units
//
// ---------------------------------------------------------------
// Author: Jonathan Madsen (Feb 13th 2018)
// ---------------------------------------------------------------
#include "PTL/VTaskGroup.hh"
#include "PTL/Globals.hh"
#include "PTL/Task.hh"
#include "PTL/TaskRunManager.hh"
#include "PTL/ThreadData.hh"
#include "PTL/ThreadPool.hh"
#include "PTL/VTask.hh"
using namespace PTL;
//======================================================================================//
std::atomic_uintmax_t&
vtask_group_counter()
{
static std::atomic_uintmax_t _instance(0);
return _instance;
}
//======================================================================================//
int VTaskGroup::f_verbose = GetEnv<int>("PTL_VERBOSE", 0);
//======================================================================================//
VTaskGroup::VTaskGroup(ThreadPool* tp)
: m_id(vtask_group_counter()++)
, m_pool(tp)
, m_tot_task_count(std::make_shared<atomic_int>(0))
, m_task_cond(std::make_shared<condition_t>())
, m_task_lock(std::make_shared<lock_t>())
, m_main_tid(std::this_thread::get_id())
{
if(!m_pool && TaskRunManager::GetMasterRunManager())
m_pool = TaskRunManager::GetMasterRunManager()->GetThreadPool();
if(!m_pool)
{
std::cerr << __FUNCTION__ << "@" << __LINE__ << " :: Warning! "
<< "nullptr to thread pool!" << std::endl;
}
}
//======================================================================================//
VTaskGroup::~VTaskGroup() {}
//======================================================================================//
void
VTaskGroup::wait()
{
// if no pool was initially present at creation
if(!m_pool)
{
// check for master MT run-manager
if(TaskRunManager::GetMasterRunManager())
m_pool = TaskRunManager::GetMasterRunManager()->GetThreadPool();
// if MTRunManager does not exist or no thread pool created
if(!m_pool)
{
if(f_verbose > 0)
{
fprintf(stderr, "%s @ %i :: Warning! nullptr to thread-pool (%p)\n",
__FUNCTION__, __LINE__, static_cast<void*>(m_pool));
std::cerr << __FUNCTION__ << "@" << __LINE__ << " :: Warning! "
<< "nullptr to thread pool!" << std::endl;
}
return;
}
}
ThreadData* data = ThreadData::GetInstance();
if(!data)
return;
ThreadPool* tpool = (m_pool) ? m_pool : data->thread_pool;
VUserTaskQueue* taskq = (tpool) ? tpool->get_queue() : data->current_queue;
bool _is_master = data->is_master;
bool _within_task = data->within_task;
auto is_active_state = [&]() {
return (tpool->state()->load(std::memory_order_relaxed) !=
thread_pool::state::STOPPED);
};
auto execute_this_threads_tasks = [&]() {
if(!taskq)
return;
// only want to process if within a task
if((!_is_master || tpool->size() < 2) && _within_task)
{
int bin = static_cast<int>(taskq->GetThreadBin());
// const auto nitr = (tpool) ? tpool->size() : Thread::hardware_concurrency();
while(this->pending() > 0)
{
task_pointer _task = taskq->GetTask(bin);
if(_task)
(*_task)();
}
}
};
// checks for validity
if(!is_native_task_group())
{
// for external threads
if(!_is_master || tpool->size() < 2)
return;
}
else if(f_verbose > 0)
{
if(!tpool || !taskq)
{
// something is wrong, didn't create thread-pool?
fprintf(
stderr,
"%s @ %i :: Warning! nullptr to thread data (%p) or task-queue (%p)\n",
__FUNCTION__, __LINE__, static_cast<void*>(tpool),
static_cast<void*>(taskq));
}
// return if thread pool isn't built
else if(is_native_task_group() && !tpool->is_alive())
{
fprintf(stderr, "%s @ %i :: Warning! thread-pool is not alive!\n",
__FUNCTION__, __LINE__);
}
else if(!is_active_state())
{
fprintf(stderr, "%s @ %i :: Warning! thread-pool is not active!\n",
__FUNCTION__, __LINE__);
}
}
intmax_t wake_size = 2;
AutoLock _lock(*m_task_lock, std::defer_lock);
while(is_active_state())
{
execute_this_threads_tasks();
// while loop protects against spurious wake-ups
while(_is_master && pending() > 0 && is_active_state())
{
// auto _wake = [&]() { return (wake_size > pending() || !is_active_state());
// };
// lock before sleeping on condition
if(!_lock.owns_lock())
_lock.lock();
// Wait until signaled that a task has been competed
// Unlock mutex while wait, then lock it back when signaled
// when true, this wakes the thread
if(pending() >= wake_size)
{
m_task_cond->wait(_lock);
}
else
{
m_task_cond->wait_for(_lock, std::chrono::microseconds(100));
}
// unlock
if(_lock.owns_lock())
_lock.unlock();
}
// if pending is not greater than zero, we are joined
if(pending() <= 0)
break;
}
if(_lock.owns_lock())
_lock.unlock();
intmax_t ntask = this->task_count().load();
if(ntask > 0)
{
std::stringstream ss;
ss << "\nWarning! Join operation issue! " << ntask << " tasks still "
<< "are running!" << std::endl;
std::cerr << ss.str();
this->wait();
}
}
//======================================================================================//
-13
View File
@@ -45,16 +45,3 @@ VUserTaskQueue::VUserTaskQueue(intmax_t nworkers)
}
//======================================================================================//
VUserTaskQueue::~VUserTaskQueue() {}
//======================================================================================//
/*
intmax_t& VUserTaskQueue::ThisThreadNumber() const
{
// get a thread id number
static thread_local intmax_t _tid;
return _tid;
}
*/
//======================================================================================//