ADuCM302x Device Drivers API Reference Manual  Release 3.1.2.0
adi_cyclecount.c
1 /*
2  *******************************************************************************
3  * @file: cyclecount_logging.c
4  *
5  * @brief: Framework to preform cycle count measurements
6  *
7  * @details this is a framework for monitoring the cycle counts, specifically
8  * for ISRs and low level function.
9 
10 *******************************************************************************
11 
12  Copyright(c) 2016 Analog Devices, Inc. All Rights Reserved.
13 
14  This software is proprietary and confidential. By using this software you agree
15  to the terms of the associated Analog Devices License Agreement.
16 
17  ******************************************************************************/
18 
19 #include <adi_cyclecount.h>
20 #include <common.h>
21 #include <adi_processor.h>
22 #include <rtos_map/adi_rtos_map.h>
23 #include <assert.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stdbool.h>
27 #include <string.h>
28 #include <stdint.h>
29 
30 
64 #ifdef __ICCARM__
65 
66 /*
67  * IAR MISRA C 2004 error suppressions.
68  *
69  * Pm073 (rule 14.7): a function should have a single point of exit
70  * Pm143 (rule 14.7): a function should have a single point of exit at the end of the function
71  * Multiple returns are used for error handling.
72  * Pm023 (rule 9.2): Braces shall be used to indicate and match the structure in the non-zero initialization of arrays and structures.
73  * Braces cannot be used to indicate and match the structure in the non-zero initialization of arrays because the total size of the array is defined by a configuration macro.
74  *
75  */
76 #pragma diag_suppress=Pm143,Pm073,Pm023
77 #endif /* __ICCARM__ */
78 
85 #define ADI_CYCLECOUNT_TOTAL_ID_SZ (ADI_CYCLECOUNT_ID_COUNT + ADI_CYCLECOUNT_NUMBER_USER_DEFINED_APIS)
86 
87 /*
88  * Names of items for which cycle counting can be enabled.
89  */
90 static const char * adi_cyclecounting_identifiers[ADI_CYCLECOUNT_TOTAL_ID_SZ] = {
91  "",
92  "ISR_EXT_3",
93  "ISR_UART",
94  "ISR_DMA_UART_TX",
95  "ISR_DMA_UART_RX",
96  "ISR_TMR_COMMON",
97  "ISR_RTC",
98  "ISR_SPI",
99  "ISR_CRC",
100  "ISR_SPORT"
101 };
102 
103 static uint32_t adi_cyclecounting_identifiers_index = ADI_CYCLECOUNT_ID_COUNT;
104 
105 /*
106  * Data structure to keep track of the per item cycle counts
107  */
109 
113 static volatile uint32_t nNumSystickInterrupts = 0u;
114 
115 #if ADI_CYCLECOUNT_ENABLED == 1u
116 void SysTick_Handler(void);
117 
123 void SysTick_Handler(void)
124 {
125  ISR_PROLOG()
126  nNumSystickInterrupts++; /* Bump the number of times systick has fired an interrupt */
127  ISR_EPILOG()
128 }
129 #endif
130 
149 static struct
150 {
153 } cycle_count_stack[ADI_CYCLECOUNT_STACK_SIZE];
154 
155 /* The "top of the cycle counting stack". Used to index into the cycle_count_stack[] array */
156 static int32_t cycle_count_stack_ndx = ADI_CYCLECOUNT_INITIAL_STACK_INDEX;
157 
167 {
168  ADI_INT_STATUS_ALLOC();
169  ADI_ENTER_CRITICAL_REGION();
170 
171  adi_cyclecount_t systickValue = (uint64_t)ADI_CYCLECOUNT_SYSTICKS - SysTick->VAL; /* down counter */
172  systickValue = systickValue + ((uint64_t)ADI_CYCLECOUNT_SYSTICKS * nNumSystickInterrupts);
173 
174  ADI_EXIT_CRITICAL_REGION();
175  return systickValue;
176 }
177 
196 {
197  if( (ADI_CYCLECOUNT_STACK_SIZE-1) == cycle_count_stack_ndx)
198  {
199  return ADI_CYCLECOUNT_FAILURE; /* need to increase the size of the nesting stack ADI_CYCLECOUNT_STACK_SIZE. */
200  }
201  cycle_count_stack_ndx++;
202 
203  cycle_count_stack[cycle_count_stack_ndx].starting_cycle_count = adi_cyclecount_get();
204  cycle_count_stack[cycle_count_stack_ndx].adjusted_cycle_count = 0u;
205 
206  return ADI_CYCLECOUNT_SUCCESS;
207 }
208 
225 {
226  if( cycle_count_stack_ndx == ADI_CYCLECOUNT_INITIAL_STACK_INDEX )
227  {
228  /* start/stop mismatch. Every call to adi_cyclecount_start() should be paired with */
229  /* a call to adi_cyclecount_stop(). */
230  return ADI_CYCLECOUNT_FAILURE;
231  }
232  /* Check for nesting. If we are stacked up on top of another item's cycle count then */
233  /* record the time spent at this cycle counting nesting level. This will allow the */
234  /* nested context to subtract this number of cycles. */
235  if( cycle_count_stack_ndx > 0 )
236  {
237 
238  /* stacked cycle counts probably caused by an ISR */
239  /* adjust by adding in the number of cycles taken by the interrupting code */
240  adi_cyclecount_t currentTime = adi_cyclecount_get();
241  adi_cyclecount_t elapsedTime = currentTime -
242  cycle_count_stack[cycle_count_stack_ndx].starting_cycle_count -
243  cycle_count_stack[cycle_count_stack_ndx].adjusted_cycle_count;
244 
245  /* compute the number of cycles that the interrupting code consumed and store this */
246  /* number at next cycle counting stack level */
247  cycle_count_stack[cycle_count_stack_ndx-1].adjusted_cycle_count += elapsedTime;
248 
249  }
250 
251  cycle_count_stack_ndx--;
252  return ADI_CYCLECOUNT_SUCCESS;
253 }
254 
265  uint32_t i;
266 
267  /* Configure SysTick */
268  SysTick_Config(ADI_CYCLECOUNT_SYSTICKS);
269 
270  /* initialize log */
271  for(i=0u; i<ADI_CYCLECOUNT_TOTAL_ID_SZ; i++){
272  cycleCounts[i].min_cycles_adjusted = UINT64_MAX;
273  cycleCounts[i].max_cycles_adjusted = 0u;
274  cycleCounts[i].average_cycles_adjusted = 0u;
275  cycleCounts[i].min_cycles_unadjusted = UINT64_MAX;
276  cycleCounts[i].max_cycles_unadjusted = 0u;
277  cycleCounts[i].average_cycles_unadjusted = 0u;
278  cycleCounts[i].sample_count = 0u;
279  }
280 
281  return;
282 }
283 
301 ADI_CYCLECOUNT_RESULT adi_cyclecount_addEntity(const char *EntityName, uint32_t *pid)
302 {
303 
304  if( adi_cyclecounting_identifiers_index >= (ADI_CYCLECOUNT_TOTAL_ID_SZ))
305  {
307  }
308 
309  adi_cyclecounting_identifiers[adi_cyclecounting_identifiers_index] = EntityName;
310  *pid = adi_cyclecounting_identifiers_index;
311  adi_cyclecounting_identifiers_index++;
312 
313  return ADI_CYCLECOUNT_SUCCESS;
314 }
315 
316 
331 
332 #ifdef ADI_DEBUG
333  if( (id == 0u) || (id >= (ADI_CYCLECOUNT_TOTAL_ID_SZ)))
334  {
336  }
337  if( (cycle_count_stack_ndx < 0) || ((cycle_count_stack_ndx >= ADI_CYCLECOUNT_STACK_SIZE)))
338  {
339  return ADI_CYCLECOUNT_FAILURE;
340  }
341 
342 #endif
343 
344  adi_cyclecount_t systickValue = adi_cyclecount_get();
345 
346  cycleCounts[id].sample_count++;
347 
348  adi_cyclecount_t startCycleCount = cycle_count_stack[cycle_count_stack_ndx].starting_cycle_count;
349  adi_cyclecount_t adjustCycles = cycle_count_stack[cycle_count_stack_ndx].adjusted_cycle_count;
350  adjustCycles += startCycleCount;
351 
352  adi_cyclecount_t adjustedValue = systickValue - adjustCycles;
353 
354  /****************************************************
355  * Update the adjusted cycle counts
356  ***************************************************/
357  if(adjustedValue > cycleCounts[id].max_cycles_adjusted ){
358  cycleCounts[id].max_cycles_adjusted = adjustedValue;
359  }
360  if(adjustedValue < cycleCounts[id].min_cycles_adjusted){
361  cycleCounts[id].min_cycles_adjusted = adjustedValue;
362  }
363  /* Accumulate the total cycle count from which the average will be calcuated */
364  cycleCounts[id].average_cycles_adjusted += adjustedValue;
365 
366  /****************************************************
367  * Update the unadjusted cycle counts
368  ****************************************************/
369  adi_cyclecount_t unadjustedCycleCount = systickValue - startCycleCount;
370  if(unadjustedCycleCount > cycleCounts[id].max_cycles_unadjusted ){
371  cycleCounts[id].max_cycles_unadjusted = unadjustedCycleCount;
372  }
373  if(unadjustedCycleCount < cycleCounts[id].min_cycles_unadjusted){
374  cycleCounts[id].min_cycles_unadjusted = unadjustedCycleCount;
375  }
376  /* Accumulate the total cycle count from which the average will be calcuated */
377  cycleCounts[id].average_cycles_unadjusted += unadjustedCycleCount;
378 
379  return ADI_CYCLECOUNT_SUCCESS;
380 }
381 
382 
396 
397  DEBUG_MESSAGE(" Cycle Count Report\n");
398  DEBUG_MESSAGE(" Adjusted Cycle Counts Unadjusted Cycles Counts No. Samples\n");
399  DEBUG_MESSAGE(" _____________________________ ____________________________ ___________\n");
400  DEBUG_MESSAGE("ISR/API Minimum Maximum Average Minimum Maximum Average\n");
401 
402  for(i=1u; i<(uint32_t)ADI_CYCLECOUNT_TOTAL_ID_SZ; i++){
403 
404  if( cycleCounts[i].sample_count )
405  {
406 
407  DEBUG_MESSAGE(
408  "%15s %10llu %10llu %10llu %10llu %10llu %10llu %10lu\n",
409  adi_cyclecounting_identifiers[i],
410  cycleCounts[i].min_cycles_adjusted,
411  cycleCounts[i].max_cycles_adjusted,
412  cycleCounts[i].average_cycles_adjusted/cycleCounts[i].sample_count,
413  cycleCounts[i].min_cycles_unadjusted,
414  cycleCounts[i].max_cycles_unadjusted,
415  cycleCounts[i].average_cycles_unadjusted/cycleCounts[i].sample_count,
416  cycleCounts[i].sample_count
417  );
418  }
419  }
420 
421  return;
422 }
423 
424 
425 /* @} */
#define ADI_CYCLECOUNT_STACK_SIZE
ADI_CYCLECOUNT_RESULT adi_cyclecount_store(uint32_t id)
Store Cycle Count.
adi_cyclecount_t adjusted_cycle_count
adi_cyclecount_t average_cycles_unadjusted
#define ADI_CYCLECOUNT_SYSTICKS
#define ADI_CYCLECOUNT_ID_COUNT
#define ADI_CYCLECOUNT_INITIAL_STACK_INDEX
void adi_cyclecount_report(void)
Generate a cycle count report.
uint64_t adi_cyclecount_t
adi_cyclecount_t starting_cycle_count
void SysTick_Handler(void)
#define ADI_CYCLECOUNT_TOTAL_ID_SZ
adi_cyclecount_t average_cycles_adjusted
adi_cyclecount_t adi_cyclecount_get(void)
Read the current number of cycle counts.
ADI_CYCLECOUNT_RESULT adi_cyclecount_start(void)
API to be called to start a new cycle counting context.
ADI_CYCLECOUNT_RESULT
adi_cyclecount_t max_cycles_adjusted
ADI_CYCLECOUNT_RESULT adi_cyclecount_addEntity(const char *EntityName, uint32_t *pid)
Add an ISR/API to the cycle counting list.
adi_cyclecount_t max_cycles_unadjusted
ADI_CYCLECOUNT_RESULT adi_cyclecount_stop(void)
Cycle Count Stop.
void adi_cyclecount_init(void)
API to be called to initialize the cycle counting framework.
adi_cyclecount_t min_cycles_adjusted
adi_cyclecount_t min_cycles_unadjusted