如何测试不同算法的效率

时间:2016-08-14 06:44:25

标签: c linux

如何测试不同算法的效率,例如排序算法?我用clock_gettime尝试一下。这准确吗?有什么方法可以解决这个问题吗?

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

/* compute interval: end - start */
struct timespec diff(struct timespec start, struct timespec end);

/* tested algorithm, just an example. Print 10000 lines "hello" */ 
void testFunc(void);

int main(void)
{
    struct timespec start;
    struct timespec end;

    struct timespec interval ;

    clock_gettime(CLOCK_REALTIME, &start);

    /* call the tested algorithm */
    testFunc();

    clock_gettime(CLOCK_REALTIME, &end);

    interval = diff(start, end);
    printf("%lld.%.9ld(seconds)\n", (long long)interval.tv_sec, interval.tv_nsec);

    return 0;
}

/* compute interval: end - start */
struct timespec diff(struct timespec start, struct timespec end)
{
    struct timespec temp;

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

    return temp;
}

/* tested algorithm, just an example. Print 10000 lines "hello" */
void testFunc(void)
{
    int i;

    for (i = 0; i < 10000; i++) {
        printf("hello\n");
    }
}

3 个答案:

答案 0 :(得分:2)

您可以使用time命令。可以找到一个很好的解释here。首先将源代码编译为可执行二进制文件。然后运行time ./executable_code并且不要根据一两个测试做出决定。祝你好运!

答案 1 :(得分:1)

根据您对效率的意义,有很多方法可以测试。最简单的是Parnab使用time命令的建议。但是,如果你真的想了解发生了什么,那可能还不够。

perf tool允许您访问更多指标,例如周期数,不同级别缓存的缓存命中/未命中数,错误预测分支数等等。还有一个API可以从C访问perf工具,但它没有很好地记录。存在其他工具,例如PAPI,但我不知道它们彼此之间的差异。

此外,由于排序算法(我猜)是数据相关的(这意味着它们不会执行相同数量的指令,具体取决于它们排序的数组),您需要在相同的输入上比较它们,它可能不是很很容易,因为有些人可能更好地排序几乎排序的数组。

答案 2 :(得分:1)

在测试算法时,除了所讨论的精确算法之外,通常最好除去所有多余的代码(例如,将算法本身与程序启动,文件读取,数据初始化隔离,除了算法的一部分)正在接受测试)。这是使用命令行中的time无法做到的一个限制。

clock_gettime函数很不错,因为它允许纳秒粒度。但是,clock ()函数也可用于计时算法。 clock()的一般用途是:

#include <time.h>
...
int main () {
    double t1 = 0.0, t2 = 0.0;
    srand (time (NULL));
    ...
    t1 = clock ();                  /* get start time (as double) */
    quicksort (a, 0, TESTLIM - 1);  /* test whatever you need     */
    t2 = clock ();                  /* get end time (as double)   */
    printf ("\n quick1 (%lf sec)\n", (t2-t1)/CLOCKS_PER_SEC);

返回的时间差异是代码执行的粗略时间。它不是精确的挂起时间,因为CLOCKS_PER_SEC被指定为常量值,无论它在哪台机器上运行。 (POSIX要求CLOCKS_PER_SEC等于1000000

使用clock_gettimeclock都可以,但正如其他答案中所述,不要期望仅基于2次运行获得良好的近似值,并使用大量迭代。

clock_gettime提供更多灵活性的地方在于允许选择使用的时钟,例如CLOCK_MONOTONIC_RAWCLOCK_PROCESS_CPUTIME_ID等,根据您的需要,可能有助于保护计时器免受中断。 (有关各种时钟行为的完整讨论,请参阅man clock_gettime)您可以使用与clock_gettime类似的实现,例如

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

typedef struct timespec timespec;

timespec diff (timespec start, timespec end);

int main (void) {
    timespec time1, time2, tmp;
    int temp;
    clock_gettime (CLOCK_PROCESS_CPUTIME_ID, &time1);
    for (int i = 0; i < 242000000; i++)
        temp += temp;
    clock_gettime (CLOCK_PROCESS_CPUTIME_ID, &time2);
    tmp = diff (time1, time2);
    printf (" timediff %ld:%ld\n", tmp.tv_sec, tmp.tv_nsec);
    return 0;
}

timespec diff (timespec start, timespec end)
{
    timespec temp;
    if ((end.tv_nsec - start.tv_nsec) < 0) {
        temp.tv_sec = end.tv_sec - start.tv_sec - 1;
        temp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec;
    } else {
        temp.tv_sec = end.tv_sec - start.tv_sec;
        temp.tv_nsec = end.tv_nsec - start.tv_nsec;
    }
    return temp;
}

(示例由profiling-code-using-clock_gettime提供,如果测试此示例则禁用优化)

仔细查看并选择最适合您需求的那个。