PAPI  5.0.1.0
x86_cpuid_info.c File Reference
Include dependency graph for x86_cpuid_info.c:

Go to the source code of this file.

Data Structures

struct  _intel_cache_info

Defines

#define TLB_SIZES   3 /* number of different page sizes for a single TLB descriptor */

Functions

static void init_mem_hierarchy (PAPI_mh_info_t *mh_info)
static int init_amd (PAPI_mh_info_t *mh_info, int *levels)
static short int _amd_L2_L3_assoc (unsigned short int pattern)
static int init_intel (PAPI_mh_info_t *mh_info, int *levels)
static void cpuid (unsigned int *a, unsigned int *b, unsigned int *c, unsigned int *d)
int _x86_cache_info (PAPI_mh_info_t *mh_info)
static void intel_decode_descriptor (struct _intel_cache_info *d, PAPI_mh_level_t *L)
static void cpuid2 (unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx, unsigned int index, unsigned int ecx_in)
static int init_intel_leaf4 (PAPI_mh_info_t *mh_info, int *num_levels)
static int init_intel_leaf2 (PAPI_mh_info_t *mh_info, int *num_levels)
int _x86_detect_hypervisor (char *vendor_name)

Variables

static struct _intel_cache_info intel_cache []

Define Documentation

#define TLB_SIZES   3 /* number of different page sizes for a single TLB descriptor */

Definition at line 349 of file x86_cpuid_info.c.


Function Documentation

static short int _amd_L2_L3_assoc ( unsigned short int  pattern) [static]

Definition at line 105 of file x86_cpuid_info.c.

{
    /* From "CPUID Specification" #25481 Rev 2.28, April 2008 */
    short int assoc[16] =
        { 0, 1, 2, -1, 4, -1, 8, -1, 16, -1, 32, 48, 64, 96, 128, SHRT_MAX };
    if ( pattern > 0xF )
        return -1;
    return ( assoc[pattern] );
}

Here is the caller graph for this function:

int _x86_cache_info ( PAPI_mh_info_t mh_info)

< Not implemented

Definition at line 40 of file x86_cpuid_info.c.

{
    int retval = 0;
    union
    {
        struct
        {
            unsigned int ax, bx, cx, dx;
        } e;
        char vendor[20];               /* leave room for terminator bytes */
    } reg;

    /* Don't use cpu_type to determine the processor.
     * get the information directly from the chip.
     */
    reg.e.ax = 0;            /* function code 0: vendor string */
    /* The vendor string is composed of EBX:EDX:ECX.
     * by swapping the register addresses in the call below,
     * the string is correctly composed in the char array.
     */
    cpuid( &reg.e.ax, &reg.e.bx, &reg.e.dx, &reg.e.cx );
    reg.vendor[16] = 0;
    MEMDBG( "Vendor: %s\n", &reg.vendor[4] );

    init_mem_hierarchy( mh_info );

    if ( !strncmp( "GenuineIntel", &reg.vendor[4], 12 ) ) {
            init_intel( mh_info, &mh_info->levels);
    } else if ( !strncmp( "AuthenticAMD", &reg.vendor[4], 12 ) ) {
      init_amd( mh_info, &mh_info->levels );
    } else {
        MEMDBG( "Unsupported cpu type; Not Intel or AMD x86\n" );
        return PAPI_ENOIMPL;
    }

    /* This works only because an empty cache element is initialized to 0 */
    MEMDBG( "Detected L1: %d L2: %d  L3: %d\n",
            mh_info->level[0].cache[0].size + mh_info->level[0].cache[1].size,
            mh_info->level[1].cache[0].size + mh_info->level[1].cache[1].size,
            mh_info->level[2].cache[0].size + mh_info->level[2].cache[1].size );
    return retval;
}

Here is the call graph for this function:

int _x86_detect_hypervisor ( char *  vendor_name)

Definition at line 1486 of file x86_cpuid_info.c.

