kmp_utility.c

Go to the documentation of this file.
00001 /*
00002  * kmp_utility.c -- Utility routines for the OpenMP support library.
00003  * $Revision: 42199 $
00004  * $Date: 2013-03-28 10:02:41 -0500 (Thu, 28 Mar 2013) $
00005  */
00006 
00007 /* <copyright>
00008     Copyright (c) 1997-2013 Intel Corporation.  All Rights Reserved.
00009 
00010     Redistribution and use in source and binary forms, with or without
00011     modification, are permitted provided that the following conditions
00012     are met:
00013 
00014       * Redistributions of source code must retain the above copyright
00015         notice, this list of conditions and the following disclaimer.
00016       * Redistributions in binary form must reproduce the above copyright
00017         notice, this list of conditions and the following disclaimer in the
00018         documentation and/or other materials provided with the distribution.
00019       * Neither the name of Intel Corporation nor the names of its
00020         contributors may be used to endorse or promote products derived
00021         from this software without specific prior written permission.
00022 
00023     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00024     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00025     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00026     A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00027     HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00028     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00029     LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00030     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00031     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00032     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00033     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034 
00035 
00036 ------------------------------------------------------------------------
00037 
00038     Portions of this software are protected under the following patents:
00039         U.S. Patent 5,812,852
00040         U.S. Patent 6,792,599
00041         U.S. Patent 7,069,556
00042         U.S. Patent 7,328,433
00043         U.S. Patent 7,500,242
00044 
00045 </copyright> */
00046 
00047 #include "kmp.h"
00048 #include "kmp_wrapper_getpid.h"
00049 #include "kmp_str.h"
00050 #include <float.h>
00051 #include "kmp_i18n.h"
00052 
00053 /* ------------------------------------------------------------------------ */
00054 /* ------------------------------------------------------------------------ */
00055 
00056 static const char *unknown = "unknown";
00057 
00058 #if KMP_ARCH_X86 || KMP_ARCH_X86_64
00059 
00060 /* NOTE: If called before serial_initialize (i.e. from runtime_initialize), then */
00061 /* the debugging package has not been initialized yet, and only "0" will print   */
00062 /* debugging output since the environment variables have not been read.          */
00063 
00064 static int trace_level = 5;
00065 
00066 /*
00067  * LOG_ID_BITS  = ( 1 + floor( log_2( max( log_per_phy - 1, 1 ))))
00068  * APIC_ID      = (PHY_ID << LOG_ID_BITS) | LOG_ID
00069  * PHY_ID       = APIC_ID >> LOG_ID_BITS
00070  */
00071 int
00072 __kmp_get_physical_id( int log_per_phy, int apic_id )
00073 {
00074    int index_lsb, index_msb, temp;
00075 
00076    if (log_per_phy > 1) {
00077     index_lsb = 0;
00078     index_msb = 31;
00079 
00080     temp = log_per_phy;
00081         while ( (temp & 1) == 0 ) {
00082         temp  >>= 1;
00083         index_lsb++;
00084     }
00085 
00086     temp = log_per_phy;
00087     while ( (temp & 0x80000000)==0 ) {
00088         temp <<= 1;
00089         index_msb--;
00090     }
00091 
00092     /* If >1 bits were set in log_per_phy, choose next higher power of 2 */
00093     if (index_lsb != index_msb) index_msb++;
00094 
00095     return ( (int) (apic_id >> index_msb) );
00096    }
00097 
00098    return apic_id;
00099 }
00100 
00101 
00102 /*
00103  * LOG_ID_BITS  = ( 1 + floor( log_2( max( log_per_phy - 1, 1 ))))
00104  * APIC_ID      = (PHY_ID << LOG_ID_BITS) | LOG_ID
00105  * LOG_ID       = APIC_ID & (( 1 << LOG_ID_BITS ) - 1 )
00106  */
00107 int
00108 __kmp_get_logical_id( int log_per_phy, int apic_id )
00109 {
00110    unsigned current_bit;
00111    int bits_seen;
00112    unsigned mask;
00113 
00114    if (log_per_phy <= 1) return ( 0 );
00115 
00116    bits_seen = 0;
00117 
00118    for (current_bit = 1; log_per_phy != 0; current_bit <<= 1) {
00119     if ( log_per_phy & current_bit ) {
00120         log_per_phy &= ~current_bit;
00121         bits_seen++;
00122     }
00123    }
00124 
00125    /* If exactly 1 bit was set in log_per_phy, choose next lower power of 2 */
00126    if (bits_seen == 1) {
00127     current_bit >>= 1;
00128    }
00129 
00130    return ( (int) ((current_bit - 1) & apic_id) );
00131 }
00132 
00133 
00134 static
00135 kmp_uint64
00136 __kmp_parse_frequency(        // R: Frequency in Hz.
00137     char const * frequency    // I: Float number and unit: MHz, GHz, or TGz.
00138 ) {
00139 
00140     double       value  = 0.0;
00141     char const * unit   = NULL;
00142     kmp_uint64   result = ~ 0;
00143 
00144     if ( frequency == NULL ) {
00145         return result;
00146     }; // if
00147     value = strtod( frequency, (char * *) & unit ); // strtod() does not like "char conts *".
00148     if ( 0 < value && value <= DBL_MAX ) {          // Good value (not overflow, underflow, etc).
00149         if ( strcmp( unit, "MHz" ) == 0 ) {
00150             value = value * 1.0E+6;
00151         } else if ( strcmp( unit, "GHz" ) == 0 ) {
00152             value = value * 1.0E+9;
00153         } else if ( strcmp( unit, "THz" ) == 0 ) {
00154             value = value * 1.0E+12;
00155         } else {                      // Wrong unit.
00156             return result;
00157         }; // if
00158         result = value;
00159     }; // if
00160     return result;
00161 
00162 }; // func __kmp_parse_cpu_frequency
00163 
00164 void
00165 __kmp_query_cpuid( kmp_cpuinfo_t *p )
00166 {
00167     struct kmp_cpuid buf;
00168     int max_arg;
00169     int log_per_phy;
00170     int cflush_size;
00171 
00172     p->initialized = 1;
00173 
00174     p->sse2 = 1; // Assume SSE2 by default.
00175 
00176     __kmp_x86_cpuid( 0, 0, &buf );
00177 
00178     KA_TRACE( trace_level, ("INFO: CPUID %d: EAX=0x%08X EBX=0x%08X ECX=0x%08X EDX=0x%08X\n",
00179         0, buf.eax, buf.ebx, buf.ecx, buf.edx ) );
00180 
00181     max_arg = buf.eax;
00182 
00183     p->apic_id = -1;
00184     
00185     if (max_arg >= 1) {
00186         int i;
00187         kmp_uint32 t, data[ 4 ];
00188         
00189         __kmp_x86_cpuid( 1, 0, &buf );
00190         KA_TRACE( trace_level, ("INFO: CPUID %d: EAX=0x%08X EBX=0x%08X ECX=0x%08X EDX=0x%08X\n",
00191                                 1, buf.eax, buf.ebx, buf.ecx, buf.edx ) );
00192         
00193         {
00194 #define get_value(reg,lo,mask) ( ( ( reg ) >> ( lo ) ) & ( mask  ) )
00195             
00196             p->signature = buf.eax;
00197             p->family    =   get_value( buf.eax, 20, 0xff )        + get_value( buf.eax, 8, 0x0f );
00198             p->model     = ( get_value( buf.eax, 16, 0x0f ) << 4 ) + get_value( buf.eax, 4, 0x0f );
00199             p->stepping  =   get_value( buf.eax,  0, 0x0f );
00200             
00201 #undef get_value
00202             
00203             KA_TRACE( trace_level, (" family = %d, model = %d, stepping = %d\n", p->family, p->model, p->stepping ) );
00204         }
00205         
00206         for ( t = buf.ebx, i = 0; i < 4; t >>= 8, ++i ) {
00207             data[ i ] = (t & 0xff);
00208         }; // for
00209         
00210         p->sse2 = ( buf.edx >> 26 ) & 1;
00211         
00212 #ifdef KMP_DEBUG
00213         
00214         if ( (buf.edx >> 4) & 1 ) {
00215             /* TSC - Timestamp Counter Available */
00216             KA_TRACE( trace_level, (" TSC" ) );
00217         }
00218         if ( (buf.edx >> 8) & 1 ) {
00219             /* CX8 - CMPXCHG8B Instruction Available */
00220             KA_TRACE( trace_level, (" CX8" ) );
00221         }
00222         if ( (buf.edx >> 9) & 1 ) {
00223             /* APIC - Local APIC Present (multi-processor operation support */
00224             KA_TRACE( trace_level, (" APIC" ) );
00225         }
00226         if ( (buf.edx >> 15) & 1 ) {
00227             /* CMOV - Conditional MOVe Instruction Available */
00228             KA_TRACE( trace_level, (" CMOV" ) );
00229         }
00230         if ( (buf.edx >> 18) & 1 ) {
00231             /* PSN - Processor Serial Number Available */
00232             KA_TRACE( trace_level, (" PSN" ) );
00233         }
00234         if ( (buf.edx >> 19) & 1 ) {
00235             /* CLFULSH - Cache Flush Instruction Available */
00236             cflush_size = data[ 1 ] * 8;    /* Bits 15-08: CLFLUSH line size = 8 (64 bytes) */
00237             KA_TRACE( trace_level, (" CLFLUSH(%db)", cflush_size ) );
00238             
00239         }
00240         if ( (buf.edx >> 21) & 1 ) {
00241             /* DTES - Debug Trace & EMON Store */
00242             KA_TRACE( trace_level, (" DTES" ) );
00243         }
00244         if ( (buf.edx >> 22) & 1 ) {
00245             /* ACPI - ACPI Support Available */
00246             KA_TRACE( trace_level, (" ACPI" ) );
00247         }
00248         if ( (buf.edx >> 23) & 1 ) {
00249             /* MMX - Multimedia Extensions */
00250             KA_TRACE( trace_level, (" MMX" ) );
00251         }
00252         if ( (buf.edx >> 25) & 1 ) {
00253             /* SSE - SSE Instructions */
00254             KA_TRACE( trace_level, (" SSE" ) );
00255         }
00256         if ( (buf.edx >> 26) & 1 ) {
00257             /* SSE2 - SSE2 Instructions */
00258             KA_TRACE( trace_level, (" SSE2" ) );
00259         }
00260         if ( (buf.edx >> 27) & 1 ) {
00261             /* SLFSNP - Self-Snooping Cache */
00262             KA_TRACE( trace_level, (" SLFSNP" ) );
00263         }
00264 #endif /* KMP_DEBUG */
00265         
00266         __kmp_ht_capable = FALSE;
00267         if ( (buf.edx >> 28) & 1 ) {
00268             
00269             /* HT - Processor is HT Enabled (formerly JT) */
00270             __kmp_ht_capable = TRUE;
00271             
00272             /* Bits 23-16: Logical Processors per Physical Processor (1 for P4) */
00273             log_per_phy = data[ 2 ];
00274             __kmp_ht_log_per_phy = log_per_phy;
00275             
00276             p->apic_id     = data[ 3 ]; /* Bits 31-24: Processor Initial APIC ID (X) */
00277             KA_TRACE( trace_level, (" HT(%d TPUs)", log_per_phy ) );
00278             
00279             if( log_per_phy > 1 ) {
00280                 /* default to 1k FOR JT-enabled processors (4k on OS X*) */
00281 #if KMP_OS_DARWIN
00282                 p->cpu_stackoffset = 4 * 1024;
00283 #else
00284                 p->cpu_stackoffset = 1 * 1024;
00285 #endif
00286             }
00287             
00288             p->physical_id = __kmp_get_physical_id( log_per_phy, p->apic_id );
00289             p->logical_id  = __kmp_get_logical_id( log_per_phy, p->apic_id );
00290         }
00291 #ifdef KMP_DEBUG
00292         if ( (buf.edx >> 29) & 1 ) {
00293             /* ATHROTL - Automatic Throttle Control */
00294             KA_TRACE( trace_level, (" ATHROTL" ) );
00295         }
00296         KA_TRACE( trace_level, (" ]\n" ) );
00297         
00298         for (i = 2; i <= max_arg; ++i) {
00299             __kmp_x86_cpuid( i, 0, &buf );
00300             KA_TRACE( trace_level,
00301                       ( "INFO: CPUID %d: EAX=0x%08X EBX=0x%08X ECX=0x%08X EDX=0x%08X\n",
00302                         i, buf.eax, buf.ebx, buf.ecx, buf.edx ) );
00303         }
00304 #endif
00305     }; // if
00306     
00307     { // Parse CPU brand string for frequency.
00308         
00309         union kmp_cpu_brand_string {
00310             struct kmp_cpuid buf[ 3 ];
00311             char             string[ sizeof( struct kmp_cpuid ) * 3 + 1 ];
00312         }; // union kmp_cpu_brand_string
00313         union kmp_cpu_brand_string brand;
00314         int i;
00315         
00316         p->frequency = 0;
00317         
00318         // Get CPU brand string.
00319         for ( i = 0; i < 3; ++ i ) {
00320             __kmp_x86_cpuid( 0x80000002 + i, 0, &brand.buf[ i ] );
00321         }; // for
00322         brand.string[ sizeof( brand.string ) - 1 ] = 0; // Just in case. ;-)
00323         KA_TRACE( trace_level, ( "cpu brand string: \"%s\"\n", brand.string ) );
00324         
00325         // Parse frequency.
00326         p->frequency = __kmp_parse_frequency( strrchr( brand.string, ' ' ) );
00327         KA_TRACE( trace_level, ( "cpu frequency from brand string: %" KMP_UINT64_SPEC "\n", p->frequency ) );
00328     }
00329 }
00330 
00331 #endif /* KMP_ARCH_X86 || KMP_ARCH_X86_64 */
00332 
00333 /* ------------------------------------------------------------------------------------ */
00334 /* ------------------------------------------------------------------------------------ */
00335 
00336 void
00337 __kmp_expand_host_name( char *buffer, size_t size )
00338 {
00339     KMP_DEBUG_ASSERT(size >= sizeof(unknown));
00340 #if KMP_OS_WINDOWS
00341     {
00342     DWORD   s = size;
00343 
00344     if (! GetComputerNameA( buffer, & s ))
00345         strcpy( buffer, unknown );
00346     }
00347 #else
00348     buffer[size - 2] = 0;
00349     if (gethostname( buffer, size ) || buffer[size - 2] != 0)
00350     strcpy( buffer, unknown );
00351 #endif
00352 }
00353 
00354 /* Expand the meta characters in the filename:
00355  *
00356  * Currently defined characters are:
00357  *
00358  * %H the hostname
00359  * %P the number of threads used.
00360  * %I the unique identifier for this run.
00361  */
00362 
00363 void
00364 __kmp_expand_file_name( char *result, size_t rlen, char *pattern )
00365 {
00366     char    *pos = result, *end = result + rlen - 1;
00367     char     buffer[256];
00368     int      default_cpu_width = 1;
00369     int          snp_result;
00370 
00371     KMP_DEBUG_ASSERT(rlen > 0);
00372     *end = 0;
00373     {
00374     int i;
00375     for(i = __kmp_xproc; i >= 10; i /= 10, ++default_cpu_width);
00376     }
00377 
00378     if (pattern != NULL) {
00379     while (*pattern != '\0' && pos < end) {
00380         if (*pattern != '%') {
00381         *pos++ = *pattern++;
00382         } else {
00383         char *old_pattern = pattern;
00384         int width = 1;
00385         int cpu_width = default_cpu_width;
00386 
00387         ++pattern;
00388 
00389         if (*pattern >= '0' && *pattern <= '9') {
00390             width = 0;
00391             do {
00392             width = (width * 10) + *pattern++ - '0';
00393             } while (*pattern >= '0' && *pattern <= '9');
00394             if (width < 0 || width > 1024)
00395             width = 1;
00396 
00397             cpu_width = width;
00398         }
00399 
00400         switch (*pattern) {
00401         case 'H':
00402         case 'h':
00403             {
00404             __kmp_expand_host_name( buffer, sizeof( buffer ) );
00405             strncpy( pos,  buffer, end - pos + 1);
00406             if(*end == 0) {
00407                 while ( *pos )
00408                 ++pos;
00409                 ++pattern;
00410             } else
00411                 pos = end;
00412             }
00413             break;
00414         case 'P':
00415         case 'p':
00416             {
00417             snp_result = snprintf( pos, end - pos + 1, "%0*d", cpu_width, __kmp_dflt_team_nth );
00418             if(snp_result >= 0 && snp_result <= end - pos) {
00419                 while ( *pos )
00420                 ++pos;
00421                 ++pattern;
00422             } else
00423                 pos = end;
00424             }
00425             break;
00426         case 'I':
00427         case 'i':
00428             {
00429             pid_t id = getpid();
00430             snp_result = snprintf( pos, end - pos + 1, "%0*d", width, id );
00431             if(snp_result >= 0 && snp_result <= end - pos) {
00432                 while ( *pos )
00433                 ++pos;
00434                 ++pattern;
00435             } else
00436                 pos = end;
00437             break;
00438             }
00439         case '%':
00440             {
00441             *pos++ = '%';
00442             ++pattern;
00443             break;
00444             }
00445         default:
00446             {
00447             *pos++ = '%';
00448             pattern = old_pattern + 1;
00449             break;
00450             }
00451         }
00452         }
00453     }
00454     /* TODO: How do we get rid of this? */
00455     if(*pattern != '\0')
00456         KMP_FATAL( FileNameTooLong );
00457     }
00458 
00459     *pos = '\0';
00460 }
00461 
00462 

Generated on 25 Aug 2013 for libomp_oss by  doxygen 1.6.1