/* $Id: x86.c,v 1.2.2.11 2010/11/07 19:46:06 mikpe Exp $ * x86-specific perfctr library procedures. * * Copyright (C) 1999-2010 Mikael Pettersson */ #include #include "libperfctr.h" struct cpuid { /* The field order must not be changed. */ unsigned int eax; unsigned int ebx; /* When eax was 1, &ebx should be the start */ unsigned int edx; /* of the 12-byte vendor identification string. */ unsigned int ecx; }; static void get_cpuid(unsigned int op, struct cpuid *cpuid) { unsigned int save_ebx; unsigned int tmp_ebx; __asm__( "movl %%ebx, %0\n\t" "cpuid\n\t" "movl %%ebx, %1\n\t" "movl %0, %%ebx" : "=m"(save_ebx), "=m"(tmp_ebx), "=a"(cpuid->eax), "=d"(cpuid->edx), "=c"(cpuid->ecx) : "a"(op)); cpuid->ebx = tmp_ebx; } static unsigned int atom_nrctrs(void) { struct cpuid cpuid; get_cpuid(0, &cpuid); if (cpuid.eax < 0xA) { printf("%s: cpuid[0].eax == %u, unable to query 0xA leaf\n", __FUNCTION__, cpuid.eax); return 0; } get_cpuid(0xA, &cpuid); if ((cpuid.eax & 0xff) < 2) { printf("%s: cpuid[0xA].eax == 0x%08x appears bogus\n", __FUNCTION__, cpuid.eax); return 0; } return ((cpuid.eax >> 8) & 0xff) + (cpuid.edx & 0x1f); } unsigned int perfctr_info_nrctrs(const struct perfctr_info *info) { switch (info->cpu_type) { #if !defined(__x86_64__) case PERFCTR_X86_INTEL_P5: case PERFCTR_X86_INTEL_P5MMX: case PERFCTR_X86_INTEL_P6: case PERFCTR_X86_INTEL_PII: case PERFCTR_X86_INTEL_PIII: case PERFCTR_X86_CYRIX_MII: case PERFCTR_X86_WINCHIP_C6: case PERFCTR_X86_WINCHIP_2: case PERFCTR_X86_INTEL_PENTM: case PERFCTR_X86_INTEL_CORE: return 2; case PERFCTR_X86_AMD_K7: return 4; case PERFCTR_X86_VIA_C3: return 1; case PERFCTR_X86_INTEL_P4: case PERFCTR_X86_INTEL_P4M2: return 18; #endif case PERFCTR_X86_INTEL_P4M3: return 18; case PERFCTR_X86_AMD_K8: case PERFCTR_X86_AMD_K8C: case PERFCTR_X86_AMD_FAM10H: return 4; case PERFCTR_X86_INTEL_CORE2: return 5; case PERFCTR_X86_INTEL_ATOM: return atom_nrctrs(); case PERFCTR_X86_INTEL_NHLM: case PERFCTR_X86_INTEL_WSTMR: return 7; case PERFCTR_X86_GENERIC: default: return 0; } } const char *perfctr_info_cpu_name(const struct perfctr_info *info) { switch (info->cpu_type) { case PERFCTR_X86_GENERIC: return "Generic x86 with TSC"; #if !defined(__x86_64__) case PERFCTR_X86_INTEL_P5: return "Intel Pentium"; case PERFCTR_X86_INTEL_P5MMX: return "Intel Pentium MMX"; case PERFCTR_X86_INTEL_P6: return "Intel Pentium Pro"; case PERFCTR_X86_INTEL_PII: return "Intel Pentium II"; case PERFCTR_X86_INTEL_PIII: return "Intel Pentium III"; case PERFCTR_X86_CYRIX_MII: return "Cyrix 6x86MX/MII/III"; case PERFCTR_X86_WINCHIP_C6: return "WinChip C6"; case PERFCTR_X86_WINCHIP_2: return "WinChip 2/3"; case PERFCTR_X86_AMD_K7: return "AMD K7"; case PERFCTR_X86_VIA_C3: return "VIA C3"; case PERFCTR_X86_INTEL_P4: return "Intel Pentium 4"; case PERFCTR_X86_INTEL_P4M2: return "Intel Pentium 4 Model 2"; case PERFCTR_X86_INTEL_PENTM: return "Intel Pentium M"; case PERFCTR_X86_INTEL_CORE: return "Intel Core"; #endif case PERFCTR_X86_INTEL_CORE2: return "Intel Core 2"; case PERFCTR_X86_INTEL_P4M3: return "Intel Pentium 4 Model 3"; case PERFCTR_X86_AMD_K8: return "AMD K8"; case PERFCTR_X86_AMD_K8C: return "AMD K8 Revision C"; case PERFCTR_X86_AMD_FAM10H: return "AMD Family 10h"; case PERFCTR_X86_INTEL_ATOM: return "Intel Atom"; case PERFCTR_X86_INTEL_NHLM: return "Intel Nehalem"; case PERFCTR_X86_INTEL_WSTMR: return "Intel Westmere"; default: return "?"; } } void perfctr_cpu_control_print(const struct perfctr_cpu_control *control) { unsigned int i, nractrs, nrictrs, nrctrs; nractrs = control->nractrs; nrictrs = control->nrictrs; nrctrs = control->nractrs + nrictrs; printf("tsc_on\t\t\t%u\n", control->tsc_on); printf("nractrs\t\t\t%u\n", nractrs); if (nrictrs) printf("nrictrs\t\t\t%u\n", nrictrs); for(i = 0; i < nrctrs; ++i) { if (control->pmc_map[i] >= 18) /* for Core2 fixed counters or P4 fast rdpmc */ printf("pmc_map[%u]\t\t0x%08X\n", i, control->pmc_map[i]); else printf("pmc_map[%u]\t\t%u\n", i, control->pmc_map[i]); printf("evntsel[%u]\t\t0x%08X\n", i, control->evntsel[i]); if (control->p4.escr[i]) printf("escr[%u]\t\t\t0x%08X\n", i, control->p4.escr[i]); if (i >= nractrs) printf("ireset[%u]\t\t%d\n", i, control->ireset[i]); } if (control->p4.pebs_enable) printf("pebs_enable\t\t0x%08X\n", control->p4.pebs_enable); if (control->p4.pebs_matrix_vert) printf("pebs_matrix_vert\t0x%08X\n", control->p4.pebs_matrix_vert); }