Skip to content

Commit

Permalink
ThreadPool: added PinWorkerThread helper function
Browse files Browse the repository at this point in the history
  • Loading branch information
TheMostDiligent committed Oct 25, 2024
1 parent 6457688 commit cb699ef
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 3 deletions.
12 changes: 12 additions & 0 deletions Common/interface/ThreadPool.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@ struct ThreadPoolCreateInfo

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

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

/// Base implementation of the IAsyncTask interface.
class AsyncTaskBase : public ObjectBase<IAsyncTask>
Expand Down
45 changes: 45 additions & 0 deletions Common/src/ThreadPool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
#include <condition_variable>
#include <cfloat>

#include "PlatformMisc.hpp"

namespace Diligent
{

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

Uint64 PinWorkerThread(Uint32 ThreadId, Uint64 AllowedCoresMask)
{
if (AllowedCoresMask == 0)
{
return 0;
}

Uint64 NumCores = std::thread::hardware_concurrency();
if (NumCores <= 1)
return 0;

Uint64 AffinityMask = AllowedCoresMask;
if (NumCores < 64)
AffinityMask &= (Uint64{1} << NumCores) - Uint64{1};

if (AffinityMask == 0)
{
LOG_WARNING_MESSAGE("Allowed cores mask (0x", std::hex, AllowedCoresMask, ") does not set any bits corresponding to ", std::dec, NumCores, " available cores");
return 0;
}

const Uint32 NumAllowedCores = PlatformMisc::CountOneBits(AffinityMask);
const Uint32 CoreBitInd = ThreadId % NumAllowedCores;

for (Uint32 bit = 0; bit < CoreBitInd; ++bit)
{
VERIFY_EXPR(AffinityMask != 0);
Uint64 LSB = PlatformMisc::GetLSB(AffinityMask);
AffinityMask &= ~(Uint64{1} << LSB);
}

VERIFY_EXPR(AffinityMask != 0);
Uint32 WorkerCore = PlatformMisc::GetLSB(AffinityMask);
VERIFY_EXPR(WorkerCore < NumCores);
Uint64 PrevMask = PlatformMisc::SetCurrentThreadAffinity(Uint64{1} << WorkerCore) != 0;
if (PrevMask == 0)
{
LOG_WARNING_MESSAGE("Failed to pin worker thread ", ThreadId, " to core ", WorkerCore);
}

return PrevMask;
}

} // namespace Diligent
5 changes: 4 additions & 1 deletion Platforms/Basic/interface/BasicPlatformMisc.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 Diligent Graphics LLC
* Copyright 2019-2024 Diligent Graphics LLC
* Copyright 2015-2019 Egor Yusov
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -107,6 +107,9 @@ struct BasicPlatformMisc
/// On failure, returns ThreadPriority::Unknown.
static ThreadPriority SetCurrentThreadPriority(ThreadPriority Priority);

/// Sets the current thread affinity mask and on success returns the previous mask.
static Uint64 SetCurrentThreadAffinity(Uint64 Mask);

private:
static void SwapBytes16(Uint16& Val)
{
Expand Down
8 changes: 7 additions & 1 deletion Platforms/Basic/src/BasicPlatformMisc.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 Diligent Graphics LLC
* Copyright 2019-2024 Diligent Graphics LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -42,4 +42,10 @@ ThreadPriority BasicPlatformMisc::SetCurrentThreadPriority(ThreadPriority Priori
return ThreadPriority::Unknown;
}

Uint64 BasicPlatformMisc::SetCurrentThreadAffinity(Uint64 Mask)
{
LOG_WARNING_MESSAGE_ONCE("SetCurrentThreadAffinity is not implemented on this platform.");
return 0;
}

} // namespace Diligent
4 changes: 3 additions & 1 deletion Platforms/Win32/interface/Win32PlatformMisc.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 Diligent Graphics LLC
* Copyright 2019-2024 Diligent Graphics LLC
* Copyright 2015-2019 Egor Yusov
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -163,6 +163,7 @@ struct WindowsMisc : public BasicPlatformMisc
return reinterpret_cast<const Type&>(SwappedBytes);
}

#if PLATFORM_WIN32
/// Sets the current thread affinity mask and on success returns the previous mask.
/// On failure, returns 0.
static Uint64 SetCurrentThreadAffinity(Uint64 Mask);
Expand All @@ -172,6 +173,7 @@ struct WindowsMisc : public BasicPlatformMisc
/// Sets the current thread priority and on success returns the previous priority.
/// On failure, returns ThreadPriority::Unknown.
static ThreadPriority SetCurrentThreadPriority(ThreadPriority Priority);
#endif
};

} // namespace Diligent

0 comments on commit cb699ef

Please sign in to comment.