背景

Fluent Bit 在代码中有将时间转化为浮点数(单位秒)再和 0.0 对比判断时间是否为 flb_time_zero 的初始值。在这个场景下用整型运算应该更快,但在提交 PR 前还是需要用数据说话,所以先来 benchmark 一下。

环境准备

这次我使用了 Google 维护的 benchmark 库,使用 Conan 管理依赖并用 CMake 构建。先安装一下:

sudo port install pipx cmake
pipx install conan

然后准备 conanfile.txtCMakeLists.txt,可以参考我的仓库 benchmarks

benchmark 单元编写

static void BM_Nano(benchmark::State& state) {
    struct flb_time out_time = {0};
    flb_time_zero(&out_time);
    bool flag;
    for (auto _ : state) {
        flag = flb_time_to_nanosec(&out_time) == 0L;
    }
}

只要把需要测试的代码放到 for 循环内就会自动测试这段代码的性能。但测试结果出来后有点奇怪:

-----------------------------------------------------
Benchmark           Time             CPU   Iterations
-----------------------------------------------------
BM_Nano         0.249 ns        0.249 ns   1000000000
BM_Sec          0.248 ns        0.248 ns   1000000000

运行了几次时间上都差不多,难道现代 CPU 的浮点性能这么强了?感觉有点不对劲,试着加上一个 BM_None 测试做对比,代码里直接赋值 true 不做任何运算:

for (auto _ : state) {
    flag = true;
}

测试出来结果和其他两个都相同,数据肯定是有问题了。

排查原因

打开 Compiler Explorer,添加 benchmark 库,一看编译出的汇编就明白了。

bm1.png

整个 for 循环都被优化掉了。。。

解决方案

在网上搜索如何阻止编译器优化某部分代码,发现最简单且相对通用的方式是使用 volatile 关键字,那给 flag 变量加上 volatile 试试。

bm2.png

汇编变长了,但还是没生成浮点运算。看来还不够 volatile,再加到函数参数上试试:

bm3.png

总算看到要 benchmark 的函数被上色了!再跑一遍 benchmark 试试?

-----------------------------------------------------
Benchmark           Time             CPU   Iterations
-----------------------------------------------------
BM_None         0.242 ns        0.242 ns   1000000000
BM_Nano         0.372 ns        0.371 ns   1000000000
BM_Sec           1.11 ns         1.11 ns    623846997

果然如我所料,浮点运算的性能还是要差一些的,于是提交 PR #4535,搞定收工。

标签: none

添加新评论