【问题标题】:General function for executing time measurement执行时间测量的通用函数
【发布时间】:2016-01-28 20:18:28
【问题描述】:

我目前正在尝试编写一个通用函数来测量另一个函数func 需要执行的时间。我可以用<time.h> 等计算时间。

我的方法如下所示:

 void measure_time(void *(func)(), unsigned loops);

现在只要在measure_time 中打印结果就足够了(稍后我可以让measure_time 返回一些信息)。

我能够计算执行时间等等(使用<time.h>),但目前我的问题是我希望这是一个通用函数,它应该能够采用具有不同返回类型和不同参数大小/类型的各种函数“func”。

目前我不知道如何设法给measure_time 函数'func' 并让它使用我能够指定的参数执行它。

例如:

int a[1000] = {15, 53, ..., 42};
void sort_something(int *a, int n_elements) { ... };
void measure_time(sort_somthing(a, 1000), 100);

这应该使用参数“a 和 1000”调用 sort_something 100 次,并测量执行所需的时间。

如果您需要,我很乐意提供更多信息。

干杯!

最后几秒

【问题讨论】:

  • 因为不同类型+参数个数的函数指针的不等式,这可能是不可能的。但是,您可以轻松地将其包装在宏中(包含对用户指定的函数的调用的宏的一部分)
  • 请给我一个关于宏的粗略想法好吗?
  • 您可以通过查看qsort 的方式来探索将函数传递给函数。您可以通过查找va_start 等来探索可变的其他参数。

标签: c function pointers reference


【解决方案1】:

一般的方案应该是:

void general_timer(void (*function)(void *context), void *context, int loops);

这接受一个不返回值的函数,并接受一个 void * 参数作为上下文,并传递上下文。根据您需要作为上下文传递的内容,这可能是结构的地址,或者像 FILE * 这样简单的地址。

实现内部:

void general_timer(void (*function)(void *context), void *context, int loops)
{
    Clock clk;
    clk_init(&clk);
    clk_start(&clk);
    for (int i = 0; i < loops; i++
        (*function)(context);
    clk_stop(&clk);
    char buffer[32];
    printf("%s seconds for %d iterations\n",
           clk_elapsed_microsecs(&clk, buffer, sizeof(buffer)), loops);
}

其中Clock 类型和以clk_ 开头的函数是高分辨率计时包的一部分,可以使用任何方便的方式。

你可以把函数调用写成:

function(context);

它的工作原理完全相同。这是更现代的风格;我更喜欢老式的(*function)(context) 调用,因为它清楚地表明function 是一个函数指针,而不是函数的名称。 YMMV。

是的,我确实有这样一个包的具体实现。但是,无论您如何实施,这个概念都很容易应用。

您可能有一个需要计时的功能。它可能使用以下结构:

struct TwoFiles
{
    FILE *f_in;
    FILE *f_out;
};

函数可能是:

void file_copier(void *ctxt)
{
    struct TwoFiles *info = ctxt;
    char buffer[4096];
    size_t bytes;
    rewind(info->f_in);
    rewind(info->f_out);
    while ((bytes = fread(buffer, sizeof(buffer), sizeof(char), info->f_in)) > 0)
    {
        if (frwite(buffer, bytes, sizeof(char), info->f_out) != bytes)
        {
            …report error…abandon loop…
        }
    }
}

电话可能是:

struct TwoFiles ctxt;
ctxt.f_in = fopen(some_file_name, "r");
ctxt.f_out = fopen(another_name, "w");

general_timer(file_copier, &ctxt, 100);

请注意,为了有用,文件复制器函数需要倒带输入和输出文件流,以便每次通用计时器函数调用它时都能正常工作。但是,这是手头特定任务的详细信息。

【讨论】:

  • 这很棒,可能我会用。非常感谢!
  • 唯一让我有点困扰的是我必须重写很多我想测试的函数,以便只接受一个参数。这是正确的,不是吗?它仍然是我可能会去的东西!
  • 更可能的是,您会编写包装器:void real_file_copier(FILE *fin, FILE *fout){ …original code… },然后是 void timed_file_copier(void *context) { struct TwoFiles *f2 = context; real_file_copier(f2-&gt;f_in,f2-&gt;f_out); }。所以,是的,您可以编写许多函数;但它们各自都很小,只是简单地包装了你真正想要计时的代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-09
  • 1970-01-01
  • 2023-03-09
相关资源
最近更新 更多