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 #include <stdio.h> 20 #include "tbb/parallel_for.h" 21 #include "tbb/global_control.h" 22 #include "tbb/enumerable_thread_specific.h" 23 24 #include "common/config.h" 25 #include "common/utils.h" 26 #include "common/utils_concurrency_limit.h" 27 #include "common/utils_report.h" 28 #include "common/vector_types.h" 29 #include "common/cpu_usertime.h" 30 #include "common/spin_barrier.h" 31 #include "common/exception_handling.h" 32 #include "common/concepts_common.h" 33 #include "test_partitioner.h" 34 35 #include <cstddef> 36 #include <vector> 37 38 //! \file test_numa_dist.cpp 39 //! \brief Test for [internal] functionality 40 #if _MSC_VER 41 #pragma warning (push) 42 // Suppress conditional expression is constant 43 #pragma warning (disable: 4127) 44 #if __TBB_MSVC_UNREACHABLE_CODE_IGNORED 45 // Suppress pointless "unreachable code" warning. 46 #pragma warning (disable: 4702) 47 #endif 48 #if defined(_Wp64) 49 // Workaround for overzealous compiler warnings in /Wp64 mode 50 #pragma warning (disable: 4267) 51 #endif 52 #define _SCL_SECURE_NO_WARNINGS 53 #endif //#if _MSC_VER 54 55 56 struct numa { 57 WORD processorGroupCount; 58 std::vector<DWORD> numaProcessors; 59 DWORD maxProcessors; 60 numa() : processorGroupCount(GetMaximumProcessorGroupCount()), maxProcessors(GetActiveProcessorCount(ALL_PROCESSOR_GROUPS)){ 61 numaProcessors.resize(processorGroupCount); 62 for (WORD i = 0; i < processorGroupCount; i++) { 63 this->numaProcessors[i] = GetActiveProcessorCount((i)); 64 } 65 } 66 }; 67 68 69 int TestNumaDistribution(std::vector<DWORD> &validateProcgrp, int additionalParallelism, bool allThreads){ 70 validateProcgrp.resize(GetMaximumProcessorGroupCount()); 71 PROCESSOR_NUMBER proc; 72 struct numa nodes; 73 GetThreadIdealProcessorEx(GetCurrentThread(), &proc); 74 int master_thread_proc_grp = proc.Group; 75 int requested_parallelism; 76 if (allThreads) 77 requested_parallelism = additionalParallelism; 78 else 79 requested_parallelism = nodes.numaProcessors.at(master_thread_proc_grp) + additionalParallelism; 80 tbb::global_control global_limit(oneapi::tbb::global_control::max_allowed_parallelism, 1024); 81 tbb::enumerable_thread_specific< std::pair<int, int> > tls; 82 tbb::enumerable_thread_specific< double > tls_dummy; 83 tbb::static_partitioner s; 84 85 utils::SpinBarrier sb(requested_parallelism); 86 oneapi::tbb::task_arena limited(requested_parallelism); 87 limited.execute([&]() { 88 89 tbb::parallel_for(0, requested_parallelism, [&](int) 90 { 91 PROCESSOR_NUMBER proc; 92 if (GetThreadIdealProcessorEx(GetCurrentThread(), &proc)) 93 { 94 tls.local() = std::pair<int, int>(proc.Group, proc.Number); 95 sb.wait(); 96 } 97 }, s); 98 for (const auto& it : tls) { 99 validateProcgrp[it.first]++; 100 } 101 }); 102 103 104 return master_thread_proc_grp; 105 } 106 107 //! Testing Numa Thread Distribution Stability 108 //! \brief \ref stress 109 TEST_CASE("Numa stability for the same node") { 110 numa example; 111 std::vector<DWORD> validateProcgrp; 112 113 int numaGrp = TestNumaDistribution(validateProcgrp,0, 0); 114 std::vector<DWORD> result(GetMaximumProcessorGroupCount(), 0); 115 result[numaGrp] = example.numaProcessors[numaGrp]; 116 REQUIRE(validateProcgrp == result); 117 } 118 119 //! Testing Numa Thread Distribution Overflow 120 //! \brief \ref stress 121 TEST_CASE("Numa overflow") { 122 numa example; 123 std::vector<DWORD> validateProcgrp; 124 125 int numaGrp = TestNumaDistribution(validateProcgrp, 1, 0); 126 std::vector<DWORD> result(GetMaximumProcessorGroupCount(), 0); 127 if (example.processorGroupCount <= 1) { // for single Numa node 128 result[numaGrp] = example.numaProcessors[numaGrp] + 1; 129 } else { 130 result[numaGrp] = example.numaProcessors[numaGrp]; 131 result[(numaGrp+1)% GetMaximumProcessorGroupCount()] = 1; 132 } 133 REQUIRE(validateProcgrp == result); 134 } 135 136 //! Testing Numa Thread Distribution Maximum 137 //! \brief \ref stress 138 TEST_CASE("Numa all threads") { 139 numa example; 140 std::vector<DWORD> validateProcgrp; 141 TestNumaDistribution(validateProcgrp, example.maxProcessors, 1); 142 REQUIRE(validateProcgrp == example.numaProcessors); 143 } 144 145 //! Testing Numa Thread Distribution Doubled Max 146 //! \brief \ref stress 147 TEST_CASE("Double threads") { 148 numa example; 149 std::vector<DWORD> validateProcgrp; 150 std::vector<DWORD> result(example.numaProcessors.size(), 0); 151 for (size_t i = 0; i < example.numaProcessors.size(); i++) result[i] = 2 * example.numaProcessors[i]; 152 TestNumaDistribution(validateProcgrp, example.maxProcessors * 2, 1); 153 REQUIRE(validateProcgrp == result); 154 } 155 156 #if _MSC_VER 157 #pragma warning (pop) 158 #endif 159