这是我用来计算从文件中读取多少时间来改变读取的字节数的代码。
for(int i = 0; i < TRIALS; i++){
fd = open(argv[1], O_RDONLY);
//Set the file offset to a random position on the file
//But still a multiple of the current current test block size,
//Simulating jumps of the given test block size
//trying to avoid prefetch
lseek(fd, test_block * rand() % (fs / test_block), SEEK_SET);
//How much time takes to read `test_block` bytes
clock_gettime(CLOCK_MONOTONIC, &ts_ini);
ssize_t bytes_read = read(fd, buffer, test_block);
clock_gettime(CLOCK_MONOTONIC, &ts_end);
if(bytes_read > 0){
accum += (((double)(ts_end.tv_sec - ts_ini.tv_sec)) +
(ts_end.tv_nsec - ts_ini.tv_nsec)/NANO_TO_SEC) / TRIALS;
}
//Closing the file after each trial to release resources
close(fd);
}
现在,如果我用这个小shell脚本运行这个程序:
echo "Block Size(bytes) | Avg. Time(seconds)"
for block in 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384
do
./bin/blocksize /tmp/random_gen $block
done
我得到了这个结果:
Block Size(bytes) | Avg. Time(seconds)
4 | 0.002927567500
8 | 0.003120735600
16 | 0.004888980800
32 | 0.003885210600
64 | 0.003578379700
128 | 0.001272970500
256 | 0.004926633700
512 | 0.001281894000
1024 | 0.000243394200
2048 | 0.000175361100
4096 | 0.000001048200
8192 | 0.000001938000
16384 | 0.000003214000
有了这个结果,我假设我的系统的块大小是4096字节(与dumpe2fs
一致),因为此时它不需要做任何额外的操作,只需传递块它从文件中获取,因此非常快,之后重复。 (这是我的猜测)
但是这里有一个奇怪的部分,如果我稍微修改sh脚本,在每次执行之前添加清理缓存,如下所示:
echo "Block Size(bytes) | Avg. Time(seconds)"
for block in 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384
do
echo "echo 3 > /proc/sys/vm/drop_caches" | sudo sh
./bin/blocksize /tmp/random_gen $block
done
然后发生这种情况:
Block Size(bytes) | Avg. Time(seconds)
4 | 0.006217417300
8 | 0.003913319300
16 | 0.004674101500
32 | 0.005444699600
64 | 0.005125086700
128 | 0.004965967700
256 | 0.002433360800
512 | 0.002100266600
1024 | 0.002221131400
2048 | 0.001623008600
4096 | 0.001936151500
8192 | 0.001391976900
16384 | 0.001270749800
这对我没有任何意义。当我先清理缓存时,为什么时间会随着测试块大小的增加而不断下降?
在Ubuntu 14.04LTS 64bit上运行
答案 0 :(得分:1)
有些观点:
文件系统可能在一个系统上具有不同的块大小。
重读相同的文件时,很可能会改善时间 因为缓存。大多数现代高清设备都有板载缓存,操作系统也有缓存。
POSIX提供了一种获取文件系统信息的标准方法,例如块大小:stavfs系统调用。 像stat一样,它也返回一个结构。这显示了我的系统中的一个,每个实现可能有一些额外/不同的字段,所以你的可能会有所不同:
u_long f_bsize; /* preferred file system block size */
u_long f_frsize; /* fundamental filesystem block
(size if supported) */
fsblkcnt_t f_blocks; /* total # of blocks on file system
in units of f_frsize */
fsblkcnt_t f_bfree; /* total # of free blocks */
fsblkcnt_t f_bavail; /* # of free blocks avail to
non-privileged user */
fsfilcnt_t f_files; /* total # of file nodes (inodes) */
fsfilcnt_t f_ffree; /* total # of free file nodes */
fsfilcnt_t f_favail; /* # of inodes avail to
non-privileged user*/
u_long f_fsid; /* file system id (dev for now) */
char f_basetype[FSTYPSZ]; /* target fs type name,
null-terminated */
u_long f_flag; /* bit mask of flags */
u_long f_namemax; /* maximum file name length */
char f_fstr[32]; /* file system specific string */
u_long f_filler[16]; /* reserved for future expansion */
http://pubs.opengroup.org/onlinepubs/009695399/basedefs/sys/statvfs.h.html
答案 1 :(得分:0)
文件系统缓存和预读,很可能。
文件系统看到您读取了第一个4k块,并且它基于您将读取文件其余部分的假设读取更多内容。
尝试使用 O_RDONLY | O_DIRECT
标记来绕过文件系统缓存。如果文件系统支持直接IO,您应该看到差异。您可能必须使用valloc()/memalign()
来获取内存页对齐的缓冲区以将数据读入。