PAPI  5.3.0.0
linux-memory.c
Go to the documentation of this file.
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 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines