4#include <Tempest/Platform>
7#if defined(__WINDOWS__)
9#include <processthreadsapi.h>
18 const DWORD MS_VC_EXCEPTION = 0x406D1388;
19 DWORD dwThreadID = GetCurrentThreadId();
21 struct THREADNAME_INFO {
22 DWORD dwType = 0x1000;
29 THREADNAME_INFO info = {};
30 info.szName = threadName;
31 info.dwThreadID = dwThreadID;
35 RaiseException(MS_VC_EXCEPTION, 0,
sizeof(info)/
sizeof(ULONG_PTR), (ULONG_PTR*)&info );
37 __except(EXCEPTION_EXECUTE_HANDLER) {
40#elif defined(__WINDOWS__)
43 pthread_setname_np(pthread_self(), threadName);
45 auto k32 = GetModuleHandleA(
"Kernel32");
46 auto fn = GetProcAddress(k32,
"SetThreadDescription");
52 for(
size_t i=0; i<63 && threadName[i]; ++i)
53 wname[i] = WCHAR(threadName[i]);
54 auto SetThreadDescription =
reinterpret_cast<HRESULT(WINAPI*)(HANDLE,PCWSTR)
>(fn);
55 SetThreadDescription(GetCurrentThread(), wname);
57#elif defined(__GNUC__) && !defined(__clang__)
59 pthread_setname_np(pthread_self(), threadName);
63 pthread_setname_np(threadName);
69using namespace Tempest;
71const size_t Workers::taskPerThread = 128;
72const size_t Workers::taskPerStep = 16;
77 i = std::thread([
this,
id]()
noexcept {
87 workSize = MAX_THREADS;
88 execWork(minWorkSize<void,void>());
99 int32_t th = int32_t(std::thread::hardware_concurrency());
107void Workers::threadFunc(
size_t id) {
115 std::unique_lock<std::mutex> lck(sync);
116 workWait.wait(lck, [
this]() {
return workTbd>0; });
121 taskDone.fetch_add(1);
125 if(workSet==
nullptr) {
126 auto idx = progressIt.fetch_add(1);
127 workFunc(workSet+idx, 1);
132 taskDone.fetch_add(1);
138uint32_t Workers::taskLoop() {
141 size_t b = size_t(progressIt.fetch_add(taskPerStep));
142 size_t e = std::min(b+taskPerStep, workSize);
146 void* d = workSet + b*workEltSize;
148 count += uint32_t(e-b);
153void Workers::execWork(uint32_t& minElts) {
157 if(workSet!=
nullptr) {
159 taskCount = uint32_t((workSize+taskPerThread-1)/taskPerThread);
161 if(taskCount>maxTheads)
162 taskCount = maxTheads;
166 taskCount = uint32_t(workSize);
169 if(running && taskCount==1) {
170 workFunc(workSet, workSize);
174 minElts = std::max<uint32_t>(minElts, taskPerThread);
176 if(workSet!=
nullptr && workSize<=minElts &&
true) {
177 workFunc(workSet, workSize);
178 if(minElts > workSize*2)
187 std::unique_lock<std::mutex> lck(sync);
188 workTbd = int32_t(taskCount);
190 workWait.notify_all();
193 if(workSet==
nullptr) {
194 std::this_thread::yield();
196 cnt = taskLoop(); (void)cnt;
200 int expect = int(taskCount);
201 if(taskDone.load()==expect) {
205 std::this_thread::yield();
static uint8_t maxThreads()
static void setThreadName(const char *threadName)