背景
最近替换了项目内部的 log 库,使用 spdlog 开源库:
github 地址: https://github.com/gabime/spdlog
spdlog 在主页中所提及到其性能达: 5,777,626/sec ,惊为天人
因此认真阅读了 spdlog 源码,做了些实验,摸底了下文件读写性能
fwrite 函数
用户态函数,作用:把文件数据从写到用户态缓冲区
缓冲区可以通过 setbuf/setvbuf/setbuffer 来指定(可自己控制其大小),或 libc 内置缓冲区(对程序不可见)
来写个测试程序,测试下其性能:
#include <chrono>
#include <cstdio>
#include <cstdlib>
void test1(int _)
{
printf("TEST CASE: 只调用 fwrite\n");
FILE* f = fopen("test.txt", "wb");
if (!f)
{
printf("can not open file\n");
exit(1);
}
int iters = 1000000;
using std::chrono::high_resolution_clock;
auto start = high_resolution_clock::now();
for (int i = 0; i < iters; i++)
{
char msg[1024];
auto len = snprintf(msg, sizeof(msg), "Hello logger: msg number %d\n", i);
fwrite(msg, len, 1, f);
}
auto delta = high_resolution_clock::now() - start;
auto delta_d = std::chrono::duration_cast<std::chrono::duration<double>>(delta).count();
printf("Elapsed: %0.2f secs %d/sec\n", delta_d, int(iters / delta_d));
fclose(f);
}
测试结果如下:
TPS 在 600w+/s
(如果想要确保上述测试无调用 fflush ,可以通过 setbuf/setvbuf/setbuffer 把缓冲区设置大些)
fflush 函数
system call 函数,会切一次用户态到内核态,作用: 把文件数据从用户态缓存区到内核态 page cache 页中
来写个测试程序,测试下其性能:
#include <chrono>
#include <cstdio>
#include <cstdlib>
void test2(int _)
{
printf("TEST CASE: 每次调用 fwrite fflush\n");
FILE* f = fopen("test.txt", "wb");
if (!f)
{
printf("can not open file\n");
exit(1);
}
int iters = 1000000;
using std::chrono::high_resolution_clock;
auto start = high_resolution_clock::now();
for (int i = 0; i < iters; i++)
{
char msg[1024];
auto len = snprintf(msg, sizeof(msg), "Hello logger: msg number %d\n", i);
fwrite(msg, len, 1, f);
fflush(f);
}
auto delta = high_resolution_clock::now() - start;
auto delta_d = std::chrono::duration_cast<std::chrono::duration<double>>(delta).count();
printf("Elapsed: %0.2f secs %d/sec\n", delta_d, int(iters / delta_d));
fclose(f);
}
测试结果如下:
TPS 在 70w+/s
spdlog 提供的性能测试分析
spdlog 提供的性能测试 TPS 在 500w+/sec ,因此可以断定该基准测试没有调用过 fflush
本人 review 了下其测试代码: https://github.com/gabime/spdlog/blob/v1.x/bench/bench.cpp
确实无调用 fflush
并提 issue ,向作者确认: https://github.com/gabime/spdlog/issues/1392
作者的回复也明确说明无调用 fflush :
This is typical and recommended usage. you Of course calling flush on each call would hurt performance and you are welcome to perform your own bench according to your needs.
因此, spdlog 对外号称的 Very fast, header-only/compiled, C++ logging library.
是有些沽名钓誉,混淆视听的
注:本文没有诋毁 spdlog 的意思, spdlog 非常好用与扩展,后续会写下其源代码分析
内核 page cache 页
fflush 后数据到 page cache 页了,有没有感性的认识呢?
是有的,请看下面的测试:
内核维护 page cache 页游自己的算法,程序通常是无法干预的,也不需要干预
一次压测遇到的容器内存占用满问题
监视容器的工具,内存计算包含了 buff/cache 字段值。
宿主机内存 150G+ ,而容器内存 8G
由于压测,服务在大量的写文件,导致 buff/cache 值很高
于是监测图形上内存都是 100% 被占满
该问题,前面合作方追问一直无法给予正面解释,现在终于弄明白啦!