ADuCM4x50 Device Drivers API Reference Manual  Release 4.0.0.0
adi_cyclecount.c
1 
15 #include <adi_cyclecount.h>
16 #include <common.h>
17 #include <adi_processor.h>
18 #include <rtos_map/adi_rtos_map.h>
19 #include <assert.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stdbool.h>
23 #include <string.h>
24 #include <stdint.h>
25 
26 
60 #ifdef __ICCARM__
61 
62 /*
63  * IAR MISRA C 2004 error suppressions.
64  *
65  * Pm073 (rule 14.7): a function should have a single point of exit
66  * Pm143 (rule 14.7): a function should have a single point of exit at the end of the function
67  * Multiple returns are used for error handling.
68  * Pm023 (rule 9.2): Braces shall be used to indicate and match the structure in the non-zero initialization of arrays and structures.
69  * 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.
70  *
71  */
72 #pragma diag_suppress=Pm143,Pm073,Pm023
73 #endif /* __ICCARM__ */
74 
81 #define ADI_CYCLECOUNT_TOTAL_ID_SZ (ADI_CYCLECOUNT_ID_COUNT + ADI_CYCLECOUNT_NUMBER_USER_DEFINED_APIS)
82 
83 /*
84  * Names of items for which cycle counting can be enabled.
85  */
86 static const char * adi_cyclecounting_identifiers[ADI_CYCLECOUNT_TOTAL_ID_SZ] = {
87  "",
88  "ISR_EXT_3",
89  "ISR_UART",
90  "ISR_DMA_UART_TX",
91  "ISR_DMA_UART_RX",
92  "ISR_TMR_COMMON",
93  "ISR_RTC",
94  "ISR_SPI",
95  "ISR_CRC",
96  "ISR_SPORT"
97 };
98 
99 static uint32_t adi_cyclecounting_identifiers_index = ADI_CYCLECOUNT_ID_COUNT;
100 
101 /*
102  * Data structure to keep track of the per item cycle counts
103  */
105 
109 static volatile uint32_t nNumSystickInterrupts = 0u;
110 
111 #if ADI_CYCLECOUNT_ENABLED == 1u
112 void SysTick_Handler(void);
113 
119 void SysTick_Handler(void)
120 {
121  ISR_PROLOG()
122  nNumSystickInterrupts++; /* Bump the number of times systick has fired an interrupt */
123  ISR_EPILOG()
124 }
125 #endif
126 
145 static struct
146 {
149 } cycle_count_stack[ADI_CYCLECOUNT_STACK_SIZE];
150 
151 /* The "top of the cycle counting stack". Used to index into the cycle_count_stack[] array */
152 static int32_t cycle_count_stack_ndx = ADI_CYCLECOUNT_INITIAL_STACK_INDEX;
153 
163 {
164  ADI_INT_STATUS_ALLOC();
165  ADI_ENTER_CRITICAL_REGION();
166 
167  adi_cyclecount_t systickValue = (uint64_t)ADI_CYCLECOUNT_SYSTICKS - SysTick->VAL; /* down counter */
168  systickValue = systickValue + ((uint64_t)ADI_CYCLECOUNT_SYSTICKS * nNumSystickInterrupts);
169 
170  ADI_EXIT_CRITICAL_REGION();
171  return systickValue;
172 }
173 
192 {
193  if( (ADI_CYCLECOUNT_STACK_SIZE-1) == cycle_count_stack_ndx)
194  {
195  return ADI_CYCLECOUNT_FAILURE; /* need to increase the size of the nesting stack ADI_CYCLECOUNT_STACK_SIZE. */
196  }
197  cycle_count_stack_ndx++;
198 
199  cycle_count_stack[cycle_count_stack_ndx].starting_cycle_count = adi_cyclecount_get();
200  cycle_count_stack[cycle_count_stack_ndx].adjusted_cycle_count = 0u;
201 
202  return ADI_CYCLECOUNT_SUCCESS;
203 }
204 
221 {
222  if( cycle_count_stack_ndx == ADI_CYCLECOUNT_INITIAL_STACK_INDEX )
223  {
224  /* start/stop mismatch. Every call to adi_cyclecount_start() should be paired with */
225  /* a call to adi_cyclecount_stop(). */
226  return ADI_CYCLECOUNT_FAILURE;
227  }
228  /* Check for nesting. If we are stacked up on top of another item's cycle count then */
229  /* record the time spent at this cycle counting nesting level. This will allow the */
230  /* nested context to subtract this number of cycles. */
231  if( cycle_count_stack_ndx > 0 )
232  {
233 
234  /* stacked cycle counts probably caused by an ISR */
235  /* adjust by adding in the number of cycles taken by the interrupting code */
236  adi_cyclecount_t currentTime = adi_cyclecount_get();
237  adi_cyclecount_t elapsedTime = currentTime -
238  cycle_count_stack[cycle_count_stack_ndx].starting_cycle_count -
239  cycle_count_stack[cycle_count_stack_ndx].adjusted_cycle_count;
240 
241  /* compute the number of cycles that the interrupting code consumed and store this */
242  /* number at next cycle counting stack level */
243  cycle_count_stack[cycle_count_stack_ndx-1].adjusted_cycle_count += elapsedTime;
244 
245  }
246 
247  cycle_count_stack_ndx--;
248  return ADI_CYCLECOUNT_SUCCESS;
249 }
250 
261  uint32_t i;
262 
263  /* Configure SysTick */
264  SysTick_Config(ADI_CYCLECOUNT_SYSTICKS);
265 
266  /* initialize log */
267  for(i=0u; i<ADI_CYCLECOUNT_TOTAL_ID_SZ; i++){
268  cycleCounts[i].min_cycles_adjusted = UINT64_MAX;
269  cycleCounts[i].max_cycles_adjusted = 0u;
270  cycleCounts[i].average_cycles_adjusted = 0u;
271  cycleCounts[i].min_cycles_unadjusted = UINT64_MAX;
272  cycleCounts[i].max_cycles_unadjusted = 0u;
273  cycleCounts[i].average_cycles_unadjusted = 0u;
274  cycleCounts[i].sample_count = 0u;
275  }
276 
277  return;
278 }
279 
297 ADI_CYCLECOUNT_RESULT adi_cyclecount_addEntity(const char *EntityName, uint32_t *pid)
298 {
299 
300  if( adi_cyclecounting_identifiers_index >= (ADI_CYCLECOUNT_TOTAL_ID_SZ))
301  {
303  }
304 
305  adi_cyclecounting_identifiers[adi_cyclecounting_identifiers_index] = EntityName;
306  *pid = adi_cyclecounting_identifiers_index;
307  adi_cyclecounting_identifiers_index++;
308 
309  return ADI_CYCLECOUNT_SUCCESS;
310 }
311 
312 
327 
328 #ifdef ADI_DEBUG
329  if( (id == 0u) || (id >= (ADI_CYCLECOUNT_TOTAL_ID_SZ)))
330  {
332  }
333  if( (cycle_count_stack_ndx < 0) || ((cycle_count_stack_ndx >= ADI_CYCLECOUNT_STACK_SIZE)))
334  {
335  return ADI_CYCLECOUNT_FAILURE;
336  }
337 
338 #endif
339 
340  adi_cyclecount_t systickValue = adi_cyclecount_get();
341 
342  cycleCounts[id].sample_count++;
343 
344  adi_cyclecount_t startCycleCount = cycle_count_stack[cycle_count_stack_ndx].starting_cycle_count;
345  adi_cyclecount_t adjustCycles = cycle_count_stack[cycle_count_stack_ndx].adjusted_cycle_count;
346  adjustCycles += startCycleCount;
347 
348  adi_cyclecount_t adjustedValue = systickValue - adjustCycles;
349 
350  /****************************************************
351  * Update the adjusted cycle counts
352  ***************************************************/
353  if(adjustedValue > cycleCounts[id].max_cycles_adjusted ){
354  cycleCounts[id].max_cycles_adjusted = adjustedValue;
355  }
356  if(adjustedValue < cycleCounts[id].min_cycles_adjusted){
357  cycleCounts[id].min_cycles_adjusted = adjustedValue;
358  }
359  /* Accumulate the total cycle count from which the average will be calcuated */
360  cycleCounts[id].average_cycles_adjusted += adjustedValue;
361 
362  /****************************************************
363  * Update the unadjusted cycle counts
364  ****************************************************/
365  adi_cyclecount_t unadjustedCycleCount = systickValue - startCycleCount;
366  if(unadjustedCycleCount > cycleCounts[id].max_cycles_unadjusted ){
367  cycleCounts[id].max_cycles_unadjusted = unadjustedCycleCount;
368  }
369  if(unadjustedCycleCount < cycleCounts[id].min_cycles_unadjusted){
370  cycleCounts[id].min_cycles_unadjusted = unadjustedCycleCount;
371  }
372  /* Accumulate the total cycle count from which the average will be calcuated */
373  cycleCounts[id].average_cycles_unadjusted += unadjustedCycleCount;
374 
375  return ADI_CYCLECOUNT_SUCCESS;
376 }
377 
378 
392 
393  DEBUG_MESSAGE(" Cycle Count Report\n");
394  DEBUG_MESSAGE(" Adjusted Cycle Counts Unadjusted Cycles Counts No. Samples\n");
395  DEBUG_MESSAGE(" _____________________________ ____________________________ ___________\n");
396  DEBUG_MESSAGE("ISR/API Minimum Maximum Average Minimum Maximum Average\n");
397 
398  for(i=1u; i<(uint32_t)ADI_CYCLECOUNT_TOTAL_ID_SZ; i++){
399 
400  if( cycleCounts[i].sample_count )
401  {
402 
403  DEBUG_MESSAGE(
404  "%15s %10llu %10llu %10llu %10llu %10llu %10llu %10lu\n",
405  adi_cyclecounting_identifiers[i],
406  cycleCounts[i].min_cycles_adjusted,
407  cycleCounts[i].max_cycles_adjusted,
408  cycleCounts[i].average_cycles_adjusted/cycleCounts[i].sample_count,
409  cycleCounts[i].min_cycles_unadjusted,
410  cycleCounts[i].max_cycles_unadjusted,
411  cycleCounts[i].average_cycles_unadjusted/cycleCounts[i].sample_count,
412  cycleCounts[i].sample_count
413  );
414  }
415  }
416 
417  return;
418 }
419 
420 
421 /* @} */
#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