如何实现c语言版本的timeit()

在上一篇博客《python计时函数timeit.timeit()使用小结》中介绍了python中timeit()及其用法,现在我们看看如何在c中实现类似功能.

可以考虑使用一个接受变参的宏(Variadic Macro)来实现,在这种定义方式中,用"..."表示形参,运行时所有传入的实参被内置标识符__VA_ARGS__来取代。一个实现如下所示: 在运行函数前获取当前时间(line 9), 之后按指定的运行次数执行函数(line 11~13), 最后再一次获取当前时间(line 15), 两次时间差即为函数运行时间 (line 16-17). 需要指出的是,这里选用clock_gettime(CLOCK_PROCESS_CPUTIME, ...)来获取当前时间,基于两点考虑:1)可以得到纳秒(nano seconds)级别的精度; 2)CLOCK_PROCESS_CPUTIME时钟意味着Per-process CPU-time clock,从而排除了函数执行期间进程被操作系统schedule out的干扰。 

 1 #include <stdio.h>
 2 #include <time.h>    // for clock_gettime
 3 #include <stdint.h>  // for int64_t
 4 
 5 
 6 #define timeit(n, func, ...) do {                                           \
 7         uint64_t duration;                                                  \
 8         struct timespec start, end;                                         \
 9         clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);                    \
10                                                                             \
11         for (int i=0; i<n; i++) {                                           \
12                 func(__VA_ARGS__);                                          \
13         }                                                                   \
14                                                                             \
15         clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end);                      \
16         duration = (end.tv_sec - start.tv_sec) * 1000000000                 \
17                    + (end.tv_nsec - start.tv_nsec);                         \
18                                                                             \
19         char strSpan[256];                                                  \
20         char strAvgSpan[256];                                               \
21         get_desc_time(duration, strSpan, sizeof(strSpan));                  \
22         get_desc_time(duration/n, strAvgSpan, sizeof(strAvgSpan));          \
23         printf("%d loops, %s, avg: %s per loop\n", n, strSpan, strAvgSpan); \
24 } while (0)

与python的timeit()相比,参数表示稍有不同:

n: 函数执行次数

func: 将要执行的函数

...: func的参数(0个或多个)

get_desc_time() 是格式化函数,将纳秒为单位的整数转换为可读性更强的字符串:

 1 void get_desc_time(uint64_t ns, char *buf, int len)
 2 {
 3         uint64_t nano_per_sec = 1000000000;
 4         uint64_t nano_per_milli = 1000000;
 5         uint64_t nano_per_micro = 1000;
 6         uint64_t unit = 1000;
 7 
 8         uint64_t nanos = ns % unit;
 9         uint64_t micros = ns / nano_per_micro % unit;
10         uint64_t millis = ns / nano_per_milli % unit;
11         uint64_t seconds = ns / nano_per_sec;
12 
13         memset(buf, '\0', sizeof buf);
14         if (seconds > 0) {
15                 snprintf(buf+strlen(buf), len-strlen(buf), "%lds", seconds);
16         }
17 
18         if (millis > 0) {
19                 snprintf(buf+strlen(buf), len-strlen(buf), "%ldms", millis);
20         }
21 
22         if (micros > 0) {
23                 snprintf(buf+strlen(buf), len-strlen(buf), "%ldµs", micros);
24         }
25 
26         if (nanos > 0) {
27                 snprintf(buf+strlen(buf), len-strlen(buf), "%ldns", nanos);
28         }
29 }

下面我们定义两个函数: 斐波那契函数fibanocci(int) 和最大公约数函数gcd(int, int), 并用timeit()对他们进行计时统计:

 1 int fibonacci(int n)
 2 {
 3         if (n <= 0) {
 4                 return 0;
 5         } else if (n == 1 || n == 2) {
 6                 return 1;
 7         }
 8 
 9         return fibonacci(n-1)  + fibonacci(n-2);
10 }
11 
12 
13 int gcd(int a, int b)
14 {
15 if (a == 0 || b== 0) { 16 return 1; 17 } 18 19 int bigger = (a > b ? a : b); 20 int smaller = (a > b ? b : a); 21 if (bigger % smaller == 0) { 22 return smaller; 23 } 24 25 return gcd(smaller, bigger % smaller); 26 }

对fibanocci()进行统计:

1        printf("timeit(5, fibonacci, 25): ");
2        timeit(5, fibonacci, 25);

结果:timeit(5, fibonacci, 25): 5 loops, 3ms646µs173ns, avg: 729µs234ns per loop

对gcd()进行统计:

1        printf("timeit(10, gcd, 15000, 5525): ");
2        timeit(10, gcd, 15000, 5525);

结果:timeit(10, gcd, 15000, 5525): 10 loops, 1µs373ns, avg: 137ns per loop

 

posted on 2019-05-20 18:56  wangwenzhi2019  阅读(242)  评论(0编辑  收藏  举报

导航