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.
116 result
= (kmp_uint64
)value
; // rounds down
120 } // func __kmp_parse_cpu_frequency
122 void __kmp_query_cpuid(kmp_cpuinfo_t
*p
) {
123 struct kmp_cpuid buf
;
132 p
->flags
.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
->flags
.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
));
233 p
->physical_id
= __kmp_get_physical_id(log_per_phy
, p
->apic_id
);
234 p
->logical_id
= __kmp_get_logical_id(log_per_phy
, p
->apic_id
);
237 if ((buf
.edx
>> 29) & 1) {
238 /* ATHROTL - Automatic Throttle Control */
239 KA_TRACE(trace_level
, (" ATHROTL"));
241 KA_TRACE(trace_level
, (" ]\n"));
243 for (i
= 2; i
<= max_arg
; ++i
) {
244 __kmp_x86_cpuid(i
, 0, &buf
);
245 KA_TRACE(trace_level
,
246 ("INFO: CPUID %d: EAX=0x%08X EBX=0x%08X ECX=0x%08X EDX=0x%08X\n",
247 i
, buf
.eax
, buf
.ebx
, buf
.ecx
, buf
.edx
));
253 /* RTM bit CPUID.07:EBX, bit 11 */
254 /* HYRBID bit CPUID.07:EDX, bit 15 */
255 __kmp_x86_cpuid(7, 0, &buf
);
256 p
->flags
.rtm
= (buf
.ebx
>> 11) & 1;
257 p
->flags
.hybrid
= (buf
.edx
>> 15) & 1;
259 KA_TRACE(trace_level
, (" RTM"));
261 if (p
->flags
.hybrid
) {
262 KA_TRACE(trace_level
, (" HYBRID"));
267 { // Parse CPU brand string for frequency, saving the string for later.
269 kmp_cpuid_t
*base
= (kmp_cpuid_t
*)&p
->name
[0];
271 // Get CPU brand string.
272 for (i
= 0; i
< 3; ++i
) {
273 __kmp_x86_cpuid(0x80000002 + i
, 0, base
+ i
);
275 p
->name
[sizeof(p
->name
) - 1] = 0; // Just in case. ;-)
276 KA_TRACE(trace_level
, ("cpu brand string: \"%s\"\n", &p
->name
[0]));
279 p
->frequency
= __kmp_parse_frequency(strrchr(&p
->name
[0], ' '));
280 KA_TRACE(trace_level
,
281 ("cpu frequency from brand string: %" KMP_UINT64_SPEC
"\n",
286 #endif /* KMP_ARCH_X86 || KMP_ARCH_X86_64 */
288 void __kmp_expand_host_name(char *buffer
, size_t size
) {
289 KMP_DEBUG_ASSERT(size
>= sizeof(unknown
));
294 if (!GetComputerNameA(buffer
, &s
))
295 KMP_STRCPY_S(buffer
, size
, unknown
);
298 buffer
[size
- 2] = 0;
299 if (gethostname(buffer
, size
) || buffer
[size
- 2] != 0)
300 KMP_STRCPY_S(buffer
, size
, unknown
);
304 /* Expand the meta characters in the filename:
305 * Currently defined characters are:
307 * %P the number of threads used.
308 * %I the unique identifier for this run.
311 void __kmp_expand_file_name(char *result
, size_t rlen
, char *pattern
) {
312 char *pos
= result
, *end
= result
+ rlen
- 1;
314 int default_cpu_width
= 1;
317 KMP_DEBUG_ASSERT(rlen
> 0);
321 for (i
= __kmp_xproc
; i
>= 10; i
/= 10, ++default_cpu_width
)
325 if (pattern
!= NULL
) {
326 while (*pattern
!= '\0' && pos
< end
) {
327 if (*pattern
!= '%') {
330 char *old_pattern
= pattern
;
332 int cpu_width
= default_cpu_width
;
336 if (*pattern
>= '0' && *pattern
<= '9') {
339 width
= (width
* 10) + *pattern
++ - '0';
340 } while (*pattern
>= '0' && *pattern
<= '9');
341 if (width
< 0 || width
> 1024)
350 __kmp_expand_host_name(buffer
, sizeof(buffer
));
351 KMP_STRNCPY(pos
, buffer
, end
- pos
+ 1);
361 snp_result
= KMP_SNPRINTF(pos
, end
- pos
+ 1, "%0*d", cpu_width
,
362 __kmp_dflt_team_nth
);
363 if (snp_result
>= 0 && snp_result
<= end
- pos
) {
373 #if (KMP_ARCH_X86_64 || KMP_ARCH_AARCH64) && defined(__MINGW32__)
374 snp_result
= KMP_SNPRINTF(pos
, end
- pos
+ 1, "%0*lld", width
, id
);
376 snp_result
= KMP_SNPRINTF(pos
, end
- pos
+ 1, "%0*d", width
, id
);
378 if (snp_result
>= 0 && snp_result
<= end
- pos
) {
393 pattern
= old_pattern
+ 1;
399 /* TODO: How do we get rid of this? */
400 if (*pattern
!= '\0')
401 KMP_FATAL(FileNameTooLong
);
409 typedef struct ompt_start_tool_result_t ompt_start_tool_result_t
;
410 // Define symbols expected by VERSION script
411 ompt_start_tool_result_t
*ompt_start_tool(unsigned int omp_version
,
412 const char *runtime_version
) {
416 void ompt_libomp_connect(ompt_start_tool_result_t
*result
) { result
= nullptr; }