我想要计算在ARM Cortex-M4(或Cortex-M3)处理器上每个周期执行的指令数。
所需的是:我想要进行性能分析的代码在运行时执行的指令数以及代码执行所需的周期数。
1 - 周期数
使用周期计数器非常简单明了。
volatile unsigned int *DWT_CYCCNT ;
volatile unsigned int *DWT_CONTROL ;
volatile unsigned int *SCB_DEMCR ;
void reset_timer(){
DWT_CYCCNT = (int *)0xE0001004; //address of the register
DWT_CONTROL = (int *)0xE0001000; //address of the register
SCB_DEMCR = (int *)0xE000EDFC; //address of the register
*SCB_DEMCR = *SCB_DEMCR | 0x01000000;
*DWT_CYCCNT = 0; // reset the counter
*DWT_CONTROL = 0;
}
void start_timer(){
*DWT_CONTROL = *DWT_CONTROL | 1 ; // enable the counter
}
void stop_timer(){
*DWT_CONTROL = *DWT_CONTROL | 0 ; // disable the counter
}
unsigned int getCycles(){
return *DWT_CYCCNT;
}
main(){
....
reset_timer(); //reset timer
start_timer(); //start timer
//Code to profile
...
myFunction();
...
stop_timer(); //stop timer
numCycles = getCycles(); //read number of cycles
...
}
2 - 指令数量
我在网上找到了一些文档,用于计算Arm Cortex-M3和Cortex-M4执行的指令数量(链接):
# instructions = CYCCNT - CPICNT - EXCCNT - SLEEPCNT - LSUCNT + FOLDCNT
他们提到的寄存器在这里有详细记录here(第11-13页),这些是访问它们的内存地址:
DWT_CYCCNT = 0xE0001004
DWT_CONTROL = 0xE0001000
SCB_DEMCR = 0xE000EDFC
DWT_CPICNT = 0xE0001008
DWT_EXCCNT = 0xE000100C
DWT_SLEEPCNT = 0xE0001010
DWT_LSUCNT = 0xE0001014
DWT_FOLDCNT = 0xE0001018
DWT_CONTROL寄存器用于启用计数器,特别是循环计数器,如此处所述。
但是,当我试图将所有内容放在一起以计算每个周期执行的指令数量时,我没有成功。
这里有一个关于如何从gdb中使用它们的简短指南。
不容易的是,一些寄存器是8位寄存器(DWT_CPICNT,DWT_EXCCNT,DWT_SLEEPCNT,DWT_LSUCNT,DWT_FOLDCNT),当它们溢出时会触发事件。我没有找到收集该事件的方法。没有代码片段来解释如何做到这一点,也没有适用于此的中断例程。
此外,似乎使用gdb的监视点在这些寄存器的地址上无法正常工作。gdb无法在寄存器更改值时停止。例如,在DWT_LSUCNT上:
(gdb) watch *0xE0001014
更新:我在GitHub上找到了这个项目,解释了如何使用DWT、ITM和ETM单位。但是我没有检查它是否有效!我会发布更新。
有关如何使用它们的任何想法吗?
谢谢!
#define DWT_CYCCNT (*(volatile uint32_t*)0xE0001004ul)
。 - Lundin