|
PAPI
5.0.1.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 sockets */ 00337 if ( hwinfo->threads > 0 && hwinfo->cores > 0 ) 00338 hwinfo->sockets = hwinfo->ncpu / hwinfo->cores / hwinfo->threads; 00339 00340 /* Number of NUMA nodes */ 00341 /* The following line assumes nnodes was initialized to zero! */ 00342 while ( path_exist( _PATH_SYS_SYSTEM "/node/node%d", hwinfo->nnodes ) ) 00343 hwinfo->nnodes++; 00344 00345 /* Number of CPUs per node */ 00346 hwinfo->ncpu = 00347 hwinfo->nnodes > 00348 1 ? hwinfo->totalcpus / hwinfo->nnodes : hwinfo->totalcpus; 00349 #if 0 00350 int *nodecpu; 00351 /* cpumap data is not currently part of the _papi_hw_info struct */ 00352 nodecpu = malloc( (unsigned int) hwinfo->nnodes * sizeof(int) ); 00353 if ( nodecpu ) { 00354 int i; 00355 for ( i = 0; i < hwinfo->nnodes; ++i ) { 00356 nodecpu[i] = path_sibling( 00357 _PATH_SYS_SYSTEM "/node/node%d/cpumap", i ); 00358 } 00359 } else { 00360 PAPIERROR( "malloc failed for variable not currently used" ); 00361 } 00362 #endif 00363 00364 00365 /* Fixup missing Megahertz Value */ 00366 /* This is missing from cpuinfo on ARM and MIPS */ 00367 if (*cpuinfo_mhz < 1.0) { 00368 rewind( f ); 00369 00370 s = search_cpu_info( f, "BogoMIPS", maxargs ); 00371 if ((!s) || (sscanf( s + 1, "%f", &mhz ) != 1)) { 00372 PAPIERROR("Mhz detection failed. Please edit file %s at line %d.\n", 00373 __FILE__,__LINE__); 00374 } 00375 00376 if (hwinfo->vendor == PAPI_VENDOR_MIPS) { 00377 /* MIPS has 2x clock multiplier */ 00378 *cpuinfo_mhz = 2*(((int)mhz)+1); 00379 00380 /* Also update version info on MIPS */ 00381 rewind( f ); 00382 s = search_cpu_info( f, "cpu model", maxargs ); 00383 s = strstr(s+1," V")+2; 00384 strtok(s," "); 00385 sscanf(s, "%f ", &hwinfo->revision ); 00386 } 00387 else { 00388 /* In general bogomips is proportional to number of CPUs */ 00389 if (hwinfo->totalcpus) { 00390 *cpuinfo_mhz = mhz / hwinfo->totalcpus; 00391 } 00392 } 00393 } 00394 00395 fclose( f ); 00396 00397 return retval; 00398 } 00399 00400 int 00401 _linux_get_mhz( int *sys_min_mhz, int *sys_max_mhz ) { 00402 00403 FILE *fff; 00404 int result; 00405 00406 /* Try checking for min MHz */ 00407 /* Assume cpu0 exists */ 00408 fff=fopen("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq","r"); 00409 if (fff==NULL) return PAPI_EINVAL; 00410 result=fscanf(fff,"%d",sys_min_mhz); 00411 fclose(fff); 00412 if (result!=1) return PAPI_EINVAL; 00413 00414 fff=fopen("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq","r"); 00415 if (fff==NULL) return PAPI_EINVAL; 00416 result=fscanf(fff,"%d",sys_max_mhz); 00417 fclose(fff); 00418 if (result!=1) return PAPI_EINVAL; 00419 00420 return PAPI_OK; 00421 00422 } 00423 00424 int 00425 _linux_get_system_info( papi_mdi_t *mdi ) { 00426 00427 int retval; 00428 00429 char maxargs[PAPI_HUGE_STR_LEN]; 00430 pid_t pid; 00431 00432 int cpuinfo_mhz,sys_min_khz,sys_max_khz; 00433 00434 /* Software info */ 00435 00436 /* Path and args */ 00437 00438 pid = getpid( ); 00439 if ( pid < 0 ) { 00440 PAPIERROR( "getpid() returned < 0" ); 00441 return PAPI_ESYS; 00442 } 00443 mdi->pid = pid; 00444 00445 sprintf( maxargs, "/proc/%d/exe", ( int ) pid ); 00446 if ( readlink( maxargs, mdi->exe_info.fullname, PAPI_HUGE_STR_LEN ) < 0 ) { 00447 PAPIERROR( "readlink(%s) returned < 0", maxargs ); 00448 return PAPI_ESYS; 00449 } 00450 00451 /* Careful, basename can modify it's argument */ 00452 00453 strcpy( maxargs, mdi->exe_info.fullname ); 00454 strcpy( mdi->exe_info.address_info.name, basename( maxargs ) ); 00455 00456 SUBDBG( "Executable is %s\n", mdi->exe_info.address_info.name ); 00457 SUBDBG( "Full Executable is %s\n", mdi->exe_info.fullname ); 00458 00459 /* Executable regions, may require reading /proc/pid/maps file */ 00460 00461 retval = _linux_update_shlib_info( mdi ); 00462 SUBDBG( "Text: Start %p, End %p, length %d\n", 00463 mdi->exe_info.address_info.text_start, 00464 mdi->exe_info.address_info.text_end, 00465 ( int ) ( mdi->exe_info.address_info.text_end - 00466 mdi->exe_info.address_info.text_start ) ); 00467 SUBDBG( "Data: Start %p, End %p, length %d\n", 00468 mdi->exe_info.address_info.data_start, 00469 mdi->exe_info.address_info.data_end, 00470 ( int ) ( mdi->exe_info.address_info.data_end - 00471 mdi->exe_info.address_info.data_start ) ); 00472 SUBDBG( "Bss: Start %p, End %p, length %d\n", 00473 mdi->exe_info.address_info.bss_start, 00474 mdi->exe_info.address_info.bss_end, 00475 ( int ) ( mdi->exe_info.address_info.bss_end - 00476 mdi->exe_info.address_info.bss_start ) ); 00477 00478 /* PAPI_preload_option information */ 00479 00480 strcpy( mdi->preload_info.lib_preload_env, "LD_PRELOAD" ); 00481 mdi->preload_info.lib_preload_sep = ' '; 00482 strcpy( mdi->preload_info.lib_dir_env, "LD_LIBRARY_PATH" ); 00483 mdi->preload_info.lib_dir_sep = ':'; 00484 00485 /* Hardware info */ 00486 00487 retval = _linux_get_cpu_info( &mdi->hw_info, &cpuinfo_mhz ); 00488 if ( retval ) 00489 return retval; 00490 00491 /* Handle MHz */ 00492 00493 retval = _linux_get_mhz( &sys_min_khz, &sys_max_khz ); 00494 if ( retval ) { 00495 00496 mdi->hw_info.cpu_max_mhz=cpuinfo_mhz; 00497 mdi->hw_info.cpu_min_mhz=cpuinfo_mhz; 00498 00499 /* 00500 mdi->hw_info.mhz=cpuinfo_mhz; 00501 mdi->hw_info.clock_mhz=cpuinfo_mhz; 00502 */ 00503 } 00504 else { 00505 mdi->hw_info.cpu_max_mhz=sys_max_khz/1000; 00506 mdi->hw_info.cpu_min_mhz=sys_min_khz/1000; 00507 00508 /* 00509 mdi->hw_info.mhz=sys_max_khz/1000; 00510 mdi->hw_info.clock_mhz=sys_max_khz/1000; 00511 */ 00512 } 00513 00514 /* Set Up Memory */ 00515 00516 retval = _linux_get_memory_info( &mdi->hw_info, mdi->hw_info.model ); 00517 if ( retval ) 00518 return retval; 00519 00520 SUBDBG( "Found %d %s(%d) %s(%d) CPUs at %d Mhz.\n", 00521 mdi->hw_info.totalcpus, 00522 mdi->hw_info.vendor_string, 00523 mdi->hw_info.vendor, 00524 mdi->hw_info.model_string, 00525 mdi->hw_info.model, 00526 mdi->hw_info.cpu_max_mhz); 00527 00528 /* Get virtualization info */ 00529 mdi->hw_info.virtualized=_linux_detect_hypervisor(mdi->hw_info.virtual_vendor_string); 00530 00531 return PAPI_OK; 00532 } 00533 00534 int 00535 _papi_hwi_init_os(void) { 00536 00537 int major=0,minor=0,sub=0; 00538 char *ptr; 00539 struct utsname uname_buffer; 00540 00541 /* Initialize the locks */ 00542 _linux_init_locks(); 00543 00544 /* Get the kernel info */ 00545 uname(&uname_buffer); 00546 00547 SUBDBG("Native kernel version %s\n",uname_buffer.release); 00548 00549 strncpy(_papi_os_info.name,uname_buffer.sysname,PAPI_MAX_STR_LEN); 00550 00551 #ifdef ASSUME_KERNEL 00552 strncpy(_papi_os_info.version,ASSUME_KERNEL,PAPI_MAX_STR_LEN); 00553 SUBDBG("Assuming kernel version %s\n",_papi_os_info.name); 00554 #else 00555 strncpy(_papi_os_info.version,uname_buffer.release,PAPI_MAX_STR_LEN); 00556 #endif 00557 00558 ptr=strtok(_papi_os_info.version,"."); 00559 if (ptr!=NULL) major=atoi(ptr); 00560 00561 ptr=strtok(NULL,"."); 00562 if (ptr!=NULL) minor=atoi(ptr); 00563 00564 ptr=strtok(NULL,"."); 00565 if (ptr!=NULL) sub=atoi(ptr); 00566 00567 _papi_os_info.os_version=LINUX_VERSION(major,minor,sub); 00568 00569 _papi_os_info.itimer_sig = PAPI_INT_MPX_SIGNAL; 00570 _papi_os_info.itimer_num = PAPI_INT_ITIMER; 00571 _papi_os_info.itimer_ns = PAPI_INT_MPX_DEF_US * 1000; 00572 _papi_os_info.itimer_res_ns = 1; 00573 _papi_os_info.clock_ticks = sysconf( _SC_CLK_TCK ); 00574 00575 /* Get Linux-specific system info */ 00576 _linux_get_system_info( &_papi_hwi_system_info ); 00577 00578 return PAPI_OK; 00579 } 00580 00581 00582 00583 int _linux_detect_nmi_watchdog() { 00584 00585 int watchdog_detected=0,watchdog_value=0; 00586 FILE *fff; 00587 00588 fff=fopen("/proc/sys/kernel/nmi_watchdog","r"); 00589 if (fff!=NULL) { 00590 if (fscanf(fff,"%d",&watchdog_value)==1) { 00591 if (watchdog_value>0) watchdog_detected=1; 00592 } 00593 fclose(fff); 00594 } 00595 00596 return watchdog_detected; 00597 } 00598 00599 papi_os_vector_t _papi_os_vector = { 00600 .get_memory_info = _linux_get_memory_info, 00601 .get_dmem_info = _linux_get_dmem_info, 00602 .get_real_cycles = _linux_get_real_cycles, 00603 .update_shlib_info = _linux_update_shlib_info, 00604 .get_system_info = _linux_get_system_info, 00605 00606 00607 #if defined(HAVE_CLOCK_GETTIME) 00608 .get_real_usec = _linux_get_real_usec_gettime, 00609 #elif defined(HAVE_GETTIMEOFDAY) 00610 .get_real_usec = _linux_get_real_usec_gettimeofday, 00611 #else 00612 .get_real_usec = _linux_get_real_usec_cycles, 00613 #endif 00614 00615 00616 #if defined(USE_PROC_PTTIMER) 00617 .get_virt_usec = _linux_get_virt_usec_pttimer, 00618 #elif defined(HAVE_CLOCK_GETTIME_THREAD) 00619 .get_virt_usec = _linux_get_virt_usec_gettime, 00620 #elif defined(HAVE_PER_THREAD_TIMES) 00621 .get_virt_usec = _linux_get_virt_usec_times, 00622 #elif defined(HAVE_PER_THREAD_GETRUSAGE) 00623 .get_virt_usec = _linux_get_virt_usec_rusage, 00624 #endif 00625 00626 00627 #if defined(HAVE_CLOCK_GETTIME) 00628 .get_real_nsec = _linux_get_real_nsec_gettime, 00629 #endif 00630 00631 #if defined(HAVE_CLOCK_GETTIME_THREAD) 00632 .get_virt_nsec = _linux_get_virt_nsec_gettime, 00633 #endif 00634 00635 00636 };