int _linux_get_cpu_info( PAPI_hw_info_t * hwinfo ) { int tmp, retval = PAPI_OK; char maxargs[PAPI_HUGE_STR_LEN], *t, *s; float mhz = 0.0; FILE *f; if ( ( f = fopen( "/proc/cpuinfo", "r" ) ) == NULL ) { PAPIERROR( "fopen(/proc/cpuinfo) errno %d", errno ); return PAPI_ESYS; } /* All of this information maybe overwritten by the substrate */ /* MHZ */ rewind( f ); s = search_cpu_info( f, "clock", maxargs ); if ( !s ) { rewind( f ); s = search_cpu_info( f, "cpu MHz", maxargs ); } if ( s ) sscanf( s + 1, "%f", &mhz ); hwinfo->mhz = mhz; hwinfo->clock_mhz = ( int ) mhz; /* Vendor Name and Vendor Code */ rewind( f ); s = search_cpu_info( f, "vendor_id", maxargs ); if ( s && ( t = strchr( s + 2, '\n' ) ) ) { *t = '\0'; strcpy( hwinfo->vendor_string, s + 2 ); } else { rewind( f ); s = search_cpu_info( f, "vendor", maxargs ); if ( s && ( t = strchr( s + 2, '\n' ) ) ) { *t = '\0'; strcpy( hwinfo->vendor_string, s + 2 ); } else { rewind( f ); s = search_cpu_info( f, "system type", maxargs ); if ( s && ( t = strchr( s + 2, '\n' ) ) ) { *t = '\0'; s = strtok( s + 2, " " ); strcpy( hwinfo->vendor_string, s ); } else { rewind( f ); s = search_cpu_info( f, "platform", maxargs ); if ( s && ( t = strchr( s + 2, '\n' ) ) ) { *t = '\0'; s = strtok( s + 2, " " ); if ( ( strcasecmp( s, "pSeries" ) == 0 ) || ( strcasecmp( s, "PowerMac" ) == 0 ) ) { strcpy( hwinfo->vendor_string, "IBM" ); } } else { rewind( f ); s = search_cpu_info( f, "CPU implementer", maxargs ); if ( s ) { strcpy( hwinfo->vendor_string, "ARM" ); } } } } } if ( strlen( hwinfo->vendor_string ) ) decode_vendor_string( hwinfo->vendor_string, &hwinfo->vendor ); /* Revision */ rewind( f ); s = search_cpu_info( f, "stepping", maxargs ); if ( s ) { sscanf( s + 1, "%d", &tmp ); hwinfo->revision = ( float ) tmp; hwinfo->cpuid_stepping = tmp; } else { rewind( f ); s = search_cpu_info( f, "revision", maxargs ); if ( s ) { sscanf( s + 1, "%d", &tmp ); hwinfo->revision = ( float ) tmp; hwinfo->cpuid_stepping = tmp; } } /* Model Name */ rewind( f ); s = search_cpu_info( f, "model name", maxargs ); if ( s && ( t = strchr( s + 2, '\n' ) ) ) { *t = '\0'; strcpy( hwinfo->model_string, s + 2 ); } else { rewind( f ); s = search_cpu_info( f, "family", maxargs ); if ( s && ( t = strchr( s + 2, '\n' ) ) ) { *t = '\0'; strcpy( hwinfo->model_string, s + 2 ); } else { rewind( f ); s = search_cpu_info( f, "cpu model", maxargs ); if ( s && ( t = strchr( s + 2, '\n' ) ) ) { *t = '\0'; strtok( s + 2, " " ); s = strtok( NULL, " " ); strcpy( hwinfo->model_string, s ); } else { rewind( f ); s = search_cpu_info( f, "cpu", maxargs ); if ( s && ( t = strchr( s + 2, '\n' ) ) ) { *t = '\0'; /* get just the first token */ s = strtok( s + 2, " " ); strcpy( hwinfo->model_string, s ); } } } } /* Family */ rewind( f ); s = search_cpu_info( f, "family", maxargs ); if ( s ) { sscanf( s + 1, "%d", &tmp ); hwinfo->cpuid_family = tmp; } else { rewind( f ); s = search_cpu_info( f, "cpu family", maxargs ); if ( s ) { sscanf( s + 1, "%d", &tmp ); hwinfo->cpuid_family = tmp; } } /* CPU Model */ rewind( f ); s = search_cpu_info( f, "model", maxargs ); if ( s ) { sscanf( s + 1, "%d", &tmp ); hwinfo->model = tmp; hwinfo->cpuid_model = tmp; } fclose( f ); /* The following new members are set using the same methodology used in lscpu. */ /* Total number of CPUs */ /* The following line assumes totalcpus was initialized to zero! */ while ( path_exist( _PATH_SYS_SYSTEM "/cpu/cpu%d", hwinfo->totalcpus ) ) hwinfo->totalcpus++; /* Number of threads per core */ if ( path_exist( _PATH_SYS_CPU0 "/topology/thread_siblings" ) ) hwinfo->threads = path_sibling( _PATH_SYS_CPU0 "/topology/thread_siblings" ); /* Number of cores per socket */ if ( path_exist( _PATH_SYS_CPU0 "/topology/core_siblings" ) && hwinfo->threads > 0 ) hwinfo->cores = path_sibling( _PATH_SYS_CPU0 "/topology/core_siblings" ) / hwinfo->threads; /* Number of sockets */ if ( hwinfo->threads > 0 && hwinfo->cores > 0 ) hwinfo->sockets = hwinfo->ncpu / hwinfo->cores / hwinfo->threads; /* Number of NUMA nodes */ /* The following line assumes nnodes was initialized to zero! */ while ( path_exist( _PATH_SYS_SYSTEM "/node/node%d", hwinfo->nnodes ) ) hwinfo->nnodes++; /* Number of CPUs per node */ hwinfo->ncpu = hwinfo->nnodes > 1 ? hwinfo->totalcpus / hwinfo->nnodes : hwinfo->totalcpus; #if 0 int *nodecpu; /* cpumap data is not currently part of the _papi_hw_info struct */ nodecpu = malloc( (unsigned int) hwinfo->nnodes * sizeof(int) ); if ( nodecpu ) { int i; for ( i = 0; i < hwinfo->nnodes; ++i ) { nodecpu[i] = path_sibling( _PATH_SYS_SYSTEM "/node/node%d/cpumap", i ); } } else { PAPIERROR( "malloc failed for variable not currently used" ); } #endif return retval; }
int _linux_get_cpu_info( PAPI_hw_info_t *hwinfo, int *cpuinfo_mhz ) { int retval = PAPI_OK; unsigned int strSize; char maxargs[PAPI_HUGE_STR_LEN], *t, *s; float mhz = 0.0; FILE *f; char cpuinfo_filename[]="/proc/cpuinfo"; if ( ( f = fopen( cpuinfo_filename, "r" ) ) == NULL ) { PAPIERROR( "fopen(/proc/cpuinfo) errno %d", errno ); return PAPI_ESYS; } /* All of this information may be overwritten by the component */ /***********************/ /* Attempt to find MHz */ /***********************/ rewind( f ); s = search_cpu_info( f, "clock", maxargs ); if ( !s ) { rewind( f ); s = search_cpu_info( f, "cpu MHz", maxargs ); } if ( s ) { sscanf( s + 1, "%f", &mhz ); } *cpuinfo_mhz = mhz; /*******************************/ /* Vendor Name and Vendor Code */ /*******************************/ /* First try to read "vendor_id" field */ /* Which is the most common field */ hwinfo->vendor_string[0]=0; rewind( f ); s = search_cpu_info( f, "vendor_id", maxargs ); strSize = sizeof(hwinfo->vendor_string); if ( s && ( t = strchr( s + 2, '\n' ) ) ) { *t = '\0'; if (strlen(s+2) >= strSize-1) { s[strSize+1] = '\0'; } strcpy( hwinfo->vendor_string, s + 2 ); } /* If not found, try "vendor" which seems to be Itanium specific */ if (!hwinfo->vendor_string[0]) { rewind( f ); s = search_cpu_info( f, "vendor", maxargs ); if ( s && ( t = strchr( s + 2, '\n' ) ) ) { *t = '\0'; if (strlen(s+2) >= strSize-1) { s[strSize+1] = '\0'; } strcpy( hwinfo->vendor_string, s + 2 ); } } /* "system type" seems to be MIPS and Alpha */ if (!hwinfo->vendor_string[0]) { rewind( f ); s = search_cpu_info( f, "system type", maxargs ); if ( s && ( t = strchr( s + 2, '\n' ) ) ) { *t = '\0'; s = strtok( s + 2, " " ); if (strlen(s) >= strSize-1) { s[strSize-1] = '\0'; } strcpy( hwinfo->vendor_string, s ); } } /* "platform" indicates Power */ if (!hwinfo->vendor_string[0]) { rewind( f ); s = search_cpu_info( f, "platform", maxargs ); if ( s && ( t = strchr( s + 2, '\n' ) ) ) { *t = '\0'; s = strtok( s + 2, " " ); if ( ( strcasecmp( s, "pSeries" ) == 0 ) || ( strcasecmp( s, "PowerNV" ) == 0 ) || ( strcasecmp( s, "PowerMac" ) == 0 ) ) { strcpy( hwinfo->vendor_string, "IBM" ); } } } /* "CPU implementer" indicates ARM */ if (!hwinfo->vendor_string[0]) { rewind( f ); s = search_cpu_info( f, "CPU implementer", maxargs ); if ( s ) { strcpy( hwinfo->vendor_string, "ARM" ); } } /* Decode the string to an implementer value */ if ( strlen( hwinfo->vendor_string ) ) { decode_vendor_string( hwinfo->vendor_string, &hwinfo->vendor ); } /**********************************************/ /* Provide more stepping/model/family numbers */ /**********************************************/ if ((hwinfo->vendor==PAPI_VENDOR_INTEL) || (hwinfo->vendor==PAPI_VENDOR_AMD)) { decode_cpuinfo_x86(f,hwinfo); } if (hwinfo->vendor==PAPI_VENDOR_IBM) { decode_cpuinfo_power(f,hwinfo); } if (hwinfo->vendor==PAPI_VENDOR_ARM) { decode_cpuinfo_arm(f,hwinfo); } /* The following members are set using the same methodology */ /* used in lscpu. */ /* Total number of CPUs */ /* The following line assumes totalcpus was initialized to zero! */ while ( path_exist( _PATH_SYS_SYSTEM "/cpu/cpu%d", hwinfo->totalcpus ) ) hwinfo->totalcpus++; /* Number of threads per core */ if ( path_exist( _PATH_SYS_CPU0 "/topology/thread_siblings" ) ) hwinfo->threads = path_sibling( _PATH_SYS_CPU0 "/topology/thread_siblings" ); /* Number of cores per socket */ if ( path_exist( _PATH_SYS_CPU0 "/topology/core_siblings" ) && hwinfo->threads > 0 ) hwinfo->cores = path_sibling( _PATH_SYS_CPU0 "/topology/core_siblings" ) / hwinfo->threads; /* Number of NUMA nodes */ /* The following line assumes nnodes was initialized to zero! */ while ( path_exist( _PATH_SYS_SYSTEM "/node/node%d", hwinfo->nnodes ) ) hwinfo->nnodes++; /* Number of CPUs per node */ hwinfo->ncpu = hwinfo->nnodes > 1 ? hwinfo->totalcpus / hwinfo->nnodes : hwinfo->totalcpus; /* Number of sockets */ if ( hwinfo->threads > 0 && hwinfo->cores > 0 ) hwinfo->sockets = hwinfo->totalcpus / hwinfo->cores / hwinfo->threads; #if 0 int *nodecpu; /* cpumap data is not currently part of the _papi_hw_info struct */ nodecpu = malloc( (unsigned int) hwinfo->nnodes * sizeof(int) ); if ( nodecpu ) { int i; for ( i = 0; i < hwinfo->nnodes; ++i ) { nodecpu[i] = path_sibling( _PATH_SYS_SYSTEM "/node/node%d/cpumap", i ); } } else { PAPIERROR( "malloc failed for variable not currently used" ); } #endif /* Fixup missing Megahertz Value */ /* This is missing from cpuinfo on ARM and MIPS */ if (*cpuinfo_mhz < 1.0) { rewind( f ); s = search_cpu_info( f, "BogoMIPS", maxargs ); if ((!s) || (sscanf( s + 1, "%f", &mhz ) != 1)) { INTDBG("Mhz detection failed. Please edit file %s at line %d.\n", __FILE__,__LINE__); } if (hwinfo->vendor == PAPI_VENDOR_MIPS) { /* MIPS has 2x clock multiplier */ *cpuinfo_mhz = 2*(((int)mhz)+1); /* Also update version info on MIPS */ rewind( f ); s = search_cpu_info( f, "cpu model", maxargs ); s = strstr(s+1," V")+2; strtok(s," "); sscanf(s, "%f ", &hwinfo->revision ); } else { /* In general bogomips is proportional to number of CPUs */ if (hwinfo->totalcpus) { if (mhz!=0) *cpuinfo_mhz = mhz / hwinfo->totalcpus; } } } fclose( f ); return retval; }