我对您概述的时序方案所做的主要修改是确保两个函数使用相同的时序代码——假设它们确实具有相同的接口,通过将函数指针传递给骨架代码。
例如,我有一些代码对验证给定数字是否为素数的一些函数计时。控制函数为:
static void test_primality_tester(const char *tag, int seed, int (*prime)(unsigned), int count)
{
srand(seed);
Clock clk;
int nprimes = 0;
clk_init(&clk);
clk_start(&clk);
for (int i = 0; i < count; i++)
{
if (prime(rand()))
nprimes++;
}
clk_stop(&clk);
char buffer[32];
printf("%9s: %d primes found (out of %d) in %s s\n", tag, nprimes,
count, clk_elapsed_us(&clk, buffer, sizeof(buffer)));
}
我很清楚srand() — why call it once?,但是每次调用此函数时使用一次srand() 的目的是确保测试处理相同的随机数序列。在 macOS 上,RAND_MAX 是 0x7FFFFFFF。
Clock 类型包含两个 struct timespec 结构的类似物,用于开始和停止时间。 clk_init() 函数初始化结构体; clk_start() 记录结构中的开始时间; clk_stop()记录结构中的停止时间; clk_elapsed_us() 计算开始和停止时间之间经过的时间(以微秒为单位)。编写该软件包的目的是为我提供跨平台的可移植性(在确定编译时可用的最佳亚秒级计时例程时有些头疼)。
你可以在 Github 上的代码库 https://github.com/jleffler/soq 的 src/libsoq 目录中找到我的计时器代码——文件 timer.h 和 timer.c。该代码尚未赶上具有 clock_gettime() 的 macOS Sierra,尽管可以将其编译为将其与 -DHAVE_CLOCK_GETTIME 一起用作命令行编译器选项。
这段代码是从函数one_test()调用的:
static void one_test(int seed)
{
printf("Seed; %d\n", seed);
enum { COUNT = 10000000 };
test_primality_tester("IsPrime1", seed, IsPrime1, COUNT);
test_primality_tester("IsPrime2", seed, IsPrime2, COUNT);
test_primality_tester("IsPrime3", seed, IsPrime3, COUNT);
test_primality_tester("isprime1", seed, isprime1, COUNT);
test_primality_tester("isprime2", seed, isprime2, COUNT);
test_primality_tester("isprime3", seed, isprime3, COUNT);
}
而主程序可以取一个或一系列种子,或者以当前时间为种子:
int main(int argc, char **argv)
{
if (argc > 1)
{
for (int i = 1; i < argc; i++)
one_test(atoi(argv[i]));
}
else
one_test(time(0));
return(0);
}