|
PAPI
5.0.1.0
|
00001 /****************************/ 00002 /* THIS IS OPEN SOURCE CODE */ 00003 /****************************/ 00004 00005 /* 00006 * File: linux-memory.c 00007 * Author: Kevin London 00008 * london@cs.utk.edu 00009 * Mods: Dan Terpstra 00010 * terpstra@eecs.utk.edu 00011 * cache and TLB info exported to a separate file 00012 * which is not OS or driver dependent 00013 * Mods: Vince Weaver 00014 * vweaver1@eecs.utk.edu 00015 * Merge all of the various copies of linux-related 00016 * memory detection info this file. 00017 */ 00018 00019 #include <string.h> 00020 #include <errno.h> 00021 00022 #include "papi.h" 00023 #include "papi_internal.h" 00024 #include "papi_memory.h" /* papi_calloc() */ 00025 00026 #include "x86_cpuid_info.h" 00027 00028 #include "linux-lock.h" 00029 00030 /* 2.6.19 has this: 00031 VmPeak: 4588 kB 00032 VmSize: 4584 kB 00033 VmLck: 0 kB 00034 VmHWM: 1548 kB 00035 VmRSS: 1548 kB 00036 VmData: 312 kB 00037 VmStk: 88 kB 00038 VmExe: 684 kB 00039 VmLib: 1360 kB 00040 VmPTE: 20 kB 00041 */ 00042 00043 00044 int 00045 _linux_get_dmem_info( PAPI_dmem_info_t * d ) 00046 { 00047 char fn[PATH_MAX], tmp[PATH_MAX]; 00048 FILE *f; 00049 int ret; 00050 long long sz = 0, lck = 0, res = 0, shr = 0, stk = 0, txt = 0, dat = 00051 0, dum = 0, lib = 0, hwm = 0; 00052 00053 sprintf( fn, "/proc/%ld/status", ( long ) getpid( ) ); 00054 f = fopen( fn, "r" ); 00055 if ( f == NULL ) { 00056 PAPIERROR( "fopen(%s): %s\n", fn, strerror( errno ) ); 00057 return PAPI_ESYS; 00058 } 00059 while ( 1 ) { 00060 if ( fgets( tmp, PATH_MAX, f ) == NULL ) 00061 break; 00062 if ( strspn( tmp, "VmSize:" ) == strlen( "VmSize:" ) ) { 00063 sscanf( tmp + strlen( "VmSize:" ), "%lld", &sz ); 00064 d->size = sz; 00065 continue; 00066 } 00067 if ( strspn( tmp, "VmHWM:" ) == strlen( "VmHWM:" ) ) { 00068 sscanf( tmp + strlen( "VmHWM:" ), "%lld", &hwm ); 00069 d->high_water_mark = hwm; 00070 continue; 00071 } 00072 if ( strspn( tmp, "VmLck:" ) == strlen( "VmLck:" ) ) { 00073 sscanf( tmp + strlen( "VmLck:" ), "%lld", &lck ); 00074 d->locked = lck; 00075 continue; 00076 } 00077 if ( strspn( tmp, "VmRSS:" ) == strlen( "VmRSS:" ) ) { 00078 sscanf( tmp + strlen( "VmRSS:" ), "%lld", &res ); 00079 d->resident = res; 00080 continue; 00081 } 00082 if ( strspn( tmp, "VmData:" ) == strlen( "VmData:" ) ) { 00083 sscanf( tmp + strlen( "VmData:" ), "%lld", &dat ); 00084 d->heap = dat; 00085 continue; 00086 } 00087 if ( strspn( tmp, "VmStk:" ) == strlen( "VmStk:" ) ) { 00088 sscanf( tmp + strlen( "VmStk:" ), "%lld", &stk ); 00089 d->stack = stk; 00090 continue; 00091 } 00092 if ( strspn( tmp, "VmExe:" ) == strlen( "VmExe:" ) ) { 00093 sscanf( tmp + strlen( "VmExe:" ), "%lld", &txt ); 00094 d->text = txt; 00095 continue; 00096 } 00097 if ( strspn( tmp, "VmLib:" ) == strlen( "VmLib:" ) ) { 00098 sscanf( tmp + strlen( "VmLib:" ), "%lld", &lib ); 00099 d->library = lib; 00100 continue; 00101 } 00102 } 00103 fclose( f ); 00104 00105 sprintf( fn, "/proc/%ld/statm", ( long ) getpid( ) ); 00106 f = fopen( fn, "r" ); 00107 if ( f == NULL ) { 00108 PAPIERROR( "fopen(%s): %s\n", fn, strerror( errno ) ); 00109 return PAPI_ESYS; 00110 } 00111 ret = 00112 fscanf( f, "%lld %lld %lld %lld %lld %lld %lld", &dum, &dum, &shr, &dum, 00113 &dum, &dat, &dum ); 00114 if ( ret != 7 ) { 00115 PAPIERROR( "fscanf(7 items): %d\n", ret ); 00116 fclose(f); 00117 return PAPI_ESYS; 00118 } 00119 d->pagesize = getpagesize( ); 00120 d->shared = ( shr * d->pagesize ) / 1024; 00121 fclose( f ); 00122 00123 return PAPI_OK; 00124 } 00125 00126 /* 00127 * Architecture-specific cache detection code 00128 */ 00129 00130 00131 #if defined(__i386__)||defined(__x86_64__) 00132 static int 00133 x86_get_memory_info( PAPI_hw_info_t * hw_info ) 00134 { 00135 int retval = PAPI_OK; 00136 00137 switch ( hw_info->vendor ) { 00138 case PAPI_VENDOR_AMD: 00139 case PAPI_VENDOR_INTEL: 00140 retval = _x86_cache_info( &hw_info->mem_hierarchy ); 00141 break; 00142 default: 00143 PAPIERROR( "Unknown vendor in memory information call for x86." ); 00144 return PAPI_ENOIMPL; 00145 } 00146 return retval; 00147 } 00148 #endif 00149 00150 #if defined(__ia64__) 00151 static int 00152 get_number( char *buf ) 00153 { 00154 char numbers[] = "0123456789"; 00155 int num; 00156 char *tmp, *end; 00157 00158 tmp = strpbrk( buf, numbers ); 00159 if ( tmp != NULL ) { 00160 end = tmp; 00161 while ( isdigit( *end ) ) 00162 end++; 00163 *end = '\0'; 00164 num = atoi( tmp ); 00165 return num; 00166 } 00167 00168 PAPIERROR( "Number could not be parsed from %s", buf ); 00169 return -1; 00170 } 00171 00172 static void 00173 fline( FILE * fp, char *rline ) 00174 { 00175 char *tmp, *end, c; 00176 00177 tmp = rline; 00178 end = &rline[1023]; 00179 00180 memset( rline, '\0', 1024 ); 00181 00182 do { 00183 if ( feof( fp ) ) 00184 return; 00185 c = getc( fp ); 00186 } 00187 while ( isspace( c ) || c == '\n' || c == '\r' ); 00188 00189 ungetc( c, fp ); 00190 00191 for ( ;; ) { 00192 if ( feof( fp ) ) { 00193 return; 00194 } 00195 c = getc( fp ); 00196 if ( c == '\n' || c == '\r' ) 00197 break; 00198 *tmp++ = c; 00199 if ( tmp == end ) { 00200 *tmp = '\0'; 00201 return; 00202 } 00203 } 00204 return; 00205 } 00206 00207 static int 00208 ia64_get_memory_info( PAPI_hw_info_t * hw_info ) 00209 { 00210 int retval = 0; 00211 FILE *f; 00212 int clevel = 0, cindex = -1; 00213 char buf[1024]; 00214 int num, i, j; 00215 PAPI_mh_info_t *meminfo = &hw_info->mem_hierarchy; 00216 PAPI_mh_level_t *L = hw_info->mem_hierarchy.level; 00217 00218 f = fopen( "/proc/pal/cpu0/cache_info", "r" ); 00219 00220 if ( !f ) { 00221 PAPIERROR( "fopen(/proc/pal/cpu0/cache_info) returned < 0" ); 00222 return PAPI_ESYS; 00223 } 00224 00225 while ( !feof( f ) ) { 00226 fline( f, buf ); 00227 if ( buf[0] == '\0' ) 00228 break; 00229 if ( !strncmp( buf, "Data Cache", 10 ) ) { 00230 cindex = 1; 00231 clevel = get_number( buf ); 00232 L[clevel - 1].cache[cindex].type = PAPI_MH_TYPE_DATA; 00233 } else if ( !strncmp( buf, "Instruction Cache", 17 ) ) { 00234 cindex = 0; 00235 clevel = get_number( buf ); 00236 L[clevel - 1].cache[cindex].type = PAPI_MH_TYPE_INST; 00237 } else if ( !strncmp( buf, "Data/Instruction Cache", 22 ) ) { 00238 cindex = 0; 00239 clevel = get_number( buf ); 00240 L[clevel - 1].cache[cindex].type = PAPI_MH_TYPE_UNIFIED; 00241 } else { 00242 if ( ( clevel == 0 || clevel > 3 ) && cindex >= 0 ) { 00243 PAPIERROR 00244 ( "Cache type could not be recognized, please send /proc/pal/cpu0/cache_info" ); 00245 return PAPI_EBUG; 00246 } 00247 00248 if ( !strncmp( buf, "Size", 4 ) ) { 00249 num = get_number( buf ); 00250 L[clevel - 1].cache[cindex].size = num; 00251 } else if ( !strncmp( buf, "Associativity", 13 ) ) { 00252 num = get_number( buf ); 00253 L[clevel - 1].cache[cindex].associativity = num; 00254 } else if ( !strncmp( buf, "Line size", 9 ) ) { 00255 num = get_number( buf ); 00256 L[clevel - 1].cache[cindex].line_size = num; 00257 L[clevel - 1].cache[cindex].num_lines = 00258 L[clevel - 1].cache[cindex].size / num; 00259 } 00260 } 00261 } 00262 00263 fclose( f ); 00264 00265 f = fopen( "/proc/pal/cpu0/vm_info", "r" ); 00266 /* No errors on fopen as I am not sure this is always on the systems */ 00267 if ( f != NULL ) { 00268 cindex = -1; 00269 clevel = 0; 00270 while ( !feof( f ) ) { 00271 fline( f, buf ); 00272 if ( buf[0] == '\0' ) 00273 break; 00274 if ( !strncmp( buf, "Data Translation", 16 ) ) { 00275 cindex = 1; 00276 clevel = get_number( buf ); 00277 L[clevel - 1].tlb[cindex].type = PAPI_MH_TYPE_DATA; 00278 } else if ( !strncmp( buf, "Instruction Translation", 23 ) ) { 00279 cindex = 0; 00280 clevel = get_number( buf ); 00281 L[clevel - 1].tlb[cindex].type = PAPI_MH_TYPE_INST; 00282 } else { 00283 if ( ( clevel == 0 || clevel > 2 ) && cindex >= 0 ) { 00284 PAPIERROR 00285 ( "TLB type could not be recognized, send /proc/pal/cpu0/vm_info" ); 00286 return PAPI_EBUG; 00287 } 00288 00289 if ( !strncmp( buf, "Number of entries", 17 ) ) { 00290 num = get_number( buf ); 00291 L[clevel - 1].tlb[cindex].num_entries = num; 00292 } else if ( !strncmp( buf, "Associativity", 13 ) ) { 00293 num = get_number( buf ); 00294 L[clevel - 1].tlb[cindex].associativity = num; 00295 } 00296 } 00297 } 00298 fclose( f ); 00299 } 00300 00301 /* Compute and store the number of levels of hierarchy actually used */ 00302 for ( i = 0; i < PAPI_MH_MAX_LEVELS; i++ ) { 00303 for ( j = 0; j < 2; j++ ) { 00304 if ( L[i].tlb[j].type != PAPI_MH_TYPE_EMPTY || 00305 L[i].cache[j].type != PAPI_MH_TYPE_EMPTY ) 00306 meminfo->levels = i + 1; 00307 } 00308 } 00309 return retval; 00310 } 00311 #endif 00312 00313 #if defined(__powerpc__) 00314 00315 PAPI_mh_info_t sys_mem_info[4] = { 00316 {2, // 970 begin 00317 { 00318 { // level 1 begins 00319 { // tlb's begin 00320 {PAPI_MH_TYPE_UNIFIED, 1024, 4, 0} 00321 , 00322 {PAPI_MH_TYPE_EMPTY, -1, -1, -1} 00323 } 00324 , 00325 { // caches begin 00326 {PAPI_MH_TYPE_INST, 65536, 128, 512, 1} 00327 , 00328 {PAPI_MH_TYPE_DATA, 32768, 128, 256, 2} 00329 } 00330 } 00331 , 00332 { // level 2 begins 00333 { // tlb's begin 00334 {PAPI_MH_TYPE_EMPTY, -1, -1, -1} 00335 , 00336 {PAPI_MH_TYPE_EMPTY, -1, -1, -1} 00337 } 00338 , 00339 { // caches begin 00340 {PAPI_MH_TYPE_UNIFIED, 524288, 128, 4096, 8} 00341 , 00342 {PAPI_MH_TYPE_EMPTY, -1, -1, -1, -1} 00343 } 00344 } 00345 , 00346 } 00347 } 00348 , // 970 end 00349 {3, 00350 { 00351 { // level 1 begins 00352 { // tlb's begin 00353 {PAPI_MH_TYPE_UNIFIED, 1024, 4, 0} 00354 , 00355 {PAPI_MH_TYPE_EMPTY, -1, -1, -1} 00356 } 00357 , 00358 { // caches begin 00359 {PAPI_MH_TYPE_INST, 65536, 128, 512, 2} 00360 , 00361 {PAPI_MH_TYPE_DATA, 32768, 128, 256, 4} 00362 } 00363 } 00364 , 00365 { // level 2 begins 00366 { // tlb's begin 00367 {PAPI_MH_TYPE_EMPTY, -1, -1, -1} 00368 , 00369 {PAPI_MH_TYPE_EMPTY, -1, -1, -1} 00370 } 00371 , 00372 { // caches begin 00373 {PAPI_MH_TYPE_UNIFIED, 1966080, 128, 15360, 10} 00374 , 00375 {PAPI_MH_TYPE_EMPTY, -1, -1, -1, -1} 00376 } 00377 } 00378 , 00379 { // level 3 begins 00380 { // tlb's begin 00381 {PAPI_MH_TYPE_EMPTY, -1, -1, -1} 00382 , 00383 {PAPI_MH_TYPE_EMPTY, -1, -1, -1} 00384 } 00385 , 00386 { // caches begin 00387 {PAPI_MH_TYPE_UNIFIED, 37748736, 256, 147456, 12} 00388 , 00389 {PAPI_MH_TYPE_EMPTY, -1, -1, -1, -1} 00390 } 00391 } 00392 , 00393 } 00394 } 00395 , // POWER5 end 00396 {3, 00397 { 00398 { // level 1 begins 00399 { // tlb's begin 00403 {PAPI_MH_TYPE_INST, 128, 2, 0} 00404 , 00405 {PAPI_MH_TYPE_DATA, 128, 128, 0} 00406 } 00407 , 00408 { // caches begin 00409 {PAPI_MH_TYPE_INST, 65536, 128, 512, 4} 00410 , 00411 {PAPI_MH_TYPE_DATA, 65536, 128, 512, 8} 00412 } 00413 } 00414 , 00415 { // level 2 begins 00416 { // tlb's begin 00417 {PAPI_MH_TYPE_EMPTY, -1, -1, -1} 00418 , 00419 {PAPI_MH_TYPE_EMPTY, -1, -1, -1} 00420 } 00421 , 00422 { // caches begin 00423 {PAPI_MH_TYPE_UNIFIED, 4194304, 128, 16384, 8} 00424 , 00425 {PAPI_MH_TYPE_EMPTY, -1, -1, -1, -1} 00426 } 00427 } 00428 , 00429 { // level 3 begins 00430 { // tlb's begin 00431 {PAPI_MH_TYPE_EMPTY, -1, -1, -1} 00432 , 00433 {PAPI_MH_TYPE_EMPTY, -1, -1, -1} 00434 } 00435 , 00436 { // caches begin 00440 {PAPI_MH_TYPE_UNIFIED, 33554432, 128, 262144, 16} 00441 , 00442 {PAPI_MH_TYPE_EMPTY, -1, -1, -1, -1} 00443 } 00444 } 00445 , 00446 } 00447 } 00448 , // POWER6 end 00449 {3, 00450 { 00451 [0] = { // level 1 begins 00452 .tlb = { 00456 [0] = { .type = PAPI_MH_TYPE_INST, 00457 .num_entries = 64, .page_size = 0, .associativity = 2 } 00458 , 00459 [1] = { .type = PAPI_MH_TYPE_DATA, 00460 .num_entries = 64, .page_size = 0, 00461 .associativity = SHRT_MAX } 00462 } 00463 , 00464 .cache = { // level 1 caches begin 00465 [0] = { .type = PAPI_MH_TYPE_INST | PAPI_MH_TYPE_PSEUDO_LRU, 00466 .size = 32768, .line_size = 128, .num_lines = 64, 00467 .associativity = 4 } 00468 , 00469 [1] = { .type = PAPI_MH_TYPE_DATA | PAPI_MH_TYPE_WT | PAPI_MH_TYPE_LRU, 00470 .size = 32768, .line_size = 128, .num_lines = 32, 00471 .associativity = 8 } 00472 } 00473 } 00474 , 00475 [1] = { // level 2 begins 00476 .tlb = { 00477 [0] = { .type = PAPI_MH_TYPE_EMPTY, .num_entries = -1, 00478 .page_size = -1, .associativity = -1 } 00479 , 00480 [1] = { .type = PAPI_MH_TYPE_EMPTY, .num_entries = -1, 00481 .page_size = -1, .associativity = -1 } 00482 } 00483 , 00484 .cache = { 00485 [0] = { .type = PAPI_MH_TYPE_UNIFIED | PAPI_MH_TYPE_PSEUDO_LRU, 00486 .size = 262144, .line_size = 128, .num_lines = 256, 00487 .associativity = 8 } 00488 , 00489 [1] = { .type = PAPI_MH_TYPE_EMPTY, .size = -1, .line_size = -1, 00490 .num_lines = -1, .associativity = -1 } 00491 } 00492 } 00493 , 00494 [2] = { // level 3 begins 00495 .tlb = { 00496 [0] = { .type = PAPI_MH_TYPE_EMPTY, .num_entries = -1, 00497 .page_size = -1, .associativity = -1 } 00498 , 00499 [1] = { .type = PAPI_MH_TYPE_EMPTY, .num_entries = -1, 00500 .page_size = -1, .associativity = -1 } 00501 } 00502 , 00503 .cache = { 00504 [0] = { .type = PAPI_MH_TYPE_UNIFIED | PAPI_MH_TYPE_PSEUDO_LRU, 00505 .size = 4194304, .line_size = 128, .num_lines = 4096, 00506 .associativity = 8 } 00507 , 00508 [1] = { .type = PAPI_MH_TYPE_EMPTY, .size = -1, .line_size = -1, 00509 .num_lines = -1, .associativity = -1 } 00510 } 00511 } 00512 , 00513 } 00514 } // POWER7 end 00515 }; 00516 00517 #define SPRN_PVR 0x11F /* Processor Version Register */ 00518 #define PVR_PROCESSOR_SHIFT 16 00519 static unsigned int 00520 mfpvr( void ) 00521 { 00522 unsigned long pvr; 00523 00524 asm( "mfspr %0,%1": "=r"( pvr ):"i"( SPRN_PVR ) ); 00525 return pvr; 00526 00527 } 00528 00529 int 00530 ppc64_get_memory_info( PAPI_hw_info_t * hw_info ) 00531 { 00532 unsigned int pvr = mfpvr( ) >> PVR_PROCESSOR_SHIFT; 00533 00534 int index; 00535 switch ( pvr ) { 00536 case 0x39: /* PPC970 */ 00537 case 0x3C: /* PPC970FX */ 00538 case 0x44: /* PPC970MP */ 00539 case 0x45: /* PPC970GX */ 00540 index = 0; 00541 break; 00542 case 0x3A: /* POWER5 */ 00543 case 0x3B: /* POWER5+ */ 00544 index = 1; 00545 break; 00546 case 0x3E: /* POWER6 */ 00547 index = 2; 00548 break; 00549 case 0x3F: /* POWER7 */ 00550 index = 3; 00551 break; 00552 default: 00553 index = -1; 00554 break; 00555 } 00556 00557 if ( index != -1 ) { 00558 int cache_level; 00559 PAPI_mh_info_t sys_mh_inf = sys_mem_info[index]; 00560 PAPI_mh_info_t *mh_inf = &hw_info->mem_hierarchy; 00561 mh_inf->levels = sys_mh_inf.levels; 00562 PAPI_mh_level_t *level = mh_inf->level; 00563 PAPI_mh_level_t sys_mh_level; 00564 for ( cache_level = 0; cache_level < sys_mh_inf.levels; cache_level++ ) { 00565 sys_mh_level = sys_mh_inf.level[cache_level]; 00566 int cache_idx; 00567 for ( cache_idx = 0; cache_idx < 2; cache_idx++ ) { 00568 // process TLB info 00569 PAPI_mh_tlb_info_t curr_tlb = sys_mh_level.tlb[cache_idx]; 00570 int type = curr_tlb.type; 00571 if ( type != PAPI_MH_TYPE_EMPTY ) { 00572 level[cache_level].tlb[cache_idx].type = type; 00573 level[cache_level].tlb[cache_idx].associativity = 00574 curr_tlb.associativity; 00575 level[cache_level].tlb[cache_idx].num_entries = 00576 curr_tlb.num_entries; 00577 } 00578 } 00579 for ( cache_idx = 0; cache_idx < 2; cache_idx++ ) { 00580 // process cache info 00581 PAPI_mh_cache_info_t curr_cache = sys_mh_level.cache[cache_idx]; 00582 int type = curr_cache.type; 00583 if ( type != PAPI_MH_TYPE_EMPTY ) { 00584 level[cache_level].cache[cache_idx].type = type; 00585 level[cache_level].cache[cache_idx].associativity = 00586 curr_cache.associativity; 00587 level[cache_level].cache[cache_idx].size = curr_cache.size; 00588 level[cache_level].cache[cache_idx].line_size = 00589 curr_cache.line_size; 00590 level[cache_level].cache[cache_idx].num_lines = 00591 curr_cache.num_lines; 00592 } 00593 } 00594 } 00595 } 00596 return 0; 00597 } 00598 #endif 00599 00600 #if defined(__sparc__) 00601 static int 00602 sparc_sysfs_cpu_attr( char *name, char **result ) 00603 { 00604 const char *path_base = "/sys/devices/system/cpu/"; 00605 char path_buf[PATH_MAX]; 00606 char val_buf[32]; 00607 DIR *sys_cpu; 00608 00609 sys_cpu = opendir( path_base ); 00610 if ( sys_cpu ) { 00611 struct dirent *cpu; 00612 00613 while ( ( cpu = readdir( sys_cpu ) ) != NULL ) { 00614 int fd; 00615 00616 if ( strncmp( "cpu", cpu->d_name, 3 ) ) 00617 continue; 00618 strcpy( path_buf, path_base ); 00619 strcat( path_buf, cpu->d_name ); 00620 strcat( path_buf, "/" ); 00621 strcat( path_buf, name ); 00622 00623 fd = open( path_buf, O_RDONLY ); 00624 if ( fd < 0 ) 00625 continue; 00626 00627 if ( read( fd, val_buf, 32 ) < 0 ) 00628 continue; 00629 close( fd ); 00630 00631 *result = strdup( val_buf ); 00632 return 0; 00633 } 00634 } 00635 return -1; 00636 } 00637 00638 static int 00639 sparc_cpu_attr( char *name, unsigned long long *val ) 00640 { 00641 char *buf; 00642 int r; 00643 00644 r = sparc_sysfs_cpu_attr( name, &buf ); 00645 if ( r == -1 ) 00646 return -1; 00647 00648 sscanf( buf, "%llu", val ); 00649 00650 free( buf ); 00651 00652 return 0; 00653 } 00654 00655 static char * 00656 search_cpu_info( FILE * f, char *search_str, char *line ) 00657 { 00658 /* This code courtesy of our friends in Germany. Thanks Rudolph Berrend\ 00659 orf! */ 00660 /* See the home page for the German version of PAPI. */ 00661 00662 char *s; 00663 00664 while ( fgets( line, 256, f ) != NULL ) { 00665 if ( strstr( line, search_str ) != NULL ) { 00666 /* ignore all characters in line up to : */ 00667 for ( s = line; *s && ( *s != ':' ); ++s ); 00668 if ( *s ) 00669 return s; 00670 } 00671 } 00672 return NULL; 00673 00674 /* End stolen code */ 00675 } 00676 00677 00678 static int 00679 sparc_get_memory_info( PAPI_hw_info_t * hw_info ) 00680 { 00681 unsigned long long cache_size, cache_line_size; 00682 unsigned long long cycles_per_second; 00683 char maxargs[PAPI_HUGE_STR_LEN]; 00684 PAPI_mh_tlb_info_t *tlb; 00685 PAPI_mh_level_t *level; 00686 char *s, *t; 00687 FILE *f; 00688 00689 /* First, fix up the cpu vendor/model/etc. values */ 00690 strcpy( hw_info->vendor_string, "Sun" ); 00691 hw_info->vendor = PAPI_VENDOR_SUN; 00692 00693 f = fopen( "/proc/cpuinfo", "r" ); 00694 if ( !f ) 00695 return PAPI_ESYS; 00696 00697 rewind( f ); 00698 s = search_cpu_info( f, "cpu", maxargs ); 00699 if ( !s ) { 00700 fclose( f ); 00701 return PAPI_ESYS; 00702 } 00703 00704 t = strchr( s + 2, '\n' ); 00705 if ( !t ) { 00706 fclose( f ); 00707 return PAPI_ESYS; 00708 } 00709 00710 *t = '\0'; 00711 strcpy( hw_info->model_string, s + 2 ); 00712 00713 fclose( f ); 00714 00715 /* 00716 if ( sparc_sysfs_cpu_attr( "clock_tick", &s ) == -1 ) 00717 return PAPI_ESYS; 00718 00719 sscanf( s, "%llu", &cycles_per_second ); 00720 free( s ); 00721 00722 hw_info->mhz = cycles_per_second / 1000000; 00723 hw_info->clock_mhz = hw_info->mhz; 00724 */ 00725 00726 /* Now fetch the cache info */ 00727 hw_info->mem_hierarchy.levels = 3; 00728 00729 level = &hw_info->mem_hierarchy.level[0]; 00730 00731 sparc_cpu_attr( "l1_icache_size", &cache_size ); 00732 sparc_cpu_attr( "l1_icache_line_size", &cache_line_size ); 00733 level[0].cache[0].type = PAPI_MH_TYPE_INST; 00734 level[0].cache[0].size = cache_size; 00735 level[0].cache[0].line_size = cache_line_size; 00736 level[0].cache[0].num_lines = cache_size / cache_line_size; 00737 level[0].cache[0].associativity = 1; 00738 00739 sparc_cpu_attr( "l1_dcache_size", &cache_size ); 00740 sparc_cpu_attr( "l1_dcache_line_size", &cache_line_size ); 00741 level[0].cache[1].type = PAPI_MH_TYPE_DATA | PAPI_MH_TYPE_WT; 00742 level[0].cache[1].size = cache_size; 00743 level[0].cache[1].line_size = cache_line_size; 00744 level[0].cache[1].num_lines = cache_size / cache_line_size; 00745 level[0].cache[1].associativity = 1; 00746 00747 sparc_cpu_attr( "l2_cache_size", &cache_size ); 00748 sparc_cpu_attr( "l2_cache_line_size", &cache_line_size ); 00749 level[1].cache[0].type = PAPI_MH_TYPE_DATA | PAPI_MH_TYPE_WB; 00750 level[1].cache[0].size = cache_size; 00751 level[1].cache[0].line_size = cache_line_size; 00752 level[1].cache[0].num_lines = cache_size / cache_line_size; 00753 level[1].cache[0].associativity = 1; 00754 00755 tlb = &hw_info->mem_hierarchy.level[0].tlb[0]; 00756 switch ( _perfmon2_pfm_pmu_type ) { 00757 case PFMLIB_SPARC_ULTRA12_PMU: 00758 tlb[0].type = PAPI_MH_TYPE_INST | PAPI_MH_TYPE_PSEUDO_LRU; 00759 tlb[0].num_entries = 64; 00760 tlb[0].associativity = SHRT_MAX; 00761 tlb[1].type = PAPI_MH_TYPE_DATA | PAPI_MH_TYPE_PSEUDO_LRU; 00762 tlb[1].num_entries = 64; 00763 tlb[1].associativity = SHRT_MAX; 00764 break; 00765 00766 case PFMLIB_SPARC_ULTRA3_PMU: 00767 case PFMLIB_SPARC_ULTRA3I_PMU: 00768 case PFMLIB_SPARC_ULTRA3PLUS_PMU: 00769 case PFMLIB_SPARC_ULTRA4PLUS_PMU: 00770 level[0].cache[0].associativity = 4; 00771 level[0].cache[1].associativity = 4; 00772 level[1].cache[0].associativity = 4; 00773 00774 tlb[0].type = PAPI_MH_TYPE_DATA | PAPI_MH_TYPE_PSEUDO_LRU; 00775 tlb[0].num_entries = 16; 00776 tlb[0].associativity = SHRT_MAX; 00777 tlb[1].type = PAPI_MH_TYPE_INST | PAPI_MH_TYPE_PSEUDO_LRU; 00778 tlb[1].num_entries = 16; 00779 tlb[1].associativity = SHRT_MAX; 00780 tlb[2].type = PAPI_MH_TYPE_DATA; 00781 tlb[2].num_entries = 1024; 00782 tlb[2].associativity = 2; 00783 tlb[3].type = PAPI_MH_TYPE_INST; 00784 tlb[3].num_entries = 128; 00785 tlb[3].associativity = 2; 00786 break; 00787 00788 case PFMLIB_SPARC_NIAGARA1: 00789 level[0].cache[0].associativity = 4; 00790 level[0].cache[1].associativity = 4; 00791 level[1].cache[0].associativity = 12; 00792 00793 tlb[0].type = PAPI_MH_TYPE_INST | PAPI_MH_TYPE_PSEUDO_LRU; 00794 tlb[0].num_entries = 64; 00795 tlb[0].associativity = SHRT_MAX; 00796 tlb[1].type = PAPI_MH_TYPE_DATA | PAPI_MH_TYPE_PSEUDO_LRU; 00797 tlb[1].num_entries = 64; 00798 tlb[1].associativity = SHRT_MAX; 00799 break; 00800 00801 case PFMLIB_SPARC_NIAGARA2: 00802 level[0].cache[0].associativity = 8; 00803 level[0].cache[1].associativity = 4; 00804 level[1].cache[0].associativity = 16; 00805 00806 tlb[0].type = PAPI_MH_TYPE_INST | PAPI_MH_TYPE_PSEUDO_LRU; 00807 tlb[0].num_entries = 64; 00808 tlb[0].associativity = SHRT_MAX; 00809 tlb[1].type = PAPI_MH_TYPE_DATA | PAPI_MH_TYPE_PSEUDO_LRU; 00810 tlb[1].num_entries = 128; 00811 tlb[1].associativity = SHRT_MAX; 00812 break; 00813 } 00814 00815 return 0; 00816 } 00817 #endif 00818 00819 /* FIXME: have code read the /sys/ cpu files to gather cache info */ 00820 /* in cases where we can't otherwise get cache size data */ 00821 00822 int 00823 generic_get_memory_info( PAPI_hw_info_t * hw_info ) 00824 { 00825 00826 00827 /* Now fetch the cache info */ 00828 hw_info->mem_hierarchy.levels = 0; 00829 00830 return 0; 00831 } 00832 00833 00834 int 00835 _linux_get_memory_info( PAPI_hw_info_t * hwinfo, int cpu_type ) 00836 { 00837 ( void ) cpu_type; /*unused */ 00838 int retval = PAPI_OK; 00839 00840 #if defined(__i386__)||defined(__x86_64__) 00841 x86_get_memory_info( hwinfo ); 00842 #elif defined(__ia64__) 00843 ia64_get_memory_info( hwinfo ); 00844 #elif defined(__powerpc__) 00845 ppc64_get_memory_info( hwinfo ); 00846 #elif defined(__sparc__) 00847 sparc_get_memory_info( hwinfo ); 00848 #elif defined(__arm__) 00849 #warning "WARNING! linux_get_memory_info() does nothing on ARM!" 00850 generic_get_memory_info (hwinfo); 00851 #else 00852 generic_get_memory_info (hwinfo); 00853 #endif 00854 00855 return retval; 00856 } 00857 00858 int 00859 _linux_update_shlib_info( papi_mdi_t *mdi ) 00860 { 00861 00862 char fname[PAPI_HUGE_STR_LEN]; 00863 unsigned long t_index = 0, d_index = 0, b_index = 0, counting = 1; 00864 char buf[PAPI_HUGE_STR_LEN + PAPI_HUGE_STR_LEN], perm[5], dev[16]; 00865 char mapname[PAPI_HUGE_STR_LEN], lastmapname[PAPI_HUGE_STR_LEN]; 00866 unsigned long begin = 0, end = 0, size = 0, inode = 0, foo = 0; 00867 PAPI_address_map_t *tmp = NULL; 00868 FILE *f; 00869 00870 memset( fname, 0x0, sizeof ( fname ) ); 00871 memset( buf, 0x0, sizeof ( buf ) ); 00872 memset( perm, 0x0, sizeof ( perm ) ); 00873 memset( dev, 0x0, sizeof ( dev ) ); 00874 memset( mapname, 0x0, sizeof ( mapname ) ); 00875 memset( lastmapname, 0x0, sizeof ( lastmapname ) ); 00876 00877 sprintf( fname, "/proc/%ld/maps", ( long ) mdi->pid ); 00878 f = fopen( fname, "r" ); 00879 00880 if ( !f ) { 00881 PAPIERROR( "fopen(%s) returned < 0", fname ); 00882 return PAPI_OK; 00883 } 00884 00885 again: 00886 while ( !feof( f ) ) { 00887 begin = end = size = inode = foo = 0; 00888 if ( fgets( buf, sizeof ( buf ), f ) == 0 ) 00889 break; 00890 /* If mapname is null in the string to be scanned, we need to detect that */ 00891 if ( strlen( mapname ) ) 00892 strcpy( lastmapname, mapname ); 00893 else 00894 lastmapname[0] = '\0'; 00895 /* If mapname is null in the string to be scanned, we need to detect that */ 00896 mapname[0] = '\0'; 00897 sscanf( buf, "%lx-%lx %4s %lx %s %ld %s", &begin, &end, perm, &foo, dev, 00898 &inode, mapname ); 00899 size = end - begin; 00900 00901 /* the permission string looks like "rwxp", where each character can 00902 * be either the letter, or a hyphen. The final character is either 00903 * p for private or s for shared. */ 00904 00905 if ( counting ) { 00906 if ( ( perm[2] == 'x' ) && ( perm[0] == 'r' ) && ( inode != 0 ) ) { 00907 if ( strcmp( mdi->exe_info.fullname, mapname ) 00908 == 0 ) { 00909 mdi->exe_info.address_info.text_start = 00910 ( caddr_t ) begin; 00911 mdi->exe_info.address_info.text_end = 00912 ( caddr_t ) ( begin + size ); 00913 } 00914 t_index++; 00915 } else if ( ( perm[0] == 'r' ) && ( perm[1] == 'w' ) && 00916 ( inode != 0 ) 00917 && 00918 ( strcmp 00919 ( mdi->exe_info.fullname, 00920 mapname ) == 0 ) ) { 00921 mdi->exe_info.address_info.data_start = 00922 ( caddr_t ) begin; 00923 mdi->exe_info.address_info.data_end = 00924 ( caddr_t ) ( begin + size ); 00925 d_index++; 00926 } else if ( ( perm[0] == 'r' ) && ( perm[1] == 'w' ) && 00927 ( inode == 0 ) 00928 && 00929 ( strcmp 00930 ( mdi->exe_info.fullname, 00931 lastmapname ) == 0 ) ) { 00932 mdi->exe_info.address_info.bss_start = 00933 ( caddr_t ) begin; 00934 mdi->exe_info.address_info.bss_end = 00935 ( caddr_t ) ( begin + size ); 00936 b_index++; 00937 } 00938 } else if ( !counting ) { 00939 if ( ( perm[2] == 'x' ) && ( perm[0] == 'r' ) && ( inode != 0 ) ) { 00940 if ( strcmp( mdi->exe_info.fullname, mapname ) 00941 != 0 ) { 00942 t_index++; 00943 tmp[t_index - 1].text_start = ( caddr_t ) begin; 00944 tmp[t_index - 1].text_end = ( caddr_t ) ( begin + size ); 00945 strncpy( tmp[t_index - 1].name, mapname, PAPI_MAX_STR_LEN ); 00946 } 00947 } else if ( ( perm[0] == 'r' ) && ( perm[1] == 'w' ) && 00948 ( inode != 0 ) ) { 00949 if ( ( strcmp 00950 ( mdi->exe_info.fullname, 00951 mapname ) != 0 ) 00952 && ( t_index > 0 ) && 00953 ( tmp[t_index - 1].data_start == 0 ) ) { 00954 tmp[t_index - 1].data_start = ( caddr_t ) begin; 00955 tmp[t_index - 1].data_end = ( caddr_t ) ( begin + size ); 00956 } 00957 } else if ( ( perm[0] == 'r' ) && ( perm[1] == 'w' ) && 00958 ( inode == 0 ) ) { 00959 if ( ( t_index > 0 ) && ( tmp[t_index - 1].bss_start == 0 ) ) { 00960 tmp[t_index - 1].bss_start = ( caddr_t ) begin; 00961 tmp[t_index - 1].bss_end = ( caddr_t ) ( begin + size ); 00962 } 00963 } 00964 } 00965 } 00966 00967 if ( counting ) { 00968 /* When we get here, we have counted the number of entries in the map 00969 for us to allocate */ 00970 00971 tmp = 00972 ( PAPI_address_map_t * ) papi_calloc( t_index, 00973 sizeof 00974 ( PAPI_address_map_t ) ); 00975 if ( tmp == NULL ) { 00976 PAPIERROR( "Error allocating shared library address map" ); 00977 fclose(f); 00978 return PAPI_ENOMEM; 00979 } 00980 t_index = 0; 00981 rewind( f ); 00982 counting = 0; 00983 goto again; 00984 } else { 00985 if ( mdi->shlib_info.map ) 00986 papi_free( mdi->shlib_info.map ); 00987 mdi->shlib_info.map = tmp; 00988 mdi->shlib_info.count = t_index; 00989 00990 fclose( f ); 00991 } 00992 00993 return PAPI_OK; 00994 }