Я хотел бы подсчитать количество инструкций за цикл, выполняемых на процессоре 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 - Количество инструкций
Я нашел документацию в Интернете, чтобы подсчитать количество инструкций, выполненных руками 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. Но не проверял, работает ли! Я буду размещать обновления.
Есть идеи, как их использовать?
Спасибо!
#define DWT_CYCCNT (*(volatile uint32_t*)0xE0001004ul)
. - person Lundin   schedule 16.09.2015