Time 如何度量函数执行所需的时间?

Time 如何度量函数执行所需的时间?,time,embedded,profiling,Time,Embedded,Profiling,如何衡量函数执行所需的时间 这是一个相对较短的函数,执行时间可能在毫秒范围内 这个问题涉及到一个嵌入式系统,用C或C++编程。调用它在一个循环中调用一个吨,然后除以调用次数来获得平均时间。 start_time = timer function() exec_time = timer - start_time 因此: //开始计时 对于(int i=0;i

如何衡量函数执行所需的时间

这是一个相对较短的函数,执行时间可能在毫秒范围内


这个问题涉及到一个嵌入式系统,用C或C++编程。

调用它在一个循环中调用一个吨,然后除以调用次数来获得平均时间。

start_time = timer
function()
exec_time = timer - start_time
因此:

//开始计时
对于(int i=0;i<10000;i++){
invokeFunction();
}
//结束时间
//除以10000得到实际时间。

在嵌入式系统上执行此操作的最佳方法是在您进入该功能时设置外部硬件pin,并在您离开该功能时将其清除。这最好是通过一点汇编指令来完成的,这样你的结果就不会有太多的偏差


编辑:其中一个好处是,您可以在实际应用程序中进行编辑,并且不需要任何特殊的测试代码。像这样的外部调试引脚是(应该是!)每个嵌入式系统的标准做法。

如果您正在寻找亚毫秒分辨率,请尝试以下计时方法之一。它们都将在至少数十或数百微秒内为您提供分辨率:

如果是嵌入式Linux,请查看Linux计时器:

嵌入式Java,看看nanoTime(),虽然我不确定这是否在嵌入式版本中:

如果您想进入硬件计数器,请尝试PAPI:

否则,您可以始终转到汇编程序。如果需要帮助,可以查看体系结构的PAPI源。

在OS X终端(可能还有Unix)中,使用“时间”:


如果代码是.Net,请使用秒表类(.Net 2.0+)而不是DateTime.Now。DateTime.Now更新不够准确,会给您带来疯狂的结果

如果您使用linux,您可以通过在命令行中键入以下命令来计时程序的运行时间:

time [funtion_name]

如果只运行main()中的函数(假设为C++),则应用程序的剩余时间应该可以忽略不计

有三种可能的解决方案:

硬件解决方案

使用处理器上的自由输出引脚,并将示波器或逻辑分析仪挂接到该引脚。在调用要测量的函数之前,将管脚初始化为低状态,将管脚断言为高状态,从函数返回后,取消管脚的断言


    *io_pin = 1;
    myfunc();
    *io_pin = 0;
书虫解决方案

如果函数相当小,并且您可以管理反汇编的代码,那么您可以打开处理器体系结构数据本,计算处理器执行每个指令所需的周期。这将为您提供所需的循环次数。
时间=#周期*处理器时钟频率/每条指令的时钟滴答声

对于较小的函数或汇编程序编写的代码(例如PIC微控制器),这更容易实现

时间戳计数器解决方案

有些处理器有一个时间戳计数器,它以很快的速度递增(每隔几个处理器时钟滴答一次)。只需在函数前后读取时间戳。 这将为您提供运行时间,但请注意,您可能必须处理计数器翻转。

Windows XP/NT Embedded或Windows CE/Mobile 可以使用QueryPerformanceCounter()在函数前后获取非常快的计数器的值。然后减去这些64位的值,得到一个增量“ticks”。使用QueryPerformanceCounterFrequency()可以将“增量刻度”转换为实际时间单位。您可以参考有关这些WIN32调用的MSDN文档

其他嵌入式系统 如果没有操作系统或只有基本操作系统,您必须:

  • 对其中一个内部CPU计时器进行编程,使其自由运行和计数
  • 将其配置为在计时器溢出时生成中断,并在该中断例程中增加一个“进位”变量(这样您可以实际测量比所选计时器分辨率更长的时间)
  • 在执行此功能之前,请保存“进位”值和CPU寄存器的值,该寄存器保存配置的计数计时器的运行刻度
  • 在你的功能之后也一样
  • 减去它们得到一个增量计数器刻度
  • 从这里开始,只需知道在设置计时器时,给定外部时钟和配置的反乘法,一个滴答声在CPU/硬件上意味着多长时间。你把“滴答声长度”乘以你刚刚得到的“滴答声增量”
非常重要不要忘记在获取这些计时器值(而不是进位和寄存器值)之前禁用中断,并在获取这些值之后恢复中断,否则可能会保存不正确的值

注释

  • 这是非常快的,因为只有少数汇编指令可以禁用中断、保存两个整数值并重新启用中断。实际的减法和实时单位转换发生在时间测量区域之外,即函数之后
  • 您可能希望将该代码放入一个函数中,以便全面重用该代码,但由于函数调用和将所有寄存器加上参数推送到堆栈中,然后再次弹出它们,这可能会使事情变慢。在嵌入式系统中,这可能非常重要。在C语言中,最好使用宏,或者编写自己的汇编例程,只保存/恢复相关寄存器

取决于您的嵌入式平台以及您需要的时间类型。对于嵌入式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;
}
您可能还想阅读
clock\u gettime
上的手册页。在基于SMP的系统上运行此代码时存在一些问题,可能会使您的测试无效。您可以使用类似于
sched_setaffinity()
或命令行的内容

    *io_pin = 1;
    myfunc();
    *io_pin = 0;
#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
#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);
}
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