Intel® OpenMP* Runtime Library
 All Classes Functions Variables Typedefs Enumerations Enumerator Modules Pages
kmp_utility.c
1 /*
2  * kmp_utility.c -- Utility routines for the OpenMP support library.
3  */
4 
5 /* <copyright>
6  Copyright (c) 1997-2015 Intel Corporation. All Rights Reserved.
7 
8  Redistribution and use in source and binary forms, with or without
9  modification, are permitted provided that the following conditions
10  are met:
11 
12  * Redistributions of source code must retain the above copyright
13  notice, this list of conditions and the following disclaimer.
14  * Redistributions in binary form must reproduce the above copyright
15  notice, this list of conditions and the following disclaimer in the
16  documentation and/or other materials provided with the distribution.
17  * Neither the name of Intel Corporation nor the names of its
18  contributors may be used to endorse or promote products derived
19  from this software without specific prior written permission.
20 
21  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 
33 </copyright> */
34 
35 #include "kmp.h"
36 #include "kmp_wrapper_getpid.h"
37 #include "kmp_str.h"
38 #include <float.h>
39 #include "kmp_i18n.h"
40 
41 /* ------------------------------------------------------------------------ */
42 /* ------------------------------------------------------------------------ */
43 
44 static const char *unknown = "unknown";
45 
46 #if KMP_ARCH_X86 || KMP_ARCH_X86_64
47 
48 /* NOTE: If called before serial_initialize (i.e. from runtime_initialize), then */
49 /* the debugging package has not been initialized yet, and only "0" will print */
50 /* debugging output since the environment variables have not been read. */
51 
52 static int trace_level = 5;
53 
54 /*
55  * LOG_ID_BITS = ( 1 + floor( log_2( max( log_per_phy - 1, 1 ))))
56  * APIC_ID = (PHY_ID << LOG_ID_BITS) | LOG_ID
57  * PHY_ID = APIC_ID >> LOG_ID_BITS
58  */
59 int
60 __kmp_get_physical_id( int log_per_phy, int apic_id )
61 {
62  int index_lsb, index_msb, temp;
63 
64  if (log_per_phy > 1) {
65  index_lsb = 0;
66  index_msb = 31;
67 
68  temp = log_per_phy;
69  while ( (temp & 1) == 0 ) {
70  temp >>= 1;
71  index_lsb++;
72  }
73 
74  temp = log_per_phy;
75  while ( (temp & 0x80000000)==0 ) {
76  temp <<= 1;
77  index_msb--;
78  }
79 
80  /* If >1 bits were set in log_per_phy, choose next higher power of 2 */
81  if (index_lsb != index_msb) index_msb++;
82 
83  return ( (int) (apic_id >> index_msb) );
84  }
85 
86  return apic_id;
87 }
88 
89 
90 /*
91  * LOG_ID_BITS = ( 1 + floor( log_2( max( log_per_phy - 1, 1 ))))
92  * APIC_ID = (PHY_ID << LOG_ID_BITS) | LOG_ID
93  * LOG_ID = APIC_ID & (( 1 << LOG_ID_BITS ) - 1 )
94  */
95 int
96 __kmp_get_logical_id( int log_per_phy, int apic_id )
97 {
98  unsigned current_bit;
99  int bits_seen;
100  unsigned mask;
101 
102  if (log_per_phy <= 1) return ( 0 );
103 
104  bits_seen = 0;
105 
106  for (current_bit = 1; log_per_phy != 0; current_bit <<= 1) {
107  if ( log_per_phy & current_bit ) {
108  log_per_phy &= ~current_bit;
109  bits_seen++;
110  }
111  }
112 
113  /* If exactly 1 bit was set in log_per_phy, choose next lower power of 2 */
114  if (bits_seen == 1) {
115  current_bit >>= 1;
116  }
117 
118  return ( (int) ((current_bit - 1) & apic_id) );
119 }
120 
121 
122 static
123 kmp_uint64
124 __kmp_parse_frequency( // R: Frequency in Hz.
125  char const * frequency // I: Float number and unit: MHz, GHz, or TGz.
126 ) {
127 
128  double value = 0.0;
129  char const * unit = NULL;
130  kmp_uint64 result = ~ 0;
131 
132  if ( frequency == NULL ) {
133  return result;
134  }; // if
135  value = strtod( frequency, (char * *) & unit ); // strtod() does not like "char conts *".
136  if ( 0 < value && value <= DBL_MAX ) { // Good value (not overflow, underflow, etc).
137  if ( strcmp( unit, "MHz" ) == 0 ) {
138  value = value * 1.0E+6;
139  } else if ( strcmp( unit, "GHz" ) == 0 ) {
140  value = value * 1.0E+9;
141  } else if ( strcmp( unit, "THz" ) == 0 ) {
142  value = value * 1.0E+12;
143  } else { // Wrong unit.
144  return result;
145  }; // if
146  result = value;
147  }; // if
148  return result;
149 
150 }; // func __kmp_parse_cpu_frequency
151 
152 void
153 __kmp_query_cpuid( kmp_cpuinfo_t *p )
154 {
155  struct kmp_cpuid buf;
156  int max_arg;
157  int log_per_phy;
158  int cflush_size;
159 
160  p->initialized = 1;
161 
162  p->sse2 = 1; // Assume SSE2 by default.
163 
164  __kmp_x86_cpuid( 0, 0, &buf );
165 
166  KA_TRACE( trace_level, ("INFO: CPUID %d: EAX=0x%08X EBX=0x%08X ECX=0x%08X EDX=0x%08X\n",
167  0, buf.eax, buf.ebx, buf.ecx, buf.edx ) );
168 
169  max_arg = buf.eax;
170 
171  p->apic_id = -1;
172 
173  if (max_arg >= 1) {
174  int i;
175  kmp_uint32 t, data[ 4 ];
176 
177  __kmp_x86_cpuid( 1, 0, &buf );
178  KA_TRACE( trace_level, ("INFO: CPUID %d: EAX=0x%08X EBX=0x%08X ECX=0x%08X EDX=0x%08X\n",
179  1, buf.eax, buf.ebx, buf.ecx, buf.edx ) );
180 
181  {
182 #define get_value(reg,lo,mask) ( ( ( reg ) >> ( lo ) ) & ( mask ) )
183 
184  p->signature = buf.eax;
185  p->family = get_value( buf.eax, 20, 0xff ) + get_value( buf.eax, 8, 0x0f );
186  p->model = ( get_value( buf.eax, 16, 0x0f ) << 4 ) + get_value( buf.eax, 4, 0x0f );
187  p->stepping = get_value( buf.eax, 0, 0x0f );
188 
189 #undef get_value
190 
191  KA_TRACE( trace_level, (" family = %d, model = %d, stepping = %d\n", p->family, p->model, p->stepping ) );
192  }
193 
194  for ( t = buf.ebx, i = 0; i < 4; t >>= 8, ++i ) {
195  data[ i ] = (t & 0xff);
196  }; // for
197 
198  p->sse2 = ( buf.edx >> 26 ) & 1;
199 
200 #ifdef KMP_DEBUG
201 
202  if ( (buf.edx >> 4) & 1 ) {
203  /* TSC - Timestamp Counter Available */
204  KA_TRACE( trace_level, (" TSC" ) );
205  }
206  if ( (buf.edx >> 8) & 1 ) {
207  /* CX8 - CMPXCHG8B Instruction Available */
208  KA_TRACE( trace_level, (" CX8" ) );
209  }
210  if ( (buf.edx >> 9) & 1 ) {
211  /* APIC - Local APIC Present (multi-processor operation support */
212  KA_TRACE( trace_level, (" APIC" ) );
213  }
214  if ( (buf.edx >> 15) & 1 ) {
215  /* CMOV - Conditional MOVe Instruction Available */
216  KA_TRACE( trace_level, (" CMOV" ) );
217  }
218  if ( (buf.edx >> 18) & 1 ) {
219  /* PSN - Processor Serial Number Available */
220  KA_TRACE( trace_level, (" PSN" ) );
221  }
222  if ( (buf.edx >> 19) & 1 ) {
223  /* CLFULSH - Cache Flush Instruction Available */
224  cflush_size = data[ 1 ] * 8; /* Bits 15-08: CLFLUSH line size = 8 (64 bytes) */
225  KA_TRACE( trace_level, (" CLFLUSH(%db)", cflush_size ) );
226 
227  }
228  if ( (buf.edx >> 21) & 1 ) {
229  /* DTES - Debug Trace & EMON Store */
230  KA_TRACE( trace_level, (" DTES" ) );
231  }
232  if ( (buf.edx >> 22) & 1 ) {
233  /* ACPI - ACPI Support Available */
234  KA_TRACE( trace_level, (" ACPI" ) );
235  }
236  if ( (buf.edx >> 23) & 1 ) {
237  /* MMX - Multimedia Extensions */
238  KA_TRACE( trace_level, (" MMX" ) );
239  }
240  if ( (buf.edx >> 25) & 1 ) {
241  /* SSE - SSE Instructions */
242  KA_TRACE( trace_level, (" SSE" ) );
243  }
244  if ( (buf.edx >> 26) & 1 ) {
245  /* SSE2 - SSE2 Instructions */
246  KA_TRACE( trace_level, (" SSE2" ) );
247  }
248  if ( (buf.edx >> 27) & 1 ) {
249  /* SLFSNP - Self-Snooping Cache */
250  KA_TRACE( trace_level, (" SLFSNP" ) );
251  }
252 #endif /* KMP_DEBUG */
253 
254  if ( (buf.edx >> 28) & 1 ) {
255  /* Bits 23-16: Logical Processors per Physical Processor (1 for P4) */
256  log_per_phy = data[ 2 ];
257  p->apic_id = data[ 3 ]; /* Bits 31-24: Processor Initial APIC ID (X) */
258  KA_TRACE( trace_level, (" HT(%d TPUs)", log_per_phy ) );
259 
260  if( log_per_phy > 1 ) {
261  /* default to 1k FOR JT-enabled processors (4k on OS X*) */
262 #if KMP_OS_DARWIN
263  p->cpu_stackoffset = 4 * 1024;
264 #else
265  p->cpu_stackoffset = 1 * 1024;
266 #endif
267  }
268 
269  p->physical_id = __kmp_get_physical_id( log_per_phy, p->apic_id );
270  p->logical_id = __kmp_get_logical_id( log_per_phy, p->apic_id );
271  }
272 #ifdef KMP_DEBUG
273  if ( (buf.edx >> 29) & 1 ) {
274  /* ATHROTL - Automatic Throttle Control */
275  KA_TRACE( trace_level, (" ATHROTL" ) );
276  }
277  KA_TRACE( trace_level, (" ]\n" ) );
278 
279  for (i = 2; i <= max_arg; ++i) {
280  __kmp_x86_cpuid( i, 0, &buf );
281  KA_TRACE( trace_level,
282  ( "INFO: CPUID %d: EAX=0x%08X EBX=0x%08X ECX=0x%08X EDX=0x%08X\n",
283  i, buf.eax, buf.ebx, buf.ecx, buf.edx ) );
284  }
285 #endif
286 #if KMP_USE_ADAPTIVE_LOCKS
287  p->rtm = 0;
288  if (max_arg > 7)
289  {
290  /* RTM bit CPUID.07:EBX, bit 11 */
291  __kmp_x86_cpuid(7, 0, &buf);
292  p->rtm = (buf.ebx >> 11) & 1;
293  KA_TRACE( trace_level, (" RTM" ) );
294  }
295 #endif
296  }; // if
297 
298  { // Parse CPU brand string for frequency.
299 
300  union kmp_cpu_brand_string {
301  struct kmp_cpuid buf[ 3 ];
302  char string[ sizeof( struct kmp_cpuid ) * 3 + 1 ];
303  }; // union kmp_cpu_brand_string
304  union kmp_cpu_brand_string brand;
305  int i;
306 
307  p->frequency = 0;
308 
309  // Get CPU brand string.
310  for ( i = 0; i < 3; ++ i ) {
311  __kmp_x86_cpuid( 0x80000002 + i, 0, &brand.buf[ i ] );
312  }; // for
313  brand.string[ sizeof( brand.string ) - 1 ] = 0; // Just in case. ;-)
314  KA_TRACE( trace_level, ( "cpu brand string: \"%s\"\n", brand.string ) );
315 
316  // Parse frequency.
317  p->frequency = __kmp_parse_frequency( strrchr( brand.string, ' ' ) );
318  KA_TRACE( trace_level, ( "cpu frequency from brand string: %" KMP_UINT64_SPEC "\n", p->frequency ) );
319  }
320 }
321 
322 #endif /* KMP_ARCH_X86 || KMP_ARCH_X86_64 */
323 
324 /* ------------------------------------------------------------------------------------ */
325 /* ------------------------------------------------------------------------------------ */
326 
327 void
328 __kmp_expand_host_name( char *buffer, size_t size )
329 {
330  KMP_DEBUG_ASSERT(size >= sizeof(unknown));
331 #if KMP_OS_WINDOWS
332  {
333  DWORD s = size;
334 
335  if (! GetComputerNameA( buffer, & s ))
336  KMP_STRCPY_S( buffer, size, unknown );
337  }
338 #else
339  buffer[size - 2] = 0;
340  if (gethostname( buffer, size ) || buffer[size - 2] != 0)
341  KMP_STRCPY_S( buffer, size, unknown );
342 #endif
343 }
344 
345 /* Expand the meta characters in the filename:
346  *
347  * Currently defined characters are:
348  *
349  * %H the hostname
350  * %P the number of threads used.
351  * %I the unique identifier for this run.
352  */
353 
354 void
355 __kmp_expand_file_name( char *result, size_t rlen, char *pattern )
356 {
357  char *pos = result, *end = result + rlen - 1;
358  char buffer[256];
359  int default_cpu_width = 1;
360  int snp_result;
361 
362  KMP_DEBUG_ASSERT(rlen > 0);
363  *end = 0;
364  {
365  int i;
366  for(i = __kmp_xproc; i >= 10; i /= 10, ++default_cpu_width);
367  }
368 
369  if (pattern != NULL) {
370  while (*pattern != '\0' && pos < end) {
371  if (*pattern != '%') {
372  *pos++ = *pattern++;
373  } else {
374  char *old_pattern = pattern;
375  int width = 1;
376  int cpu_width = default_cpu_width;
377 
378  ++pattern;
379 
380  if (*pattern >= '0' && *pattern <= '9') {
381  width = 0;
382  do {
383  width = (width * 10) + *pattern++ - '0';
384  } while (*pattern >= '0' && *pattern <= '9');
385  if (width < 0 || width > 1024)
386  width = 1;
387 
388  cpu_width = width;
389  }
390 
391  switch (*pattern) {
392  case 'H':
393  case 'h':
394  {
395  __kmp_expand_host_name( buffer, sizeof( buffer ) );
396  KMP_STRNCPY( pos, buffer, end - pos + 1);
397  if(*end == 0) {
398  while ( *pos )
399  ++pos;
400  ++pattern;
401  } else
402  pos = end;
403  }
404  break;
405  case 'P':
406  case 'p':
407  {
408  snp_result = KMP_SNPRINTF( pos, end - pos + 1, "%0*d", cpu_width, __kmp_dflt_team_nth );
409  if(snp_result >= 0 && snp_result <= end - pos) {
410  while ( *pos )
411  ++pos;
412  ++pattern;
413  } else
414  pos = end;
415  }
416  break;
417  case 'I':
418  case 'i':
419  {
420  pid_t id = getpid();
421  snp_result = KMP_SNPRINTF( pos, end - pos + 1, "%0*d", width, id );
422  if(snp_result >= 0 && snp_result <= end - pos) {
423  while ( *pos )
424  ++pos;
425  ++pattern;
426  } else
427  pos = end;
428  break;
429  }
430  case '%':
431  {
432  *pos++ = '%';
433  ++pattern;
434  break;
435  }
436  default:
437  {
438  *pos++ = '%';
439  pattern = old_pattern + 1;
440  break;
441  }
442  }
443  }
444  }
445  /* TODO: How do we get rid of this? */
446  if(*pattern != '\0')
447  KMP_FATAL( FileNameTooLong );
448  }
449 
450  *pos = '\0';
451 }
452