利用strace查找文件热点
在做性能调优时,遇到这么一个问题:已知国产机(飞腾+麒麟OS)上机械硬盘的性能非常差,文件读写会有不少开销,那么怎么跟踪程序的读写情况,尽量优化掉不必要的读写呢?这需要查找文件热点。对于这项工作,BPF Compiler Collection里的filetop是个很好的选择,不过BCC这组工具在麒麟OS源里没有提供,遂考虑用strace实现。 跟踪系统调用 严格来说,strace并不能直接跟踪文件的读写情况,而是跟踪所有接受一个文件名为参数的系统调用。不过无论是频繁读写还是频繁判断文件状态,对于调优而言都是可待优化的,因此这里没有严格区分两者。 跟踪文件相关的系统调用: $ strace -t -e trace=file -o strace.log COMMAND # --trace=file # Trace all system calls which take a file name as an argument. You can think of this as an abbreviation for -e trace=open,stat,chmod,unlink,... which is useful to seeing what files the process is referencing. --trace=还可以使用process、network、signal、desc、memory等等,参见https://man7.org/linux/man-pages/man1/strace.1.html 示例 $ strace -t -e trace=file -o strace.log fc-list $ cat strace.log 18:07:24 execve("/home/tanqiao/program/hotspot/hotspot", ["hotspot"], 0x7ffc0b28a138 /* 80 vars */) = 0 18:07:24 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (没有那个文件或目录) 18:07:24 openat(AT_FDCWD, "/usr/local/cuda-11.5/lib64/tls/x86_64/x86_64/libtinfo.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录) 18:07:24 stat("/usr/local/cuda-11.5/lib64/tls/x86_64/x86_64", 0x7ffc75b3d900) = -1 ENOENT (没有那个文件或目录) 18:07:24 openat(AT_FDCWD, "/usr/local/cuda-11.5/lib64/tls/x86_64/libtinfo.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录) 18:07:24 stat("/usr/local/cuda-11.5/lib64/tls/x86_64", 0x7ffc75b3d900) = -1 ENOENT (没有那个文件或目录) 18:07:24 openat(AT_FDCWD, "/usr/local/cuda-11.5/lib64/tls/x86_64/libtinfo.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录) 18:07:24 stat("/usr/local/cuda-11.5/lib64/tls/x86_64", 0x7ffc75b3d900) = -1 ENOENT (没有那个文件或目录) 18:07:24 openat(AT_FDCWD, "/usr/local/cuda-11.5/lib64/tls/libtinfo.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录) 18:07:24 stat("/usr/local/cuda-11.5/lib64/tls", 0x7ffc75b3d900) = -1 ENOENT (没有那个文件或目录) 18:07:24 openat(AT_FDCWD, "/usr/local/cuda-11.5/lib64/x86_64/x86_64/libtinfo.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (没有那个文件或目录) 18:07:24 stat("/usr/local/cuda-11.5/lib64/x86_64/x86_64", 0x7ffc75b3d900) = -1 ENOENT (没有那个文件或目录) 文件处理 用grep去除打开失败的文件 $ cat strace.log | grep -v 'ENOENT' # -v, --invert-match 改变匹配的意义,只选择不匹配的行 用awk提取双引号内的值 $ awk -F '"' '{print $2}' 结合sort和uniq去重 $ sort | uniq -c # uniq # -c, --count 每行前附上重复出现的次数作为前缀 输出类似于: ...