3.性能分析

性能分析用于将优化工作集中在占大部分运行时的函数上。

下面是几种不同的性能分析方法:

  • Code Composer Studio™ (CCS) 性能分析时钟功能
  • CPUTimer
  • CPUTimer 和函数入口/出口挂钩
  • 切换 GPIO 引脚

3.1.CCS 性能分析时钟

Code Composer Studio 性能分析时钟功能可用于计算从一个断点到下一个断点的周期数。这是确定任意代码区域所占用周期数的快速方法。

3.2.CPUTimer

使用 CPUTimer 是一种编程方法,用于确定代码中任意两点之间的周期数。例如,列表 3.3 说明了如何使用 CPUTimer 确定循环所占用的周期数。

列表 3.1 CPUTimer 头文件 (cycle_counter.h)
1 2 3 4 5 6 7 8 9 10
#ifndef _CYCLE_COUNTER_H_#define _CYCLE_COUNTER_H_#include<stdint.h>voidCycleCounter_Init(void);uint32_tCycleCounter_Read(void);voidCycleCounter_Stop(void);#endif
列表 3.2 CPUTimer 源文件 (cycle_counter.c)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
#include"common/inc/cycle_counter.h"#include"driverlib/cputimer.h"#define CPUTIMER_MAX_PERIOD (0xFFFFFFFFUL)voidCycleCounter_Init(void){CPUTimer_clearOverflowFlag(CPUTIMER1_BASE);CPUTimer_setPeriod(CPUTIMER1_BASE,CPUTIMER_MAX_PERIOD);CPUTimer_setPreScaler(CPUTIMER1_BASE,0UL);CPUTimer_reloadTimerCounter(CPUTIMER1_BASE);CPUTimer_stopTimer(CPUTIMER1_BASE);CPUTimer_startTimer(CPUTIMER1_BASE);}voidCycleCounter_Stop(void){CPUTimer_stopTimer(CPUTIMER1_BASE);}// With higher levels of optimization, it’s possible that the compiler moves// application code before the first call to CycleCounter_Read() or after the// second call to CycleCounter_Read().This can result in the reported cycle// count being lower than the actual cycle count.// Disabling inlining of CycleCounter_Read prevents this from occurring.#pragma FUNC_CANNOT_INLINE(CycleCounter_Read)uint32_tCycleCounter_Read(void){returnCPUTIMER_MAX_PERIOD-CPUTimer_getTimerCount(CPUTIMER1_BASE);}

注释

  • 为简单起见,此实现不考虑溢出。
  • 有关 DriverLib CPU Timer 函数的详细信息,请参阅器件的 DriverLib 用户指南。例如,F28004x 的用户指南可参见<C2000Wareinstalldir>/device_support/f28004x/docs/F28004x_DriverLib_Users_Guide.pdf
列表 3.3 CPUTimer 示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14
CycleCounter_Init();uint32_tstart=CycleCounter_Read();uint32_toverhead=CycleCounter_Read()-start;start=CycleCounter_Read();inti;for(i=0;i<100;i++)asm("\tNOP;");uint32_ttime=CycleCounter_Read()-start-overhead;printf("Cycles: %ld\n",time);

3.3.具有函数入口/出口挂钩的 CPUTimer

CPUTimer 可以与编译器中可用的函数入口/出口挂钩功能相结合,以生成快速性能分析器。

当使用 --entry_hook--exit_hook 选项启用入口/出口挂钩功能时,编译器会在进入程序中的每个函数时插入对入口挂钩的调用。编译器还会在退出每个函数时插入对出口挂钩的调用。请参阅 TMS320C28x 优化 C/C++ 编译器用户指南中的第 2.14 节“启用入口挂钩和出口挂钩函数”。

列表 3.4 展示了使用入口和出口挂钩以及 CPUTimer 来实现一个简单的性能分析器。

列表 3.4 使用入口和出口挂钩来实现性能分析器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
#include"common/inc/cycle_counter.h"#include"common/inc/profiling_hooks.h"#include<stdio.h>#define MAX_ENTRIES (64)// Indicate if the timestamp is associated with function entry or exittypedefenum{PD_ENTRY=0,PD_EXIT}PD_Mode;// Struct for data associated with a single timestamptypedefstruct{uint32_tfunction_address;uint32_ttimestamp;PD_Modemode;}ProfileData;// Array to store profile dataProfileDatatable[MAX_ENTRIES];intindex=0;// Entry hook function used to record cycle count on entry into functionvoid__entry_hook(void(*addr)()){if(index>=MAX_ENTRIES)return;table[index].function_address=(uint32_t)addr;table[index].mode=PD_ENTRY;table[index].timestamp=CycleCounter_Read();index++;}// Exit hook function used to record cycle count on exit from functionvoid__exit_hook(void(*addr)()){if(index>=MAX_ENTRIES)return;table[index].timestamp=CycleCounter_Read();table[index].function_address=(uint32_t)addr;table[index].mode=PD_EXIT;index++;}

对于包含需要进行性能分析的函数的文件,使用 --entry_hook--entry_parm=address--exit_hook--exit_parm=address 选项进行编译。

使用列表 3.4 中的入口/出口挂钩构建应用程序时,表中会填充性能分析数据。例如,列表 3.5 中的代码片段会生成下表:

列表 3.5 使用挂钩函数进行性能分析的示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
intmain(){ProfileData_init();foo();ProfileData_print();return0;}voidfoo(){inti;for(i=0;i<100;i++)asm("\tNOP;");bar();bar();}voidbar(){inti;for(i=0;i<100;i++)asm("\tNOP;");}
0x00a647,0,250x00a637,0,5620x00a637,1,10900x00a637,0,11340x00a637,1,16620x00a647,1,1697