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; 62 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 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