Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1094768
  • 博文数量: 139
  • 博客积分: 2510
  • 博客等级: 少校
  • 技术积分: 1712
  • 用 户 组: 普通用户
  • 注册时间: 2006-03-13 23:10
个人简介

每天进步一点点。

文章分类

全部博文(139)

文章存档

2015年(3)

2014年(11)

2013年(25)

2011年(1)

2009年(3)

2008年(29)

2007年(45)

2006年(22)

分类: 嵌入式

2013-05-11 09:37:00

ARMv6和ARMv7处理器均提供了 performance monitoring unit(PMU),可以用于测试程序运行时消耗的Cycle数,最终可以得到程序运行时的MCPS(百万周期数每秒)。
下面的代码是从网上抄来的,可以用来测试ARMv7上面程序运行的开销mcps。当然,也可以自己写,那就需要参考ARM的官方手册,根据寄存器说明重新写一份,例如,可以参考文档:DDI0344K里面的3.2.42小节,里面对PMU的寄存器有详细的说明。不过网上既然有现成了,本着不重复造轮子的原则,就直接使用现成的代码好了。代码如下:


1.pmu_v7.h
该文件提供了经过封装的,对外函数接口声明

点击(此处)折叠或打开

  1. // ------------------------------------------------------------
  2. // PMU for Cortex-A/R (v7-A/R)
  3. // ------------------------------------------------------------

  4. #ifndef _V7_PMU_H
  5. #define _V7_PMU_H

  6. // Returns the number of progammable counters
  7. unsigned int getPMN(void);

  8. // Sets the event for a programmable counter to record
  9. // counter = r0 = Which counter to program (e.g. 0 for PMN0, 1 for PMN1)
  10. // event = r1 = The event code (from appropiate TRM or ARM Architecture Reference Manual)
  11. void pmn_config(unsigned int counter, unsigned int event);

  12. // Enables/disables the divider (1/64) on CCNT
  13. // divider = r0 = If 0 disable divider, else enable dvider
  14. void ccnt_divider(int divider);

  15. //
  16. // Enables and disables
  17. //

  18. // Global PMU enable
  19. // On ARM11 this enables the PMU, and the counters start immediately
  20. // On Cortex this enables the PMU, there are individual enables for the counters
  21. void enable_pmu(void);

  22. // Global PMU disable
  23. // On Cortex, this overrides the enable state of the individual counters
  24. void disable_pmu(void);

  25. // Enable the CCNT
  26. void enable_ccnt(void);

  27. // Disable the CCNT
  28. void disable_ccnt(void);

  29. // Enable PMN{n}
  30. // counter = The counter to enable (e.g. 0 for PMN0, 1 for PMN1)
  31. void enable_pmn(unsigned int counter);

  32. // Enable PMN{n}
  33. // counter = The counter to enable (e.g. 0 for PMN0, 1 for PMN1)
  34. void disable_pmn(unsigned int counter);

  35. //
  36. // Read counter values
  37. //

  38. // Returns the value of CCNT
  39. unsigned int read_ccnt(void);

  40. // Returns the value of PMN{n}
  41. // counter = The counter to read (e.g. 0 for PMN0, 1 for PMN1)
  42. unsigned int read_pmn(unsigned int counter);

  43. //
  44. // Overflow and interrupts
  45. //

  46. // Returns the value of the overflow flags
  47. unsigned int read_flags(void);

  48. // Writes the overflow flags
  49. void write_flags(unsigned int flags);

  50. // Enables interrupt generation on overflow of the CCNT
  51. void enable_ccnt_irq(void);

  52. // Disables interrupt generation on overflow of the CCNT
  53. void disable_ccnt_irq(void);

  54. // Enables interrupt generation on overflow of PMN{x}
  55. // counter = The counter to enable the interrupt for (e.g. 0 for PMN0, 1 for PMN1)
  56. void enable_pmn_irq(unsigned int counter);

  57. // Disables interrupt generation on overflow of PMN{x}
  58. // counter = r0 = The counter to disable the interrupt for (e.g. 0 for PMN0, 1 for PMN1)
  59. void disable_pmn_irq(unsigned int counter);

  60. //
  61. // Counter reset functions
  62. //

  63. // Resets the programmable counters
  64. void reset_pmn(void);

  65. // Resets the CCNT
  66. void reset_ccnt(void);

  67. //
  68. // Software Increment

  69. // Writes to software increment register
  70. // counter = The counter to increment (e.g. 0 for PMN0, 1 for PMN1)
  71. void pmu_software_increment(unsigned int counter);

  72. //
  73. // User mode access
  74. //

  75. // Enables User mode access to the PMU (must be called in a priviledged mode)
  76. void enable_pmu_user_access(void);

  77. // Disables User mode access to the PMU (must be called in a priviledged mode)
  78. void disable_pmu_user_access(void);

  79. #endif
  80. // ------------------------------------------------------------
  81. // End of v7_pmu.h
  82. // ------------------------------------------------------------
