xref: /oneTBB/src/tbb/misc.cpp (revision 49e08aac)
1 /*
2     Copyright (c) 2005-2020 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 // Source file for miscellaneous entities that are infrequently referenced by
18 // an executing program.
19 
20 #include "oneapi/tbb/detail/_exception.h"
21 #include "oneapi/tbb/detail/_machine.h"
22 
23 #include "oneapi/tbb/version.h"
24 
25 #include "misc.h"
26 #include "governor.h"
27 #include "assert_impl.h" // Out-of-line TBB assertion handling routines are instantiated here.
28 
29 #include <cstdio>
30 #include <cstdlib>
31 #include <stdexcept>
32 #include <cstring>
33 #include <cstdarg>
34 
35 #if _WIN32||_WIN64
36 #include <windows.h>
37 #endif
38 
39 #if !_WIN32
40 #include <unistd.h> // sysconf(_SC_PAGESIZE)
41 #endif
42 
43 namespace tbb {
44 namespace detail {
45 namespace r1 {
46 
47 //------------------------------------------------------------------------
48 // governor data
49 //------------------------------------------------------------------------
50 cpu_features_type governor::cpu_features;
51 
52 
53 size_t DefaultSystemPageSize() {
54 #if _WIN32
55     SYSTEM_INFO si;
56     GetSystemInfo(&si);
57     return si.dwPageSize;
58 #else
59     return sysconf(_SC_PAGESIZE);
60 #endif
61 }
62 
63 /** The leading "\0" is here so that applying "strings" to the binary delivers a clean result. */
64 static const char VersionString[] = "\0" TBB_VERSION_STRINGS;
65 
66 static bool PrintVersionFlag = false;
67 
68 void PrintVersion() {
69     PrintVersionFlag = true;
70     std::fputs(VersionString+1,stderr);
71 }
72 
73 void PrintExtraVersionInfo( const char* category, const char* format, ... ) {
74     if( PrintVersionFlag ) {
75         char str[1024]; std::memset(str, 0, 1024);
76         va_list args; va_start(args, format);
77         // Note: correct vsnprintf definition obtained from tbb_assert_impl.h
78         std::vsnprintf( str, 1024-1, format, args);
79         va_end(args);
80         std::fprintf(stderr, "oneTBB: %s\t%s\n", category, str );
81     }
82 }
83 
84 //! check for transaction support.
85 #if _MSC_VER
86 #include <intrin.h> // for __cpuid
87 #endif
88 
89 #if __TBB_x86_32 || __TBB_x86_64
90 void check_cpuid(int leaf, int sub_leaf, int registers[4]) {
91 #if _MSC_VER
92     __cpuidex(registers, leaf, sub_leaf);
93 #else
94     int reg_eax = 0;
95     int reg_ebx = 0;
96     int reg_ecx = 0;
97     int reg_edx = 0;
98 #if __TBB_x86_32 && __PIC__
99     // On 32-bit systems with position-independent code GCC fails to work around the stuff in EBX
100     // register. We help it using backup and restore.
101     __asm__("mov %%ebx, %%esi\n\t"
102             "cpuid\n\t"
103             "xchg %%ebx, %%esi"
104             : "=a"(reg_eax), "=S"(reg_ebx), "=c"(reg_ecx), "=d"(reg_edx)
105             : "0"(leaf), "2"(sub_leaf) // read value from eax and ecx
106     );
107 #else
108     __asm__("cpuid"
109             : "=a"(reg_eax), "=b"(reg_ebx), "=c"(reg_ecx), "=d"(reg_edx)
110             : "0"(leaf), "2"(sub_leaf) // read value from eax and ecx
111     );
112 #endif
113     registers[0] = reg_eax;
114     registers[1] = reg_ebx;
115     registers[2] = reg_ecx;
116     registers[3] = reg_edx;
117 #endif
118 }
119 #endif
120 
121 void detect_cpu_features(cpu_features_type& cpu_features) {
122     suppress_unused_warning(cpu_features);
123 #if __TBB_x86_32 || __TBB_x86_64
124     const int rtm_ebx_mask = 1 << 11;
125     const int waitpkg_ecx_mask = 1 << 5;
126     int registers[4] = {0};
127 
128     // Check RTM and WAITPKG
129     check_cpuid(7, 0, registers);
130     cpu_features.rtm_enabled = (registers[1] & rtm_ebx_mask) != 0;
131     cpu_features.waitpkg_enabled = (registers[2] & waitpkg_ecx_mask) != 0;
132 #endif /* (__TBB_x86_32 || __TBB_x86_64) */
133 }
134 
135 } // namespace r1
136 } // namespace detail
137 } // namespace tbb
138