在 Linux 中是否有可能看到有多少来自用户空间的读写请求最终导致块设备的缓存命中和未命中?
答案1
您可以开发自己的系统水龙头脚本。您需要考虑以下两个子系统:
- VFS:这代表缓冲区缓存之前的所有 I/O 请求(即绝对每个 I/O 请求);查看“vfs.read”、“vfs.write”和“kernel.function(“vfs_*”)”探测;您需要根据各自的主设备号+次设备号过滤出您想要监控的块设备。
- 块:这代表在 I/O 调度程序(它还会合并 + 重新排序 I/O 请求)之前发送到块设备的所有 I/O 请求;在这里我们知道缓冲区缓存错过了哪些请求;查看“ioblock.request”探测。
SystemTap 开发需要一些时间来学习。如果您是一名中等水平的开发人员,并且对 Linux 有很好的了解,那么您应该在 3-4 天内完成。是的,学习需要时间,但您会对结果非常满意 - SystemTap 让您有机会(安全地)在 Linux 内核的几乎任何地方放置探测器。
请注意,您的内核必须支持加载和卸载内核模块。如今大多数现成的内核都支持此功能。您还需要为内核安装调试符号。对于我的 Ubuntu 系统,这就像下载几百 MB 的 .deb 文件一样简单,Ubuntu 内核开发团队为我编译了该文件。这在系统tapOnUbuntu例如,Wiki 页面。
PS:仅当您没有其他解决方案时才采用 SystemTap 方法,因为它是一个全新的框架,您必须学习,这会花费时间/金钱,有时还会令人沮丧。
答案2
我继续为此编写了一个 stap 脚本。systemtap wiki 上有一个,但它似乎不正确。在基本测试中,这似乎非常准确,但 YMMV。
#! /usr/bin/env stap
global total_bytes, disk_bytes, counter
probe vfs.read.return {
if (bytes_read>0) {
if (devname=="N/A") {
} else {
total_bytes += bytes_read
}
}
}
probe ioblock.request
{
if (rw == 0 && size > 0)
{
if (devname=="N/A") {
} else {
disk_bytes += size
}
}
}
# print VFS hits and misses every 5 second, plus the hit rate in %
probe timer.s(5) {
if (counter%15 == 0) {
printf ("\n%18s %18s %10s %10s\n",
"Cache Reads (KB)", "Disk Reads (KB)", "Miss Rate", "Hit Rate")
}
cache_bytes = total_bytes - disk_bytes
if (cache_bytes < 0)
cache_bytes = 0
counter++
hitrate = 10000 * cache_bytes / (cache_bytes+disk_bytes)
missrate = 10000 * disk_bytes / (cache_bytes+disk_bytes)
printf ("%18d %18d %6d.%02d%% %6d.%02d%%\n",
cache_bytes/1024, disk_bytes/1024,
missrate/100, missrate%100, hitrate/100, hitrate%100)
total_bytes = 0
disk_bytes = 0
}
答案3
/proc/slabinfo 是一个不错的开始,但并没有提供您所需的全部信息(不要被启用了多个核心和统计信息的系统的命中/未命中百分比所欺骗;那些是其他东西)。据我所知,没有办法从内核中提取出这些特定信息,尽管编写一些代码来做这件事应该不会太难。
编辑:http://www.kernel.org/doc/man-pages/online/pages/man5/slabinfo.5.html
答案4
如果您对特定进程的 IO 命中/未命中率感兴趣,一种简单但非常有效的方法是读取文件/proc/<pid>/io
。
在这里你会发现 4 个关键价值:
rchar
:从中读取的字节总数应用观点(即:从物理存储和缓存中读取没有区别)wchar
:如上所述,但关于写入的字节数read_bytes
:字节真的从存储子系统读取write_bytes
:字节真的写入存储子系统
假设一个进程有以下值:
rchar: 1000000
read_bytes: 200000
读取缓存未命中率(以字节为单位)为100*200000/1000000 = 20%
,命中率为100-20 = 80%
但是还有一个问题:该rchar
值包括 tty IO 之类的东西,因此对于从管道读取/写入大量数据的进程,上述计算会出现偏差,报告的命中率会高于有效命中率。