Bee*_*ope 4 c++ performance templates
想象一下,我有M个方法,我想要时间,以及N个计时方法(让我们称之为时钟实现)1.具体细节在这里并不重要,但我提到它所以我可以举一个具体的例子.
现在让我们说我有一个模板化的计时方法,如下所示:
typedef void (bench_f)(uint64_t);
template <bench_f METHOD, typename CLOCK>
uint64_t time_method(size_t loop_count) {
auto t0 = CLOCK::now();
METHOD(loop_count);
auto t1 = CLOCK::now();
return t1 - t0;
}
Run Code Online (Sandbox Code Playgroud)
基本上,它将调用括号括METHOD起来CLOCK::now()并返回差异.另请注意,METHOD它不是作为函数指针传递的,而是仅作为模板参数传递 - 因此您获得每个方法的唯一实例化,而不是一个,然后通过指针进行间接调用.
这对我的情况很有效,因为时钟调用和被测方法都是直接静态调用(即类似于call <function address>汇编级别的东西).
现在我想要测试N个方法(可能是50个)和M个时钟方法(可能是5个).我想在编译时实例化所有M*N方法,以便我可以使用特定的时钟实现调用所有测试方法.
现在,执行此操作的"标准"方法只是为被测方法和时钟实现传递一个函数指针(或实现虚函数的类),此时我只需要一个time_method方法就可以创建任何东西我想在运行时组合.在这种特殊情况下,间接调用的性能影响太大,所以我想要模板实例化,并且我愿意支付结果二进制膨胀(例如,M*N = 250实例化我的数字组合).
例如,在运行时,我想获得一个N方法的列表,该方法与特定时钟相结合.
我很好地明确列出了所有N方法和所有M个时钟,但我不想写出M*N实例(DRY和所有这些).
1我在这里非常松散地使用字时钟 - 一些"时钟"实际上可能测量与时间无关的方面,例如堆内存使用或某些特定于应用程序的度量.
template<bench_f* ...> struct method_list {};
template<class...> struct clock_list {};
using time_method_t = uint64_t (*)(size_t);
template<bench_f Method, class...Clocks>
constexpr auto make_single_method_table()
-> std::array<time_method_t, sizeof...(Clocks)> {
return { time_method<Method, Clocks>... };
}
template<bench_f*... Methods, class... Clocks>
constexpr auto make_method_table(method_list<Methods...>, clock_list<Clocks...>)
-> std::array<std::array<time_method_t, sizeof...(Clocks)>, sizeof...(Methods)> {
return { make_single_method_table<Methods, Clocks...>()... };
}
Run Code Online (Sandbox Code Playgroud)