你如何衡量一个函数的执行时间?
这是一个相对较短的函数,执行时间可能在毫秒范围内。
这个特定的问题与使用 C 或 C++ 编程的嵌入式系统有关。
在嵌入式系统上执行此操作的最佳方法是在您进入该功能时设置一个外部硬件引脚,并在您离开该功能时清除它。最好用一点汇编指令来完成,这样你就不会过多地扭曲你的结果。
编辑:好处之一是您可以在实际应用程序中执行此操作,并且不需要任何特殊的测试代码。像这样的外部调试引脚是(应该是!)每个嵌入式系统的标准做法。
有三种可能的解决方案:
硬件解决方案:
使用处理器上的空闲输出引脚并将示波器或逻辑分析仪连接到该引脚。将引脚初始化为低电平状态,在调用要测量的函数之前,将引脚置为高电平状态,然后在从函数返回后,取消置位引脚。
*io_pin = 1;
myfunc();
*io_pin = 0;
书虫解决方案:
如果函数相当小,并且您可以管理反汇编代码,则可以打开处理器架构数据手册并计算处理器执行每条指令所需的周期。这将为您提供所需的周期数。
时间 = # 个周期 * 处理器时钟速率 / 每条指令的时钟滴答数
对于较小的功能或用汇编程序编写的代码(例如,对于 PIC 微控制器),这更容易做到
时间戳计数器解决方案:
一些处理器有一个时间戳计数器,它会快速递增(每隔几个处理器时钟滴答声)。只需读取函数前后的时间戳即可。这将为您提供经过的时间,但请注意您可能必须处理计数器翻转。
在具有大量调用的循环中调用它,然后除以调用次数以获得平均时间。
所以:
// begin timing
for (int i = 0; i < 10000; i++) {
invokeFunction();
}
// end time
// divide by 10000 to get actual time.
如果您使用的是 linux,您可以通过在命令行中键入来计时程序的运行时间:
time [funtion_name]
如果您只运行 main() 中的函数(假设 C++),则应用程序的其余时间应该可以忽略不计。
我多次重复函数调用(数百万次),但也使用以下方法来降低循环开销:
start = getTicks();
repeat n times {
myFunction();
myFunction();
}
lap = getTicks();
repeat n times {
myFunction();
}
finish = getTicks();
// overhead + function + function
elapsed1 = lap - start;
// overhead + function
elapsed2 = finish - lap;
// overhead + function + function - overhead - function = function
ntimes = elapsed1 - elapsed2;
once = ntimes / n; // Average time it took for one function call, sans loop overhead
而不是在第一个循环中调用 function() 两次,在第二个循环中调用一次,您可以在第一个循环中调用它一次,并且在第二个循环中根本不调用它(即空循环),但是空循环可以由编译器优化,给你负时序结果:)
start_time = timer
function()
exec_time = timer - start_time
您可以使用 QueryPerformanceCounter() 在函数之前和之后获取 VERY FAST 计数器的值。然后你减去那些 64 位值并得到一个增量“滴答声”。使用 QueryPerformanceCounterFrequency() 您可以将“增量刻度”转换为实际时间单位。您可以参考有关这些 WIN32 调用的 MSDN 文档。
如果没有操作系统或只有基本操作系统,您将不得不:
非常重要不要忘记在获取这些计时器值(进位和寄存器值)之前禁用并恢复中断,否则您可能会保存不正确的值。
笔记
取决于您的嵌入式平台和您正在寻找的时间类型。对于嵌入式 Linux,有几种方法可以完成。如果您希望测量函数使用的 CPU 时间量,可以执行以下操作:
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#define SEC_TO_NSEC(s) ((s) * 1000 * 1000 * 1000)
int work_function(int c) {
// do some work here
int i, j;
int foo = 0;
for (i = 0; i < 1000; i++) {
for (j = 0; j < 1000; j++) {
for ^= i + j;
}
}
}
int main(int argc, char *argv[]) {
struct timespec pre;
struct timespec post;
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &pre);
work_function(0);
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &post);
printf("time %d\n",
(SEC_TO_NSEC(post.tv_sec) + post.tv_nsec) -
(SEC_TO_NSEC(pre.tv_sec) + pre.tv_nsec));
return 0;
}
您需要将其与实时库链接,只需使用以下代码编译您的代码:
gcc -o test test.c -lrt
您可能还想阅读有关clock_gettime
在基于 SMP 的系统上运行此代码的一些问题的手册页,这可能会使您的测试无效。您可以使用类似的东西sched_setaffinity()
或命令行cpuset
来强制仅在一个核心上执行代码。
如果您正在寻找测量用户和系统时间,那么您可以使用times(NULL)
which 返回类似 jiffies 的东西。或者您可以将参数clock_gettime()
from更改CLOCK_THREAD_CPUTIME_ID
为CLOCK_MONOTONIC
...,但请注意使用CLOCK_MONOTONIC
.
对于其他平台,您就靠自己了。
德鲁
我总是实现一个中断驱动的股票程序。然后这会更新一个计数器,该计数器计算自启动以来的毫秒数。然后使用 GetTickCount() 函数访问此计数器。
例子:
#define TICK_INTERVAL 1 // milliseconds between ticker interrupts
static unsigned long tickCounter;
interrupt ticker (void)
{
tickCounter += TICK_INTERVAL;
...
}
unsigned in GetTickCount(void)
{
return tickCounter;
}
在您的代码中,您将按如下方式对代码进行计时:
int function(void)
{
unsigned long time = GetTickCount();
do something ...
printf("Time is %ld", GetTickCount() - ticks);
}
如果您正在寻找亚毫秒级的分辨率,请尝试其中一种计时方法。它们都会在至少几十或几百微秒内为您解决问题:
如果是嵌入式 Linux,请查看 Linux 计时器:
http://linux.die.net/man/3/clock_gettime
嵌入式 Java,看看 nanoTime(),虽然我不确定这是否在嵌入式版本中:
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/System.html#nanoTime()
如果您想获得硬件柜台,请尝试 PAPI:
否则你总是可以去汇编程序。如果您需要一些帮助,您可以查看您的体系结构的 PAPI 源代码。
在 OS X 终端(也可能是 Unix)中,使用“时间”:
time python function.py
如果代码是 .Net,请使用秒表类 (.net 2.0+) 而不是 DateTime.Now。DateTime.Now 更新不够准确,会给你带来疯狂的结果