测量N代码块执行时间的问题

时间:2010-05-12 19:16:49

标签: c time clock performance

编辑:我写完这篇长篇文章解释每一个小细节之后才发现我的问题...如果有人能给我一个很好的答案我做错了什么怎么能得到以秒为单位的执行时间(使用带有5位小数的浮点数),我会将其标记为已接受。提示:问题在于我如何解释clock_getttime()手册页。

您好,

假设我有一个名为myOperation的函数,我需要测量它的执行时间。为了衡量它,我在其中一条评论中使用了clock_gettime(),因为它推荐here

我的老师建议我们对其进行衡量N次,以便我们获得最终报告的平均值,标准差和中位数。他还建议我们执行myOperation M次而不是一次。如果myOperation是一个非常快速的操作,那么测量它M次就可以让我们了解它所需的“实时”;因为正在使用的时钟可能没有测量此类操作所需的精度。因此,执行myOperation只有一次或M次真正取决于操作本身是否足够长时间来处理我们正在使用的时钟精度。

我在处理M次执行时遇到问题。增加M会减少(很多)最终平均值。这对我没有意义。就像这样,从A点到B点平均需要3到5秒。然后你从A到B然后再回到A 5次(这使它成为10次,因为A到B与B相同)到A),你衡量。除了你除以10,你得到的平均值应该是你从A点到B点旅行的平均值,这是3到5秒。

这就是我想要我的代码所做的事情,但它不起作用。如果我继续增加从A到B并返回A的次数,平均值每次都会越来越低,这对我来说毫无意义。

足够的理论,这是我的代码:

#include <stdio.h>
#include <time.h>

#define MEASUREMENTS 1
#define OPERATIONS   1

typedef struct timespec TimeClock;

TimeClock diffTimeClock(TimeClock start, TimeClock end) {
    TimeClock aux;

    if((end.tv_nsec - start.tv_nsec) < 0) {
        aux.tv_sec = end.tv_sec - start.tv_sec - 1;
        aux.tv_nsec = 1E9 + end.tv_nsec - start.tv_nsec;
    } else {
        aux.tv_sec = end.tv_sec - start.tv_sec;
        aux.tv_nsec = end.tv_nsec - start.tv_nsec;
    }

    return aux;
}

int main(void) {
    TimeClock sTime, eTime, dTime;
    int i, j;

    for(i = 0; i < MEASUREMENTS; i++) {
        printf(" » MEASURE %02d\n", i+1);

        clock_gettime(CLOCK_REALTIME, &sTime);

        for(j = 0; j < OPERATIONS; j++) {
            myOperation();
        }

        clock_gettime(CLOCK_REALTIME, &eTime);

        dTime = diffTimeClock(sTime, eTime);

        printf("   - NSEC (TOTAL): %ld\n", dTime.tv_nsec);
        printf("   - NSEC (OP): %ld\n\n", dTime.tv_nsec / OPERATIONS);
    }

    return 0;
}

注意:上述diffTimeClock功能来自此blog post。我用myOperation()替换了我的实际操作,因为发布我的实际函数没有任何意义,因为我必须发布长代码块,你可以轻松编写myOperation()任何你喜欢的代码如果你愿意,可以编译代码。

如您所见,OPERATIONS = 1的结果是:

 » MEASURE 01
   - NSEC (TOTAL): 27456580
   - NSEC (OP): 27456580

对于OPERATIONS = 100,结果为:

 » MEASURE 01
   - NSEC (TOTAL): 218929736
   - NSEC (OP): 2189297

对于OPERATIONS = 1000,结果为:

 » MEASURE 01
   - NSEC (TOTAL): 862834890
   - NSEC (OP): 862834

对于OPERATIONS = 10000,结果为:

 » MEASURE 01
   - NSEC (TOTAL): 574133641
   - NSEC (OP): 57413

现在,我不是一个数学专家,实际上远非它,但这对我来说没有任何意义。我已经和一个和我一起参与这个项目的朋友谈过这件事了,他也无法理解这些差异。我不明白为什么当我增加OPERATIONS时价值越来越低。无论执行多少次,操作本身都应该花费相同的时间(平均当然,不是完全相同的时间)。

你可以告诉我,这实际上取决于操作本身,正在读取的数据以及某些数据可能已经存在于缓存和bla bla中,但我认为这不是问题所在。就我而言,myOperation正在从CSV文件中读取5000行文本,将值分隔;并将这些值插入数据结构中。对于每次迭代,我都在破坏数据结构并再次初始化它。

现在我想到了,我也认为用clock_gettime()测量时间有问题,也许我没有正确使用它。我的意思是,看看最后一个例子,OPERATIONS = 10000。它花费的总时间是574133641ns,大概是0.5s;这是不可能的,花了几分钟,因为我无法忍受看着屏幕等着去吃东西。

4 个答案:

答案 0 :(得分:1)

看起来TimeClock类型有两个字段,一个用于秒,一个用于纳秒。将nanosec字段与操作次数分开是没有意义的。你需要划分总时间。

答案 1 :(得分:1)

如果您使用的是POSIX系统,其中有gettimeofday()函数,您可以使用类似这样的内容来获取当前时间(以微秒为单位):

long long timeInMicroseconds(void) {
    struct timeval tv;

    gettimeofday(&tv,NULL);
    return (((long long)tv.tv_sec)*1000000)+tv.tv_usec;
}

这个非常方便的原因是,为了计算你的功能花了多少你需要这样做:

long long start = timeInMicroseconds();
... do your task N times ...
printf("Total microseconds: %lld", timeInMicroseconds()-start);

所以你不必处理两个整数,一个用秒,一个用微秒。添加和减去时间将以明显的方式起作用。

答案 2 :(得分:1)

您只需更改diffTimeClock()功能即可返回差异的秒数,double

double diffTimeClock(TimeClock start, TimeClock end) {
    double diff;

    diff = (end.tv_nsec - start.tv_nsec) / 1E9;
    diff += (end.tv_sec - start.tv_sec);

    return diff;
}

并在主例程中将dTime更改为double,并将printfs更改为:

printf("   - SEC (TOTAL): %f\n", dTime);
printf("   - SEC (OP): %f\n\n", dTime / OPERATIONS);

答案 3 :(得分:0)

我通常使用time()函数。它显示了挂钟时间,但这才是我最终关心的。

性能测试的一个问题是操作系统可能会缓存与文件系统相关的操作。所以第二次(以及后来的)运行速度可能比第一次运行快得多。您通常需要测试may操作并对结果取平均值,以便对您所做的任何更改的结果有一个良好的感觉。这么多变量可以帮助你滤除噪音。