2.pmu_v7.s
该文件里面是相关功能的实现:

点击(此处)折叠或打开

  1. /*------------------------------------------------------------
  2. Performance Monitor Block
  3. ------------------------------------------------------------*/
  4.     .arm @ Make sure we are in ARM mode.
  5.     .text
  6.     .align 2
  7.     .global getPMN @ export this function for the linker

  8. /* Returns the number of progammable counters uint32_t getPMN(void) */

  9. getPMN:
  10.   MRC p15, 0, r0, c9, c12, 0 /* Read PMNC Register */
  11.   MOV r0, r0, LSR #11 /* Shift N field down to bit 0 */
  12.   AND r0, r0, #0x1F /* Mask to leave just the 5 N bits */
  13.   BX lr

  14.   

  15.     .global pmn_config @ export this function for the linker
  16.   /* Sets the event for a programmable counter to record */
  17.   /* void pmn_config(unsigned counter, uint32_t event) */
  18.   /* counter = r0 = Which counter to program (e.g. 0 for PMN0, 1 for PMN1) */
  19.   /* event = r1 = The event code */
  20. pmn_config:
  21.   AND r0, r0, #0x1F /* Mask to leave only bits 4:0 */
  22.   MCR p15, 0, r0, c9, c12, 5 /* Write PMNXSEL Register */
  23.   MCR p15, 0, r1, c9, c13, 1 /* Write EVTSELx Register */
  24.   BX lr

  25.   

  26.     .global ccnt_divider @ export this function for the linker
  27.   /* Enables/disables the divider (1/64) on CCNT */
  28.   /* void ccnt_divider(int divider) */
  29.   /* divider = r0 = If 0 disable divider, else enable dvider */
  30. ccnt_divider:
  31.   MRC p15, 0, r1, c9, c12, 0 /* Read PMNC */

  32.   CMP r0, #0x0 /* IF (r0 == 0) */
  33.   BICEQ r1, r1, #0x08 /* THEN: Clear the D bit (disables the divisor) */
  34.   ORRNE r1, r1, #0x08 /* ELSE: Set the D bit (enables the divisor) */

  35.   MCR p15, 0, r1, c9, c12, 0 /* Write PMNC */
  36.   BX lr
  37.  

  38.   /* --------------------------------------------------------------- */
  39.   /* Enable/Disable */
  40.   /* --------------------------------------------------------------- */

  41.     .global enable_pmu @ export this function for the linker
  42.   /* Global PMU enable */
  43.   /* void enable_pmu(void) */
  44. enable_pmu:
  45.   MRC p15, 0, r0, c9, c12, 0 /* Read PMNC */
  46.   ORR r0, r0, #0x01 /* Set E bit */
  47.   MCR p15, 0, r0, c9, c12, 0 /* Write PMNC */
  48.   BX lr
  49.  


  50.     .global disable_pmu @ export this function for the linker
  51.   /* Global PMU disable */
  52.   /* void disable_pmu(void) */
  53. disable_pmu:
  54.   MRC p15, 0, r0, c9, c12, 0 /* Read PMNC */
  55.   BIC r0, r0, #0x01 /* Clear E bit */
  56.   MCR p15, 0, r0, c9, c12, 0 /* Write PMNC */
  57.   BX lr
  58.  
  59.   

  60.     .global enable_ccnt @ export this function for the linker
  61.   /* Enable the CCNT */
  62.   /* void enable_ccnt(void) */
  63. enable_ccnt:
  64.   MOV r0, #0x80000000 /* Set C bit */
  65.   MCR p15, 0, r0, c9, c12, 1 /* Write CNTENS Register */
  66.   BX lr
  67.  
  68.   

  69.     .global disable_ccnt @ export this function for the linker
  70.   /* Disable the CCNT */
  71.   /* void disable_ccnt(void) */
  72. disable_ccnt:
  73.   MOV r0, #0x80000000 /* Clear C bit */
  74.   MCR p15, 0, r0, c9, c12, 2 /* Write CNTENC Register */
  75.   BX lr
  76.  
  77.   

  78.     .global enable_pmn @ export this function for the linker
  79.   /* Enable PMN{n} */
  80.   /* void enable_pmn(uint32_t counter) */
  81.   /* counter = r0 = The counter to enable (e.g. 0 for PMN0, 1 for PMN1) */
  82. enable_pmn:
  83.   MOV r1, #0x1 /* Use arg (r0) to set which counter to disable */
  84.   MOV r1, r1, LSL r0

  85.   MCR p15, 0, r1, c9, c12, 1 /* Write CNTENS Register */
  86.   BX lr

  87.   

  88.     .global disable_pmn @ export this function for the linker
  89.   /* Enable PMN{n} */
  90.   /* void disable_pmn(uint32_t counter) */
  91.   /* counter = r0 = The counter to enable (e.g. 0 for PMN0, 1 for PMN1) */
  92. disable_pmn:
  93.   MOV r1, #0x1 /* Use arg (r0) to set which counter to disable */
  94.   MOV r1, r1, LSL r0

  95.   MCR p15, 0, r1, c9, c12, 1 /* Write CNTENS Register */
  96.   BX lr
  97.  
  98.   
  99.   
  100.     .global enable_pmu_user_access @ export this function for the linker
  101.   /* Enables User mode access to the PMU (must be called in a priviledged mode) */
  102.   /* void enable_pmu_user_access(void) */
  103. enable_pmu_user_access:
  104.   MRC p15, 0, r0, c9, c14, 0 /* Read PMUSERENR Register */
  105.   ORR r0, r0, #0x01 /* Set EN bit (bit 0) */
  106.   MCR p15, 0, r0, c9, c14, 0 /* Write PMUSERENR Register */
  107.   BX lr
  108.   
  109.   
  110.   
  111.     .global disable_pmu_user_access @ export this function for the linker
  112.   /* Disables User mode access to the PMU (must be called in a priviledged mode) */
  113.   /* void disable_pmu_user_access(void) */
  114. disable_pmu_user_access:
  115.   MRC p15, 0, r0, c9, c14, 0 /* Read PMUSERENR Register */
  116.   BIC r0, r0, #0x01 /* Clear EN bit (bit 0) */
  117.   MCR p15, 0, r0, c9, c14, 0 /* Write PMUSERENR Register */
  118.   BX lr


  119.   /* --------------------------------------------------------------- */
  120.   /* Counter read registers */
  121.   /* --------------------------------------------------------------- */

  122.     .global read_ccnt @ export this function for the linker
  123.   /* Returns the value of CCNT */
  124.   /* uint32_t read_ccnt(void) */
  125. read_ccnt:
  126.   MRC p15, 0, r0, c9, c13, 0 /* Read CCNT Register */
  127.   BX lr


  128.     .global read_pmn @ export this function for the linker
  129.   /* Returns the value of PMN{n} */
  130.   /* uint32_t read_pmn(uint32_t counter) */
  131.   /* counter = r0 = The counter to read (e.g. 0 for PMN0, 1 for PMN1) */
  132. read_pmn:
  133.   AND r0, r0, #0x1F /* Mask to leave only bits 4:0 */
  134.   MCR p15, 0, r0, c9, c12, 5 /* Write PMNXSEL Register */
  135.   MRC p15, 0, r0, c9, c13, 2 /* Read current PMNx Register */
  136.   BX lr
  137.   
  138.   
  139.   /* --------------------------------------------------------------- */
  140.   /* Software Increment */
  141.   /* --------------------------------------------------------------- */

  142.     .global pmu_software_increment @ export this function for the linker
  143.         /* Writes to software increment register */
  144.         /* void pmu_software_increment(uint32_t counter) */
  145.         /* counter = r0 = The counter to increment (e.g. 0 for PMN0, 1 for PMN1) */
  146. pmu_software_increment:
  147.   MOV r1, #0x01
  148.   MOV r1, r1, LSL r0
  149.   MCR p15, 0, r1, c9, c12, 4 /* Write SWINCR Register */
  150.   BX lr

  151.   /* --------------------------------------------------------------- */
  152.   /* Overflow & Interrupt Generation */
  153.   /* --------------------------------------------------------------- */

  154.     .global read_flags @ export this function for the linker
  155.   /* Returns the value of the overflow flags */
  156.   /* uint32_t read_flags(void) */
  157. read_flags:
  158.   MRC p15, 0, r0, c9, c12, 3 /* Read FLAG Register */
  159.   BX lr
  160.   

  161.     .global write_flags @ export this function for the linker
  162.   /* Writes the overflow flags */
  163.   /* void write_flags(uint32_t flags) */
  164. write_flags:
  165.   MCR p15, 0, r0, c9, c12, 3 /* Write FLAG Register */
  166.   BX lr
  167.   

  168.     .global enable_ccnt_irq @ export this function for the linker
  169.   /* Enables interrupt generation on overflow of the CCNT */
  170.   /* void enable_ccnt_irq(void) */
  171. enable_ccnt_irq:
  172.   MOV r0, #0x80000000
  173.   MCR p15, 0, r0, c9, c14, 1 /* Write INTENS Register */
  174.   BX lr

  175.     .global disable_ccnt_irq @ export this function for the linker
  176.   /* Disables interrupt generation on overflow of the CCNT */
  177.   /* void disable_ccnt_irq(void) */
  178. disable_ccnt_irq:
  179.   MOV r0, #0x80000000
  180.   MCR p15, 0, r0, c9, c14, 2 /* Write INTENC Register */
  181.   BX lr
  182.   

  183.     .global enable_pmn_irq @ export this function for the linker
  184.   /* Enables interrupt generation on overflow of PMN{x} */
  185.   /* void enable_pmn_irq(uint32_t counter) */
  186.   /* counter = r0 = The counter to enable the interrupt for (e.g. 0 for PMN0, 1 for PMN1) */
  187. enable_pmn_irq:
  188.   MOV r1, #0x1 /* Use arg (r0) to set which counter to disable */
  189.   MOV r0, r1, LSL r0
  190.   MCR p15, 0, r0, c9, c14, 1 /* Write INTENS Register */
  191.   BX lr

  192.     .global disable_pmn_irq @ export this function for the linker
  193.   /* Disables interrupt generation on overflow of PMN{x} */
  194.   /* void disable_pmn_irq(uint32_t counter) */
  195.   /* counter = r0 = The counter to disable the interrupt for (e.g. 0 for PMN0, 1 for PMN1) */
  196. disable_pmn_irq:
  197.   MOV r1, #0x1 /* Use arg (r0) to set which counter to disable */
  198.   MOV r0, r1, LSL r0
  199.   MCR p15, 0, r0, c9, c14, 2 /* Write INTENC Register */
  200.   BX lr

  201.   /* --------------------------------------------------------------- */
  202.   /* Reset Functions */
  203.   /* --------------------------------------------------------------- */

  204.     .global reset_pmn @ export this function for the linker
  205.   /* Resets the programmable counters */
  206.   /* void reset_pmn(void) */
  207. reset_pmn:
  208.   MRC p15, 0, r0, c9, c12, 0 /* Read PMNC */
  209.   ORR r0, r0, #0x02 /* Set P bit (Event Counter Reset) */
  210.   MCR p15, 0, r0, c9, c12, 0 /* Write PMNC */
  211.   BX lr


  212.         .global reset_ccnt @ export this function for the linker
  213.   /* Resets the CCNT */
  214.   /* void reset_ccnt(void) */
  215. reset_ccnt:
  216.   MRC p15, 0, r0, c9, c12, 0 /* Read PMNC */
  217.   ORR r0, r0, #0x04 /* Set C bit (Event Counter Reset) */
  218.   MCR p15, 0, r0, c9, c12, 0 /* Write PMNC */
  219.   BX lr

  220.  
  221.     .end @end of code, this line is optional.
  222. /* ------------------------------------------------------------ */
  223. /* End of v7_pmu.s */
  224. /* ------------------------------------------------------------ */
