Jac*_*cob 1 c performance fsync
我们需要尽可能多的应用程序,保证在报告记录持续存在时,它确实是.我明白你要这样做fsync(fd).但是,由于一些奇怪的原因,使用fsync()会加速写入磁盘的代码,而不是像预期的那样减慢速度.
一些示例测试代码返回以下结果:
no sync() seconds:0.013388 writes per second:0.000001
sync() seconds:0.006268 writes per second:0.000002
Run Code Online (Sandbox Code Playgroud)
以下是产生这些结果的代码:
#include <stdio.h>
#include <fcntl.h>
#include <time.h>
#include <unistd.h>
void withSync() {
int f = open( "/tmp/t8" , O_RDWR | O_CREAT );
lseek (f, 0, SEEK_SET );
int records = 10*1000;
clock_t ustart = clock();
for(int i = 0; i < records; i++) {
write(f, "012345678901234567890123456789" , 30);
fsync(f);
}
clock_t uend = clock();
close (f);
printf(" sync() seconds:%lf writes per second:%lf\n", ((double)(uend-ustart))/(CLOCKS_PER_SEC), ((double)records)/((double)(uend-ustart))/(CLOCKS_PER_SEC));
}
void withoutSync() {
int f = open( "/tmp/t10" , O_RDWR | O_CREAT );
lseek (f, 0, SEEK_SET );
int records = 10*1000;
clock_t ustart = clock();
for(int i = 0; i < records; i++) {
write(f, "012345678901234567890123456789" , 30 );
}
clock_t uend = clock();
close (f);
printf("no sync() seconds:%lf writes per second:%lf \n", ((double)(uend-ustart))/(CLOCKS_PER_SEC), ((double)records)/((double)(uend-ustart))/(CLOCKS_PER_SEC));
}
int main(int argc, const char * argv[])
{
withoutSync();
withSync();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
问题在于您尝试计时I/O写入的方式.您在语义上想要测量I/O记录写入之间的挂钟时间,但您正在使用C库函数clock,该函数测量CPU执行时间而不是总时间.使用clock_gettime时钟选择CLOCK_MONOTONIC或理想情况下CLOCK_MONOTONIC_RAW(后者是Linux扩展).
您没有收集调用之间经过的总时间clock:您正在收集进程旋转CPU周期的时间估计值.您的磁盘I/O(特别是对write和的两个调用fsync)都是阻塞的,这意味着每个系统调用都由内核代表您处理,并且不会在您的进程上下文中消耗CPU.因此,您需要测量挂钟时间的实际差异,这听起来是现实世界中经过的总时间,超出了测试程序流程的范围.实际上,您根本不关心CPU时间fsync.大多数I/O操作的执行时间不会由内核甚至CPU处理; 这将是由于磁盘控制器.
此外,小记录大小可以作为基准.它是同步I/O的常见用例(例如,为事务日志写入元数据).为了获得更大记录大小的时序稳定性,只需在每个定时器间隔和平均/摊销中显着增加循环迭代次数.这将准确地模拟正在写入和同步刷新的小阻塞记录的成本.
请考虑fdatasync提高性能.