xref: /oneTBB/test/tbb/test_numa_dist.cpp (revision f3303b11)
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