Я хотел бы подсчитать количество инструкций за цикл, выполненных на процессоре ARM cortex-M4 (или cortex-M3).
В чем он нуждается: количество инструкций (выполняется во время выполнения) кода, который я хочу профилировать, и количество циклов, которое должен выполнить код. p >
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 - количество инструкций
Я нашел некоторую документацию для серфинга в Интернете, чтобы подсчитать количество инструкций, выполненных консолью cortex-M3 и cortex-M4 (ссылка):
# instructions = CYCCNT - CPICNT - EXCCNT - SLEEPCNT - LSUCNT + FOLDCNT
Регистры, о которых они упоминают, документированы здесь (со страницы 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. Но я не проверял, работает ли это! Я буду публиковать обновления.
Любая идея о том, как их использовать?
Спасибо!