Счетчики ARM M4 для каждого цикла (IPC)

Я хотел бы подсчитать количество инструкций за цикл, выполненных на процессоре 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), и когда они переполняются, они вызывают событие. Я не нашел способ собрать это событие. Нет fragmentа кода, который объясняет, как это сделать или подпрограммы, подходящие для этого.

Более того, похоже, что использование точек наблюдения из gdb по адресам этих регистров не работает. gdb не может остановиться, когда регистры меняют значение. Например, DWT_LSUCNT:

 (gdb) watch *0xE0001014 

Обновление: Я нашел этот проект в GitHub, объясняющем, как использовать модули DWT, ITM и ETM. Но я не проверял, работает ли это! Я опубликую обновления.

Любая идея о том, как их использовать?

Спасибо!

    В примере кода, который вы указали, возникла проблема при очистке бит разрешения. Вы должны очистить бит «AND», а не «OR»:

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

    Я понятия не имею, как использовать регистры так, как вы хотите их использовать. Но вот как я занимаюсь измерительными циклами.

    Убедитесь, что вы активируете счетчик в регистре управления и регистрации SysTick . С соответствующими заголовками вы должны иметь доступ к регистрам SysTick как структуре.

    Измерьте количество циклов, выполняемых функцией счетчика. Это позже вычитается из любых измерений.

      SysTick->VAL = 0; // set 0 // Measure delay on measurement __disable_irq(); a = (uint32_t) SysTick->VAL; //... measuring zero instructions b = (uint32_t) SysTick->VAL; __enable_irq(); measure_delay = a - b; 

    Теперь измерим функцию.

     SysTick->VAL = 0; __disable_irq(); a = (uint32_t) SysTick->VAL; //Assuming this function doesn't require interruptions // INSERT CODE TO BE PROFILED function_to_be_examined(); b = (uint32_t) SysTick->VAL; __enable_irq(); cycles_profiled_code = a - b - measure_delay; 

    Я надеюсь, что это помогает.

    Я думаю, что если вы хотите измерить циклы точности, использование отладчика – хороший выбор. Keil-MDK может накапливать государственный регистр и не будет переполняться. результат в отладчике совпадает с результатом с использованием DWT.

    если вы хотите измерить другие значения, т.е. FOLDCNT, используя трассировку в Keil-MDK -> Debug -> Setting -> Trace -> Trace Enable.

    При этом во время отладки в окне Trace Windows выберите событие трассировки, значение этого 8-битного регистра может быть собрано и добавлено вместе Keil.

    Это кажется немного глупым, но я не знаю, как собрать событие переполнения, я думаю, что это событие может быть отправлено только ITM, потому что либо DWT, либо ITM – это отдельный компонент из программы. если мы хотим собрать мероприятие в программе клиента, действие collect должно будет влиять на точность результата.

    ITM? ЭТМ? CoreSight? DWT? AHB?