|
PAPI
5.3.0.0
|
00001 /* 00002 * File: linux-common.c 00003 */ 00004 00005 #include <unistd.h> 00006 #include <string.h> 00007 #include <stdlib.h> 00008 #include <ctype.h> 00009 #include <err.h> 00010 #include <stdarg.h> 00011 #include <stdio.h> 00012 #include <errno.h> 00013 #include <syscall.h> 00014 #include <sys/utsname.h> 00015 #include <sys/time.h> 00016 00017 #include "papi.h" 00018 #include "papi_internal.h" 00019 #include "papi_vector.h" 00020 00021 #include "linux-memory.h" 00022 #include "linux-common.h" 00023 #include "linux-timer.h" 00024 00025 #include "x86_cpuid_info.h" 00026 00027 PAPI_os_info_t _papi_os_info; 00028 00029 /* The locks used by Linux */ 00030 00031 #if defined(USE_PTHREAD_MUTEXES) 00032 pthread_mutex_t _papi_hwd_lock_data[PAPI_MAX_LOCK]; 00033 #else 00034 volatile unsigned int _papi_hwd_lock_data[PAPI_MAX_LOCK]; 00035 #endif 00036 00037 00038 static int _linux_init_locks(void) { 00039 00040 int i; 00041 00042 for ( i = 0; i < PAPI_MAX_LOCK; i++ ) { 00043 #if defined(USE_PTHREAD_MUTEXES) 00044 pthread_mutex_init(&_papi_hwd_lock_data[i],NULL); 00045 #else 00046 _papi_hwd_lock_data[i] = MUTEX_OPEN; 00047 #endif 00048 } 00049 00050 return PAPI_OK; 00051 } 00052 00053 00054 int 00055 _linux_detect_hypervisor(char *virtual_vendor_name) { 00056 00057 int retval=0; 00058 00059 #if defined(__i386__)||defined(__x86_64__) 00060 retval=_x86_detect_hypervisor(virtual_vendor_name); 00061 #else 00062 (void) virtual_vendor_name; 00063 #endif 00064 00065 return retval; 00066 } 00067 00068 00069 #define _PATH_SYS_SYSTEM "/sys/devices/system" 00070 #define _PATH_SYS_CPU0 _PATH_SYS_SYSTEM "/cpu/cpu0" 00071 00072 static char pathbuf[PATH_MAX] = "/"; 00073 00074 00075 static char * 00076 search_cpu_info( FILE * f, char *search_str, char *line ) 00077 { 00078 /* This function courtesy of Rudolph Berrendorf! */ 00079 /* See the home page for the German version of PAPI. */ 00080 char *s; 00081 00082 while ( fgets( line, 256, f ) != NULL ) { 00083 if ( strstr( line, search_str ) != NULL ) { 00084 /* ignore all characters in line up to : */ 00085 for ( s = line; *s && ( *s != ':' ); ++s ); 00086 if ( *s ) 00087 return s; 00088 } 00089 } 00090 return NULL; 00091 } 00092 00093 static void 00094 decode_vendor_string( char *s, int *vendor ) 00095 { 00096 if ( strcasecmp( s, "GenuineIntel" ) == 0 ) 00097 *vendor = PAPI_VENDOR_INTEL; 00098 else if ( ( strcasecmp( s, "AMD" ) == 0 ) || 00099 ( strcasecmp( s, "AuthenticAMD" ) == 0 ) ) 00100 *vendor = PAPI_VENDOR_AMD; 00101 else if ( strcasecmp( s, "IBM" ) == 0 ) 00102 *vendor = PAPI_VENDOR_IBM; 00103 else if ( strcasecmp( s, "Cray" ) == 0 ) 00104 *vendor = PAPI_VENDOR_CRAY; 00105 else if ( strcasecmp( s, "ARM" ) == 0 ) 00106 *vendor = PAPI_VENDOR_ARM; 00107 else if ( strcasecmp( s, "MIPS" ) == 0 ) 00108 *vendor = PAPI_VENDOR_MIPS; 00109 else if ( strcasecmp( s, "SiCortex" ) == 0 ) 00110 *vendor = PAPI_VENDOR_MIPS; 00111 else 00112 *vendor = PAPI_VENDOR_UNKNOWN; 00113 } 00114 00115 static FILE * 00116 xfopen( const char *path, const char *mode ) 00117 { 00118 FILE *fd = fopen( path, mode ); 00119 if ( !fd ) 00120 err( EXIT_FAILURE, "error: %s", path ); 00121 return fd; 00122 } 00123 00124 static FILE * 00125 path_vfopen( const char *mode, const char *path, va_list ap ) 00126 { 00127 vsnprintf( pathbuf, sizeof ( pathbuf ), path, ap ); 00128 return xfopen( pathbuf, mode ); 00129 } 00130 00131 00132 static int 00133 path_sibling( const char *path, ... ) 00134 { 00135 int c; 00136 long n; 00137 int result = 0; 00138 char s[2]; 00139 FILE *fp; 00140 va_list ap; 00141 va_start( ap, path ); 00142 fp = path_vfopen( "r", path, ap ); 00143 va_end( ap ); 00144 00145 while ( ( c = fgetc( fp ) ) != EOF ) { 00146 if ( isxdigit( c ) ) { 00147 s[0] = ( char ) c; 00148 s[1] = '\0'; 00149 for ( n = strtol( s, NULL, 16 ); n > 0; n /= 2 ) { 00150 if ( n % 2 ) 00151 result++; 00152 } 00153 } 00154 } 00155 00156 fclose( fp ); 00157 return result; 00158 } 00159 00160 static int 00161 path_exist( const char *path, ... ) 00162 { 00163 va_list ap; 00164 va_start( ap, path ); 00165 vsnprintf( pathbuf, sizeof ( pathbuf ), path, ap ); 00166 va_end( ap ); 00167 return access( pathbuf, F_OK ) == 0; 00168 } 00169 00170 int 00171 _linux_get_cpu_info( PAPI_hw_info_t *hwinfo, int *cpuinfo_mhz ) 00172 { 00173 int tmp, retval = PAPI_OK; 00174 char maxargs[PAPI_HUGE_STR_LEN], *t, *s; 00175 float mhz = 0.0; 00176 FILE *f; 00177 00178 if ( ( f = fopen( "/proc/cpuinfo", "r" ) ) == NULL ) { 00179 PAPIERROR( "fopen(/proc/cpuinfo) errno %d", errno ); 00180 return PAPI_ESYS; 00181 } 00182 00183 /* All of this information maybe overwritten by the component */ 00184 00185 /* MHZ */ 00186 rewind( f ); 00187 s = search_cpu_info( f, "clock", maxargs ); 00188 if ( !s ) { 00189 rewind( f ); 00190 s = search_cpu_info( f, "cpu MHz", maxargs ); 00191 } 00192 if ( s ) { 00193 sscanf( s + 1, "%f", &mhz ); 00194 } 00195 *cpuinfo_mhz = mhz; 00196 00197 /* Vendor Name and Vendor Code */ 00198 rewind( f ); 00199 s = search_cpu_info( f, "vendor_id", maxargs ); 00200 if ( s && ( t = strchr( s + 2, '\n' ) ) ) { 00201 *t = '\0'; 00202 strcpy( hwinfo->vendor_string, s + 2 ); 00203 } else { 00204 rewind( f ); 00205 s = search_cpu_info( f, "vendor", maxargs ); 00206 if ( s && ( t = strchr( s + 2, '\n' ) ) ) { 00207 *t = '\0'; 00208 strcpy( hwinfo->vendor_string, s + 2 ); 00209 } else { 00210 rewind( f ); 00211 s = search_cpu_info( f, "system type", maxargs ); 00212 if ( s && ( t = strchr( s + 2, '\n' ) ) ) { 00213 *t = '\0'; 00214 s = strtok( s + 2, " " ); 00215 strcpy( hwinfo->vendor_string, s ); 00216 } else { 00217 rewind( f ); 00218 s = search_cpu_info( f, "platform", maxargs ); 00219 if ( s && ( t = strchr( s + 2, '\n' ) ) ) { 00220 *t = '\0'; 00221 s = strtok( s + 2, " " ); 00222 if ( ( strcasecmp( s, "pSeries" ) == 0 ) || 00223 ( strcasecmp( s, "PowerMac" ) == 0 ) ) { 00224 strcpy( hwinfo->vendor_string, "IBM" ); 00225 } 00226 } else { 00227 rewind( f ); 00228 s = search_cpu_info( f, "CPU implementer", maxargs ); 00229 if ( s ) { 00230 strcpy( hwinfo->vendor_string, "ARM" ); 00231 } 00232 } 00233 } 00234 } 00235 } 00236 00237 if ( strlen( hwinfo->vendor_string ) ) { 00238 decode_vendor_string( hwinfo->vendor_string, &hwinfo->vendor ); 00239 } 00240 00241 /* Revision */ 00242 rewind( f ); 00243 s = search_cpu_info( f, "stepping", maxargs ); 00244 if ( s ) { 00245 sscanf( s + 1, "%d", &tmp ); 00246 hwinfo->revision = ( float ) tmp; 00247 hwinfo->cpuid_stepping = tmp; 00248 } else { 00249 rewind( f ); 00250 s = search_cpu_info( f, "revision", maxargs ); 00251 if ( s ) { 00252 sscanf( s + 1, "%d", &tmp ); 00253 hwinfo->revision = ( float ) tmp; 00254 hwinfo->cpuid_stepping = tmp; 00255 } 00256 } 00257 00258 /* Model Name */ 00259 rewind( f ); 00260 s = search_cpu_info( f, "model name", maxargs ); 00261 if ( s && ( t = strchr( s + 2, '\n' ) ) ) { 00262 *t = '\0'; 00263 strcpy( hwinfo->model_string, s + 2 ); 00264 } else { 00265 rewind( f ); 00266 s = search_cpu_info( f, "family", maxargs ); 00267 if ( s && ( t = strchr( s + 2, '\n' ) ) ) { 00268 *t = '\0'; 00269 strcpy( hwinfo->model_string, s + 2 ); 00270 } else { 00271 rewind( f ); 00272 s = search_cpu_info( f, "cpu model", maxargs ); 00273 if ( s && ( t = strchr( s + 2, '\n' ) ) ) { 00274 *t = '\0'; 00275 strtok( s + 2, " " ); 00276 s = strtok( NULL, " " ); 00277 strcpy( hwinfo->model_string, s ); 00278 } else { 00279 rewind( f ); 00280 s = search_cpu_info( f, "cpu", maxargs ); 00281 if ( s && ( t = strchr( s + 2, '\n' ) ) ) { 00282 *t = '\0'; 00283 /* get just the first token */ 00284 s = strtok( s + 2, " " ); 00285 strcpy( hwinfo->model_string, s ); 00286 } 00287 } 00288 } 00289 } 00290 00291 /* Family */ 00292 rewind( f ); 00293 s = search_cpu_info( f, "family", maxargs ); 00294 if ( s ) { 00295 sscanf( s + 1, "%d", &tmp ); 00296 hwinfo->cpuid_family = tmp; 00297 } else { 00298 rewind( f ); 00299 s = search_cpu_info( f, "cpu family", maxargs ); 00300 if ( s ) { 00301 sscanf( s + 1, "%d", &tmp ); 00302 hwinfo->cpuid_family = tmp; 00303 } 00304 } 00305 00306 /* CPU Model */ 00307 rewind( f ); 00308 s = search_cpu_info( f, "model", maxargs ); 00309 if ( s ) { 00310 sscanf( s + 1, "%d", &tmp ); 00311 hwinfo->model = tmp; 00312 hwinfo->cpuid_model = tmp; 00313 } 00314 00315 00316 /* The following members are set using the same methodology */ 00317 /* used in lscpu. */ 00318 00319 /* Total number of CPUs */ 00320 /* The following line assumes totalcpus was initialized to zero! */ 00321 while ( path_exist( _PATH_SYS_SYSTEM "/cpu/cpu%d", hwinfo->totalcpus ) ) 00322 hwinfo->totalcpus++; 00323 00324 /* Number of threads per core */ 00325 if ( path_exist( _PATH_SYS_CPU0 "/topology/thread_siblings" ) ) 00326 hwinfo->threads = 00327 path_sibling( _PATH_SYS_CPU0 "/topology/thread_siblings" ); 00328 00329 /* Number of cores per socket */ 00330 if ( path_exist( _PATH_SYS_CPU0 "/topology/core_siblings" ) && 00331 hwinfo->threads > 0 ) 00332 hwinfo->cores = 00333 path_sibling( _PATH_SYS_CPU0 "/topology/core_siblings" ) / 00334 hwinfo->threads; 00335 00336 /* Number of NUMA nodes */ 00337 /* The following line assumes nnodes was initialized to zero! */ 00338 while ( path_exist( _PATH_SYS_SYSTEM "/node/node%d", hwinfo->nnodes ) ) 00339 hwinfo->nnodes++; 00340 00341 /* Number of CPUs per node */ 00342 hwinfo->ncpu = 00343 hwinfo->nnodes > 00344 1 ? hwinfo->totalcpus / hwinfo->nnodes : hwinfo->totalcpus; 00345 00346 /* Number of sockets */ 00347 if ( hwinfo->threads > 0 && hwinfo->cores > 0 ) 00348 hwinfo->sockets = hwinfo->totalcpus / hwinfo->cores / hwinfo->threads; 00349 00350 #if 0 00351 int *nodecpu; 00352 /* cpumap data is not currently part of the _papi_hw_info struct */ 00353 nodecpu = malloc( (unsigned int) hwinfo->nnodes * sizeof(int) ); 00354 if ( nodecpu ) { 00355 int i; 00356 for ( i = 0; i < hwinfo->nnodes; ++i ) { 00357 nodecpu[i] = path_sibling( 00358 _PATH_SYS_SYSTEM "/node/node%d/cpumap", i ); 00359 } 00360 } else { 00361 PAPIERROR( "malloc failed for variable not currently used" ); 00362 } 00363 #endif 00364 00365 00366 /* Fixup missing Megahertz Value */ 00367 /* This is missing from cpuinfo on ARM and MIPS */ 00368 if (*cpuinfo_mhz < 1.0) { 00369 rewind( f ); 00370 00371 s = search_cpu_info( f, "BogoMIPS", maxargs ); 00372 if ((!s) || (sscanf( s + 1, "%f", &mhz ) != 1)) { 00373 INTDBG("Mhz detection failed. Please edit file %s at line %d.\n", 00374 __FILE__,__LINE__); 00375 } 00376 00377 if (hwinfo->vendor == PAPI_VENDOR_MIPS) { 00378 /* MIPS has 2x clock multiplier */ 00379 *cpuinfo_mhz = 2*(((int)mhz)+1); 00380 00381 /* Also update version info on MIPS */ 00382 rewind( f ); 00383 s = search_cpu_info( f, "cpu model", maxargs ); 00384 s = strstr(s+1," V")+2; 00385 strtok(s," "); 00386 sscanf(s, "%f ", &hwinfo->revision ); 00387 } 00388 else { 00389 /* In general bogomips is proportional to number of CPUs */ 00390 if (hwinfo->totalcpus) { 00391 if (mhz!=0) *cpuinfo_mhz = mhz / hwinfo->totalcpus; 00392 } 00393 } 00394 } 00395 00396 fclose( f ); 00397 00398 return retval; 00399 } 00400 00401 int 00402 _linux_get_mhz( int *sys_min_mhz, int *sys_max_mhz ) { 00403 00404 FILE *fff; 00405 int result; 00406 00407 /* Try checking for min MHz */ 00408 /* Assume cpu0 exists */ 00409 fff=fopen("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq","r"); 00410 if (fff==NULL) return PAPI_EINVAL; 00411 result=fscanf(fff,"%d",sys_min_mhz); 00412 fclose(fff); 00413 if (result!=1) return PAPI_EINVAL; 00414 00415 fff=fopen("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq","r"); 00416 if (fff==NULL) return PAPI_EINVAL; 00417 result=fscanf(fff,"%d",sys_max_mhz); 00418 fclose(fff); 00419 if (result!=1) return PAPI_EINVAL; 00420 00421 return PAPI_OK; 00422 00423 } 00424 00425 int 00426 _linux_get_system_info( papi_mdi_t *mdi ) { 00427 00428 int retval; 00429 00430 char maxargs[PAPI_HUGE_STR_LEN]; 00431 pid_t pid; 00432 00433 int cpuinfo_mhz,sys_min_khz,sys_max_khz; 00434 00435 /* Software info */ 00436 00437 /* Path and args */ 00438 00439 pid = getpid( ); 00440 if ( pid < 0 ) { 00441 PAPIERROR( "getpid() returned < 0" ); 00442 return PAPI_ESYS; 00443 } 00444 mdi->pid = pid; 00445 00446 sprintf( maxargs, "/proc/%d/exe", ( int ) pid ); 00447 if ( readlink( maxargs, mdi->exe_info.fullname, PAPI_HUGE_STR_LEN ) < 0 ) { 00448 PAPIERROR( "readlink(%s) returned < 0", maxargs ); 00449 return PAPI_ESYS; 00450 } 00451 00452 /* Careful, basename can modify it's argument */ 00453 00454 strcpy( maxargs, mdi->exe_info.fullname ); 00455 strcpy( mdi->exe_info.address_info.name, basename( maxargs ) ); 00456 00457 SUBDBG( "Executable is %s\n", mdi->exe_info.address_info.name ); 00458 SUBDBG( "Full Executable is %s\n", mdi->exe_info.fullname ); 00459 00460 /* Executable regions, may require reading /proc/pid/maps file */ 00461 00462 retval = _linux_update_shlib_info( mdi ); 00463 SUBDBG( "Text: Start %p, End %p, length %d\n", 00464 mdi->exe_info.address_info.text_start, 00465 mdi->exe_info.address_info.text_end, 00466 ( int ) ( mdi->exe_info.address_info.text_end - 00467 mdi->exe_info.address_info.text_start ) ); 00468 SUBDBG( "Data: Start %p, End %p, length %d\n", 00469 mdi->exe_info.address_info.data_start, 00470 mdi->exe_info.address_info.data_end, 00471 ( int ) ( mdi->exe_info.address_info.data_end - 00472 mdi->exe_info.address_info.data_start ) ); 00473 SUBDBG( "Bss: Start %p, End %p, length %d\n", 00474 mdi->exe_info.address_info.bss_start, 00475 mdi->exe_info.address_info.bss_end, 00476 ( int ) ( mdi->exe_info.address_info.bss_end - 00477 mdi->exe_info.address_info.bss_start ) ); 00478 00479 /* PAPI_preload_option information */ 00480 00481 strcpy( mdi->preload_info.lib_preload_env, "LD_PRELOAD" ); 00482 mdi->preload_info.lib_preload_sep = ' '; 00483 strcpy( mdi->preload_info.lib_dir_env, "LD_LIBRARY_PATH" ); 00484 mdi->preload_info.lib_dir_sep = ':'; 00485 00486 /* Hardware info */ 00487 00488 retval = _linux_get_cpu_info( &mdi->hw_info, &cpuinfo_mhz ); 00489 if ( retval ) 00490 return retval; 00491 00492 /* Handle MHz */ 00493 00494 retval = _linux_get_mhz( &sys_min_khz, &sys_max_khz ); 00495 if ( retval ) { 00496 00497 mdi->hw_info.cpu_max_mhz=cpuinfo_mhz; 00498 mdi->hw_info.cpu_min_mhz=cpuinfo_mhz; 00499 00500 /* 00501 mdi->hw_info.mhz=cpuinfo_mhz; 00502 mdi->hw_info.clock_mhz=cpuinfo_mhz; 00503 */ 00504 } 00505 else { 00506 mdi->hw_info.cpu_max_mhz=sys_max_khz/1000; 00507 mdi->hw_info.cpu_min_mhz=sys_min_khz/1000; 00508 00509 /* 00510 mdi->hw_info.mhz=sys_max_khz/1000; 00511 mdi->hw_info.clock_mhz=sys_max_khz/1000; 00512 */ 00513 } 00514 00515 /* Set Up Memory */ 00516 00517 retval = _linux_get_memory_info( &mdi->hw_info, mdi->hw_info.model ); 00518 if ( retval ) 00519 return retval; 00520 00521 SUBDBG( "Found %d %s(%d) %s(%d) CPUs at %d Mhz.\n", 00522 mdi->hw_info.totalcpus, 00523 mdi->hw_info.vendor_string, 00524 mdi->hw_info.vendor, 00525 mdi->hw_info.model_string, 00526 mdi->hw_info.model, 00527 mdi->hw_info.cpu_max_mhz); 00528 00529 /* Get virtualization info */ 00530 mdi->hw_info.virtualized=_linux_detect_hypervisor(mdi->hw_info.virtual_vendor_string); 00531 00532 return PAPI_OK; 00533 } 00534 00535 int 00536 _papi_hwi_init_os(void) { 00537 00538 int major=0,minor=0,sub=0; 00539 char *ptr; 00540 struct utsname uname_buffer; 00541 00542 /* Initialize the locks */ 00543 _linux_init_locks(); 00544 00545 /* Get the kernel info */ 00546 uname(&uname_buffer); 00547 00548 SUBDBG("Native kernel version %s\n",uname_buffer.release); 00549 00550 strncpy(_papi_os_info.name,uname_buffer.sysname,PAPI_MAX_STR_LEN); 00551 00552 #ifdef ASSUME_KERNEL 00553 strncpy(_papi_os_info.version,ASSUME_KERNEL,PAPI_MAX_STR_LEN); 00554 SUBDBG("Assuming kernel version %s\n",_papi_os_info.name); 00555 #else 00556 strncpy(_papi_os_info.version,uname_buffer.release,PAPI_MAX_STR_LEN); 00557 #endif 00558 00559 ptr=strtok(_papi_os_info.version,"."); 00560 if (ptr!=NULL) major=atoi(ptr); 00561 00562 ptr=strtok(NULL,"."); 00563 if (ptr!=NULL) minor=atoi(ptr); 00564 00565 ptr=strtok(NULL,"."); 00566 if (ptr!=NULL) sub=atoi(ptr); 00567 00568 _papi_os_info.os_version=LINUX_VERSION(major,minor,sub); 00569 00570 _papi_os_info.itimer_sig = PAPI_INT_MPX_SIGNAL; 00571 _papi_os_info.itimer_num = PAPI_INT_ITIMER; 00572 _papi_os_info.itimer_ns = PAPI_INT_MPX_DEF_US * 1000; 00573 _papi_os_info.itimer_res_ns = 1; 00574 _papi_os_info.clock_ticks = sysconf( _SC_CLK_TCK ); 00575 00576 /* Get Linux-specific system info */ 00577 _linux_get_system_info( &_papi_hwi_system_info ); 00578 00579 return PAPI_OK; 00580 } 00581 00582 00583 00584 int _linux_detect_nmi_watchdog() { 00585 00586 int watchdog_detected=0,watchdog_value=0; 00587 FILE *fff; 00588 00589 fff=fopen("/proc/sys/kernel/nmi_watchdog","r"); 00590 if (fff!=NULL) { 00591 if (fscanf(fff,"%d",&watchdog_value)==1) { 00592 if (watchdog_value>0) watchdog_detected=1; 00593 } 00594 fclose(fff); 00595 } 00596 00597 return watchdog_detected; 00598 } 00599 00600 papi_os_vector_t _papi_os_vector = { 00601 .get_memory_info = _linux_get_memory_info, 00602 .get_dmem_info = _linux_get_dmem_info, 00603 .get_real_cycles = _linux_get_real_cycles, 00604 .update_shlib_info = _linux_update_shlib_info, 00605 .get_system_info = _linux_get_system_info, 00606 00607 00608 #if defined(HAVE_CLOCK_GETTIME) 00609 .get_real_usec = _linux_get_real_usec_gettime, 00610 #elif defined(HAVE_GETTIMEOFDAY) 00611 .get_real_usec = _linux_get_real_usec_gettimeofday, 00612 #else 00613 .get_real_usec = _linux_get_real_usec_cycles, 00614 #endif 00615 00616 00617 #if defined(USE_PROC_PTTIMER) 00618 .get_virt_usec = _linux_get_virt_usec_pttimer, 00619 #elif defined(HAVE_CLOCK_GETTIME_THREAD) 00620 .get_virt_usec = _linux_get_virt_usec_gettime, 00621 #elif defined(HAVE_PER_THREAD_TIMES) 00622 .get_virt_usec = _linux_get_virt_usec_times, 00623 #elif defined(HAVE_PER_THREAD_GETRUSAGE) 00624 .get_virt_usec = _linux_get_virt_usec_rusage, 00625 #endif 00626 00627 00628 #if defined(HAVE_CLOCK_GETTIME) 00629 .get_real_nsec = _linux_get_real_nsec_gettime, 00630 #endif 00631 00632 #if defined(HAVE_CLOCK_GETTIME_THREAD) 00633 .get_virt_nsec = _linux_get_virt_nsec_gettime, 00634 #endif 00635 00636 00637 };