| 1 | /* |
| 2 | Copyright (c) 2005-2019 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 | #ifndef tbb_tests_harness_concurrency_H |
| 18 | #define tbb_tests_harness_concurrency_H |
| 19 | |
| 20 | #if _WIN32||_WIN64 |
| 21 | #include "tbb/machine/windows_api.h" |
| 22 | #elif __linux__ |
| 23 | #include <unistd.h> |
| 24 | #include <sys/sysinfo.h> |
| 25 | #include <string.h> |
| 26 | #include <sched.h> |
| 27 | #elif __FreeBSD__ |
| 28 | #include <unistd.h> |
| 29 | #include <errno.h> |
| 30 | #include <string.h> |
| 31 | #include <sys/param.h> // Required by <sys/cpuset.h> |
| 32 | #include <sys/cpuset.h> |
| 33 | #endif |
| 34 | |
| 35 | #include <limits.h> |
| 36 | |
| 37 | namespace Harness { |
| 38 | static int maxProcs = 0; |
| 39 | static int GetMaxProcs() { |
| 40 | if ( !maxProcs ) { |
| 41 | #if _WIN32||_WIN64 |
| 42 | SYSTEM_INFO si; |
| 43 | GetNativeSystemInfo(&si); |
| 44 | maxProcs = si.dwNumberOfProcessors; |
| 45 | #elif __linux__ |
| 46 | maxProcs = get_nprocs(); |
| 47 | #else /* __FreeBSD__ */ |
| 48 | maxProcs = sysconf(_SC_NPROCESSORS_ONLN); |
| 49 | #endif |
| 50 | } |
| 51 | return maxProcs; |
| 52 | } |
| 53 | |
| 54 | int LimitNumberOfThreads(int max_threads) { |
| 55 | ASSERT( max_threads >= 1 , "The limited number of threads should be positive." ); |
| 56 | maxProcs = GetMaxProcs(); |
| 57 | if ( maxProcs < max_threads ) |
| 58 | // Suppose that process mask is not set so the number of available threads equals maxProcs |
| 59 | return maxProcs; |
| 60 | |
| 61 | #if _WIN32||_WIN64 |
| 62 | ASSERT( max_threads <= 64 , "LimitNumberOfThreads doesn't support max_threads to be more than 64 on Windows." ); |
| 63 | DWORD_PTR mask = 1; |
| 64 | for ( int i = 1; i < max_threads; ++i ) |
| 65 | mask |= mask << 1; |
| 66 | bool err = !SetProcessAffinityMask( GetCurrentProcess(), mask ); |
| 67 | #else /* !WIN */ |
| 68 | #if __linux__ |
| 69 | typedef cpu_set_t mask_t; |
| 70 | #if __TBB_MAIN_THREAD_AFFINITY_BROKEN |
| 71 | #define setaffinity(mask) sched_setaffinity(0 /*get the mask of the calling thread*/, sizeof(mask_t), &mask) |
| 72 | #else |
| 73 | #define setaffinity(mask) sched_setaffinity(getpid(), sizeof(mask_t), &mask) |
| 74 | #endif |
| 75 | #else /* __FreeBSD__ */ |
| 76 | typedef cpuset_t mask_t; |
| 77 | #if __TBB_MAIN_THREAD_AFFINITY_BROKEN |
| 78 | #define setaffinity(mask) cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(mask_t), &mask) |
| 79 | #else |
| 80 | #define setaffinity(mask) cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, sizeof(mask_t), &mask) |
| 81 | #endif |
| 82 | #endif /* __FreeBSD__ */ |
| 83 | mask_t newMask; |
| 84 | CPU_ZERO(&newMask); |
| 85 | |
| 86 | int maskSize = (int)sizeof(mask_t) * CHAR_BIT; |
| 87 | ASSERT_WARNING( maskSize >= maxProcs, "The mask size doesn't seem to be big enough to call setaffinity. The call may return an error." ); |
| 88 | |
| 89 | ASSERT( max_threads <= (int)sizeof(mask_t) * CHAR_BIT , "The mask size is not enough to set the requested number of threads." ); |
| 90 | for ( int i = 0; i < max_threads; ++i ) |
| 91 | CPU_SET( i, &newMask ); |
| 92 | int err = setaffinity( newMask ); |
| 93 | #endif /* !WIN */ |
| 94 | ASSERT( !err, "Setting process affinity failed" ); |
| 95 | |
| 96 | return max_threads; |
| 97 | } |
| 98 | |
| 99 | } // namespace Harness |
| 100 | |
| 101 | #endif /* tbb_tests_harness_concurrency_H */ |
| 102 | |