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 static kmp_uint64
__kmp_parse_frequency( // R: Frequency in Hz.
32 char const *frequency
// I: Float number and unit: MHz, GHz, or TGz.
37 kmp_uint64 result
= 0; /* Zero is a better unknown value than all ones. */
39 if (frequency
== NULL
) {
42 value
= strtod(frequency
, &unit
);
44 value
<= DBL_MAX
) { // Good value (not overflow, underflow, etc).
45 if (strcmp(unit
, "MHz") == 0) {
46 value
= value
* 1.0E+6;
47 } else if (strcmp(unit
, "GHz") == 0) {
48 value
= value
* 1.0E+9;
49 } else if (strcmp(unit
, "THz") == 0) {
50 value
= value
* 1.0E+12;
51 } else { // Wrong unit.
54 result
= (kmp_uint64
)value
; // rounds down
58 } // func __kmp_parse_cpu_frequency
60 void __kmp_query_cpuid(kmp_cpuinfo_t
*p
) {
69 p
->flags
.sse2
= 1; // Assume SSE2 by default.
71 __kmp_x86_cpuid(0, 0, &buf
);
74 ("INFO: CPUID %d: EAX=0x%08X EBX=0x%08X ECX=0x%08X EDX=0x%08X\n", 0,
75 buf
.eax
, buf
.ebx
, buf
.ecx
, buf
.edx
));
83 kmp_uint32 t
, data
[4];
85 __kmp_x86_cpuid(1, 0, &buf
);
87 ("INFO: CPUID %d: EAX=0x%08X EBX=0x%08X ECX=0x%08X EDX=0x%08X\n",
88 1, buf
.eax
, buf
.ebx
, buf
.ecx
, buf
.edx
));
91 #define get_value(reg, lo, mask) (((reg) >> (lo)) & (mask))
93 p
->signature
= buf
.eax
;
94 p
->family
= get_value(buf
.eax
, 20, 0xff) + get_value(buf
.eax
, 8, 0x0f);
96 (get_value(buf
.eax
, 16, 0x0f) << 4) + get_value(buf
.eax
, 4, 0x0f);
97 p
->stepping
= get_value(buf
.eax
, 0, 0x0f);
101 KA_TRACE(trace_level
, (" family = %d, model = %d, stepping = %d\n",
102 p
->family
, p
->model
, p
->stepping
));
105 for (t
= buf
.ebx
, i
= 0; i
< 4; t
>>= 8, ++i
) {
106 data
[i
] = (t
& 0xff);
109 p
->flags
.sse2
= (buf
.edx
>> 26) & 1;
113 if ((buf
.edx
>> 4) & 1) {
114 /* TSC - Timestamp Counter Available */
115 KA_TRACE(trace_level
, (" TSC"));
117 if ((buf
.edx
>> 8) & 1) {
118 /* CX8 - CMPXCHG8B Instruction Available */
119 KA_TRACE(trace_level
, (" CX8"));
121 if ((buf
.edx
>> 9) & 1) {
122 /* APIC - Local APIC Present (multi-processor operation support */
123 KA_TRACE(trace_level
, (" APIC"));
125 if ((buf
.edx
>> 15) & 1) {
126 /* CMOV - Conditional MOVe Instruction Available */
127 KA_TRACE(trace_level
, (" CMOV"));
129 if ((buf
.edx
>> 18) & 1) {
130 /* PSN - Processor Serial Number Available */
131 KA_TRACE(trace_level
, (" PSN"));
133 if ((buf
.edx
>> 19) & 1) {
134 /* CLFLUSH - Cache Flush Instruction Available */
136 data
[1] * 8; /* Bits 15-08: CLFLUSH line size = 8 (64 bytes) */
137 KA_TRACE(trace_level
, (" CLFLUSH(%db)", cflush_size
));
139 if ((buf
.edx
>> 21) & 1) {
140 /* DTES - Debug Trace & EMON Store */
141 KA_TRACE(trace_level
, (" DTES"));
143 if ((buf
.edx
>> 22) & 1) {
144 /* ACPI - ACPI Support Available */
145 KA_TRACE(trace_level
, (" ACPI"));
147 if ((buf
.edx
>> 23) & 1) {
148 /* MMX - Multimedia Extensions */
149 KA_TRACE(trace_level
, (" MMX"));
151 if ((buf
.edx
>> 25) & 1) {
152 /* SSE - SSE Instructions */
153 KA_TRACE(trace_level
, (" SSE"));
155 if ((buf
.edx
>> 26) & 1) {
156 /* SSE2 - SSE2 Instructions */
157 KA_TRACE(trace_level
, (" SSE2"));
159 if ((buf
.edx
>> 27) & 1) {
160 /* SLFSNP - Self-Snooping Cache */
161 KA_TRACE(trace_level
, (" SLFSNP"));
163 #endif /* KMP_DEBUG */
165 if ((buf
.edx
>> 28) & 1) {
166 /* Bits 23-16: Logical Processors per Physical Processor (1 for P4) */
167 p
->apic_id
= data
[3]; /* Bits 31-24: Processor Initial APIC ID (X) */
168 KA_TRACE(trace_level
, (" HT(%d TPUs)", data
[2]));
171 if ((buf
.edx
>> 29) & 1) {
172 /* ATHROTL - Automatic Throttle Control */
173 KA_TRACE(trace_level
, (" ATHROTL"));
175 KA_TRACE(trace_level
, (" ]\n"));
177 for (i
= 2; i
<= max_arg
; ++i
) {
178 __kmp_x86_cpuid(i
, 0, &buf
);
179 KA_TRACE(trace_level
,
180 ("INFO: CPUID %d: EAX=0x%08X EBX=0x%08X ECX=0x%08X EDX=0x%08X\n",
181 i
, buf
.eax
, buf
.ebx
, buf
.ecx
, buf
.edx
));
187 /* RTM bit CPUID.07:EBX, bit 11 */
188 /* HYRBID bit CPUID.07:EDX, bit 15 */
189 __kmp_x86_cpuid(7, 0, &buf
);
190 p
->flags
.rtm
= (buf
.ebx
>> 11) & 1;
191 p
->flags
.hybrid
= (buf
.edx
>> 15) & 1;
193 KA_TRACE(trace_level
, (" RTM"));
195 if (p
->flags
.hybrid
) {
196 KA_TRACE(trace_level
, (" HYBRID"));
201 { // Parse CPU brand string for frequency, saving the string for later.
203 kmp_cpuid_t
*base
= (kmp_cpuid_t
*)&p
->name
[0];
205 // Get CPU brand string.
206 for (i
= 0; i
< 3; ++i
) {
207 __kmp_x86_cpuid(0x80000002 + i
, 0, base
+ i
);
209 p
->name
[sizeof(p
->name
) - 1] = 0; // Just in case. ;-)
210 KA_TRACE(trace_level
, ("cpu brand string: \"%s\"\n", &p
->name
[0]));
213 p
->frequency
= __kmp_parse_frequency(strrchr(&p
->name
[0], ' '));
214 KA_TRACE(trace_level
,
215 ("cpu frequency from brand string: %" KMP_UINT64_SPEC
"\n",
220 #endif /* KMP_ARCH_X86 || KMP_ARCH_X86_64 */
222 void __kmp_expand_host_name(char *buffer
, size_t size
) {
223 KMP_DEBUG_ASSERT(size
>= sizeof(unknown
));
228 if (!GetComputerNameA(buffer
, &s
))
229 KMP_STRCPY_S(buffer
, size
, unknown
);
232 KMP_STRCPY_S(buffer
, size
, unknown
);
234 buffer
[size
- 2] = 0;
235 if (gethostname(buffer
, size
) || buffer
[size
- 2] != 0)
236 KMP_STRCPY_S(buffer
, size
, unknown
);
240 /* Expand the meta characters in the filename:
241 * Currently defined characters are:
243 * %P the number of threads used.
244 * %I the unique identifier for this run.
247 void __kmp_expand_file_name(char *result
, size_t rlen
, char *pattern
) {
248 char *pos
= result
, *end
= result
+ rlen
- 1;
250 int default_cpu_width
= 1;
253 KMP_DEBUG_ASSERT(rlen
> 0);
257 for (i
= __kmp_xproc
; i
>= 10; i
/= 10, ++default_cpu_width
)
261 if (pattern
!= NULL
) {
262 while (*pattern
!= '\0' && pos
< end
) {
263 if (*pattern
!= '%') {
266 char *old_pattern
= pattern
;
268 int cpu_width
= default_cpu_width
;
272 if (*pattern
>= '0' && *pattern
<= '9') {
275 width
= (width
* 10) + *pattern
++ - '0';
276 } while (*pattern
>= '0' && *pattern
<= '9');
277 if (width
< 0 || width
> 1024)
286 __kmp_expand_host_name(buffer
, sizeof(buffer
));
287 KMP_STRNCPY(pos
, buffer
, end
- pos
+ 1);
297 snp_result
= KMP_SNPRINTF(pos
, end
- pos
+ 1, "%0*d", cpu_width
,
298 __kmp_dflt_team_nth
);
299 if (snp_result
>= 0 && snp_result
<= end
- pos
) {
309 #if (KMP_ARCH_X86_64 || KMP_ARCH_AARCH64) && defined(__MINGW32__)
310 snp_result
= KMP_SNPRINTF(pos
, end
- pos
+ 1, "%0*lld", width
, id
);
312 snp_result
= KMP_SNPRINTF(pos
, end
- pos
+ 1, "%0*d", width
, id
);
314 if (snp_result
>= 0 && snp_result
<= end
- pos
) {
329 pattern
= old_pattern
+ 1;
335 /* TODO: How do we get rid of this? */
336 if (*pattern
!= '\0')
337 KMP_FATAL(FileNameTooLong
);
345 typedef struct ompt_start_tool_result_t ompt_start_tool_result_t
;
346 // Define symbols expected by VERSION script
347 ompt_start_tool_result_t
*ompt_start_tool(unsigned int omp_version
,
348 const char *runtime_version
) {
352 void ompt_libomp_connect(ompt_start_tool_result_t
*result
) { result
= nullptr; }