在Linux上,access()比stat()更快吗?

Jos*_*vin 11 linux performance posix file stat

我会假设access()只是stat()的一个包装,但我一直在谷歌上搜索并找到一些关于用"更便宜"的访问调用替换stat调用的轶事.假设您只对检查文件是否存在感兴趣,访问速度更快吗?文件系统完全不同吗?

mya*_*aut 9

理论

我不信.

在内核的较低层中,两者之间没有太大区别,access()并且stat()调用都执行查找操作:它们将文件名映射到dentry缓存中的条目和inode(它是实际的内核结构inode).查找是缓慢的操作,因为您需要为路径的每个部分执行它,即/usr/bin/cat您需要查找usr,bin然后cat它可能需要从磁盘读取 - 这就是为什么inode和dentries缓存在内存中.

这些调用之间的主要区别在于stat()执行inode结构到stat结构的转换,同时access()会进行简单的检查,但与查找时间相比,这个时间很短.

真正的性能增益可以实现像-operations faccessat()fstatat(),它允许open()目录一次,只是比较:

struct stat s;
stat("/usr/bin/cat", &s);   // lookups usr, bin and cat = 3
stat("/usr/bin/less", &s);  // lookups usr, bin and less = 3

int fd = open("/usr/bin");  // lookups usr, bin = 2
fstatat(fd, "cat", &s);     // lookups cat = 1
fstatat(fd, "less", &s);    // lookups less = 1
Run Code Online (Sandbox Code Playgroud)

实验

我写了一个小的python脚本,调用stat()access():

import os, time, random
files = ['gzexe', 'catchsegv', 'gtroff', 'gencat', 'neqn', 'gzip', 
        'getent', 'sdiff', 'zcat', 'iconv', 'not_exists', 'ldd', 
        'unxz', 'zcmp', 'locale', 'xz', 'zdiff', 'localedef', 'xzcat']
access = lambda fn: os.access(fn, os.R_OK)

for i in xrange(1, 80000): 
    try:
        random.choice((access, os.stat))("/usr/bin/" + random.choice(files))
    except:
        continue
Run Code Online (Sandbox Code Playgroud)

我使用SystemTap跟踪系统以测量在不同操作中花费的时间.两者stat()access()系统调用都使用user_path_at_empty()代表查找操作的内核函数:

stap -ve ' global tm, times, path;
probe lookup = kernel.function("user_path_at_empty") 
    { name = "lookup"; pathname = user_string_quoted($name); }
probe lookup.return = kernel.function("user_path_at_empty").return 
    { name = "lookup"; }
probe stat = syscall.stat 
    { pathname = filename; }
probe stat, syscall.access, lookup
        { if(pid() == target() && isinstr(pathname, "/usr/bin")) {
        tm[name] = local_clock_ns(); } }
probe syscall.stat.return, syscall.access.return, lookup.return
        { if(pid() == target() && tm[name]) {
        times[name] <<< local_clock_ns() - tm[name];
        delete tm[name];
        } }
    ' -c 'python stat-access.py'
Run Code Online (Sandbox Code Playgroud)

结果如下:

         COUNT      AVG
lookup   80018    1.67 us
stat     40106    3.92 us
access   39903    4.27 us
Run Code Online (Sandbox Code Playgroud)

请注意,我在实验中禁用了SELinux,因为它会对结果产生重大影响.

  • 你正在测量缓存的情况.有可能`stat`必须检查'access`没有的东西,比如块数.大多数文件系统可能存储​​块计数在inode中,而不是走块映射B树,因为STAT-每一个文件的目录是他们需要优化的一个很常见的操作.鉴于此,回答`stat`查询所需的一切可能来自一个磁盘寻求读取inode. (3认同)
  • @Siscia 你的实验是如何进行的?如果没有更多信息,很难判断哪些因素起作用。 (2认同)