1*03ce13f7SAndroid Build Coastguard Worker // Copyright 2019 The Marl Authors.
2*03ce13f7SAndroid Build Coastguard Worker //
3*03ce13f7SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*03ce13f7SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*03ce13f7SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*03ce13f7SAndroid Build Coastguard Worker //
7*03ce13f7SAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*03ce13f7SAndroid Build Coastguard Worker //
9*03ce13f7SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*03ce13f7SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*03ce13f7SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*03ce13f7SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*03ce13f7SAndroid Build Coastguard Worker // limitations under the License.
14*03ce13f7SAndroid Build Coastguard Worker
15*03ce13f7SAndroid Build Coastguard Worker #include "marl/thread.h"
16*03ce13f7SAndroid Build Coastguard Worker
17*03ce13f7SAndroid Build Coastguard Worker #include "marl/debug.h"
18*03ce13f7SAndroid Build Coastguard Worker #include "marl/defer.h"
19*03ce13f7SAndroid Build Coastguard Worker #include "marl/trace.h"
20*03ce13f7SAndroid Build Coastguard Worker
21*03ce13f7SAndroid Build Coastguard Worker #include <algorithm> // std::sort
22*03ce13f7SAndroid Build Coastguard Worker
23*03ce13f7SAndroid Build Coastguard Worker #include <cstdarg>
24*03ce13f7SAndroid Build Coastguard Worker #include <cstdio>
25*03ce13f7SAndroid Build Coastguard Worker
26*03ce13f7SAndroid Build Coastguard Worker #if defined(_WIN32)
27*03ce13f7SAndroid Build Coastguard Worker #define WIN32_LEAN_AND_MEAN 1
28*03ce13f7SAndroid Build Coastguard Worker #include <windows.h>
29*03ce13f7SAndroid Build Coastguard Worker #include <array>
30*03ce13f7SAndroid Build Coastguard Worker #include <cstdlib> // mbstowcs
31*03ce13f7SAndroid Build Coastguard Worker #include <limits> // std::numeric_limits
32*03ce13f7SAndroid Build Coastguard Worker #include <vector>
33*03ce13f7SAndroid Build Coastguard Worker #undef max
34*03ce13f7SAndroid Build Coastguard Worker #elif defined(__APPLE__)
35*03ce13f7SAndroid Build Coastguard Worker #include <mach/thread_act.h>
36*03ce13f7SAndroid Build Coastguard Worker #include <pthread.h>
37*03ce13f7SAndroid Build Coastguard Worker #include <unistd.h>
38*03ce13f7SAndroid Build Coastguard Worker #include <thread>
39*03ce13f7SAndroid Build Coastguard Worker #elif defined(__FreeBSD__)
40*03ce13f7SAndroid Build Coastguard Worker #include <pthread.h>
41*03ce13f7SAndroid Build Coastguard Worker #include <pthread_np.h>
42*03ce13f7SAndroid Build Coastguard Worker #include <unistd.h>
43*03ce13f7SAndroid Build Coastguard Worker #include <thread>
44*03ce13f7SAndroid Build Coastguard Worker #else
45*03ce13f7SAndroid Build Coastguard Worker #include <pthread.h>
46*03ce13f7SAndroid Build Coastguard Worker #include <unistd.h>
47*03ce13f7SAndroid Build Coastguard Worker #include <thread>
48*03ce13f7SAndroid Build Coastguard Worker #endif
49*03ce13f7SAndroid Build Coastguard Worker
50*03ce13f7SAndroid Build Coastguard Worker namespace {
51*03ce13f7SAndroid Build Coastguard Worker
52*03ce13f7SAndroid Build Coastguard Worker struct CoreHasher {
operator ()__anon9f7b20ce0111::CoreHasher53*03ce13f7SAndroid Build Coastguard Worker inline uint64_t operator()(marl::Thread::Core core) const {
54*03ce13f7SAndroid Build Coastguard Worker return core.pthread.index;
55*03ce13f7SAndroid Build Coastguard Worker }
56*03ce13f7SAndroid Build Coastguard Worker };
57*03ce13f7SAndroid Build Coastguard Worker
58*03ce13f7SAndroid Build Coastguard Worker } // anonymous namespace
59*03ce13f7SAndroid Build Coastguard Worker
60*03ce13f7SAndroid Build Coastguard Worker namespace marl {
61*03ce13f7SAndroid Build Coastguard Worker
62*03ce13f7SAndroid Build Coastguard Worker #if defined(_WIN32)
63*03ce13f7SAndroid Build Coastguard Worker static constexpr size_t MaxCoreCount =
64*03ce13f7SAndroid Build Coastguard Worker std::numeric_limits<decltype(Thread::Core::windows.index)>::max() + 1ULL;
65*03ce13f7SAndroid Build Coastguard Worker static constexpr size_t MaxGroupCount =
66*03ce13f7SAndroid Build Coastguard Worker std::numeric_limits<decltype(Thread::Core::windows.group)>::max() + 1ULL;
67*03ce13f7SAndroid Build Coastguard Worker static_assert(sizeof(KAFFINITY) * 8ULL <= MaxCoreCount,
68*03ce13f7SAndroid Build Coastguard Worker "Thread::Core::windows.index is too small");
69*03ce13f7SAndroid Build Coastguard Worker
70*03ce13f7SAndroid Build Coastguard Worker namespace {
71*03ce13f7SAndroid Build Coastguard Worker #define CHECK_WIN32(expr) \
72*03ce13f7SAndroid Build Coastguard Worker do { \
73*03ce13f7SAndroid Build Coastguard Worker auto res = expr; \
74*03ce13f7SAndroid Build Coastguard Worker (void)res; \
75*03ce13f7SAndroid Build Coastguard Worker MARL_ASSERT(res == TRUE, #expr " failed with error: %d", \
76*03ce13f7SAndroid Build Coastguard Worker (int)GetLastError()); \
77*03ce13f7SAndroid Build Coastguard Worker } while (false)
78*03ce13f7SAndroid Build Coastguard Worker
79*03ce13f7SAndroid Build Coastguard Worker struct ProcessorGroup {
80*03ce13f7SAndroid Build Coastguard Worker unsigned int count; // number of logical processors in this group.
81*03ce13f7SAndroid Build Coastguard Worker KAFFINITY affinity; // affinity mask.
82*03ce13f7SAndroid Build Coastguard Worker };
83*03ce13f7SAndroid Build Coastguard Worker
84*03ce13f7SAndroid Build Coastguard Worker struct ProcessorGroups {
85*03ce13f7SAndroid Build Coastguard Worker std::array<ProcessorGroup, MaxGroupCount> groups;
86*03ce13f7SAndroid Build Coastguard Worker size_t count;
87*03ce13f7SAndroid Build Coastguard Worker };
88*03ce13f7SAndroid Build Coastguard Worker
getProcessorGroups()89*03ce13f7SAndroid Build Coastguard Worker const ProcessorGroups& getProcessorGroups() {
90*03ce13f7SAndroid Build Coastguard Worker static ProcessorGroups groups = [] {
91*03ce13f7SAndroid Build Coastguard Worker ProcessorGroups out = {};
92*03ce13f7SAndroid Build Coastguard Worker SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info[32] = {};
93*03ce13f7SAndroid Build Coastguard Worker DWORD size = sizeof(info);
94*03ce13f7SAndroid Build Coastguard Worker CHECK_WIN32(GetLogicalProcessorInformationEx(RelationGroup, info, &size));
95*03ce13f7SAndroid Build Coastguard Worker DWORD count = size / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX);
96*03ce13f7SAndroid Build Coastguard Worker for (DWORD i = 0; i < count; i++) {
97*03ce13f7SAndroid Build Coastguard Worker if (info[i].Relationship == RelationGroup) {
98*03ce13f7SAndroid Build Coastguard Worker auto groupCount = info[i].Group.ActiveGroupCount;
99*03ce13f7SAndroid Build Coastguard Worker for (WORD groupIdx = 0; groupIdx < groupCount; groupIdx++) {
100*03ce13f7SAndroid Build Coastguard Worker auto const& groupInfo = info[i].Group.GroupInfo[groupIdx];
101*03ce13f7SAndroid Build Coastguard Worker out.groups[out.count++] = ProcessorGroup{
102*03ce13f7SAndroid Build Coastguard Worker groupInfo.ActiveProcessorCount, groupInfo.ActiveProcessorMask};
103*03ce13f7SAndroid Build Coastguard Worker MARL_ASSERT(out.count <= MaxGroupCount, "Group index overflow");
104*03ce13f7SAndroid Build Coastguard Worker }
105*03ce13f7SAndroid Build Coastguard Worker }
106*03ce13f7SAndroid Build Coastguard Worker }
107*03ce13f7SAndroid Build Coastguard Worker return out;
108*03ce13f7SAndroid Build Coastguard Worker }();
109*03ce13f7SAndroid Build Coastguard Worker return groups;
110*03ce13f7SAndroid Build Coastguard Worker }
111*03ce13f7SAndroid Build Coastguard Worker } // namespace
112*03ce13f7SAndroid Build Coastguard Worker #endif // defined(_WIN32)
113*03ce13f7SAndroid Build Coastguard Worker
114*03ce13f7SAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
115*03ce13f7SAndroid Build Coastguard Worker // Thread::Affinty
116*03ce13f7SAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
117*03ce13f7SAndroid Build Coastguard Worker
Affinity(Allocator * allocator)118*03ce13f7SAndroid Build Coastguard Worker Thread::Affinity::Affinity(Allocator* allocator) : cores(allocator) {}
Affinity(Affinity && other)119*03ce13f7SAndroid Build Coastguard Worker Thread::Affinity::Affinity(Affinity&& other) : cores(std::move(other.cores)) {}
operator =(Affinity && other)120*03ce13f7SAndroid Build Coastguard Worker Thread::Affinity& Thread::Affinity::operator=(Affinity&& other) {
121*03ce13f7SAndroid Build Coastguard Worker cores = std::move(other.cores);
122*03ce13f7SAndroid Build Coastguard Worker return *this;
123*03ce13f7SAndroid Build Coastguard Worker }
Affinity(const Affinity & other,Allocator * allocator)124*03ce13f7SAndroid Build Coastguard Worker Thread::Affinity::Affinity(const Affinity& other, Allocator* allocator)
125*03ce13f7SAndroid Build Coastguard Worker : cores(other.cores, allocator) {}
126*03ce13f7SAndroid Build Coastguard Worker
Affinity(std::initializer_list<Core> list,Allocator * allocator)127*03ce13f7SAndroid Build Coastguard Worker Thread::Affinity::Affinity(std::initializer_list<Core> list,
128*03ce13f7SAndroid Build Coastguard Worker Allocator* allocator)
129*03ce13f7SAndroid Build Coastguard Worker : cores(allocator) {
130*03ce13f7SAndroid Build Coastguard Worker cores.reserve(list.size());
131*03ce13f7SAndroid Build Coastguard Worker for (auto core : list) {
132*03ce13f7SAndroid Build Coastguard Worker cores.push_back(core);
133*03ce13f7SAndroid Build Coastguard Worker }
134*03ce13f7SAndroid Build Coastguard Worker }
135*03ce13f7SAndroid Build Coastguard Worker
Affinity(const containers::vector<Core,32> & coreList,Allocator * allocator)136*03ce13f7SAndroid Build Coastguard Worker Thread::Affinity::Affinity(const containers::vector<Core, 32>& coreList,
137*03ce13f7SAndroid Build Coastguard Worker Allocator* allocator)
138*03ce13f7SAndroid Build Coastguard Worker : cores(coreList, allocator) {}
139*03ce13f7SAndroid Build Coastguard Worker
all(Allocator * allocator)140*03ce13f7SAndroid Build Coastguard Worker Thread::Affinity Thread::Affinity::all(
141*03ce13f7SAndroid Build Coastguard Worker Allocator* allocator /* = Allocator::Default */) {
142*03ce13f7SAndroid Build Coastguard Worker Thread::Affinity affinity(allocator);
143*03ce13f7SAndroid Build Coastguard Worker
144*03ce13f7SAndroid Build Coastguard Worker #if defined(_WIN32)
145*03ce13f7SAndroid Build Coastguard Worker const auto& groups = getProcessorGroups();
146*03ce13f7SAndroid Build Coastguard Worker for (size_t groupIdx = 0; groupIdx < groups.count; groupIdx++) {
147*03ce13f7SAndroid Build Coastguard Worker const auto& group = groups.groups[groupIdx];
148*03ce13f7SAndroid Build Coastguard Worker Core core;
149*03ce13f7SAndroid Build Coastguard Worker core.windows.group = static_cast<decltype(Core::windows.group)>(groupIdx);
150*03ce13f7SAndroid Build Coastguard Worker for (unsigned int coreIdx = 0; coreIdx < group.count; coreIdx++) {
151*03ce13f7SAndroid Build Coastguard Worker if ((group.affinity >> coreIdx) & 1) {
152*03ce13f7SAndroid Build Coastguard Worker core.windows.index = static_cast<decltype(core.windows.index)>(coreIdx);
153*03ce13f7SAndroid Build Coastguard Worker affinity.cores.emplace_back(std::move(core));
154*03ce13f7SAndroid Build Coastguard Worker }
155*03ce13f7SAndroid Build Coastguard Worker }
156*03ce13f7SAndroid Build Coastguard Worker }
157*03ce13f7SAndroid Build Coastguard Worker #elif defined(__linux__) && !defined(__ANDROID__) && !defined(__BIONIC__)
158*03ce13f7SAndroid Build Coastguard Worker auto thread = pthread_self();
159*03ce13f7SAndroid Build Coastguard Worker cpu_set_t cpuset;
160*03ce13f7SAndroid Build Coastguard Worker CPU_ZERO(&cpuset);
161*03ce13f7SAndroid Build Coastguard Worker if (pthread_getaffinity_np(thread, sizeof(cpu_set_t), &cpuset) == 0) {
162*03ce13f7SAndroid Build Coastguard Worker int count = CPU_COUNT(&cpuset);
163*03ce13f7SAndroid Build Coastguard Worker for (int i = 0; i < count; i++) {
164*03ce13f7SAndroid Build Coastguard Worker Core core;
165*03ce13f7SAndroid Build Coastguard Worker core.pthread.index = static_cast<uint16_t>(i);
166*03ce13f7SAndroid Build Coastguard Worker affinity.cores.emplace_back(std::move(core));
167*03ce13f7SAndroid Build Coastguard Worker }
168*03ce13f7SAndroid Build Coastguard Worker }
169*03ce13f7SAndroid Build Coastguard Worker #elif defined(__FreeBSD__)
170*03ce13f7SAndroid Build Coastguard Worker auto thread = pthread_self();
171*03ce13f7SAndroid Build Coastguard Worker cpuset_t cpuset;
172*03ce13f7SAndroid Build Coastguard Worker CPU_ZERO(&cpuset);
173*03ce13f7SAndroid Build Coastguard Worker if (pthread_getaffinity_np(thread, sizeof(cpuset_t), &cpuset) == 0) {
174*03ce13f7SAndroid Build Coastguard Worker int count = CPU_COUNT(&cpuset);
175*03ce13f7SAndroid Build Coastguard Worker for (int i = 0; i < count; i++) {
176*03ce13f7SAndroid Build Coastguard Worker Core core;
177*03ce13f7SAndroid Build Coastguard Worker core.pthread.index = static_cast<uint16_t>(i);
178*03ce13f7SAndroid Build Coastguard Worker affinity.cores.emplace_back(std::move(core));
179*03ce13f7SAndroid Build Coastguard Worker }
180*03ce13f7SAndroid Build Coastguard Worker }
181*03ce13f7SAndroid Build Coastguard Worker #else
182*03ce13f7SAndroid Build Coastguard Worker static_assert(!supported,
183*03ce13f7SAndroid Build Coastguard Worker "marl::Thread::Affinity::supported is true, but "
184*03ce13f7SAndroid Build Coastguard Worker "Thread::Affinity::all() is not implemented for this platform");
185*03ce13f7SAndroid Build Coastguard Worker #endif
186*03ce13f7SAndroid Build Coastguard Worker
187*03ce13f7SAndroid Build Coastguard Worker return affinity;
188*03ce13f7SAndroid Build Coastguard Worker }
189*03ce13f7SAndroid Build Coastguard Worker
anyOf(Affinity && affinity,Allocator * allocator)190*03ce13f7SAndroid Build Coastguard Worker std::shared_ptr<Thread::Affinity::Policy> Thread::Affinity::Policy::anyOf(
191*03ce13f7SAndroid Build Coastguard Worker Affinity&& affinity,
192*03ce13f7SAndroid Build Coastguard Worker Allocator* allocator /* = Allocator::Default */) {
193*03ce13f7SAndroid Build Coastguard Worker struct Policy : public Thread::Affinity::Policy {
194*03ce13f7SAndroid Build Coastguard Worker Affinity affinity;
195*03ce13f7SAndroid Build Coastguard Worker Policy(Affinity&& affinity) : affinity(std::move(affinity)) {}
196*03ce13f7SAndroid Build Coastguard Worker
197*03ce13f7SAndroid Build Coastguard Worker Affinity get(uint32_t threadId, Allocator* allocator) const override {
198*03ce13f7SAndroid Build Coastguard Worker #if defined(_WIN32)
199*03ce13f7SAndroid Build Coastguard Worker auto count = affinity.count();
200*03ce13f7SAndroid Build Coastguard Worker if (count == 0) {
201*03ce13f7SAndroid Build Coastguard Worker return Affinity(affinity, allocator);
202*03ce13f7SAndroid Build Coastguard Worker }
203*03ce13f7SAndroid Build Coastguard Worker auto group = affinity[threadId % affinity.count()].windows.group;
204*03ce13f7SAndroid Build Coastguard Worker Affinity out(allocator);
205*03ce13f7SAndroid Build Coastguard Worker out.cores.reserve(count);
206*03ce13f7SAndroid Build Coastguard Worker for (auto core : affinity.cores) {
207*03ce13f7SAndroid Build Coastguard Worker if (core.windows.group == group) {
208*03ce13f7SAndroid Build Coastguard Worker out.cores.push_back(core);
209*03ce13f7SAndroid Build Coastguard Worker }
210*03ce13f7SAndroid Build Coastguard Worker }
211*03ce13f7SAndroid Build Coastguard Worker return out;
212*03ce13f7SAndroid Build Coastguard Worker #else
213*03ce13f7SAndroid Build Coastguard Worker return Affinity(affinity, allocator);
214*03ce13f7SAndroid Build Coastguard Worker #endif
215*03ce13f7SAndroid Build Coastguard Worker }
216*03ce13f7SAndroid Build Coastguard Worker };
217*03ce13f7SAndroid Build Coastguard Worker
218*03ce13f7SAndroid Build Coastguard Worker return allocator->make_shared<Policy>(std::move(affinity));
219*03ce13f7SAndroid Build Coastguard Worker }
220*03ce13f7SAndroid Build Coastguard Worker
oneOf(Affinity && affinity,Allocator * allocator)221*03ce13f7SAndroid Build Coastguard Worker std::shared_ptr<Thread::Affinity::Policy> Thread::Affinity::Policy::oneOf(
222*03ce13f7SAndroid Build Coastguard Worker Affinity&& affinity,
223*03ce13f7SAndroid Build Coastguard Worker Allocator* allocator /* = Allocator::Default */) {
224*03ce13f7SAndroid Build Coastguard Worker struct Policy : public Thread::Affinity::Policy {
225*03ce13f7SAndroid Build Coastguard Worker Affinity affinity;
226*03ce13f7SAndroid Build Coastguard Worker Policy(Affinity&& affinity) : affinity(std::move(affinity)) {}
227*03ce13f7SAndroid Build Coastguard Worker
228*03ce13f7SAndroid Build Coastguard Worker Affinity get(uint32_t threadId, Allocator* allocator) const override {
229*03ce13f7SAndroid Build Coastguard Worker auto count = affinity.count();
230*03ce13f7SAndroid Build Coastguard Worker if (count == 0) {
231*03ce13f7SAndroid Build Coastguard Worker return Affinity(affinity, allocator);
232*03ce13f7SAndroid Build Coastguard Worker }
233*03ce13f7SAndroid Build Coastguard Worker return Affinity({affinity[threadId % affinity.count()]}, allocator);
234*03ce13f7SAndroid Build Coastguard Worker }
235*03ce13f7SAndroid Build Coastguard Worker };
236*03ce13f7SAndroid Build Coastguard Worker
237*03ce13f7SAndroid Build Coastguard Worker return allocator->make_shared<Policy>(std::move(affinity));
238*03ce13f7SAndroid Build Coastguard Worker }
239*03ce13f7SAndroid Build Coastguard Worker
count() const240*03ce13f7SAndroid Build Coastguard Worker size_t Thread::Affinity::count() const {
241*03ce13f7SAndroid Build Coastguard Worker return cores.size();
242*03ce13f7SAndroid Build Coastguard Worker }
243*03ce13f7SAndroid Build Coastguard Worker
operator [](size_t index) const244*03ce13f7SAndroid Build Coastguard Worker Thread::Core Thread::Affinity::operator[](size_t index) const {
245*03ce13f7SAndroid Build Coastguard Worker return cores[index];
246*03ce13f7SAndroid Build Coastguard Worker }
247*03ce13f7SAndroid Build Coastguard Worker
add(const Thread::Affinity & other)248*03ce13f7SAndroid Build Coastguard Worker Thread::Affinity& Thread::Affinity::add(const Thread::Affinity& other) {
249*03ce13f7SAndroid Build Coastguard Worker containers::unordered_set<Core, CoreHasher> set(cores.allocator);
250*03ce13f7SAndroid Build Coastguard Worker for (auto core : cores) {
251*03ce13f7SAndroid Build Coastguard Worker set.emplace(core);
252*03ce13f7SAndroid Build Coastguard Worker }
253*03ce13f7SAndroid Build Coastguard Worker for (auto core : other.cores) {
254*03ce13f7SAndroid Build Coastguard Worker if (set.count(core) == 0) {
255*03ce13f7SAndroid Build Coastguard Worker cores.push_back(core);
256*03ce13f7SAndroid Build Coastguard Worker }
257*03ce13f7SAndroid Build Coastguard Worker }
258*03ce13f7SAndroid Build Coastguard Worker std::sort(cores.begin(), cores.end());
259*03ce13f7SAndroid Build Coastguard Worker return *this;
260*03ce13f7SAndroid Build Coastguard Worker }
261*03ce13f7SAndroid Build Coastguard Worker
remove(const Thread::Affinity & other)262*03ce13f7SAndroid Build Coastguard Worker Thread::Affinity& Thread::Affinity::remove(const Thread::Affinity& other) {
263*03ce13f7SAndroid Build Coastguard Worker containers::unordered_set<Core, CoreHasher> set(cores.allocator);
264*03ce13f7SAndroid Build Coastguard Worker for (auto core : other.cores) {
265*03ce13f7SAndroid Build Coastguard Worker set.emplace(core);
266*03ce13f7SAndroid Build Coastguard Worker }
267*03ce13f7SAndroid Build Coastguard Worker for (size_t i = 0; i < cores.size(); i++) {
268*03ce13f7SAndroid Build Coastguard Worker if (set.count(cores[i]) != 0) {
269*03ce13f7SAndroid Build Coastguard Worker cores[i] = cores.back();
270*03ce13f7SAndroid Build Coastguard Worker cores.resize(cores.size() - 1);
271*03ce13f7SAndroid Build Coastguard Worker }
272*03ce13f7SAndroid Build Coastguard Worker }
273*03ce13f7SAndroid Build Coastguard Worker std::sort(cores.begin(), cores.end());
274*03ce13f7SAndroid Build Coastguard Worker return *this;
275*03ce13f7SAndroid Build Coastguard Worker }
276*03ce13f7SAndroid Build Coastguard Worker
277*03ce13f7SAndroid Build Coastguard Worker #if defined(_WIN32)
278*03ce13f7SAndroid Build Coastguard Worker
279*03ce13f7SAndroid Build Coastguard Worker class Thread::Impl {
280*03ce13f7SAndroid Build Coastguard Worker public:
Impl(Func && func,_PROC_THREAD_ATTRIBUTE_LIST * attributes)281*03ce13f7SAndroid Build Coastguard Worker Impl(Func&& func, _PROC_THREAD_ATTRIBUTE_LIST* attributes)
282*03ce13f7SAndroid Build Coastguard Worker : func(std::move(func)),
283*03ce13f7SAndroid Build Coastguard Worker handle(CreateRemoteThreadEx(GetCurrentProcess(),
284*03ce13f7SAndroid Build Coastguard Worker nullptr,
285*03ce13f7SAndroid Build Coastguard Worker 0,
286*03ce13f7SAndroid Build Coastguard Worker &Impl::run,
287*03ce13f7SAndroid Build Coastguard Worker this,
288*03ce13f7SAndroid Build Coastguard Worker 0,
289*03ce13f7SAndroid Build Coastguard Worker attributes,
290*03ce13f7SAndroid Build Coastguard Worker nullptr)) {}
~Impl()291*03ce13f7SAndroid Build Coastguard Worker ~Impl() { CloseHandle(handle); }
292*03ce13f7SAndroid Build Coastguard Worker
293*03ce13f7SAndroid Build Coastguard Worker Impl(const Impl&) = delete;
294*03ce13f7SAndroid Build Coastguard Worker Impl(Impl&&) = delete;
295*03ce13f7SAndroid Build Coastguard Worker Impl& operator=(const Impl&) = delete;
296*03ce13f7SAndroid Build Coastguard Worker Impl& operator=(Impl&&) = delete;
297*03ce13f7SAndroid Build Coastguard Worker
Join() const298*03ce13f7SAndroid Build Coastguard Worker void Join() const { WaitForSingleObject(handle, INFINITE); }
299*03ce13f7SAndroid Build Coastguard Worker
run(void * self)300*03ce13f7SAndroid Build Coastguard Worker static DWORD WINAPI run(void* self) {
301*03ce13f7SAndroid Build Coastguard Worker reinterpret_cast<Impl*>(self)->func();
302*03ce13f7SAndroid Build Coastguard Worker return 0;
303*03ce13f7SAndroid Build Coastguard Worker }
304*03ce13f7SAndroid Build Coastguard Worker
305*03ce13f7SAndroid Build Coastguard Worker private:
306*03ce13f7SAndroid Build Coastguard Worker const Func func;
307*03ce13f7SAndroid Build Coastguard Worker const HANDLE handle;
308*03ce13f7SAndroid Build Coastguard Worker };
309*03ce13f7SAndroid Build Coastguard Worker
Thread(Affinity && affinity,Func && func)310*03ce13f7SAndroid Build Coastguard Worker Thread::Thread(Affinity&& affinity, Func&& func) {
311*03ce13f7SAndroid Build Coastguard Worker SIZE_T size = 0;
312*03ce13f7SAndroid Build Coastguard Worker InitializeProcThreadAttributeList(nullptr, 1, 0, &size);
313*03ce13f7SAndroid Build Coastguard Worker MARL_ASSERT(size > 0,
314*03ce13f7SAndroid Build Coastguard Worker "InitializeProcThreadAttributeList() did not give a size");
315*03ce13f7SAndroid Build Coastguard Worker
316*03ce13f7SAndroid Build Coastguard Worker std::vector<uint8_t> buffer(size);
317*03ce13f7SAndroid Build Coastguard Worker LPPROC_THREAD_ATTRIBUTE_LIST attributes =
318*03ce13f7SAndroid Build Coastguard Worker reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST>(buffer.data());
319*03ce13f7SAndroid Build Coastguard Worker CHECK_WIN32(InitializeProcThreadAttributeList(attributes, 1, 0, &size));
320*03ce13f7SAndroid Build Coastguard Worker defer(DeleteProcThreadAttributeList(attributes));
321*03ce13f7SAndroid Build Coastguard Worker
322*03ce13f7SAndroid Build Coastguard Worker GROUP_AFFINITY groupAffinity = {};
323*03ce13f7SAndroid Build Coastguard Worker
324*03ce13f7SAndroid Build Coastguard Worker auto count = affinity.count();
325*03ce13f7SAndroid Build Coastguard Worker if (count > 0) {
326*03ce13f7SAndroid Build Coastguard Worker groupAffinity.Group = affinity[0].windows.group;
327*03ce13f7SAndroid Build Coastguard Worker for (size_t i = 0; i < count; i++) {
328*03ce13f7SAndroid Build Coastguard Worker auto core = affinity[i];
329*03ce13f7SAndroid Build Coastguard Worker MARL_ASSERT(groupAffinity.Group == core.windows.group,
330*03ce13f7SAndroid Build Coastguard Worker "Cannot create thread that uses multiple affinity groups");
331*03ce13f7SAndroid Build Coastguard Worker groupAffinity.Mask |= (1ULL << core.windows.index);
332*03ce13f7SAndroid Build Coastguard Worker }
333*03ce13f7SAndroid Build Coastguard Worker CHECK_WIN32(UpdateProcThreadAttribute(
334*03ce13f7SAndroid Build Coastguard Worker attributes, 0, PROC_THREAD_ATTRIBUTE_GROUP_AFFINITY, &groupAffinity,
335*03ce13f7SAndroid Build Coastguard Worker sizeof(groupAffinity), nullptr, nullptr));
336*03ce13f7SAndroid Build Coastguard Worker }
337*03ce13f7SAndroid Build Coastguard Worker
338*03ce13f7SAndroid Build Coastguard Worker impl = new Impl(std::move(func), attributes);
339*03ce13f7SAndroid Build Coastguard Worker }
340*03ce13f7SAndroid Build Coastguard Worker
~Thread()341*03ce13f7SAndroid Build Coastguard Worker Thread::~Thread() {
342*03ce13f7SAndroid Build Coastguard Worker delete impl;
343*03ce13f7SAndroid Build Coastguard Worker }
344*03ce13f7SAndroid Build Coastguard Worker
join()345*03ce13f7SAndroid Build Coastguard Worker void Thread::join() {
346*03ce13f7SAndroid Build Coastguard Worker MARL_ASSERT(impl != nullptr, "join() called on unjoinable thread");
347*03ce13f7SAndroid Build Coastguard Worker impl->Join();
348*03ce13f7SAndroid Build Coastguard Worker }
349*03ce13f7SAndroid Build Coastguard Worker
setName(const char * fmt,...)350*03ce13f7SAndroid Build Coastguard Worker void Thread::setName(const char* fmt, ...) {
351*03ce13f7SAndroid Build Coastguard Worker static auto setThreadDescription =
352*03ce13f7SAndroid Build Coastguard Worker reinterpret_cast<HRESULT(WINAPI*)(HANDLE, PCWSTR)>(GetProcAddress(
353*03ce13f7SAndroid Build Coastguard Worker GetModuleHandleA("kernelbase.dll"), "SetThreadDescription"));
354*03ce13f7SAndroid Build Coastguard Worker if (setThreadDescription == nullptr) {
355*03ce13f7SAndroid Build Coastguard Worker return;
356*03ce13f7SAndroid Build Coastguard Worker }
357*03ce13f7SAndroid Build Coastguard Worker
358*03ce13f7SAndroid Build Coastguard Worker char name[1024];
359*03ce13f7SAndroid Build Coastguard Worker va_list vararg;
360*03ce13f7SAndroid Build Coastguard Worker va_start(vararg, fmt);
361*03ce13f7SAndroid Build Coastguard Worker vsnprintf(name, sizeof(name), fmt, vararg);
362*03ce13f7SAndroid Build Coastguard Worker va_end(vararg);
363*03ce13f7SAndroid Build Coastguard Worker
364*03ce13f7SAndroid Build Coastguard Worker wchar_t wname[1024];
365*03ce13f7SAndroid Build Coastguard Worker mbstowcs(wname, name, 1024);
366*03ce13f7SAndroid Build Coastguard Worker setThreadDescription(GetCurrentThread(), wname);
367*03ce13f7SAndroid Build Coastguard Worker MARL_NAME_THREAD("%s", name);
368*03ce13f7SAndroid Build Coastguard Worker }
369*03ce13f7SAndroid Build Coastguard Worker
numLogicalCPUs()370*03ce13f7SAndroid Build Coastguard Worker unsigned int Thread::numLogicalCPUs() {
371*03ce13f7SAndroid Build Coastguard Worker unsigned int count = 0;
372*03ce13f7SAndroid Build Coastguard Worker const auto& groups = getProcessorGroups();
373*03ce13f7SAndroid Build Coastguard Worker for (size_t groupIdx = 0; groupIdx < groups.count; groupIdx++) {
374*03ce13f7SAndroid Build Coastguard Worker const auto& group = groups.groups[groupIdx];
375*03ce13f7SAndroid Build Coastguard Worker count += group.count;
376*03ce13f7SAndroid Build Coastguard Worker }
377*03ce13f7SAndroid Build Coastguard Worker return count;
378*03ce13f7SAndroid Build Coastguard Worker }
379*03ce13f7SAndroid Build Coastguard Worker
380*03ce13f7SAndroid Build Coastguard Worker #else
381*03ce13f7SAndroid Build Coastguard Worker
382*03ce13f7SAndroid Build Coastguard Worker class Thread::Impl {
383*03ce13f7SAndroid Build Coastguard Worker public:
Impl(Affinity && affinity,Thread::Func && f)384*03ce13f7SAndroid Build Coastguard Worker Impl(Affinity&& affinity, Thread::Func&& f)
385*03ce13f7SAndroid Build Coastguard Worker : affinity(std::move(affinity)), func(std::move(f)), thread([this] {
386*03ce13f7SAndroid Build Coastguard Worker setAffinity();
387*03ce13f7SAndroid Build Coastguard Worker func();
388*03ce13f7SAndroid Build Coastguard Worker }) {}
389*03ce13f7SAndroid Build Coastguard Worker
390*03ce13f7SAndroid Build Coastguard Worker Affinity affinity;
391*03ce13f7SAndroid Build Coastguard Worker Func func;
392*03ce13f7SAndroid Build Coastguard Worker std::thread thread;
393*03ce13f7SAndroid Build Coastguard Worker
setAffinity()394*03ce13f7SAndroid Build Coastguard Worker void setAffinity() {
395*03ce13f7SAndroid Build Coastguard Worker auto count = affinity.count();
396*03ce13f7SAndroid Build Coastguard Worker if (count == 0) {
397*03ce13f7SAndroid Build Coastguard Worker return;
398*03ce13f7SAndroid Build Coastguard Worker }
399*03ce13f7SAndroid Build Coastguard Worker
400*03ce13f7SAndroid Build Coastguard Worker #if defined(__linux__) && !defined(__ANDROID__) && !defined(__BIONIC__)
401*03ce13f7SAndroid Build Coastguard Worker cpu_set_t cpuset;
402*03ce13f7SAndroid Build Coastguard Worker CPU_ZERO(&cpuset);
403*03ce13f7SAndroid Build Coastguard Worker for (size_t i = 0; i < count; i++) {
404*03ce13f7SAndroid Build Coastguard Worker CPU_SET(affinity[i].pthread.index, &cpuset);
405*03ce13f7SAndroid Build Coastguard Worker }
406*03ce13f7SAndroid Build Coastguard Worker auto thread = pthread_self();
407*03ce13f7SAndroid Build Coastguard Worker pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
408*03ce13f7SAndroid Build Coastguard Worker #elif defined(__FreeBSD__)
409*03ce13f7SAndroid Build Coastguard Worker cpuset_t cpuset;
410*03ce13f7SAndroid Build Coastguard Worker CPU_ZERO(&cpuset);
411*03ce13f7SAndroid Build Coastguard Worker for (size_t i = 0; i < count; i++) {
412*03ce13f7SAndroid Build Coastguard Worker CPU_SET(affinity[i].pthread.index, &cpuset);
413*03ce13f7SAndroid Build Coastguard Worker }
414*03ce13f7SAndroid Build Coastguard Worker auto thread = pthread_self();
415*03ce13f7SAndroid Build Coastguard Worker pthread_setaffinity_np(thread, sizeof(cpuset_t), &cpuset);
416*03ce13f7SAndroid Build Coastguard Worker #else
417*03ce13f7SAndroid Build Coastguard Worker MARL_ASSERT(!marl::Thread::Affinity::supported,
418*03ce13f7SAndroid Build Coastguard Worker "Attempting to use thread affinity on a unsupported platform");
419*03ce13f7SAndroid Build Coastguard Worker #endif
420*03ce13f7SAndroid Build Coastguard Worker }
421*03ce13f7SAndroid Build Coastguard Worker };
422*03ce13f7SAndroid Build Coastguard Worker
Thread(Affinity && affinity,Func && func)423*03ce13f7SAndroid Build Coastguard Worker Thread::Thread(Affinity&& affinity, Func&& func)
424*03ce13f7SAndroid Build Coastguard Worker : impl(new Thread::Impl(std::move(affinity), std::move(func))) {}
425*03ce13f7SAndroid Build Coastguard Worker
~Thread()426*03ce13f7SAndroid Build Coastguard Worker Thread::~Thread() {
427*03ce13f7SAndroid Build Coastguard Worker MARL_ASSERT(!impl, "Thread::join() was not called before destruction");
428*03ce13f7SAndroid Build Coastguard Worker }
429*03ce13f7SAndroid Build Coastguard Worker
join()430*03ce13f7SAndroid Build Coastguard Worker void Thread::join() {
431*03ce13f7SAndroid Build Coastguard Worker impl->thread.join();
432*03ce13f7SAndroid Build Coastguard Worker delete impl;
433*03ce13f7SAndroid Build Coastguard Worker impl = nullptr;
434*03ce13f7SAndroid Build Coastguard Worker }
435*03ce13f7SAndroid Build Coastguard Worker
setName(const char * fmt,...)436*03ce13f7SAndroid Build Coastguard Worker void Thread::setName(const char* fmt, ...) {
437*03ce13f7SAndroid Build Coastguard Worker char name[1024];
438*03ce13f7SAndroid Build Coastguard Worker va_list vararg;
439*03ce13f7SAndroid Build Coastguard Worker va_start(vararg, fmt);
440*03ce13f7SAndroid Build Coastguard Worker vsnprintf(name, sizeof(name), fmt, vararg);
441*03ce13f7SAndroid Build Coastguard Worker va_end(vararg);
442*03ce13f7SAndroid Build Coastguard Worker
443*03ce13f7SAndroid Build Coastguard Worker #if defined(__APPLE__)
444*03ce13f7SAndroid Build Coastguard Worker pthread_setname_np(name);
445*03ce13f7SAndroid Build Coastguard Worker #elif defined(__FreeBSD__)
446*03ce13f7SAndroid Build Coastguard Worker pthread_set_name_np(pthread_self(), name);
447*03ce13f7SAndroid Build Coastguard Worker #elif !defined(__Fuchsia__) && !defined(__EMSCRIPTEN__)
448*03ce13f7SAndroid Build Coastguard Worker pthread_setname_np(pthread_self(), name);
449*03ce13f7SAndroid Build Coastguard Worker #endif
450*03ce13f7SAndroid Build Coastguard Worker
451*03ce13f7SAndroid Build Coastguard Worker MARL_NAME_THREAD("%s", name);
452*03ce13f7SAndroid Build Coastguard Worker }
453*03ce13f7SAndroid Build Coastguard Worker
numLogicalCPUs()454*03ce13f7SAndroid Build Coastguard Worker unsigned int Thread::numLogicalCPUs() {
455*03ce13f7SAndroid Build Coastguard Worker return static_cast<unsigned int>(sysconf(_SC_NPROCESSORS_ONLN));
456*03ce13f7SAndroid Build Coastguard Worker }
457*03ce13f7SAndroid Build Coastguard Worker
458*03ce13f7SAndroid Build Coastguard Worker #endif // OS
459*03ce13f7SAndroid Build Coastguard Worker
Thread(Thread && rhs)460*03ce13f7SAndroid Build Coastguard Worker Thread::Thread(Thread&& rhs) : impl(rhs.impl) {
461*03ce13f7SAndroid Build Coastguard Worker rhs.impl = nullptr;
462*03ce13f7SAndroid Build Coastguard Worker }
463*03ce13f7SAndroid Build Coastguard Worker
operator =(Thread && rhs)464*03ce13f7SAndroid Build Coastguard Worker Thread& Thread::operator=(Thread&& rhs) {
465*03ce13f7SAndroid Build Coastguard Worker if (impl) {
466*03ce13f7SAndroid Build Coastguard Worker delete impl;
467*03ce13f7SAndroid Build Coastguard Worker impl = nullptr;
468*03ce13f7SAndroid Build Coastguard Worker }
469*03ce13f7SAndroid Build Coastguard Worker impl = rhs.impl;
470*03ce13f7SAndroid Build Coastguard Worker rhs.impl = nullptr;
471*03ce13f7SAndroid Build Coastguard Worker return *this;
472*03ce13f7SAndroid Build Coastguard Worker }
473*03ce13f7SAndroid Build Coastguard Worker
474*03ce13f7SAndroid Build Coastguard Worker } // namespace marl
475