【linux kernel 3.10】查看文件内容是否全部被page cache所缓存

前言

bpf提供了一种方法,可以使用户在内核函数运行的某个阶段(如运行前和运行后)插入一段用户指定的程序并运行。这篇文章实现了一个bpf小程序,可以查看某个文件是否全部被缓存到page cache中,并打印出文件被缓存了多少页和文件一共有多少页

1. 安装bcc

centos发行版为例,直接yum install bcc -y即可
其他系统请参见INSTALL

2. bpf程序源码

#!/usr/bin/env python3
#coding=utf-8

from __future__ import print_function
from bcc import BPF
from bcc.utils import printb
import sys
import argparse

# arguments
examples = """examples:
    ./stacksnoop     # print nr_cached_pages and nr_all_pages for all files that called sys_read
    ./stacksnoop -f ext4_sync_fs    # print nr_cached_pages and nr_all_pages for 'ext4_sync_fs' file
    ./stacksnoop -p 185 -f ext4_sync_fs    # ... only when PID 185 is on-CPU
"""
parser = argparse.ArgumentParser(
    description="Trace and print kernel stack traces for a kernel function",
    formatter_class=argparse.RawDescriptionHelpFormatter,
    epilog=examples)
parser.add_argument("-p", "--pid",
    help="trace this PID only")
parser.add_argument("-f", "--f_name",
    help = "trace this file only")
args = parser.parse_args()

# define BPF program
bpf_text = """
#include <uapi/linux/ptrace.h>
#include <linux/pagemap.h>

static int my_strlen(const char* str) {
    int i = 0;

    for(; str[i] != '\\0'; ++i) { }

    return i;
}

void trace_start(struct pt_regs *ctx, struct file *file, char __user *buf, size_t count, loff_t *ppos) {
    struct address_space *mapping = file->f_mapping;
    struct inode *inode = mapping->host;
    unsigned long nr_cached_pages = 0;
    unsigned long nr_all_pages = 0;
    loff_t size = 0;
    const unsigned char *f_name = file->f_path.dentry->d_name.name;
    const char *filter_name = "NAME";
    int i = 0;

    u32 pid = bpf_get_current_pid_tgid();
    PID_FILTER
    NAME_FILTER

    nr_cached_pages = mapping->nrpages;
    bpf_probe_read(&size, sizeof(inode->i_size), &inode->i_size);
    size += (PAGE_CACHE_SIZE - 1);
    nr_all_pages = (size -1) >> PAGE_CACHE_SHIFT;

    bpf_trace_printk("file_name:%s nr_cached_pages:%lu nr_all_pages:%lu\\n", f_name, nr_cached_pages, nr_all_pages);
}

"""

if args.pid:
    bpf_text = bpf_text.replace('PID_FILTER',
            'if (pid != %s) { return; }' % args.pid)
else:
    bpf_text = bpf_text.replace('PID_FILTER','')

if args.f_name:
    bpf_text = bpf_text.replace('NAME_FILTER',
            'for(; i < my_strlen(filter_name); ++i) { if (filter_name[i] != f_name[i]) return ;}')
    bpf_text = bpf_text.replace('NAME', args.f_name)
else:
    bpf_text = bpf_text.replace('NAME_FILTER','')

# print(bpf_text)
# init BPF
b = BPF(text=bpf_text)
if BPF.get_kprobe_functions(b'vfs_read'):
    print("trace vfs_read succ")
    b.attach_kprobe(event="vfs_read", fn_name="trace_start")
else:
    print("don't support trace vfs_read, exit")
    sys.exit(-1)

# print header
print("%-16s %-6s %s" % ("COMM", "PID", "MESSAGE"))

# format output
while 1:
    try:
        (task, pid, cpu, flags, ts, msg) = b.trace_fields()
        printb(b"%-16s %-6d %s" % (task, pid, msg))
    except KeyboardInterrupt:
        exit()

3. 使用方法

在这里插入图片描述

第一列打印进程名,第二列打印进程pid,第三列打印我们自定义消息
nr_cached_pages是已经被page cache所缓存的页面数量,nr_all_pages是文件所有的页面数量
可以看到,第一次读his文件时,并没有文件内容被缓存,第二次则全部被page cache所缓存
注意,使用时最好使用-f或者-p参数,否则会把所有正在读文件的进程全部打印出来

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值