Я хотел бы подсчитать количество инструкций за цикл, выполненных на процессоре ARM cortex-M4 (или cortex-M3).Счетчики ARM M4 в цикле (IPC)
Что нужно, это: количество инструкций (выполняемых во время выполнения) кода я хочу профилировать и число циклов, что код требуется для выполнения.
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 (link):
# 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 используется для включения счетчиков, особенно счетчика циклов, как задокументировано here.
Но когда я попытался собрать все вместе, чтобы подсчитать количество инструкций, выполненных за цикл, мне не удалось.
Here есть небольшой справочник о том, как использовать их из gdb.
Нелегко, что некоторые регистры являются 8-битными регистрами (DWT_CPICNT, DWT_EXCCNT, DWT_SLEEPCNT, DWT_LSUCNT, DWT_FOLDCNT), и когда они переполняются, они вызывают событие. Я не нашел способ собрать это событие. Нет фрагмента кода, который объясняет, как это сделать или подпрограммы, подходящие для этого.
Похоже, что использование точек наблюдения из gdb по адресам этих регистров не работает. gdb не может остановиться, когда регистры меняют значение. Например. на DWT_LSUCNT:
(gdb) watch *0xE0001014
Обновление: Я нашел этот project на GitHub объясняет, как использовать DWT, ITM и ETM единиц. Но я не проверял, работает ли это! Я опубликую обновления.
Любая идея о том, как их использовать?
Спасибо!
Возможно, слишком очевидно, но вы всегда вызываете reset_timer() перед выполнением любой другой функции, правильно? Не могли бы вы разместить код вызова, как минимальный пример? – Lundin
Я бы предложил объявить регистры как '#define DWT_CYCCNT (* (volatile uint32_t *) 0xE0001004ul) вместо этого. – Lundin
Являются ли события не отладки событий, которые могут вызвать исключение отладочного монитора? – Notlikethat