PAPI  5.0.1.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 <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 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines