Advertisement
Guest User

perfcount.c

a guest
Dec 31st, 2015
720
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 21.40 KB | None | 0 0
  1. /* Includes */
  2. #include <asm/uaccess.h>
  3. #include <linux/init.h>
  4. #include <linux/kernel.h>
  5. #include <linux/module.h>
  6. #include <linux/sysfs.h>
  7.  
  8.  
  9. /* Defines */
  10.  
  11. /**
  12.  * Maximum number of PMCs (fixed-function and general-purpose combined)
  13.  */
  14.  
  15. #define MAXPMC 25
  16. #define MSR_IA32_PERFEVTSEL0               0x186
  17. #define MSR_IA32_FIXED_CTR0                0x309
  18. #define MSR_IA32_FIXED_CTR_CTRL            0x38D
  19. #define MSR_IA32_PERF_GLOBAL_STATUS        0x38E
  20. #define MSR_IA32_PERF_GLOBAL_CTRL          0x38F
  21. #define MSR_IA32_PERF_GLOBAL_OVF_CTRL      0x390
  22. #define MSR_IA32_A_PMC0                    0x4C1
  23.  
  24.  
  25. /* Forward Declarations */
  26. static ssize_t pfcCfgRd (struct file*          f,
  27.                                     struct kobject*       kobj,
  28.                                     struct bin_attribute* binattr,
  29.                                     char*                 buf,
  30.                                     loff_t                off,
  31.                                     size_t                len);
  32. static ssize_t pfcCfgWr(struct file*          f,
  33.                                     struct kobject*       kobj,
  34.                                     struct bin_attribute* binattr,
  35.                                     char*                 buf,
  36.                                     loff_t                off,
  37.                                     size_t                len);
  38. static ssize_t pfcCntRd (struct file*          f,
  39.                                     struct kobject*       kobj,
  40.                                     struct bin_attribute* binattr,
  41.                                     char*                 buf,
  42.                                     loff_t                off,
  43.                                     size_t                len);
  44. static ssize_t pfcCntWr(struct file*          f,
  45.                                     struct kobject*       kobj,
  46.                                     struct bin_attribute* binattr,
  47.                                     char*                 buf,
  48.                                     loff_t                off,
  49.                                     size_t                len);
  50.  
  51.  
  52.  
  53. /* Global Variables & Constants */
  54. static int       pmcArchVer           = 0;
  55. static int       pmcFf                = 0;
  56. static int       pmcGp                = 0;
  57. static int       pmcStartFf           = 0;
  58. static int       pmcEndFf             = 0;
  59. static int       pmcStartGp           = 0;
  60. static int       pmcEndGp             = 0;
  61. static uint64_t  pmcMaskFf            = 0;
  62. static uint64_t  pmcMaskGp            = 0;
  63.  
  64. /**
  65.  * The counters consist in the following MSRs on Core i7:
  66.  * [0   ] IA32_FIXED_CTR0:             Fixed-function  - Retired Instructions
  67.  * [1   ] IA32_FIXED_CTR1:             Fixed-function  - Unhalted Core CCs
  68.  * [2   ] IA32_FIXED_CTR2:             Fixed-function  - Unhalted Reference CCs
  69.  * [3+  ] IA32_A_PMCx:                 General-purpose - Configurable
  70.  */
  71.  
  72.  
  73. /* Attribute Hierarchy */
  74. static const struct bin_attribute  PFC_ATTR_config = {
  75.     .attr    = {.name="config", .mode=0666},
  76.     .size    = MAXPMC*sizeof(uint64_t),
  77.     .read    = pfcCfgRd,
  78.     .write   = pfcCfgWr
  79. };
  80. static const struct bin_attribute  PFC_ATTR_counts = {
  81.     .attr    = {.name="counts", .mode=0666},
  82.     .size    = MAXPMC*sizeof(uint64_t),
  83.     .read    = pfcCntRd,
  84.     .write   = pfcCntWr
  85. };
  86. static const struct bin_attribute* PFC_ATTR_GRP_LIST[] = {
  87.     &PFC_ATTR_config,
  88.     &PFC_ATTR_counts,
  89.     NULL
  90. };
  91. static const struct attribute_group PFC_ATTR_GRP = {
  92.     .name       = NULL,
  93.     .bin_attrs  = (struct bin_attribute **)PFC_ATTR_GRP_LIST
  94. };
  95.  
  96.  
  97.  
  98. /* Static Function Definitions */
  99.  
  100. /***************** UTILITIES *****************/
  101.  
  102. /**
  103.  * @brief Ones Vector.
  104.  *
  105.  * Generate a 64-bit bitvector of ones with
  106.  *
  107.  * val[63   :n+k] = 0
  108.  * val[n+k-1:  k] = 1
  109.  * val[  k-1:  0] = 0
  110.  *
  111.  * i.e. where the n bits starting at k counting from the LSB are all set, and
  112.  * all other bits are 0.
  113.  */
  114.  
  115. static uint64_t OV(int n, int k){
  116.     uint64_t v = n >= 64 ? ~0 : ((uint64_t)1 << n) - 1;
  117.     return v << k;
  118. }
  119.  
  120. /**
  121.  * @brief Bit Vector.
  122.  *
  123.  * Generate a 64-bit bitvector with
  124.  *
  125.  * val[63   :n+k] = 0
  126.  * val[n+k-1:  k] = v[n:0]
  127.  * val[  k-1:  0] = 0
  128.  *
  129.  * i.e. where the n bits starting at k counting from the LSB are taken from
  130.  * the LSBs of v, and all other bits are 0.
  131.  */
  132.  
  133. static uint64_t BV(uint64_t v, int n, int k){
  134.     v &= OV(n, 0);
  135.     return v << k;
  136. }
  137.  
  138. /**
  139.  * @brief Clear Vector.
  140.  *
  141.  * Generate a 64-bit bitvector with
  142.  *
  143.  * val            = v
  144.  * val[n+k-1:  k] = 0
  145.  *
  146.  * i.e. where the n bits starting at k counting from the LSB are set to 0,
  147.  * and all other bits are taken from v.
  148.  */
  149.  
  150. static uint64_t CV(uint64_t v, int n, int k){
  151.     return v & ~OV(n,k);
  152. }
  153.  
  154. /**
  155.  * @brief CPUID wrapper.
  156.  *
  157.  * @note Makes no attempt at validating EAX/ECX before calling CPUID!
  158.  */
  159.  
  160. static void pfcCPUID(uint32_t  ieax,
  161.                      uint32_t  iecx,
  162.                      uint32_t* oeax,
  163.                      uint32_t* oebx,
  164.                      uint32_t* oecx,
  165.                      uint32_t* oedx){
  166.     asm volatile(
  167.         "cpuid\n\t"                  /* ASM */
  168.         :"=a"(*oeax),                /* Outputs */
  169.          "=b"(*oebx),
  170.          "=c"(*oecx),
  171.          "=d"(*oedx)
  172.         :"a"(ieax),                  /* Inputs */
  173.          "c"(iecx)
  174.         :"memory"                    /* Clobbers */
  175.     );
  176. }
  177.  
  178. /**
  179.  * @brief RDMSR wrapper.
  180.  *
  181.  * Returns the unmodified value of the given MSR.
  182.  *
  183.  * @returns The value read at the given MSR.
  184.  * @note    Does *not* check that addr is valid!
  185.  */
  186.  
  187. static uint64_t pfcRDMSR(uint64_t addr){
  188.     uint32_t lo, hi;
  189.     uint64_t lo64, hi64;
  190.    
  191.     asm volatile(
  192.         "rdmsr\n\t"                  /* ASM */
  193.         :"=a"(lo),                   /* Outputs */
  194.          "=d"(hi)
  195.         :"c"(addr)                   /* Inputs */
  196.         :"memory"                    /* Clobbers */
  197.     );
  198.    
  199.     lo64 = lo;
  200.     hi64 = hi;
  201.    
  202.     return (hi64 << 32) | (lo64 <<  0);
  203. }
  204.  
  205. /**
  206.  * @brief WRMSR wrapper.
  207.  *
  208.  * Writes to the given MSR. If it is a known MSR, mask out reserved bits into
  209.  * a temporary, logic-OR the reserved bits into the temporary and write back
  210.  * this temporary.
  211.  *
  212.  * @note    Does *not* check that addr is valid!
  213.  */
  214.  
  215. static void pfcWRMSR(uint64_t addr, uint64_t val){
  216.     uint64_t oldVal, mask;
  217.    
  218.     /**
  219.      * For writing to MSRs, it's required to retrieve the old value of
  220.      * reserved bits and write them back. Things seem to blow up big-time
  221.      * otherwise.
  222.      *
  223.      * We retrieve a mask which indicates using the bits that are set what
  224.      * corresponding bits are reserved.
  225.      */
  226.    
  227.     if(addr == MSR_IA32_PERF_GLOBAL_CTRL){          mask=~(OV(pmcGp,0)|OV(pmcFf,32));
  228.     }else if(addr == MSR_IA32_PERF_GLOBAL_OVF_CTRL){mask=~(OV(pmcGp,0)|OV(pmcFf,32)|OV(2,62));
  229.     }else if(addr == MSR_IA32_FIXED_CTR_CTRL){      mask=~OV(4*pmcFf,0);
  230.     }else if(addr == MSR_IA32_PERF_GLOBAL_STATUS){  return;/* RO MSR! */
  231.     }else if(addr >= MSR_IA32_FIXED_CTR0  &&
  232.              addr <  MSR_IA32_FIXED_CTR0+pmcFf){    mask=~pmcMaskFf;
  233.     }else if(addr >= MSR_IA32_PERFEVTSEL0 &&
  234.              addr <  MSR_IA32_PERFEVTSEL0+pmcGp){   mask=OV(32,32);
  235.     }else if(addr >= MSR_IA32_A_PMC0      &&
  236.              addr <  MSR_IA32_A_PMC0+pmcGp){        mask=~pmcMaskGp;
  237.     }else{                                          mask=OV(64,0);
  238.     }
  239.     oldVal = pfcRDMSR(addr);
  240.    
  241.    
  242.    
  243.     /**
  244.      * Blend new and old & Writeback
  245.      */
  246.    
  247.     val = (val&~mask) | (oldVal&mask);
  248.     asm volatile(
  249.         "wrmsr\n\t"                  /* ASM */
  250.         :
  251.         :"c"(addr),                  /* Inputs */
  252.          "a"((uint32_t)val),
  253.          "d"((uint32_t)(val >> 32))
  254.         :"memory"                    /* Clobbers */
  255.     );
  256. }
  257.  
  258. /**
  259.  * Clamp offset+len into a given counter range.
  260.  *
  261.  * Writes out the overlap's bounds through the output arguments.
  262.  *
  263.  * Returns whether or not [offset+len) overlaps [rangeStart, rangeEnd)
  264.  */
  265.  
  266. static int  pfcClampRange(int    off,
  267.                           int    len,
  268.                           int    rangeStart,
  269.                           int    rangeEnd,
  270.                           int*   pmcStart,
  271.                           int*   pmcEnd){
  272.     if(off+len <= rangeStart || /* If given range is fully before or     */
  273.        off     >= rangeEnd   || /* fully after the target range, or      */
  274.        len     <= 0){           /* its length is <=0, then               */
  275.         return 0;
  276.     }else{
  277.         *pmcStart = off     < rangeStart ? rangeStart : off;
  278.         *pmcEnd   = off+len > rangeEnd   ? rangeEnd   : off+len;
  279.         return 1;
  280.     }
  281. }
  282.  
  283. /**
  284.  * Check whether or not the given offset+length are sanely aligned.
  285.  */
  286.  
  287. static int  pfcIsAligned(loff_t off, size_t len, size_t mask){
  288.     return !((off|len) & mask);
  289. }
  290.  
  291. /*************** END UTILITIES ***************/
  292.  
  293.  
  294.  
  295. /**
  296.  * The basic operations on a single counter are:
  297.  *
  298.  * - Write Enable
  299.  * - Read Enable
  300.  * - Write Configuration
  301.  * - Read Configuration
  302.  * - Write Value
  303.  * - Read Value
  304.  * - Clear Flags
  305.  * - Read Flags / Status
  306.  *
  307.  * The following operations can be done globally over all counters atomically:
  308.  *
  309.  * - Write Enable
  310.  * - Read Enable
  311.  * - Ff Write Configuration
  312.  * - Ff Read Configuration
  313.  * - Clear Flags
  314.  * - Read Flags/Status
  315.  */
  316.  
  317. /* All */
  318. void     pfcAllCntWrEnb  (uint64_t v){
  319.     pfcWRMSR(MSR_IA32_PERF_GLOBAL_CTRL, v);
  320. }
  321. uint64_t pfcAllCntRdEnb  (void){
  322.     return pfcRDMSR(MSR_IA32_PERF_GLOBAL_CTRL);
  323. }
  324. void     pfcAllFfCntWrCfg(uint64_t c){
  325.     /**
  326.      * We forbid the setting of the following bits in each 4-bit config group.
  327.      *     Bit 3: PMI Interrupt on counter overflow
  328.      *     Bit 2: AnyThread bit
  329.      *     Bit 0: OS-mode bit
  330.      * for all counters. Effectively the only bit permitted is Bit 1 (User-mode
  331.      * tracking of event).
  332.      */
  333.    
  334.     c &= ~0xDDDDDDDDDDDDDDDDULL;
  335.     pfcWRMSR(MSR_IA32_FIXED_CTR_CTRL, c);
  336. }
  337. uint64_t pfcAllFfCntRdCfg(void){
  338.     return pfcRDMSR(MSR_IA32_FIXED_CTR_CTRL);
  339. }
  340. void     pfcAllCntClFlg  (uint64_t v){
  341.     pfcWRMSR(MSR_IA32_PERF_GLOBAL_OVF_CTRL, v);
  342. }
  343. uint64_t pfcAllCntRdFlg  (void){
  344.     return pfcRDMSR(MSR_IA32_PERF_GLOBAL_STATUS);
  345. }
  346.  
  347. /* Ff */
  348. void     pfcFfCntWrEnb(int i, int v){
  349.     int n = 1, k = 32+i;
  350.     pfcAllCntWrEnb(CV(pfcAllCntRdEnb(),n,k) | BV(v,n,k));
  351. }
  352. int      pfcFfCntRdEnb(int i){
  353.     int n = 1, k = 32+i;
  354.     return !!(pfcAllCntRdEnb() & OV(n,k));
  355. }
  356. void     pfcFfCntWrCfg(int i, uint64_t c){
  357.     int n = 4, k = 4*i;
  358.     pfcAllFfCntWrCfg(CV(pfcAllFfCntRdCfg(),n,k) | BV(c,n,k));
  359. }
  360. uint64_t pfcFfCntRdCfg(int i){
  361.     int n = 4, k = 4*i;
  362.     return (pfcAllFfCntRdCfg() & OV(n,k)) >> k;
  363. }
  364. void     pfcFfCntWrVal(int i, uint64_t v){
  365.     pfcWRMSR(MSR_IA32_FIXED_CTR0+i, v);
  366. }
  367. uint64_t pfcFfCntRdVal(int i){
  368.     return pfcRDMSR(MSR_IA32_FIXED_CTR0+i);
  369. }
  370. void     pfcFfCntClFlg(int i, int v){
  371.     int n = 1, k = 32+i;
  372.     pfcAllCntClFlg(BV(v,n,k));
  373. }
  374. int      pfcFfCntRdFlg(int i){
  375.     int n = 1, k = 32+i;
  376.     return !!(pfcAllCntRdFlg() & OV(n,k));
  377. }
  378.  
  379. /* Gp */
  380. void     pfcGpCntWrEnb(int i, int v){
  381.     int n = 1, k = i;
  382.     pfcAllCntWrEnb(CV(pfcAllCntRdEnb(),n,k) | BV(v,n,k));
  383. }
  384. int      pfcGpCntRdEnb(int i){
  385.     int n = 1, k = i;
  386.     return !!(pfcAllCntRdEnb() & OV(n,k));
  387. }
  388. void     pfcGpCntWrCfg(int i, uint64_t c){
  389.     uint64_t evtNum, umask;
  390.    
  391.     /**
  392.      * We forbid the setting of the following bits in each PERFEVTSELx MSR:
  393.      *     Bit 21: AnyThread bit
  394.      *     Bit 20: APIC Interrupt Enable on overflow bit
  395.      *     Bit 19: Pin Control bit
  396.      *     Bit 17: OS-mode bit
  397.      * for all counters.
  398.      */
  399.    
  400.     c &= ~0x00000000003A0000ULL;
  401.    
  402.     /**
  403.      * For odd reasons, certain cache statistics can only be collected on
  404.      * certain counters.
  405.      */
  406.    
  407.     evtNum = (c >>  0) & 0xFF;
  408.     umask  = (c >>  8) & 0xFF;
  409.    
  410.     if((evtNum == 0x48) ||                                   /* l1d_pend_miss */
  411.        (evtNum == 0xA3 && (umask == 0x08 || umask == 0x0C))){/* cycle_activity.l1d_pending */
  412.         if(i != 2){
  413.             c = 0;/* Disable. */
  414.         }
  415.     }
  416.    
  417.     if(evtNum == 0xC0 && umask == 0x01){
  418.         if(i != 1){
  419.             c = 0;/* Disable. */
  420.         }
  421.     }
  422.    
  423.    
  424.     pfcWRMSR(MSR_IA32_PERFEVTSEL0+i, c);
  425. }
  426. uint64_t pfcGpCntRdCfg(int i){
  427.     return pfcRDMSR(MSR_IA32_PERFEVTSEL0+i);
  428. }
  429. void     pfcGpCntWrVal(int i, uint64_t v){
  430.     pfcWRMSR(MSR_IA32_A_PMC0+i, v);
  431. }
  432. uint64_t pfcGpCntRdVal(int i){
  433.     return pfcRDMSR(MSR_IA32_A_PMC0+i);
  434. }
  435. void     pfcGpCntClFlg(int i, int v){
  436.     int n = 1, k = i;
  437.     pfcAllCntClFlg(BV(v,n,k));
  438. }
  439. int      pfcGpCntRdFlg(int i){
  440.     int n = 1, k = i;
  441.     return !!(pfcAllCntRdFlg() & OV(n,k));
  442. }
  443.  
  444.  
  445.  
  446.  
  447. /**************** SYSFS ATTRIBUTES ****************/
  448.  
  449. /**
  450.  * Read configuration.
  451.  *
  452.  * Returns the configuration of the selected counters, one 64-bit word per
  453.  * counter, with the Ff counters first and the Gp counters last.
  454.  *
  455.  * @return Bytes of configuration data read
  456.  */
  457.  
  458. static ssize_t pfcCfgRd (struct file*          f,
  459.                          struct kobject*       kobj,
  460.                          struct bin_attribute* binattr,
  461.                          char*                 buf,
  462.                          loff_t                off,
  463.                          size_t                len){
  464.     int pmcStart, pmcEnd, i, j;
  465.     uint64_t* buf64 = (uint64_t*)buf;
  466.    
  467.     /* Check access is reasonable. */
  468.     if(!pfcIsAligned(off, len, 0x7) || off<0 || len<0){
  469.         return -1;
  470.     }
  471.    
  472.     /* Read relevant MSRs */
  473.     j=0;
  474.     if(pfcClampRange(off>>3, len>>3, pmcStartFf, pmcEndFf, &pmcStart, &pmcEnd)){
  475.         for(i=pmcStart;i<pmcEnd;i++,j++){
  476.             /* READ */    buf64[j] = pfcFfCntRdCfg(i-pmcStartFf);
  477.         }
  478.     }
  479.     if(pfcClampRange(off>>3, len>>3, pmcStartGp, pmcEndGp, &pmcStart, &pmcEnd)){
  480.         for(i=pmcStart;i<pmcEnd;i++,j++){
  481.             /* READ */    buf64[j] = pfcGpCntRdCfg(i-pmcStartGp);
  482.         }
  483.     }
  484.    
  485.     /* Report read data */
  486.     return j*sizeof(uint64_t);
  487. }
  488.  
  489. /**
  490.  * Write configuration.
  491.  *
  492.  * Sets the configuration of the selected counters, given one 64-bit word per
  493.  * counter, with the Ff counters first and the Gp counters last.
  494.  *
  495.  * Disables and leaves disabled all selected counters.
  496.  *
  497.  * @return Bytes of configuration data written
  498.  */
  499.  
  500. static ssize_t pfcCfgWr(struct file*          f,
  501.                         struct kobject*       kobj,
  502.                         struct bin_attribute* binattr,
  503.                         char*                 buf,
  504.                         loff_t                off,
  505.                         size_t                len){
  506.     int pmcStart, pmcEnd, i, j;
  507.     uint64_t* buf64 = (uint64_t*)buf;
  508.    
  509.     /* Check access is reasonable. */
  510.     if(!pfcIsAligned(off, len, 0x7) || off<0 || len<0){
  511.         return -1;
  512.     }
  513.    
  514.     /* Read relevant MSRs */
  515.     j=0;
  516.     if(pfcClampRange(off>>3, len>>3, pmcStartFf, pmcEndFf, &pmcStart, &pmcEnd)){
  517.         for(i=pmcStart;i<pmcEnd;i++,j++){
  518.             /* DISABLE */ pfcFfCntWrEnb(i-pmcStartFf, 0);
  519.             /* WRITE */   pfcFfCntWrCfg(i-pmcStartFf, buf64[j]);
  520.         }
  521.     }
  522.     if(pfcClampRange(off>>3, len>>3, pmcStartGp, pmcEndGp, &pmcStart, &pmcEnd)){
  523.         for(i=pmcStart;i<pmcEnd;i++,j++){
  524.             /* DISABLE */ pfcGpCntWrEnb(i-pmcStartGp, 0);
  525.             /* WRITE */   pfcGpCntWrCfg(i-pmcStartGp, buf64[j]);
  526.         }
  527.     }
  528.    
  529.     /* Report written data */
  530.     return j*sizeof(uint64_t);
  531. }
  532.  
  533. /**
  534.  * Reads counts.
  535.  *
  536.  * Returns the counts of the selected counters, one 64-bit word per counter,
  537.  * with the Ff counters first and the Gp counters last.
  538.  *
  539.  * Enables and starts the selected counters.
  540.  *
  541.  * @return Bytes of counter data read
  542.  */
  543.  
  544. static ssize_t pfcCntRd (struct file*          f,
  545.                          struct kobject*       kobj,
  546.                          struct bin_attribute* binattr,
  547.                          char*                 buf,
  548.                          loff_t                off,
  549.                          size_t                len){
  550.     int pmcStart, pmcEnd, i, j;
  551.     uint64_t* buf64 = (uint64_t*)buf;
  552.    
  553.     /* Check access is reasonable. */
  554.     if(!pfcIsAligned(off, len, 0x7) || off<0 || len<0){
  555.         return -1;
  556.     }
  557.    
  558.     /* Read relevant MSRs */
  559.     j=0;
  560.     if(pfcClampRange(off>>3, len>>3, pmcStartFf, pmcEndFf, &pmcStart, &pmcEnd)){
  561.         for(i=pmcStart;i<pmcEnd;i++,j++){
  562.             /* READ */    buf64[j] = pfcFfCntRdVal(i-pmcStartFf);
  563.             /* ENABLE */  pfcFfCntWrEnb(i-pmcStartFf, 1);
  564.         }
  565.     }
  566.     if(pfcClampRange(off>>3, len>>3, pmcStartGp, pmcEndGp, &pmcStart, &pmcEnd)){
  567.         for(i=pmcStart;i<pmcEnd;i++,j++){
  568.             /* READ */    buf64[j] = pfcGpCntRdVal(i-pmcStartGp);
  569.             /* ENABLE */  pfcGpCntWrEnb(i-pmcStartGp, 1);
  570.         }
  571.     }
  572.    
  573.     /* Report read data */
  574.     return j*sizeof(uint64_t);
  575. }
  576.  
  577. /**
  578.  * Write counts.
  579.  *
  580.  * Sets the value of the selected counters, given one 64-bit word per
  581.  * counter, with the Ff counters first and the Gp counters last.
  582.  *
  583.  * Disables and leaves disabled all selected counters.
  584.  *
  585.  * @return Bytes of counter data written
  586.  */
  587.  
  588. static ssize_t pfcCntWr(struct file*          f,
  589.                         struct kobject*       kobj,
  590.                         struct bin_attribute* binattr,
  591.                         char*                 buf,
  592.                         loff_t                off,
  593.                         size_t                len){
  594.     int pmcStart, pmcEnd, i, j;
  595.     uint64_t* buf64 = (uint64_t*)buf;
  596.    
  597.     /* Check access is reasonable. */
  598.     if(!pfcIsAligned(off, len, 0x7) || off<0 || len<0){
  599.         return -1;
  600.     }
  601.    
  602.     /* Read relevant MSRs */
  603.     j=0;
  604.     if(pfcClampRange(off>>3, len>>3, pmcStartFf, pmcEndFf, &pmcStart, &pmcEnd)){
  605.         for(i=pmcStart;i<pmcEnd;i++,j++){
  606.             /* DISABLE */ pfcFfCntWrEnb(i-pmcStartFf, 0);
  607.             /* WRITE */   pfcFfCntWrVal(i-pmcStartFf, buf64[j]);
  608.         }
  609.     }
  610.     if(pfcClampRange(off>>3, len>>3, pmcStartGp, pmcEndGp, &pmcStart, &pmcEnd)){
  611.         for(i=pmcStart;i<pmcEnd;i++,j++){
  612.             /* DISABLE */ pfcGpCntWrEnb(i-pmcStartGp, 0);
  613.             /* WRITE */   pfcGpCntWrVal(i-pmcStartGp, buf64[j]);
  614.         }
  615.     }
  616.    
  617.     /* Report written data */
  618.     return j*sizeof(uint64_t);
  619. }
  620.  
  621.  
  622.  
  623.  
  624.  
  625. /**************** INIT CODE ****************/
  626.  
  627. /**
  628.  * Read CPUID to identify # of fixed-function and general-purpose PMCs, as well
  629.  * as quite a few other things.
  630.  */
  631.  
  632. static void pfcInitCPUID(void){
  633.     uint32_t a,b,c,d;
  634.    
  635.     /**
  636.      * PMC information is gotten by CPUID.EAX = 0xA.
  637.      * PerfMon architecture version is in EAX[ 7: 0].
  638.      * #Gp PMCs                     is in EAX[15: 8]
  639.      * Gp bitwidth                  is in EAX[23:16]
  640.      * #Ff PMCs                     is in EDX[ 4: 0] if PMArchVer > 1.
  641.      * Ff bitwidth                  is in EDX[12: 5] if PMArchVer > 1.
  642.      */
  643.    
  644.     pfcCPUID(0xA,0,&a,&b,&c,&d);
  645.     pmcArchVer = (a >>  0) & 0xFF;
  646.     pmcGp      = (a >>  8) & 0xFF;
  647.     pmcMaskGp  = (a >> 16) & 0xFF;
  648.    
  649.     if(pmcArchVer <= 1){
  650.         pmcFf = 0;
  651.     }else{
  652.         pmcFf     = (d >>  0) & 0x1F;
  653.         pmcMaskFf = (d >>  5) & 0xFF;
  654.     }
  655.    
  656.     pmcMaskGp  = OV(pmcMaskGp,0);
  657.     pmcMaskFf  = OV(pmcMaskFf,0);
  658.    
  659.     /* Dump out this data */
  660.     printk(KERN_INFO "PM Arch Version:      %d\n", pmcArchVer);
  661.     if(pmcFf + pmcGp > MAXPMC){
  662.         printk(KERN_INFO "More than %d PMCs found! Clamping to %d.\n",
  663.                MAXPMC,
  664.                MAXPMC);
  665.         pmcGp = pmcGp>MAXPMC       ?       MAXPMC : pmcGp;
  666.         pmcFf = pmcGp+pmcFf>MAXPMC ? MAXPMC-pmcGp : pmcFf;
  667.     }
  668.     printk(KERN_INFO "Fixed-function  PMCs: %d\tMask %016llx\n", pmcFf, pmcMaskFf);
  669.     printk(KERN_INFO "General-purpose PMCs: %d\tMask %016llx\n", pmcGp, pmcMaskGp);
  670.    
  671.     /* Save bounds. */
  672.     pmcStartFf = 0;
  673.     pmcEndFf   = pmcFf;
  674.     pmcStartGp = pmcFf;
  675.     pmcEndGp   = pmcFf+pmcGp;
  676. }
  677.  
  678. /**
  679.  * Initialize all counters.
  680.  *
  681.  * For each counter, therefore,
  682.  * 1. Globally disable (En=0)
  683.  * 2. Deconfigure      (Cf=0)
  684.  * 3. Zero             (Wr=0)
  685.  * 4. Clear Flags      (Cl=1)
  686.  */
  687.  
  688. void pfcInitCnts(void){
  689.     int i;
  690.    
  691.     pfcAllCntWrEnb  (0);
  692.     pfcAllFfCntWrCfg(0);
  693.     for(i=0;i<pmcFf;i++){
  694.         pfcFfCntWrVal(i, 0);
  695.     }
  696.     for(i=0;i<pmcGp;i++){
  697.         pfcGpCntWrCfg(i, 0);
  698.         pfcGpCntWrVal(i, 0);
  699.     }
  700.     pfcAllCntClFlg  (1);
  701. }
  702.  
  703. /**
  704.  * Load module.
  705.  *
  706.  * @return 0 if module load successful, non-0 otherwise.
  707.  */
  708.  
  709. static int __init pfcInit(void){
  710.     int ret;
  711.     /* Loading sequence begins... */
  712.     printk(KERN_INFO "Module perfcount loading...\n");
  713.    
  714.    
  715.     /**
  716.      * Initialization depends on various constants retrieved using CPUID.
  717.      */
  718.    
  719.     pfcInitCPUID();
  720.    
  721.    
  722.     /**
  723.      * We implicitly rely far too heavily on PMArchVer being 3.
  724.      *
  725.      * Abort if PM Arch Version != 3
  726.      */
  727.    
  728.     if(pmcArchVer != 3){
  729.         printk(KERN_INFO "Performance monitoring architecture version %d, not 3!"
  730.                "Failed to load module perfcount.\n", pmcArchVer);
  731.         return 1;
  732.     }
  733.    
  734.    
  735.     /**
  736.      * If it is pmcArchVer == 3, we can safely proceed with counter init.
  737.      */
  738.    
  739.     pfcInitCnts();
  740.    
  741.    
  742.     /**
  743.      * Register binary attributes under own directory.
  744.      */
  745.    
  746.     ret = sysfs_create_group((struct kobject*)&THIS_MODULE->mkobj,
  747.                              &PFC_ATTR_GRP);
  748.    
  749.    
  750.    
  751.     /* Either it was successful, or no. */
  752.     if(ret != 0){
  753.         printk(KERN_INFO "Failed to create sysfs attributes. Failed to load "
  754.                          "module perfcount.\n");
  755.         return ret;
  756.     }else{
  757.         printk(KERN_INFO "Module perfcount loaded successfully.\n");
  758.         return 0;
  759.     }
  760. }
  761.  
  762. /**
  763.  * Exit module.
  764.  */
  765.  
  766. static void __exit pfcExit(void){
  767.     printk(KERN_INFO "Module perfcount exiting...\n");
  768.    
  769.     /* Disable everything */
  770.     pfcInitCnts();
  771.    
  772.     /* Deregister binary attributes under own directory. */
  773.     sysfs_remove_group((struct kobject*)&THIS_MODULE->mkobj,
  774.                        &PFC_ATTR_GRP);
  775.    
  776.     printk(KERN_INFO "Module perfcount exited.\n");
  777. }
  778.  
  779.  
  780.  
  781.  
  782. /* Module magic */
  783. module_init(pfcInit);
  784. module_exit(pfcExit);
  785. MODULE_LICENSE("Dual MIT/GPL");
  786. MODULE_AUTHOR("");
  787. MODULE_DESCRIPTION("Grants ***EXTREMELY UNSAFE*** access to the Intel Performance Monitor Counters (PMC).");
  788.  
  789.  
  790.  
  791. /* Notes */
  792.  
  793. /**
  794.  * Required boot args:
  795.  *     nmi_watchdog=0 modprobe.blacklist=iTCO_wdt,iTCO_vendor_support
  796.  *
  797.  * Otherwise, IA32_FIXED_CTR1 is monopolised by !@#$ NMI watchdog crapware. Even
  798.  * so, it seems that something gratuitously, though rarely, sets IA32_PMC0 to
  799.  * 0xFFFF every so often.
  800.  */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement