Skip to content

Commit e701494

Browse files
ThreadPool: added PinWorkerThread helper function
1 parent 6457688 commit e701494

File tree

5 files changed

+73
-3
lines changed

5 files changed

+73
-3
lines changed

Common/interface/ThreadPool.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,18 @@ struct ThreadPoolCreateInfo
6262

6363
RefCntAutoPtr<IThreadPool> CreateThreadPool(const ThreadPoolCreateInfo& ThreadPoolCI);
6464

65+
/// Pins the worker thread to one of the allowed cores.
66+
///
67+
/// \param ThreadId - The thread ID.
68+
/// \param AllowedCoresMask - The bit mask of allowed cores.
69+
/// \return - Previous thread affinity mask, or 0 if the function failed.
70+
///
71+
/// \remarks The function selects the core by looping through the bits in the AllowedCoresMask.
72+
/// For example, if cores 1, 3, 6 are allowed by the mask, the threads will be assigned
73+
/// to cores 1, 3, 6, 1, 3, 6, etc.
74+
///
75+
/// This function can be used as the OnThreadStarted callback in the ThreadPoolCreateInfo.
76+
Uint64 PinWorkerThread(Uint32 ThreadId, Uint64 AllowedCoresMask);
6577

6678
/// Base implementation of the IAsyncTask interface.
6779
class AsyncTaskBase : public ObjectBase<IAsyncTask>

Common/src/ThreadPool.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
#include <condition_variable>
3535
#include <cfloat>
3636

37+
#include "PlatformMisc.hpp"
38+
3739
namespace Diligent
3840
{
3941

@@ -350,4 +352,47 @@ RefCntAutoPtr<IThreadPool> CreateThreadPool(const ThreadPoolCreateInfo& ThreadPo
350352
return RefCntAutoPtr<ThreadPoolImpl>{MakeNewRCObj<ThreadPoolImpl>()(ThreadPoolCI)};
351353
}
352354

355+
Uint64 PinWorkerThread(Uint32 ThreadId, Uint64 AllowedCoresMask)
356+
{
357+
if (AllowedCoresMask == 0)
358+
{
359+
return 0;
360+
}
361+
362+
Uint64 NumCores = std::thread::hardware_concurrency();
363+
if (NumCores <= 1)
364+
return 0;
365+
366+
Uint64 AffinityMask = AllowedCoresMask;
367+
if (NumCores < 64)
368+
AffinityMask &= (Uint64{1} << NumCores) - Uint64{1};
369+
370+
if (AffinityMask == 0)
371+
{
372+
LOG_WARNING_MESSAGE("Allowed cores mask (0x", std::hex, AllowedCoresMask, ") does not set any bits corresponding to ", std::dec, NumCores, " available cores");
373+
return 0;
374+
}
375+
376+
const Uint32 NumAllowedCores = PlatformMisc::CountOneBits(AffinityMask);
377+
const Uint32 CoreBitInd = ThreadId % NumAllowedCores;
378+
379+
for (Uint32 bit = 0; bit < CoreBitInd; ++bit)
380+
{
381+
VERIFY_EXPR(AffinityMask != 0);
382+
Uint64 LSB = PlatformMisc::GetLSB(AffinityMask);
383+
AffinityMask &= ~(Uint64{1} << LSB);
384+
}
385+
386+
VERIFY_EXPR(AffinityMask != 0);
387+
Uint32 WorkerCore = PlatformMisc::GetLSB(AffinityMask);
388+
VERIFY_EXPR(WorkerCore < NumCores);
389+
Uint64 PrevMask = PlatformMisc::SetCurrentThreadAffinity(Uint64{1} << WorkerCore) != 0;
390+
if (PrevMask == 0)
391+
{
392+
LOG_WARNING_MESSAGE("Failed to pin worker thread ", ThreadId, " to core ", WorkerCore);
393+
}
394+
395+
return PrevMask;
396+
}
397+
353398
} // namespace Diligent

Platforms/Basic/interface/BasicPlatformMisc.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019-2022 Diligent Graphics LLC
2+
* Copyright 2019-2024 Diligent Graphics LLC
33
* Copyright 2015-2019 Egor Yusov
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -107,6 +107,9 @@ struct BasicPlatformMisc
107107
/// On failure, returns ThreadPriority::Unknown.
108108
static ThreadPriority SetCurrentThreadPriority(ThreadPriority Priority);
109109

110+
/// Sets the current thread affinity mask and on success returns the previous mask.
111+
static Uint64 SetCurrentThreadAffinity(Uint64 Mask);
112+
110113
private:
111114
static void SwapBytes16(Uint16& Val)
112115
{

Platforms/Basic/src/BasicPlatformMisc.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019-2022 Diligent Graphics LLC
2+
* Copyright 2019-2024 Diligent Graphics LLC
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -42,4 +42,10 @@ ThreadPriority BasicPlatformMisc::SetCurrentThreadPriority(ThreadPriority Priori
4242
return ThreadPriority::Unknown;
4343
}
4444

45+
Uint64 BasicPlatformMisc::SetCurrentThreadAffinity(Uint64 Mask)
46+
{
47+
LOG_WARNING_MESSAGE_ONCE("SetCurrentThreadAffinity is not implemented on this platform.");
48+
return 0;
49+
}
50+
4551
} // namespace Diligent

Platforms/Win32/src/Win32PlatformMisc.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019-2022 Diligent Graphics LLC
2+
* Copyright 2019-2024 Diligent Graphics LLC
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -35,8 +35,12 @@ namespace Diligent
3535

3636
Uint64 WindowsMisc::SetCurrentThreadAffinity(Uint64 Mask)
3737
{
38+
#if PLATFORM_WIN32
3839
const auto hCurrThread = GetCurrentThread();
3940
return SetThreadAffinityMask(hCurrThread, static_cast<DWORD_PTR>(Mask));
41+
#else
42+
return BasicPlatformMisc::SetCurrentThreadAffinity(Mask);
43+
#endif
4044
}
4145

4246

0 commit comments

Comments
 (0)