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