1 /*
2 Copyright (c) 2005-2022 Intel Corporation
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17 #include "common/test.h"
18
19 #if !__TBB_WIN8UI_SUPPORT
20
21 #include <stdio.h>
22 #include "tbb/parallel_for.h"
23 #include "tbb/global_control.h"
24 #include "tbb/enumerable_thread_specific.h"
25
26 #include "common/config.h"
27 #include "common/utils.h"
28 #include "common/utils_concurrency_limit.h"
29 #include "common/utils_report.h"
30 #include "common/vector_types.h"
31 #include "common/cpu_usertime.h"
32 #include "common/spin_barrier.h"
33 #include "common/exception_handling.h"
34 #include "common/concepts_common.h"
35 #include "test_partitioner.h"
36
37 #include <cstddef>
38 #include <vector>
39
40 //! \file test_numa_dist.cpp
41 //! \brief Test for [internal] functionality
42 #if _MSC_VER
43 #pragma warning (push)
44 // Suppress conditional expression is constant
45 #pragma warning (disable: 4127)
46 #if __TBB_MSVC_UNREACHABLE_CODE_IGNORED
47 // Suppress pointless "unreachable code" warning.
48 #pragma warning (disable: 4702)
49 #endif
50 #if defined(_Wp64)
51 // Workaround for overzealous compiler warnings in /Wp64 mode
52 #pragma warning (disable: 4267)
53 #endif
54 #define _SCL_SECURE_NO_WARNINGS
55 #endif //#if _MSC_VER
56
57
58 struct numa {
59 WORD processorGroupCount;
60 std::vector<DWORD> numaProcessors;
61 DWORD maxProcessors;
numanuma62 numa() : processorGroupCount(GetMaximumProcessorGroupCount()), maxProcessors(GetActiveProcessorCount(ALL_PROCESSOR_GROUPS)){
63 numaProcessors.resize(processorGroupCount);
64 for (WORD i = 0; i < processorGroupCount; i++) {
65 this->numaProcessors[i] = GetActiveProcessorCount((i));
66 }
67 }
68 };
69
70
TestNumaDistribution(std::vector<DWORD> & validateProcgrp,int additionalParallelism,bool allThreads)71 int TestNumaDistribution(std::vector<DWORD> &validateProcgrp, int additionalParallelism, bool allThreads){
72 validateProcgrp.resize(GetMaximumProcessorGroupCount());
73 PROCESSOR_NUMBER proc;
74 struct numa nodes;
75 GetThreadIdealProcessorEx(GetCurrentThread(), &proc);
76 int master_thread_proc_grp = proc.Group;
77 int requested_parallelism;
78 if (allThreads)
79 requested_parallelism = additionalParallelism;
80 else
81 requested_parallelism = nodes.numaProcessors.at(master_thread_proc_grp) + additionalParallelism;
82 tbb::global_control global_limit(oneapi::tbb::global_control::max_allowed_parallelism, 1024);
83 tbb::enumerable_thread_specific< std::pair<int, int> > tls;
84 tbb::enumerable_thread_specific< double > tls_dummy;
85 tbb::static_partitioner s;
86
87 utils::SpinBarrier sb(requested_parallelism);
88 oneapi::tbb::task_arena limited(requested_parallelism);
89 limited.execute([&]() {
90
91 tbb::parallel_for(0, requested_parallelism, [&](int)
92 {
93 PROCESSOR_NUMBER proc;
94 if (GetThreadIdealProcessorEx(GetCurrentThread(), &proc))
95 {
96 tls.local() = std::pair<int, int>(proc.Group, proc.Number);
97 sb.wait();
98 }
99 }, s);
100 for (const auto& it : tls) {
101 validateProcgrp[it.first]++;
102 }
103 });
104
105
106 return master_thread_proc_grp;
107 }
108
109 //! Testing Numa Thread Distribution Stability
110 //! \brief \ref stress
111 TEST_CASE("Numa stability for the same node") {
112 numa example;
113 std::vector<DWORD> validateProcgrp;
114
115 int numaGrp = TestNumaDistribution(validateProcgrp,0, 0);
116 std::vector<DWORD> result(GetMaximumProcessorGroupCount(), 0);
117 result[numaGrp] = example.numaProcessors[numaGrp];
118 REQUIRE(validateProcgrp == result);
119 }
120
121 //! Testing Numa Thread Distribution Overflow
122 //! \brief \ref stress
123 TEST_CASE("Numa overflow") {
124 numa example;
125 std::vector<DWORD> validateProcgrp;
126
127 int numaGrp = TestNumaDistribution(validateProcgrp, 1, 0);
128 std::vector<DWORD> result(GetMaximumProcessorGroupCount(), 0);
129 if (example.processorGroupCount <= 1) { // for single Numa node
130 result[numaGrp] = example.numaProcessors[numaGrp] + 1;
131 } else {
132 result[numaGrp] = example.numaProcessors[numaGrp];
133 result[(numaGrp+1)% GetMaximumProcessorGroupCount()] = 1;
134 }
135 REQUIRE(validateProcgrp == result);
136 }
137
138 //! Testing Numa Thread Distribution Maximum
139 //! \brief \ref stress
140 TEST_CASE("Numa all threads") {
141 numa example;
142 std::vector<DWORD> validateProcgrp;
143 TestNumaDistribution(validateProcgrp, example.maxProcessors, 1);
144 REQUIRE(validateProcgrp == example.numaProcessors);
145 }
146
147 //! Testing Numa Thread Distribution Doubled Max
148 //! \brief \ref stress
149 TEST_CASE("Double threads") {
150 numa example;
151 std::vector<DWORD> validateProcgrp;
152 std::vector<DWORD> result(example.numaProcessors.size(), 0);
153 for (size_t i = 0; i < example.numaProcessors.size(); i++) result[i] = 2 * example.numaProcessors[i];
154 TestNumaDistribution(validateProcgrp, example.maxProcessors * 2, 1);
155 REQUIRE(validateProcgrp == result);
156 }
157
158 #if _MSC_VER
159 #pragma warning (pop)
160 #endif
161
162 #endif // !__TBB_WIN8UI_SUPPORT
163