可以使用下面的代码测试一下,看看是否能够正确测试出开销来。

点击(此处)折叠或打开

  1. #include "v7_pmu.h"
  2. #include <stdio.h>
  3. #include <time.h>
  4. #include <stdlib.h>

  5. int random_range(int max);
  6. void pmu_start(unsigned int event0,unsigned int event1,unsigned int event2,unsigned int event3,unsigned int event4,unsigned int event5);
  7. void pmu_stop(void);

  8. int main ( int argc, char *argv[] ){
  9. int matrix_size;
  10. int i,j,k,z;



  11. // To access CPU time
  12. clock_t start, end;
  13. double cpu_time_used;

  14.   if ( argc != 2 ) {
  15.     fputs ( "usage: $prog n", stderr );
  16.     exit ( EXIT_FAILURE );
  17.         }

  18.     matrix_size = (int)strtol(argv[1],NULL,10);


  19. printf("square matrix size = %dn", matrix_size);


  20. /*Using time function output for seed value*/
  21.         unsigned int seed = (unsigned int)time(NULL);
  22.         srand(seed);

  23. /* Initialize square matrix with command line input value */
  24. int a[matrix_size][matrix_size], b[matrix_size][matrix_size], c[matrix_size][matrix_size];

  25. /* Intialize both A[][] and B[][] with random values between 0-5 and set C[][] to zero*/
  26.         for(i=0;i<matrix_size;i++){
  27.                 for(j=0;j<matrix_size;j++){
  28.                 a[i][j]=random_range(6);
  29.                 b[i][j]=random_range(6);
  30.                 c[i][j]=0;
  31.                 }
  32.         }

  33. /* Multiply A[][] and B[][] and store into C[][]*/
  34.  start = clock();



  35. for(z=0;z<7;z++){
  36.         if(z==0)
  37.         pmu_start(0x01,0x02,0x03,0x04,0x05,0x06);
  38.         if(z==1)
  39.         pmu_start(0x07,0x08,0x09,0x0A,0x0B,0x0C);
  40.         if(z==2)
  41.         pmu_start(0x0D,0x0E,0x0F,0x10,0x11,0x12);
  42.         if(z==3)
  43.         pmu_start(0x50,0x51,0x60,0x61,0x62,0x63);
  44.         if(z==4)
  45.         pmu_start(0x64,0x65,0x66,0x67,0x68,0x6E);
  46.         if(z==5)
  47.         pmu_start(0x70,0x71,0x72,0x73,0x74,0x81);
  48.         if(z==6)
  49.         pmu_start(0x82,0x83,0x84,0x85,0x86,0x8A);

  50.    for(i=0; i<matrix_size; i++)
  51.    {
  52.          for(j=0; j<matrix_size; j++)
  53.          {
  54.             for(k=0; k<matrix_size; k++)
  55.             {
  56.                   /* c[0][0]=a[0][0]*b[0][0]+a[0][1]*b[1][0]+a[0][2]*b[2][0]; */
  57.                   c[i][j] += a[i][k]*b[k][j];
  58.             }
  59.          }
  60.   }

  61.         pmu_stop();

  62. }
  63.     end = clock();
  64.     cpu_time_used = (end - start) / ((double) CLOCKS_PER_SEC);

  65. printf("CPU time used = %.4lfn",cpu_time_used);
  66. printf("square matrix size = %dn", matrix_size);


  67.   return 0;
  68. }

  69. int random_range(int max){
  70.     return ((rand()%(max-1)) +1);
  71. }



  72. void pmu_start(unsigned int event0,unsigned int event1,unsigned int event2,unsigned int event3,unsigned int event4,unsigned int event5){

  73.   enable_pmu(); // Enable the PMU
  74.   reset_ccnt(); // Reset the CCNT (cycle counter)
  75.   reset_pmn(); // Reset the configurable counters
  76.   pmn_config(0, event0); // Configure counter 0 to count event code 0x03
  77.   pmn_config(1, event1); // Configure counter 1 to count event code 0x03
  78.   pmn_config(2, event2); // Configure counter 2 to count event code 0x03
  79.   pmn_config(3, event3); // Configure counter 3 to count event code 0x03
  80.   pmn_config(4, event4); // Configure counter 4 to count event code 0x03
  81.   pmn_config(5, event5); // Configure counter 5 to count event code 0x03

  82.   enable_ccnt(); // Enable CCNT
  83.   enable_pmn(0); // Enable counter
  84.   enable_pmn(1); // Enable counter
  85.   enable_pmn(2); // Enable counter
  86.   enable_pmn(3); // Enable counter
  87.   enable_pmn(4); // Enable counter
  88.   enable_pmn(5); // Enable counter

  89.   printf("CountEvent0=0x%x,CountEvent1=0x%x,CountEvent2=0x%x,CountEvent3=0x%x,CountEvent4=0x%x,CountEvent5=0x%xn", event0,event1,event2,event3,event4,event5);
  90. }

  91. void pmu_stop(void){
  92.   unsigned int cycle_count, overflow, counter0, counter1, counter2, counter3, counter4, counter5;

  93.   disable_ccnt(); // Stop CCNT
  94.   disable_pmn(0); // Stop counter 0
  95.   disable_pmn(1); // Stop counter 1
  96.   disable_pmn(2); // Stop counter 2
  97.   disable_pmn(3); // Stop counter 3
  98.   disable_pmn(4); // Stop counter 4
  99.   disable_pmn(5); // Stop counter 5

  100.   counter0 = read_pmn(0); // Read counter 0
  101.   counter1 = read_pmn(1); // Read counter 1
  102.   counter2 = read_pmn(2); // Read counter 2
  103.   counter3 = read_pmn(3); // Read counter 3
  104.   counter4 = read_pmn(4); // Read counter 4
  105.   counter5 = read_pmn(5); // Read counter 5

  106.   cycle_count = read_ccnt(); // Read CCNT
  107.   overflow=read_flags(); //Check for overflow flag

  108.   printf("Counter0=%d,Counter1=%d,Counter2=%d,Counter3=%d,Counter4=%d,Counter5=%dn", counter0, counter1,counter2,counter3,counter4,counter5);
  109.   printf("Overflow flag: = %d, Cycle Count: = %d nn", overflow,cycle_count);
  110. }



阅读(5800) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~