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