{
  unsigned int eax, ebx, ecx, edx;
  char hyper_vendor_id[13];

  cpuid2(&eax, &ebx, &ecx, &edx,0x1,0);
  /* This is the hypervisor bit, ecx bit 31 */
  if  (ecx&0x80000000) {
    /* There are various values in the 0x4000000X range */
    /* It is questionable how standard they are         */
    /* For now we just return the name.                 */
    cpuid2(&eax, &ebx, &ecx, &edx, 0x40000000,0);
    memcpy(hyper_vendor_id + 0, &ebx, 4);
    memcpy(hyper_vendor_id + 4, &ecx, 4);
    memcpy(hyper_vendor_id + 8, &edx, 4);
    hyper_vendor_id[12] = '\0';
    strncpy(vendor_name,hyper_vendor_id,PAPI_MAX_STR_LEN);
    return 1;
  }
  else {
    strncpy(vendor_name,"none",PAPI_MAX_STR_LEN);
  }
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void cpuid ( unsigned int *  a,
unsigned int *  b,
unsigned int *  c,
unsigned int *  d 
) [inline, static]

Definition at line 26 of file x86_cpuid_info.c.

{
    unsigned int op = *a;
    // .byte 0x53 == push ebx. it's universal for 32 and 64 bit
    // .byte 0x5b == pop ebx.
    // Some gcc's (4.1.2 on Core2) object to pairing push/pop and ebx in 64 bit mode.
    // Using the opcode directly avoids this problem.
  __asm__ __volatile__( ".byte 0x53\n\tcpuid\n\tmovl %%ebx, %%esi\n\t.byte 0x5b":"=a"( *a ), "=S"( *b ), "=c"( *c ),
                          "=d"
                          ( *d )
  :                   "a"( op ) );
}

Here is the caller graph for this function:

static void cpuid2 ( unsigned int *  eax,
unsigned int *  ebx,
unsigned int *  ecx,
unsigned int *  edx,
unsigned int  index,
unsigned int  ecx_in 
) [inline, static]

Definition at line 1251 of file x86_cpuid_info.c.

{
  unsigned int a,b,c,d;
  __asm__ __volatile__ (".byte 0x53\n\tcpuid\n\tmovl %%ebx, %%esi\n\t.byte 0x5b"
        : "=a" (a), "=S" (b), "=c" (c), "=d" (d) \
        : "0" (index), "2"(ecx_in) );
  *eax = a; *ebx = b; *ecx = c; *edx = d;
}

Here is the caller graph for this function:

static int init_amd ( PAPI_mh_info_t mh_info,
int *  levels 
) [static]

< No error

Definition at line 117 of file x86_cpuid_info.c.

{
    union
    {
        struct
        {
            unsigned int ax, bx, cx, dx;
        } e;
        unsigned char byt[16];
    } reg;
    int i, j, levels = 0;
    PAPI_mh_level_t *L = mh_info->level;

    /*
     * Layout of CPU information taken from :
     * "CPUID Specification" #25481 Rev 2.28, April 2008 for most current info.
     */

    MEMDBG( "Initializing AMD memory info\n" );
    /* AMD level 1 cache info */
    reg.e.ax = 0x80000005;   /* extended function code 5: L1 Cache and TLB Identifiers */
    cpuid( &reg.e.ax, &reg.e.bx, &reg.e.cx, &reg.e.dx );

    MEMDBG( "e.ax=0x%8.8x e.bx=0x%8.8x e.cx=0x%8.8x e.dx=0x%8.8x\n",
            reg.e.ax, reg.e.bx, reg.e.cx, reg.e.dx );
    MEMDBG
        ( ":\neax: %x %x %x %x\nebx: %x %x %x %x\necx: %x %x %x %x\nedx: %x %x %x %x\n",
          reg.byt[0], reg.byt[1], reg.byt[2], reg.byt[3], reg.byt[4],
          reg.byt[5], reg.byt[6], reg.byt[7], reg.byt[8], reg.byt[9],
          reg.byt[10], reg.byt[11], reg.byt[12], reg.byt[13], reg.byt[14],
          reg.byt[15] );

    /* NOTE: We assume L1 cache and TLB always exists */
    /* L1 TLB info */

    /* 4MB memory page information; half the number of entries as 2MB */
    L[0].tlb[0].type = PAPI_MH_TYPE_INST;
    L[0].tlb[0].num_entries = reg.byt[0] / 2;
    L[0].tlb[0].page_size = 4096 << 10;
    L[0].tlb[0].associativity = reg.byt[1];

    L[0].tlb[1].type = PAPI_MH_TYPE_DATA;
    L[0].tlb[1].num_entries = reg.byt[2] / 2;
    L[0].tlb[1].page_size = 4096 << 10;
    L[0].tlb[1].associativity = reg.byt[3];

    /* 2MB memory page information */
    L[0].tlb[2].type = PAPI_MH_TYPE_INST;
    L[0].tlb[2].num_entries = reg.byt[0];
    L[0].tlb[2].page_size = 2048 << 10;
    L[0].tlb[2].associativity = reg.byt[1];

    L[0].tlb[3].type = PAPI_MH_TYPE_DATA;
    L[0].tlb[3].num_entries = reg.byt[2];
    L[0].tlb[3].page_size = 2048 << 10;
    L[0].tlb[3].associativity = reg.byt[3];

    /* 4k page information */
    L[0].tlb[4].type = PAPI_MH_TYPE_INST;
    L[0].tlb[4].num_entries = reg.byt[4];
    L[0].tlb[4].page_size = 4 << 10;
    L[0].tlb[4].associativity = reg.byt[5];

    L[0].tlb[5].type = PAPI_MH_TYPE_DATA;
    L[0].tlb[5].num_entries = reg.byt[6];
    L[0].tlb[5].page_size = 4 << 10;
    L[0].tlb[5].associativity = reg.byt[7];

    for ( i = 0; i < PAPI_MH_MAX_LEVELS; i++ ) {
        if ( L[0].tlb[i].associativity == 0xff )
            L[0].tlb[i].associativity = SHRT_MAX;
    }

    /* L1 D-cache info */
    L[0].cache[0].type =
        PAPI_MH_TYPE_DATA | PAPI_MH_TYPE_WB | PAPI_MH_TYPE_PSEUDO_LRU;
    L[0].cache[0].size = reg.byt[11] << 10;
    L[0].cache[0].associativity = reg.byt[10];
    L[0].cache[0].line_size = reg.byt[8];
    /* Byt[9] is "Lines per tag" */
    /* Is that == lines per cache? */
    /* L[0].cache[1].num_lines = reg.byt[9]; */
    if ( L[0].cache[0].line_size )
        L[0].cache[0].num_lines = L[0].cache[0].size / L[0].cache[0].line_size;
    MEMDBG( "D-Cache Line Count: %d; Computed: %d\n", reg.byt[9],
            L[0].cache[0].num_lines );

    /* L1 I-cache info */
    L[0].cache[1].type = PAPI_MH_TYPE_INST;
    L[0].cache[1].size = reg.byt[15] << 10;
    L[0].cache[1].associativity = reg.byt[14];
    L[0].cache[1].line_size = reg.byt[12];
    /* Byt[13] is "Lines per tag" */
    /* Is that == lines per cache? */
    /* L[0].cache[1].num_lines = reg.byt[13]; */
    if ( L[0].cache[1].line_size )
        L[0].cache[1].num_lines = L[0].cache[1].size / L[0].cache[1].line_size;
    MEMDBG( "I-Cache Line Count: %d; Computed: %d\n", reg.byt[13],
            L[0].cache[1].num_lines );

    for ( i = 0; i < 2; i++ ) {
        if ( L[0].cache[i].associativity == 0xff )
            L[0].cache[i].associativity = SHRT_MAX;
    }

    /* AMD L2/L3 Cache and L2 TLB info */
    /* NOTE: For safety we assume L2 and L3 cache and TLB may not exist */

    reg.e.ax = 0x80000006;   /* extended function code 6: L2/L3 Cache and L2 TLB Identifiers */
    cpuid( &reg.e.ax, &reg.e.bx, &reg.e.cx, &reg.e.dx );

    MEMDBG( "e.ax=0x%8.8x e.bx=0x%8.8x e.cx=0x%8.8x e.dx=0x%8.8x\n",
            reg.e.ax, reg.e.bx, reg.e.cx, reg.e.dx );
    MEMDBG
        ( ":\neax: %x %x %x %x\nebx: %x %x %x %x\necx: %x %x %x %x\nedx: %x %x %x %x\n",
          reg.byt[0], reg.byt[1], reg.byt[2], reg.byt[3], reg.byt[4],
          reg.byt[5], reg.byt[6], reg.byt[7], reg.byt[8], reg.byt[9],
          reg.byt[10], reg.byt[11], reg.byt[12], reg.byt[13], reg.byt[14],
          reg.byt[15] );

    /* L2 TLB info */

    if ( reg.byt[0] | reg.byt[1] ) {    /* Level 2 ITLB exists */
        /* 4MB ITLB page information; half the number of entries as 2MB */
        L[1].tlb[0].type = PAPI_MH_TYPE_INST;
        L[1].tlb[0].num_entries =
            ( ( ( short ) ( reg.byt[1] & 0xF ) << 8 ) + reg.byt[0] ) / 2;
        L[1].tlb[0].page_size = 4096 << 10;
        L[1].tlb[0].associativity =
            _amd_L2_L3_assoc( ( reg.byt[1] & 0xF0 ) >> 4 );

        /* 2MB ITLB page information */
        L[1].tlb[2].type = PAPI_MH_TYPE_INST;
        L[1].tlb[2].num_entries = L[1].tlb[0].num_entries * 2;
        L[1].tlb[2].page_size = 2048 << 10;
        L[1].tlb[2].associativity = L[1].tlb[0].associativity;
    }

    if ( reg.byt[2] | reg.byt[3] ) {    /* Level 2 DTLB exists */
        /* 4MB DTLB page information; half the number of entries as 2MB */
        L[1].tlb[1].type = PAPI_MH_TYPE_DATA;
        L[1].tlb[1].num_entries =
            ( ( ( short ) ( reg.byt[3] & 0xF ) << 8 ) + reg.byt[2] ) / 2;
        L[1].tlb[1].page_size = 4096 << 10;
        L[1].tlb[1].associativity =
            _amd_L2_L3_assoc( ( reg.byt[3] & 0xF0 ) >> 4 );

        /* 2MB DTLB page information */
        L[1].tlb[3].type = PAPI_MH_TYPE_DATA;
        L[1].tlb[3].num_entries = L[1].tlb[1].num_entries * 2;
        L[1].tlb[3].page_size = 2048 << 10;
        L[1].tlb[3].associativity = L[1].tlb[1].associativity;
    }

    /* 4k page information */
    if ( reg.byt[4] | reg.byt[5] ) {    /* Level 2 ITLB exists */
        L[1].tlb[4].type = PAPI_MH_TYPE_INST;
        L[1].tlb[4].num_entries =
            ( ( short ) ( reg.byt[5] & 0xF ) << 8 ) + reg.byt[4];
        L[1].tlb[4].page_size = 4 << 10;
        L[1].tlb[4].associativity =
            _amd_L2_L3_assoc( ( reg.byt[5] & 0xF0 ) >> 4 );
    }
    if ( reg.byt[6] | reg.byt[7] ) {    /* Level 2 DTLB exists */
        L[1].tlb[5].type = PAPI_MH_TYPE_DATA;
        L[1].tlb[5].num_entries =
            ( ( short ) ( reg.byt[7] & 0xF ) << 8 ) + reg.byt[6];
        L[1].tlb[5].page_size = 4 << 10;
        L[1].tlb[5].associativity =
            _amd_L2_L3_assoc( ( reg.byt[7] & 0xF0 ) >> 4 );
    }

    /* AMD Level 2 cache info */
    if ( reg.e.cx ) {
        L[1].cache[0].type =
            PAPI_MH_TYPE_UNIFIED | PAPI_MH_TYPE_WT | PAPI_MH_TYPE_PSEUDO_LRU;
        L[1].cache[0].size = ( int ) ( ( reg.e.cx & 0xffff0000 ) >> 6 );    /* right shift by 16; multiply by 2^10 */
        L[1].cache[0].associativity =
            _amd_L2_L3_assoc( ( reg.byt[9] & 0xF0 ) >> 4 );
        L[1].cache[0].line_size = reg.byt[8];
/*      L[1].cache[0].num_lines = reg.byt[9]&0xF; */
        if ( L[1].cache[0].line_size )
            L[1].cache[0].num_lines =
                L[1].cache[0].size / L[1].cache[0].line_size;
        MEMDBG( "U-Cache Line Count: %d; Computed: %d\n", reg.byt[9] & 0xF,
                L[1].cache[0].num_lines );
    }

    /* AMD Level 3 cache info (shared across cores) */
    if ( reg.e.dx ) {
        L[2].cache[0].type =
            PAPI_MH_TYPE_UNIFIED | PAPI_MH_TYPE_WT | PAPI_MH_TYPE_PSEUDO_LRU;
        L[2].cache[0].size = ( int ) ( reg.e.dx & 0xfffc0000 ) << 1;    /* in blocks of 512KB (2^19) */
        L[2].cache[0].associativity =
            _amd_L2_L3_assoc( ( reg.byt[13] & 0xF0 ) >> 4 );
        L[2].cache[0].line_size = reg.byt[12];
/*      L[2].cache[0].num_lines = reg.byt[13]&0xF; */
        if ( L[2].cache[0].line_size )
            L[2].cache[0].num_lines =
                L[2].cache[0].size / L[2].cache[0].line_size;
        MEMDBG( "U-Cache Line Count: %d; Computed: %d\n", reg.byt[13] & 0xF,
                L[1].cache[0].num_lines );
    }
    for ( i = 0; i < PAPI_MAX_MEM_HIERARCHY_LEVELS; i++ ) {
        for ( j = 0; j < PAPI_MH_MAX_LEVELS; j++ ) {
            /* Compute the number of levels of hierarchy actually used */
            if ( L[i].tlb[j].type != PAPI_MH_TYPE_EMPTY ||
                 L[i].cache[j].type != PAPI_MH_TYPE_EMPTY )
                levels = i + 1;
        }
    }
    *num_levels = levels;
    return PAPI_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int init_intel ( PAPI_mh_info_t mh_info,
int *  levels 
) [static]

< No error

< No error

Definition at line 1463 of file x86_cpuid_info.c.

{

  int result;
  int num_levels;

  /* try using the oldest leaf2 method first */
  result=init_intel_leaf2(mh_info, &num_levels);
  
  if (result!=PAPI_OK) {
     /* All Core2 and newer also support leaf4 detection */
     /* Starting with Westmere *only* leaf4 is supported */
     result=init_intel_leaf4(mh_info, &num_levels);
  }

  *levels=num_levels;
  return PAPI_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int init_intel_leaf2 ( PAPI_mh_info_t mh_info,
int *  num_levels 
) [static]

< Not supported

< Not supported

< No error

Definition at line 1373 of file x86_cpuid_info.c.

{
    /* cpuid() returns memory copies of 4 32-bit registers
     * this union allows them to be accessed as either registers
     * or individual bytes. Remember that Intel is little-endian.
     */
    union
    {
        struct
        {
            unsigned int ax, bx, cx, dx;
        } e;
        unsigned char descrip[16];
    } reg;

    int r;                             /* register boundary index */
    int b;                             /* byte index into a register */
    int i;                             /* byte index into the descrip array */
    int t;                             /* table index into the static descriptor table */
    int count;                         /* how many times to call cpuid; from eax:lsb */
    int size;                          /* size of the descriptor table */
    int last_level = 0;                /* how many levels in the cache hierarchy */

    int need_leaf4=0;

    /* All of Intel's cache info is in 1 call to cpuid
     * however it is a table lookup :(
     */
    MEMDBG( "Initializing Intel Cache and TLB descriptors\n" );

#ifdef DEBUG
    if ( ISLEVEL( DEBUG_MEMORY ) )
        print_intel_cache_table(  );
#endif

    reg.e.ax = 0x2;          /* function code 2: cache descriptors */
    cpuid( &reg.e.ax, &reg.e.bx, &reg.e.cx, &reg.e.dx );

    MEMDBG( "e.ax=0x%8.8x e.bx=0x%8.8x e.cx=0x%8.8x e.dx=0x%8.8x\n",
            reg.e.ax, reg.e.bx, reg.e.cx, reg.e.dx );
    MEMDBG
        ( ":\nd0: %x %x %x %x\nd1: %x %x %x %x\nd2: %x %x %x %x\nd3: %x %x %x %x\n",
          reg.descrip[0], reg.descrip[1], reg.descrip[2], reg.descrip[3],
          reg.descrip[4], reg.descrip[5], reg.descrip[6], reg.descrip[7],
          reg.descrip[8], reg.descrip[9], reg.descrip[10], reg.descrip[11],
          reg.descrip[12], reg.descrip[13], reg.descrip[14], reg.descrip[15] );

    count = reg.descrip[0];  /* # times to repeat CPUID call. Not implemented. */
    size = ( sizeof ( intel_cache ) / sizeof ( struct _intel_cache_info ) );    /* # descriptors */
    MEMDBG( "Repeat cpuid(2,...) %d times. If not 1, code is broken.\n",
            count );
    if (count!=1) {
       fprintf(stderr,"Warning: Unhandled cpuid count of %d\n",count);
    }

    for ( r = 0; r < 4; r++ ) { /* walk the registers */
        if ( ( reg.descrip[r * 4 + 3] & 0x80 ) == 0 ) { /* only process if high order bit is 0 */
            for ( b = 3; b >= 0; b-- ) {    /* walk the descriptor bytes from high to low */
                i = r * 4 + b;  /* calculate an index into the array of descriptors */
                if ( i ) {   /* skip the low order byte in eax [0]; it's the count (see above) */
                   if ( reg.descrip[i] == 0xff ) {
                      MEMDBG("Warning! PAPI x86_cache: must implement cpuid leaf 4\n");
                      need_leaf4=1;
                      return PAPI_ENOSUPP;
                      /* we might continue instead */
                      /* in order to get TLB info  */
                      /* continue;                 */
                   }
                    for ( t = 0; t < size; t++ ) {  /* walk the descriptor table */                    
                        if ( reg.descrip[i] == intel_cache[t].descriptor ) {    /* find match */
                            if ( intel_cache[t].level > last_level )
                                last_level = intel_cache[t].level;
                            intel_decode_descriptor( &intel_cache[t],
                                                     mh_info->level );
                        }
                    }
                }
            }
        }
    }
    MEMDBG( "# of Levels: %d\n", last_level );
    *num_levels=last_level;
    if (need_leaf4) {
       return PAPI_ENOSUPP;
    }
    return PAPI_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int init_intel_leaf4 ( PAPI_mh_info_t mh_info,
int *  num_levels 
) [static]

< Not supported

< No error

Definition at line 1264 of file x86_cpuid_info.c.

{

  unsigned int eax, ebx, ecx, edx;
  unsigned int maxidx, ecx_in;
  int next;

  int cache_type,cache_level,cache_selfinit,cache_fullyassoc;
  int cache_linesize,cache_partitions,cache_ways,cache_sets;

  PAPI_mh_cache_info_t *c;

  *num_levels=0;

  cpuid2(&eax,&ebx,&ecx,&edx, 0, 0);
  maxidx = eax;
  
  if (maxidx<4) {
    MEMDBG("Warning!  CPUID Index 4 not supported!\n");
    return PAPI_ENOSUPP;
  }

  ecx_in=0;
  while(1) {
    cpuid2(&eax,&ebx,&ecx,&edx, 4, ecx_in);


    
    /* decoded as per table 3-12 in Intel Software Developer's Manual Volume 2A */
     
    cache_type=eax&0x1f;
    if (cache_type==0) break;     
     
    cache_level=(eax>>5)&0x3;
    cache_selfinit=(eax>>8)&0x1;
    cache_fullyassoc=(eax>>9)&0x1;

    cache_linesize=(ebx&0xfff)+1;
    cache_partitions=((ebx>>12)&0x3ff)+1;
    cache_ways=((ebx>>22)&0x3ff)+1;
       
    cache_sets=(ecx)+1;

    /* should we export this info?

    cache_maxshare=((eax>>14)&0xfff)+1;
    cache_maxpackage=((eax>>26)&0x3f)+1;
     
    cache_wb=(edx)&1;
    cache_inclusive=(edx>>1)&1;
    cache_indexing=(edx>>2)&1;
    */

    if (cache_level>*num_levels) *num_levels=cache_level;

    /* find next slot available to hold cache info */
    for ( next = 0; next < PAPI_MH_MAX_LEVELS - 1; next++ ) {
        if ( mh_info->level[cache_level-1].cache[next].type == PAPI_MH_TYPE_EMPTY ) break;
    }

    c=&(mh_info->level[cache_level-1].cache[next]);

    switch(cache_type) {
      case 1: MEMDBG("L%d Data Cache\n",cache_level); 
    c->type=PAPI_MH_TYPE_DATA;
    break;
      case 2: MEMDBG("L%d Instruction Cache\n",cache_level); 
    c->type=PAPI_MH_TYPE_INST;
    break;
      case 3: MEMDBG("L%d Unified Cache\n",cache_level); 
    c->type=PAPI_MH_TYPE_UNIFIED;
    break;
    }
     
    if (cache_selfinit) { MEMDBG("\tSelf-init\n"); }
    if (cache_fullyassoc) { MEMDBG("\tFully Associtative\n"); }
     
    //MEMDBG("\tMax logical processors sharing cache: %d\n",cache_maxshare);
    //MEMDBG("\tMax logical processors sharing package: %d\n",cache_maxpackage);
     
    MEMDBG("\tCache linesize: %d\n",cache_linesize);

    MEMDBG("\tCache partitions: %d\n",cache_partitions);
    MEMDBG("\tCache associaticity: %d\n",cache_ways);

    MEMDBG("\tCache sets: %d\n",cache_sets);
    MEMDBG("\tCache size = %dkB\n",
       (cache_ways*cache_partitions*cache_linesize*cache_sets)/1024);

    //MEMDBG("\tWBINVD/INVD acts on lower caches: %d\n",cache_wb);
    //MEMDBG("\tCache is not inclusive: %d\n",cache_inclusive);
    //MEMDBG("\tComplex cache indexing: %d\n",cache_indexing);

    c->line_size=cache_linesize;
    if (cache_fullyassoc) {
       c->associativity=SHRT_MAX;
    }
    else {
       c->associativity=cache_ways;
    }
    c->size=(cache_ways*cache_partitions*cache_linesize*cache_sets);
    c->num_lines=cache_ways*cache_partitions*cache_sets;
     
    ecx_in++;
  }
  return PAPI_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void init_mem_hierarchy ( PAPI_mh_info_t mh_info) [static]

Definition at line 84 of file x86_cpuid_info.c.

{
    int i, j;
    PAPI_mh_level_t *L = mh_info->level;

    /* initialize entire memory hierarchy structure to benign values */
    for ( i = 0; i < PAPI_MAX_MEM_HIERARCHY_LEVELS; i++ ) {
        for ( j = 0; j < PAPI_MH_MAX_LEVELS; j++ ) {
            L[i].tlb[j].type = PAPI_MH_TYPE_EMPTY;
            L[i].tlb[j].num_entries = 0;
            L[i].tlb[j].associativity = 0;
            L[i].cache[j].type = PAPI_MH_TYPE_EMPTY;
            L[i].cache[j].size = 0;
            L[i].cache[j].line_size = 0;
            L[i].cache[j].num_lines = 0;
            L[i].cache[j].associativity = 0;
        }
    }
}

Here is the caller graph for this function:

static void intel_decode_descriptor ( struct _intel_cache_info d,
PAPI_mh_level_t L 
) [static]

Definition at line 1200 of file x86_cpuid_info.c.

{
    int i, next;
    int level = d->level - 1;
    PAPI_mh_tlb_info_t *t;
    PAPI_mh_cache_info_t *c;

    if ( d->descriptor == 0x49 ) {  /* special case */
        unsigned int r_eax, r_ebx, r_ecx, r_edx;
        r_eax = 0x1;         /* function code 1: family & model */
        cpuid( &r_eax, &r_ebx, &r_ecx, &r_edx );
        /* override table for Family F, model 6 only */
        if ( ( r_eax & 0x0FFF3FF0 ) == 0xF60 )
            level = 3;
    }
    if ( d->type & PAPI_MH_TYPE_TLB ) {
        for ( next = 0; next < PAPI_MH_MAX_LEVELS - 1; next++ ) {
            if ( L[level].tlb[next].type == PAPI_MH_TYPE_EMPTY )
                break;
        }
        /* expand TLB entries for multiple possible page sizes */
        for ( i = 0; i < TLB_SIZES && next < PAPI_MH_MAX_LEVELS && d->size[i];
              i++, next++ ) {
//          printf("Level %d Descriptor: %x TLB type %x next: %d, i: %d\n", level, d->descriptor, d->type, next, i);
            t = &L[level].tlb[next];
            t->type = PAPI_MH_CACHE_TYPE( d->type );
            t->num_entries = d->entries;
            t->page_size = d->size[i] << 10;    /* minimum page size in KB */
            t->associativity = d->associativity;
            /* another special case */
            if ( d->descriptor == 0xB1 && d->size[i] == 4096 )
                t->num_entries = d->entries / 2;
        }
    } else {
        for ( next = 0; next < PAPI_MH_MAX_LEVELS - 1; next++ ) {
            if ( L[level].cache[next].type == PAPI_MH_TYPE_EMPTY )
                break;
        }
//      printf("Level %d Descriptor: %x Cache type %x next: %d\n", level, d->descriptor, d->type, next);
        c = &L[level].cache[next];
        c->type = PAPI_MH_CACHE_TYPE( d->type );
        c->size = d->size[0] << 10; /* convert from KB to bytes */
        c->associativity = d->associativity;
        if ( d->line_size ) {
            c->line_size = d->line_size;
            c->num_lines = c->size / c->line_size;
        }
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

struct _intel_cache_info intel_cache[] [static]

Definition at line 362 of file x86_cpuid_info.c.

 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines