2 * kmp_utility.cpp -- Utility routines for the OpenMP support library.
5 //===----------------------------------------------------------------------===//
7 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
8 // See https://llvm.org/LICENSE.txt for license information.
9 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
11 //===----------------------------------------------------------------------===//
16 #include "kmp_wrapper_getpid.h"
19 static const char *unknown
= "unknown";
21 #if KMP_ARCH_X86 || KMP_ARCH_X86_64
23 /* NOTE: If called before serial_initialize (i.e. from runtime_initialize), then
24 the debugging package has not been initialized yet, and only "0" will print
25 debugging output since the environment variables have not been read. */
28 static int trace_level
= 5;
31 /* LOG_ID_BITS = ( 1 + floor( log_2( max( log_per_phy - 1, 1 ))))
32 * APIC_ID = (PHY_ID << LOG_ID_BITS) | LOG_ID
33 * PHY_ID = APIC_ID >> LOG_ID_BITS
35 int __kmp_get_physical_id(int log_per_phy
, int apic_id
) {
36 int index_lsb
, index_msb
, temp
;
38 if (log_per_phy
> 1) {
43 while ((temp
& 1) == 0) {
49 while ((temp
& 0x80000000) == 0) {
54 /* If >1 bits were set in log_per_phy, choose next higher power of 2 */
55 if (index_lsb
!= index_msb
)
58 return ((int)(apic_id
>> index_msb
));
65 * LOG_ID_BITS = ( 1 + floor( log_2( max( log_per_phy - 1, 1 ))))
66 * APIC_ID = (PHY_ID << LOG_ID_BITS) | LOG_ID
67 * LOG_ID = APIC_ID & (( 1 << LOG_ID_BITS ) - 1 )
69 int __kmp_get_logical_id(int log_per_phy
, int apic_id
) {
78 for (current_bit
= 1; log_per_phy
!= 0; current_bit
<<= 1) {
79 if (log_per_phy
& current_bit
) {
80 log_per_phy
&= ~current_bit
;
85 /* If exactly 1 bit was set in log_per_phy, choose next lower power of 2 */
90 return ((int)((current_bit
- 1) & apic_id
));
93 static kmp_uint64
__kmp_parse_frequency( // R: Frequency in Hz.
94 char const *frequency
// I: Float number and unit: MHz, GHz, or TGz.
99 kmp_uint64 result
= 0; /* Zero is a better unknown value than all ones. */
101 if (frequency
== NULL
) {
104 value
= strtod(frequency
, &unit
);
106 value
<= DBL_MAX
) { // Good value (not overflow, underflow, etc).
107 if (strcmp(unit
, "MHz") == 0) {
108 value
= value
* 1.0E+6;
109 } else if (strcmp(unit
, "GHz") == 0) {
110 value
= value
* 1.0E+9;
111 } else if (strcmp(unit
, "THz") == 0) {
112 value
= value
* 1.0E+12;
113 } else { // Wrong unit.
120 } // func __kmp_parse_cpu_frequency
122 void __kmp_query_cpuid(kmp_cpuinfo_t
*p
) {
123 struct kmp_cpuid buf
;
132 p
->sse2
= 1; // Assume SSE2 by default.
134 __kmp_x86_cpuid(0, 0, &buf
);
136 KA_TRACE(trace_level
,
137 ("INFO: CPUID %d: EAX=0x%08X EBX=0x%08X ECX=0x%08X EDX=0x%08X\n", 0,
138 buf
.eax
, buf
.ebx
, buf
.ecx
, buf
.edx
));
146 kmp_uint32 t
, data
[4];
148 __kmp_x86_cpuid(1, 0, &buf
);
149 KA_TRACE(trace_level
,
150 ("INFO: CPUID %d: EAX=0x%08X EBX=0x%08X ECX=0x%08X EDX=0x%08X\n",
151 1, buf
.eax
, buf
.ebx
, buf
.ecx
, buf
.edx
));
154 #define get_value(reg, lo, mask) (((reg) >> (lo)) & (mask))
156 p
->signature
= buf
.eax
;
157 p
->family
= get_value(buf
.eax
, 20, 0xff) + get_value(buf
.eax
, 8, 0x0f);
159 (get_value(buf
.eax
, 16, 0x0f) << 4) + get_value(buf
.eax
, 4, 0x0f);
160 p
->stepping
= get_value(buf
.eax
, 0, 0x0f);
164 KA_TRACE(trace_level
, (" family = %d, model = %d, stepping = %d\n",
165 p
->family
, p
->model
, p
->stepping
));
168 for (t
= buf
.ebx
, i
= 0; i
< 4; t
>>= 8, ++i
) {
169 data
[i
] = (t
& 0xff);
172 p
->sse2
= (buf
.edx
>> 26) & 1;
176 if ((buf
.edx
>> 4) & 1) {
177 /* TSC - Timestamp Counter Available */
178 KA_TRACE(trace_level
, (" TSC"));
180 if ((buf
.edx
>> 8) & 1) {
181 /* CX8 - CMPXCHG8B Instruction Available */
182 KA_TRACE(trace_level
, (" CX8"));
184 if ((buf
.edx
>> 9) & 1) {
185 /* APIC - Local APIC Present (multi-processor operation support */
186 KA_TRACE(trace_level
, (" APIC"));
188 if ((buf
.edx
>> 15) & 1) {
189 /* CMOV - Conditional MOVe Instruction Available */
190 KA_TRACE(trace_level
, (" CMOV"));
192 if ((buf
.edx
>> 18) & 1) {
193 /* PSN - Processor Serial Number Available */
194 KA_TRACE(trace_level
, (" PSN"));
196 if ((buf
.edx
>> 19) & 1) {
197 /* CLFLUSH - Cache Flush Instruction Available */
199 data
[1] * 8; /* Bits 15-08: CLFLUSH line size = 8 (64 bytes) */
200 KA_TRACE(trace_level
, (" CLFLUSH(%db)", cflush_size
));
202 if ((buf
.edx
>> 21) & 1) {
203 /* DTES - Debug Trace & EMON Store */
204 KA_TRACE(trace_level
, (" DTES"));
206 if ((buf
.edx
>> 22) & 1) {
207 /* ACPI - ACPI Support Available */
208 KA_TRACE(trace_level
, (" ACPI"));
210 if ((buf
.edx
>> 23) & 1) {
211 /* MMX - Multimedia Extensions */
212 KA_TRACE(trace_level
, (" MMX"));
214 if ((buf
.edx
>> 25) & 1) {
215 /* SSE - SSE Instructions */
216 KA_TRACE(trace_level
, (" SSE"));
218 if ((buf
.edx
>> 26) & 1) {
219 /* SSE2 - SSE2 Instructions */
220 KA_TRACE(trace_level
, (" SSE2"));
222 if ((buf
.edx
>> 27) & 1) {
223 /* SLFSNP - Self-Snooping Cache */
224 KA_TRACE(trace_level
, (" SLFSNP"));
226 #endif /* KMP_DEBUG */
228 if ((buf
.edx
>> 28) & 1) {
229 /* Bits 23-16: Logical Processors per Physical Processor (1 for P4) */
230 log_per_phy
= data
[2];
231 p
->apic_id
= data
[3]; /* Bits 31-24: Processor Initial APIC ID (X) */
232 KA_TRACE(trace_level
, (" HT(%d TPUs)", log_per_phy
));
234 if (log_per_phy
> 1) {
235 /* default to 1k FOR JT-enabled processors (4k on OS X*) */
237 p
->cpu_stackoffset
= 4 * 1024;
239 p
->cpu_stackoffset
= 1 * 1024;
243 p
->physical_id
= __kmp_get_physical_id(log_per_phy
, p
->apic_id
);
244 p
->logical_id
= __kmp_get_logical_id(log_per_phy
, p
->apic_id
);
247 if ((buf
.edx
>> 29) & 1) {
248 /* ATHROTL - Automatic Throttle Control */
249 KA_TRACE(trace_level
, (" ATHROTL"));
251 KA_TRACE(trace_level
, (" ]\n"));
253 for (i
= 2; i
<= max_arg
; ++i
) {
254 __kmp_x86_cpuid(i
, 0, &buf
);
255 KA_TRACE(trace_level
,
256 ("INFO: CPUID %d: EAX=0x%08X EBX=0x%08X ECX=0x%08X EDX=0x%08X\n",
257 i
, buf
.eax
, buf
.ebx
, buf
.ecx
, buf
.edx
));
260 #if KMP_USE_ADAPTIVE_LOCKS
263 /* RTM bit CPUID.07:EBX, bit 11 */
264 __kmp_x86_cpuid(7, 0, &buf
);
265 p
->rtm
= (buf
.ebx
>> 11) & 1;
266 KA_TRACE(trace_level
, (" RTM"));
271 { // Parse CPU brand string for frequency, saving the string for later.
273 kmp_cpuid_t
*base
= (kmp_cpuid_t
*)&p
->name
[0];
275 // Get CPU brand string.
276 for (i
= 0; i
< 3; ++i
) {
277 __kmp_x86_cpuid(0x80000002 + i
, 0, base
+ i
);
279 p
->name
[sizeof(p
->name
) - 1] = 0; // Just in case. ;-)
280 KA_TRACE(trace_level
, ("cpu brand string: \"%s\"\n", &p
->name
[0]));
283 p
->frequency
= __kmp_parse_frequency(strrchr(&p
->name
[0], ' '));
284 KA_TRACE(trace_level
,
285 ("cpu frequency from brand string: %" KMP_UINT64_SPEC
"\n",
290 #endif /* KMP_ARCH_X86 || KMP_ARCH_X86_64 */
292 void __kmp_expand_host_name(char *buffer
, size_t size
) {
293 KMP_DEBUG_ASSERT(size
>= sizeof(unknown
));
298 if (!GetComputerNameA(buffer
, &s
))
299 KMP_STRCPY_S(buffer
, size
, unknown
);
302 buffer
[size
- 2] = 0;
303 if (gethostname(buffer
, size
) || buffer
[size
- 2] != 0)
304 KMP_STRCPY_S(buffer
, size
, unknown
);
308 /* Expand the meta characters in the filename:
309 * Currently defined characters are:
311 * %P the number of threads used.
312 * %I the unique identifier for this run.
315 void __kmp_expand_file_name(char *result
, size_t rlen
, char *pattern
) {
316 char *pos
= result
, *end
= result
+ rlen
- 1;
318 int default_cpu_width
= 1;
321 KMP_DEBUG_ASSERT(rlen
> 0);
325 for (i
= __kmp_xproc
; i
>= 10; i
/= 10, ++default_cpu_width
)
329 if (pattern
!= NULL
) {
330 while (*pattern
!= '\0' && pos
< end
) {
331 if (*pattern
!= '%') {
334 char *old_pattern
= pattern
;
336 int cpu_width
= default_cpu_width
;
340 if (*pattern
>= '0' && *pattern
<= '9') {
343 width
= (width
* 10) + *pattern
++ - '0';
344 } while (*pattern
>= '0' && *pattern
<= '9');
345 if (width
< 0 || width
> 1024)
354 __kmp_expand_host_name(buffer
, sizeof(buffer
));
355 KMP_STRNCPY(pos
, buffer
, end
- pos
+ 1);
365 snp_result
= KMP_SNPRINTF(pos
, end
- pos
+ 1, "%0*d", cpu_width
,
366 __kmp_dflt_team_nth
);
367 if (snp_result
>= 0 && snp_result
<= end
- pos
) {
377 #if KMP_ARCH_X86_64 && defined(__MINGW32__)
378 snp_result
= KMP_SNPRINTF(pos
, end
- pos
+ 1, "%0*lld", width
, id
);
380 snp_result
= KMP_SNPRINTF(pos
, end
- pos
+ 1, "%0*d", width
, id
);
382 if (snp_result
>= 0 && snp_result
<= end
- pos
) {
397 pattern
= old_pattern
+ 1;
403 /* TODO: How do we get rid of this? */
404 if (*pattern
!= '\0')
405 KMP_FATAL(FileNameTooLong
);