ARM M4 每周期指令 (IPC) 计数器 [英] ARM M4 Instructions per Cycle (IPC) counters

查看:72
本文介绍了ARM M4 每周期指令 (IPC) 计数器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想计算在 ARM cortex-M4(或 cortex-M3)处理器上执行的每个周期的指令数.

需要的是:我要分析的代码的指令数(在运行时执行)和代码执行所需的周期数.p>

1 - 循环数

使用循环计数器非常简单直接.

volatile unsigned int *DWT_CYCCNT ;volatile unsigned int *DWT_CONTROL ;volatile unsigned int *SCB_DEMCR ;无效重置定时器(){DWT_CYCCNT = (int *)0xE0001004;//寄存器地址DWT_CONTROL = (int *)0xE0001000;//寄存器地址SCB_DEMCR = (int *)0xE000EDFC;//寄存器地址*SCB_DEMCR = *SCB_DEMCR |0x01000000;*DWT_CYCCNT = 0;//重置计数器*DWT_CONTROL = 0;}无效 start_timer(){*DWT_CONTROL = *DWT_CONTROL |1;//启用计数器}无效停止计时器(){*DWT_CONTROL = *DWT_CONTROL |0;//禁用计数器}无符号整数 getCycles(){返回 *DWT_CYCCNT;}主要的(){……重置定时器();//重置定时器start_timer();//启动定时器//要配置文件的代码...我的函数();...stop_timer();//停止定时器numCycles = getCycles();//读取周期数...}

2 - 指令数

我在网上找到了一些文档来计算 arm cortex-M3 和 cortex-M4 执行的指令数(链接):

 # 指令 = CYCCNT - CPICNT - EXCCNT - SLEEPCNT - LSUCNT + FOLDCNT

他们提到的寄存器记录在这里(从第 11-13 页开始),这些是访问它们的内存地址:

DWT_CYCCNT = 0xE0001004DWT_CONTROL = 0xE0001000SCB_DEMCR = 0xE000EDFCDWT_CPICNT = 0xE0001008DWT_EXCCNT = 0xE000100CDWT_SLEEPCNT = 0xE0001010DWT_LSUCNT = 0xE0001014DWT_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 单元.但我没有检查它是否有效!我会发布更新.

知道如何使用它们吗?

谢谢!

解决方案

您提供的代码示例在清除启用位时出现问题.您应该使用 'AND' 而不是 'OR' 清除该位:

*DWT_CONTROL = *DWT_CONTROL &0xFFFFFFFE ;//通过清除启用位来禁用计数器

I would like to count the number of Instructions per Cycle executed on an ARM cortex-M4 (or cortex-M3) processor.

What it's needed is: number of instructions (executed at runtime) of the code I want to profile and number of cycles that the code takes to execute.

1 - Number of Cycles

Use the cycle counter is quite easy and straightforward.

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 - Number of Instructions

I found some documentation surfing the internet to count the number of instructions executed by the arm cortex-M3 and cortex-M4 (link):

  # instructions = CYCCNT - CPICNT - EXCCNT - SLEEPCNT - LSUCNT + FOLDCNT

The registers that they mention are documented here (from page 11-13) and these are the memory addresses to access them:

DWT_CYCCNT   = 0xE0001004
DWT_CONTROL  = 0xE0001000
SCB_DEMCR    = 0xE000EDFC
DWT_CPICNT   = 0xE0001008
DWT_EXCCNT   = 0xE000100C
DWT_SLEEPCNT = 0xE0001010
DWT_LSUCNT   = 0xE0001014
DWT_FOLDCNT  = 0xE0001018

The DWT_CONTROL register is used to enable counters, especially cycle counter as documented here.

But when I tried to put all together to count the number of instructions executed per cycle I didn't succeed.

Here there is a small guide on how to use them from gdb.

What is not easy is that some registers are 8 bit registers (DWT_CPICNT, DWT_EXCCNT, DWT_SLEEPCNT, DWT_LSUCNT, DWT_FOLDCNT) and when they overflow they trigger an event. I didn't find a way to collect that event. There are no code snippet that explains how to do that or interrupt routines suitable for that.

It seems moreover that using watchpoints from gdb on the addresses of those registers doesn't work. gdb is not able to stop when registers change value. E.g. on DWT_LSUCNT:

(gdb) watch *0xE0001014

Update: I found this project on GitHub explaining how to use DWT, ITM and ETM units. But I didn't check if it works! I will post updates.

Any idea on how to use them?

Thank you!

解决方案

The code sample you provided has a problem in clearing the enable bit. You should clear the bit using 'AND' not 'OR':

*DWT_CONTROL = *DWT_CONTROL & 0xFFFFFFFE ; // disable the counter by clearing the enable bit

这篇关于ARM M4 每周期指令 (IPC) 计数器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