测量在C中使用函数宏测量函数调用的执行时间

huangapple go评论85阅读模式
英文:

Measuring the execution time of a function call in C using a function-like macro

问题

以下是您要翻译的内容:

使用标准库函数 clock() 是在 C 中测量函数调用执行时间的几种方法之一。例如,可以如下比较两个函数(具有不同原型)的执行时间:

  1. #include <stdio.h>
  2. #include <time.h>
  3. int f(int n) { return n < 3 ? 1 : f(n-1) + f(n-2); }
  4. int g(int n, int a, int b) { return n < 3 ? b : g(n-1, b, a+b); }
  5. int main(void) {
  6. double start, elapsed1, elapsed2;
  7. printf("n f g\n");
  8. for(int n = 30; n <= 40; n++) {
  9. start = (double) clock();
  10. f(n);
  11. elapsed1 = (clock() - start) / CLOCKS_PER_SEC;
  12. start = (double) clock();
  13. g(n, 1, 1);
  14. elapsed2 = ((double) clock() - start) / CLOCKS_PER_SEC;
  15. printf("%d %.1f %.1f\n", n, elapsed1, elapsed2);
  16. }
  17. return 0;
  18. }

为了使这段代码更加简洁,我们可以定义一个类似函数的宏(因为在 C 中没有“通用函数”指针):

  1. #include <stdio.h>
  2. #include <time.h>
  3. double START, ELAPSED;
  4. #define CPUTIME(FCALL) (START = (double) clock(), FCALL, ELAPSED = ((double) clock() - START) / CLOCKS_PER_SEC)
  5. int f(int n) { return n < 3 ? 1 : f(n-1) + f(n-2); }
  6. int g(int n, int a, int b) { return n < 3 ? b : g(n-1,b,a+b); }
  7. int main(void) {
  8. printf("n f g\n");
  9. for(int n = 30; n <= 40; n++)
  10. printf("%d %.1f %.1f\n", n, CPUTIME(f(n)), CPUTIME(g(n, 1, 1)) );
  11. return 0;
  12. }

问题: 是否有办法使变量 START 和 ELAPSED 局部于宏定义,以便宏仍然可以作为非 void “函数”调用?是否有更好的方法使代码更简洁,而不使用宏定义?

英文:

Using the standard library function clock() is one of several methods to measure the execution time of a function call in C. So, for example, the comparison of the execution times of two functions (with different prototypes) can be done as follows:

  1. #include &lt;stdio.h&gt;
  2. #include &lt;time.h&gt;
  3. int f(int n) { return n &lt; 3 ? 1 : f(n-1) + f(n-2); }
  4. int g(int n, int a, int b) { return n &lt; 3 ? b : g(n-1, b, a+b); }
  5. int main(void) {
  6. double start, elapsed1, elapsed2;
  7. printf(&quot;n f g\n&quot;);
  8. for(int n = 30; n &lt;= 40; n++) {
  9. start = (double) clock();
  10. f(n);
  11. elapsed1 = (clock() - start) / CLOCKS_PER_SEC;
  12. start = (double) clock();
  13. g(n, 1, 1);
  14. elapsed2 = ((double) clock() - start) / CLOCKS_PER_SEC;
  15. printf(&quot;%d %.1f %.1f\n&quot;, n, elapsed1, elapsed2);
  16. }
  17. return 0;
  18. }

To make this code more concise, we could define a function-like macro (since there is no "generic function" pointer in C):

  1. #include &lt;stdio.h&gt;
  2. #include &lt;time.h&gt;
  3. double START, ELAPSED;
  4. #define CPUTIME(FCALL) (START = (double) clock(), FCALL, ELAPSED = ((double) clock() - START) / CLOCKS_PER_SEC)
  5. int f(int n) { return n &lt; 3 ? 1 : f(n-1) + f(n-2); }
  6. int g(int n, int a, int b) { return n &lt; 3 ? b : g(n-1,b,a+b); }
  7. int main(void) {
  8. printf(&quot;n f g\n&quot;);
  9. for(int n = 30; n &lt;= 40; n++)
  10. printf(&quot;%d %.1f %.1f\n&quot;, n, CPUTIME(f(n)), CPUTIME(g(n, 1, 1)) );
  11. return 0;
  12. }

