我正在使用一个叫做i.MX515的ARM Cortex A8处理器。有LinuxUbuntu9.10发行版。我正在运行一个用C编写的非常大的应用程序,我正在使用gettimeofday();函数来度量我的应用程序所需的时间。
main()
{
gettimeofday(start);
....
....
....
gettimeofday(end);
}此方法足以查看我的应用程序的哪些块占用了多少时间。但是,现在,我正在非常彻底地优化代码,使用计算时间的gettimeofday()方法,我看到连续运行(在优化之前和之后运行)之间存在很大的波动,因此无法确定实际的执行时间,因此影响了我的改进。
有人能建议我该怎么做吗?
如果通过访问循环计数器(Idea在ARM网站上为Cortex-m3提出的建议),任何人可以向我指出一些代码,这些代码给了我访问Cortex-A8上的计时器寄存器所必须遵循的步骤。
如果这种方法不太准确,那么请提出一些备选方案。
谢谢
后续行动
后续1:在Code上编写了以下程序,生成了可执行文件,当我尝试在板上运行时,我得到了-非法指令消息:( )
static inline unsigned int get_cyclecount (void)
{
unsigned int value;
// Read CCNT Register
asm volatile ("MRC p15, 0, %0, c9, c13, 0\t\n": "=r"(value));
return value;
}
static inline void init_perfcounters (int32_t do_reset, int32_t enable_divider)
{
// in general enable all counters (including cycle counter)
int32_t value = 1;
// peform reset:
if (do_reset)
{
value |= 2; // reset all counters to zero.
value |= 4; // reset cycle counter to zero.
}
if (enable_divider)
value |= 8; // enable "by 64" divider for CCNT.
value |= 16;
// program the performance-counter control-register:
asm volatile ("MCR p15, 0, %0, c9, c12, 0\t\n" :: "r"(value));
// enable all counters:
asm volatile ("MCR p15, 0, %0, c9, c12, 1\t\n" :: "r"(0x8000000f));
// clear overflows:
asm volatile ("MCR p15, 0, %0, c9, c12, 3\t\n" :: "r"(0x8000000f));
}
int main()
{
/* enable user-mode access to the performance counter*/
asm ("MCR p15, 0, %0, C9, C14, 0\n\t" :: "r"(1));
/* disable counter overflow interrupts (just in case)*/
asm ("MCR p15, 0, %0, C9, C14, 2\n\t" :: "r"(0x8000000f));
init_perfcounters (1, 0);
// measure the counting overhead:
unsigned int overhead = get_cyclecount();
overhead = get_cyclecount() - overhead;
unsigned int t = get_cyclecount();
// do some stuff here..
printf("\nHello World!!");
t = get_cyclecount() - t;
printf ("function took exactly %d cycles (including function call) ", t - overhead);
get_cyclecount();
return 0;
}后续2:我写信给飞思卡尔寻求支持,他们给我发回了以下回复和一个程序(我对此不太了解)
下面是我们现在可以帮助您的内容:我正在向您发送一个代码示例,它使用UART发送一个流,从您的代码来看,您似乎没有正确地加入MPU。
(hash)include <stdio.h>
(hash)include <stdlib.h>
(hash)define BIT13 0x02000
(hash)define R32 volatile unsigned long *
(hash)define R16 volatile unsigned short *
(hash)define R8 volatile unsigned char *
(hash)define reg32_UART1_USR1 (*(R32)(0x73FBC094))
(hash)define reg32_UART1_UTXD (*(R32)(0x73FBC040))
(hash)define reg16_WMCR (*(R16)(0x73F98008))
(hash)define reg16_WSR (*(R16)(0x73F98002))
(hash)define AIPS_TZ1_BASE_ADDR 0x70000000
(hash)define IOMUXC_BASE_ADDR AIPS_TZ1_BASE_ADDR+0x03FA8000
typedef unsigned long U32;
typedef unsigned short U16;
typedef unsigned char U8;
void serv_WDOG()
{
reg16_WSR = 0x5555;
reg16_WSR = 0xAAAA;
}
void outbyte(char ch)
{
while( !(reg32_UART1_USR1 & BIT13) );
reg32_UART1_UTXD = ch ;
}
void _init()
{
}
void pause(int time)
{
int i;
for ( i=0 ; i < time ; i++);
}
void led()
{
//Write to Data register [DR]
*(R32)(0x73F88000) = 0x00000040; // 1 --> GPIO 2_6
pause(500000);
*(R32)(0x73F88000) = 0x00000000; // 0 --> GPIO 2_6
pause(500000);
}
void init_port_for_led()
{
//GPIO 2_6 [73F8_8000] EIM_D22 (AC11) DIAG_LED_GPIO
//ALT1 mode
//IOMUXC_SW_MUX_CTL_PAD_EIM_D22 [+0x0074]
//MUX_MODE [2:0] = 001: Select mux mode: ALT1 mux port: GPIO[6] of instance: gpio2.
// IOMUXC control for GPIO2_6
*(R32)(IOMUXC_BASE_ADDR + 0x74) = 0x00000001;
//Write to DIR register [DIR]
*(R32)(0x73F88004) = 0x00000040; // 1 : GPIO 2_6 - output
*(R32)(0x83FDA090) = 0x00003001;
*(R32)(0x83FDA090) = 0x00000007;
}
int main ()
{
int k = 0x12345678 ;
reg16_WMCR = 0 ; // disable watchdog
init_port_for_led() ;
while(1)
{
printf("Hello word %x\n\r", k ) ;
serv_WDOG() ;
led() ;
}
return(1) ;
}发布于 2010-07-14 21:50:29
访问性能计数器并不困难,但您必须通过内核模式启用它们。默认情况下,计数器是禁用的。
简而言之,您必须在内核中执行以下两行代码。无论是作为一个可加载的模块,还是仅仅将这两行添加到板中的某个位置-init就可以了:
/* enable user-mode access to the performance counter*/
asm ("MCR p15, 0, %0, C9, C14, 0\n\t" :: "r"(1));
/* disable counter overflow interrupts (just in case)*/
asm ("MCR p15, 0, %0, C9, C14, 2\n\t" :: "r"(0x8000000f));一旦您这样做,循环计数器将开始对每个周期递增。寄存器的溢出将被忽略,不会引起任何问题(除非它们可能会破坏您的测量)。
现在,您希望从用户模式访问循环计数器:
我们从一个读取寄存器的函数开始:
static inline unsigned int get_cyclecount (void)
{
unsigned int value;
// Read CCNT Register
asm volatile ("MRC p15, 0, %0, c9, c13, 0\t\n": "=r"(value));
return value;
}而且您很可能也希望重置和设置分隔符:
static inline void init_perfcounters (int32_t do_reset, int32_t enable_divider)
{
// in general enable all counters (including cycle counter)
int32_t value = 1;
// peform reset:
if (do_reset)
{
value |= 2; // reset all counters to zero.
value |= 4; // reset cycle counter to zero.
}
if (enable_divider)
value |= 8; // enable "by 64" divider for CCNT.
value |= 16;
// program the performance-counter control-register:
asm volatile ("MCR p15, 0, %0, c9, c12, 0\t\n" :: "r"(value));
// enable all counters:
asm volatile ("MCR p15, 0, %0, c9, c12, 1\t\n" :: "r"(0x8000000f));
// clear overflows:
asm volatile ("MCR p15, 0, %0, c9, c12, 3\t\n" :: "r"(0x8000000f));
}do_reset将周期计数器设置为零.就这么简单。
enable_diver将启用1/64分配器。如果没有这个标志设置,你将测量每一个周期。启用它后,计数器每64个周期就会增加一次。如果要测量可能导致计数器溢出的长时间,则此操作非常有用。
如何使用:
// init counters:
init_perfcounters (1, 0);
// measure the counting overhead:
unsigned int overhead = get_cyclecount();
overhead = get_cyclecount() - overhead;
unsigned int t = get_cyclecount();
// do some stuff here..
call_my_function();
t = get_cyclecount() - t;
printf ("function took exactly %d cycles (including function call) ", t - overhead);应该在所有的Cortex-A8 CPU上工作。
哦-还有一些笔记:
使用这些计数器,您将测量对get_cyclecount()的两个调用之间的确切时间,包括在其他进程或内核中花费的一切。无法将度量限制在进程或单个线程上。
同时,打电话给get_cyclecount()也不是免费的。它将编译成一个单一的asm指令,但从协处理器的移动将拖住整个ARM管道。开销很高,可能会使你的测量结果倾斜。幸运的是,开销也是固定的,所以您可以测量它,并从您的时间减去它。
在我的例子中,我对每一个度量都这样做。不要在实践中这样做。中断迟早会发生在这两个调用之间,并进一步扭曲您的测量结果。我建议您在空闲系统上测量几次开销,忽略所有外部变量,而使用固定的常量。
发布于 2010-07-14 15:02:54
您需要在优化前后使用性能分析工具分析代码。
加记是一个命令行和一个函数,您可以使用它来监视资源。您可以搜索更多关于dat文件的使用和查看的信息,因此由acct生成。
我将用其他开源性能分析工具更新这篇文章。
格罗夫是另一个这样的工具。请查阅文件中的相同内容。
发布于 2014-04-07 11:17:10
现在已经过去几年了,为了进一步了解Nils的答案,访问这些计数器的一种简单方法是访问用gator构建内核。然后报告计数器值以用于流线,这是ARM的性能分析工具。
它将在时间线上显示每个函数(向您提供系统执行情况的高级概述),显示执行所需的确切时间,以及它占用的% CPU。您可以将其与设置为收集和跟踪CPU密集型任务的每个计数器的图表进行比较,直到源代码级别。
流线型适用于所有Cortex-A系列处理器.
https://stackoverflow.com/questions/3247373
复制相似问题