Cycle Counter

Features Supported

  • API to return CPU cycles executed so far

  • API to reset the CPU cycle counter

Features NOT Supported

  • Additional event counters in the CPU are not supported via this API. Refer to CPU architecture specific technical and architecture reference manuals, to access additional CPU architecture specific counter features.

Important Usage Guidelines

  • Make sure to call CycleCounterP_reset() to enable and reset the CPU cycle counter before using it

  • CycleCounterP_getCount32() uses a CPU architecture specific counter to count every CPU cycle. Since this is a 32b counter, this will typically wraparound and overflow within few seconds. E.g. for 500Mhz CPU, the counter will overflow in ~ 8secs.

  • Application can have logic to handle one wraparound of the counter, as shown in the example usage below. i.e max time duration that can be measured will be limited to 0xFFFFFFFF CPU cycles, i.e few seconds only.

  • This API is meant to used for very fine, short duration measurements. To measure longer durations use ClockP_getTimeUsec() from Clock module.

  • Cortex A53 and TI C75 have 64b counter, so use CycleCounterP_getCount64(). The CycleCounterP_getCount32() API typecasts 64b value to 32b value for these cores.

  • R5F + FreeRTOS limitation: On R5F cores running FreeRTOS, the underlying ARM PMU cycle counter (PMCCNTR) stops incrementing while the core is in the WFI (Wait For Interrupt) low-power state executed by the FreeRTOS idle task. As a result, CycleCounterP_getCount32() reflects only the cycles during which the core is actively executing code, and will significantly under-count wall-clock elapsed time during idle periods (e.g. inside ClockP_usleep()). Use ClockP_getTimeUsec() for wall-clock time measurement on R5F FreeRTOS.

Example Usage

Include the below file to access the APIs,


//! [include]
#include <kernel/dpl/CycleCounterP.h>
#include <kernel/dpl/DebugP.h>
//! [include]
 


void samples()
{

Example usage for counting CPU cycles:

//! [usage]
        uint32_t cycleCountBefore, cycleCountAfter, cpuCycles;

        /* enable and reset CPU cycle coutner */
        CycleCounterP_reset();

        cycleCountBefore = CycleCounterP_getCount32();

        /* call functions to profile */

        cycleCountAfter = CycleCounterP_getCount32();

        /* Check for overflow and wrap around. 
         *
         * This logic will only work for one overflow.
         * If multiple overflows happen during the profile period, 
         * then CPU cycles count will be wrong, 
         */
        if(cycleCountAfter > cycleCountBefore)
        {
            cpuCycles = cycleCountAfter - cycleCountBefore;
        }
        else
        {
            cpuCycles = (0xFFFFFFFFU - cycleCountBefore) + cycleCountAfter;
        }
        DebugP_log("CPU cycles:%u\n", cpuCycles);
//! [usage]         
    }

API Reference

Functions

void CycleCounterP_init(const uint64_t cpuFreqHz)

initialize PMU Cycle Counter

uint32_t CycleCounterP_getCount32(void)

Get 32b CPU cycle counter value.

For A53 and C75 CPUs, this API typecast a 64-bit register to 32-bit value. It is recommended to use CycleCounterP_getCount64() for A53 and C75 cores.

Make sure to handle overflow condition in your application.

Note

R5F + FreeRTOS limitation: On R5F cores running FreeRTOS, the underlying ARM PMU cycle counter (PMCCNTR) stops incrementing while the core is in the WFI (Wait For Interrupt) low-power state that the FreeRTOS idle task executes. As a result, this API under-counts wall-clock elapsed time whenever the CPU is idle. It accurately reflects only the cycles during which the core is actively executing code. Use ClockP_getTimeUsec() for wall-clock time measurement on R5F FreeRTOS.

Returns:

32b cycle counter value

void CycleCounterP_reset(void)

Enable, reset, clear overflow for CPU cycle counter.

  • Call this API atleast once before using CycleCounterP_getCount32() to reset and enable the counter

  • Call this API to reset counter to zero.

uint64_t CycleCounterP_getCount64(void)

Get 64b CPU cycle counter value.

Only support with below CPUs,

  • A53, C75

Returns:

64b cycle counter value

uint64_t CycleCounterP_nsToTicks(const uint64_t nanosecs)

API function to convert nanosecs to PMU counter ticks.

Parameters:

nanosecs – time unit in nano sec

Returns:

PMU counter ticks