Questions: Is there a way to make variables START and ELAPSED local to the macro definition so that the macro can still be called as a non-void "function"? Is there a better way to make the code more concise, without using a macro definition?

答案1

得分: 2

你可以使用非标准的 statement-expression C 扩展(至少在 clang、gcc 和 tinycc 中可用)。

  1. #include <stdio.h>
  2. #include <time.h>
  3. #define CPUTIME(FCALL) ({ double START = clock(); FCALL; ((double) clock() - START) / CLOCKS_PER_SEC; })
  4. int f(int n) { return n < 3 ? 1 : f(n-1) + f(n-2); }
  5. int g(int n, int a, int b) { return n < 3 ? b : g(n-1, b, a+b); }
  6. int main(void) {
  7. printf("n f g\n");
  8. for(int n = 30; n <= 40; n++)
  9. printf("%d %.1f %.1f\n", n, CPUTIME(f(n)), CPUTIME(g(n, 1, 1)) );
  10. return 0;
  11. }

这是一个括号包围的块,它被评估为其中的最后一个语句所评估的结果。

我认为在标准 C 中没有通用的解决方案能够满足您的 API 约束。如果您追求标准 C 的线程安全性和/或稍微更好的代码生成,您可以使用您的原始解决方案,并在调用宏的块内(重新)声明变量。

英文:

You can use the nonstandard statement-expression C extension
(available in at least clang, gcc, and tinycc).

  1. #include &lt;stdio.h&gt;
  2. #include &lt;time.h&gt;
  3. #define CPUTIME(FCALL) ({ double START = clock(); FCALL; ((double) clock() - START) / CLOCKS_PER_SEC; })
  4. int f(int n) { return n &lt; 3 ? 1 : f(n-1) + f(n-2); }
  5. int g(int n, int a, int b) { return n &lt; 3 ? b : g(n-1,b,a+b); }
  6. int main(void) {
  7. printf(&quot;n f g\n&quot;);
  8. for(int n = 30; n &lt;= 40; n++)
  9. printf(&quot;%d %.1f %.1f\n&quot;, n, CPUTIME(f(n)), CPUTIME(g(n, 1, 1)) );
  10. return 0;
  11. }

It's a parenthesized block that's evaluated to what the last statement in it evaluates to.

I don't think there's a generic solution within standard C that would satisfy your API constraints. If you're after standard-c-only threadsafety and/or slightly better codegen, you could use your original solution and (re)declare the variable(s) locally within the block that calls the macro.

答案2

得分: 1

以下是翻译好的内容:

"在不使用宏定义的情况下,有没有更简洁的方法来编写代码呢?

虽然宏定义很巧妙,但普通的函数可以减少重复,并且更容易理解:

  1. double seconds_since(clock_t start)
  2. {
  3. return (double)(clock() - start) / CLOCKS_PER_SEC;
  4. }
  5. int main(void) {
  6. clock_t start;
  7. double elapsed1, elapsed2;
  8. printf("n f g\n");
  9. for(int n = 30; n <= 40; n++) {
  10. start = clock();
  11. f(n);
  12. elapsed1 = seconds_since(start);
  13. start = clock();
  14. g(n, 1, 1);
  15. elapsed2 = seconds_since(start);
  16. printf("%d %.1f %.1f\n", n, elapsed1, elapsed2);
  17. }
  18. return 0;
  19. }
  20. ```"
  21. <details>
  22. <summary>英文:</summary>
  23. &gt; Is there a better way to make the code more concise, without using a macro definition?
  24. While the macro definition is clever, just a plain function can reduce the repetition and is simple to understand:
  25. double seconds_since(clock_t start)
  26. {
  27. return (double)(clock() - start) / CLOCKS_PER_SEC;
  28. }
  29. int main(void) {
  30. clock_t start;
  31. double elapsed1, elapsed2;
  32. printf(&quot;n f g\n&quot;);
  33. for(int n = 30; n &lt;= 40; n++) {
  34. start = clock();
  35. f(n);
  36. elapsed1 = seconds_since(start);
  37. start = clock();
  38. g(n, 1, 1);
  39. elapsed2 = seconds_since(start);
  40. printf(&quot;%d %.1f %.1f\n&quot;, n, elapsed1, elapsed2);
  41. }
  42. return 0;
  43. }
  44. </details>

huangapple
  • 本文由 发表于 2023年4月16日 23:06:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/76028547.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定