xref: /aosp_15_r20/external/bcc/tools/readahead.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/env python
2*387f9dfdSAndroid Build Coastguard Worker# @lint-avoid-python-3-compatibility-imports
3*387f9dfdSAndroid Build Coastguard Worker#
4*387f9dfdSAndroid Build Coastguard Worker# readahead     Show performance of read-ahead cache
5*387f9dfdSAndroid Build Coastguard Worker#               For Linux, uses BCC, eBPF
6*387f9dfdSAndroid Build Coastguard Worker#
7*387f9dfdSAndroid Build Coastguard Worker# Copyright (c) 2020 Suchakra Sharma <[email protected]>
8*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License")
9*387f9dfdSAndroid Build Coastguard Worker# This was originally created for the BPF Performance Tools book
10*387f9dfdSAndroid Build Coastguard Worker# published by Addison Wesley. ISBN-13: 9780136554820
11*387f9dfdSAndroid Build Coastguard Worker# When copying or porting, include this comment.
12*387f9dfdSAndroid Build Coastguard Worker#
13*387f9dfdSAndroid Build Coastguard Worker# 20-Aug-2020   Suchakra Sharma     Ported from bpftrace to BCC
14*387f9dfdSAndroid Build Coastguard Worker# 17-Sep-2021   Hengqi Chen         Migrated to kfunc
15*387f9dfdSAndroid Build Coastguard Worker# 30-Jan-2023   Rong Tao            Support more kfunc/kprobe, introduce folio
16*387f9dfdSAndroid Build Coastguard Worker
17*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function
18*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF
19*387f9dfdSAndroid Build Coastguard Workerfrom time import sleep
20*387f9dfdSAndroid Build Coastguard Workerimport ctypes as ct
21*387f9dfdSAndroid Build Coastguard Workerimport argparse
22*387f9dfdSAndroid Build Coastguard Worker
23*387f9dfdSAndroid Build Coastguard Worker# arguments
24*387f9dfdSAndroid Build Coastguard Workerexamples = """examples:
25*387f9dfdSAndroid Build Coastguard Worker    ./readahead -d 20       # monitor for 20 seconds and generate stats
26*387f9dfdSAndroid Build Coastguard Worker"""
27*387f9dfdSAndroid Build Coastguard Worker
28*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser(
29*387f9dfdSAndroid Build Coastguard Worker    description="Monitor performance of read ahead cache",
30*387f9dfdSAndroid Build Coastguard Worker    formatter_class=argparse.RawDescriptionHelpFormatter,
31*387f9dfdSAndroid Build Coastguard Worker    epilog=examples)
32*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-d", "--duration", type=int,
33*387f9dfdSAndroid Build Coastguard Worker    help="total duration to monitor for, in seconds")
34*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args()
35*387f9dfdSAndroid Build Coastguard Workerif not args.duration:
36*387f9dfdSAndroid Build Coastguard Worker    args.duration = 99999999
37*387f9dfdSAndroid Build Coastguard Worker
38*387f9dfdSAndroid Build Coastguard Worker# BPF program
39*387f9dfdSAndroid Build Coastguard Workerbpf_text = """
40*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h>
41*387f9dfdSAndroid Build Coastguard Worker#include <linux/mm_types.h>
42*387f9dfdSAndroid Build Coastguard Worker#include <linux/mm.h>
43*387f9dfdSAndroid Build Coastguard Worker
44*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(flag, u32, u8);            // used to track if we are in do_page_cache_readahead()
45*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(birth, struct page*, u64); // used to track timestamps of cache alloc'ed page
46*387f9dfdSAndroid Build Coastguard WorkerBPF_ARRAY(pages);                   // increment/decrement readahead pages
47*387f9dfdSAndroid Build Coastguard WorkerBPF_HISTOGRAM(dist);
48*387f9dfdSAndroid Build Coastguard Worker"""
49*387f9dfdSAndroid Build Coastguard Worker
50*387f9dfdSAndroid Build Coastguard Workerbpf_text_kprobe = """
51*387f9dfdSAndroid Build Coastguard Workerint entry__do_page_cache_readahead(struct pt_regs *ctx) {
52*387f9dfdSAndroid Build Coastguard Worker    u32 pid;
53*387f9dfdSAndroid Build Coastguard Worker    u8 one = 1;
54*387f9dfdSAndroid Build Coastguard Worker    pid = bpf_get_current_pid_tgid();
55*387f9dfdSAndroid Build Coastguard Worker    flag.update(&pid, &one);
56*387f9dfdSAndroid Build Coastguard Worker    return 0;
57*387f9dfdSAndroid Build Coastguard Worker}
58*387f9dfdSAndroid Build Coastguard Worker
59*387f9dfdSAndroid Build Coastguard Workerint exit__do_page_cache_readahead(struct pt_regs *ctx) {
60*387f9dfdSAndroid Build Coastguard Worker    u32 pid;
61*387f9dfdSAndroid Build Coastguard Worker    u8 zero = 0;
62*387f9dfdSAndroid Build Coastguard Worker    pid = bpf_get_current_pid_tgid();
63*387f9dfdSAndroid Build Coastguard Worker    flag.update(&pid, &zero);
64*387f9dfdSAndroid Build Coastguard Worker    return 0;
65*387f9dfdSAndroid Build Coastguard Worker}
66*387f9dfdSAndroid Build Coastguard Worker
67*387f9dfdSAndroid Build Coastguard Workerint exit__page_cache_alloc(struct pt_regs *ctx) {
68*387f9dfdSAndroid Build Coastguard Worker    u32 pid;
69*387f9dfdSAndroid Build Coastguard Worker    u64 ts;
70*387f9dfdSAndroid Build Coastguard Worker    struct page *retval = (struct page*) GET_RETVAL_PAGE;
71*387f9dfdSAndroid Build Coastguard Worker    u32 zero = 0; // static key for accessing pages[0]
72*387f9dfdSAndroid Build Coastguard Worker    pid = bpf_get_current_pid_tgid();
73*387f9dfdSAndroid Build Coastguard Worker    u8 *f = flag.lookup(&pid);
74*387f9dfdSAndroid Build Coastguard Worker    if (f != NULL && *f == 1) {
75*387f9dfdSAndroid Build Coastguard Worker        ts = bpf_ktime_get_ns();
76*387f9dfdSAndroid Build Coastguard Worker        birth.update(&retval, &ts);
77*387f9dfdSAndroid Build Coastguard Worker        pages.atomic_increment(zero);
78*387f9dfdSAndroid Build Coastguard Worker    }
79*387f9dfdSAndroid Build Coastguard Worker    return 0;
80*387f9dfdSAndroid Build Coastguard Worker}
81*387f9dfdSAndroid Build Coastguard Worker
82*387f9dfdSAndroid Build Coastguard Workerint entry_mark_page_accessed(struct pt_regs *ctx) {
83*387f9dfdSAndroid Build Coastguard Worker    u64 ts, delta;
84*387f9dfdSAndroid Build Coastguard Worker    struct page *arg0 = (struct page *) PT_REGS_PARM1(ctx);
85*387f9dfdSAndroid Build Coastguard Worker    u32 zero = 0; // static key for accessing pages[0]
86*387f9dfdSAndroid Build Coastguard Worker    u64 *bts = birth.lookup(&arg0);
87*387f9dfdSAndroid Build Coastguard Worker    if (bts != NULL) {
88*387f9dfdSAndroid Build Coastguard Worker        delta = bpf_ktime_get_ns() - *bts;
89*387f9dfdSAndroid Build Coastguard Worker        dist.atomic_increment(bpf_log2l(delta/1000000));
90*387f9dfdSAndroid Build Coastguard Worker        pages.atomic_increment(zero, -1);
91*387f9dfdSAndroid Build Coastguard Worker        birth.delete(&arg0); // remove the entry from hashmap
92*387f9dfdSAndroid Build Coastguard Worker    }
93*387f9dfdSAndroid Build Coastguard Worker    return 0;
94*387f9dfdSAndroid Build Coastguard Worker}
95*387f9dfdSAndroid Build Coastguard Worker"""
96*387f9dfdSAndroid Build Coastguard Worker
97*387f9dfdSAndroid Build Coastguard Workerbpf_text_kfunc = """
98*387f9dfdSAndroid Build Coastguard WorkerKFUNC_PROBE(RA_FUNC)
99*387f9dfdSAndroid Build Coastguard Worker{
100*387f9dfdSAndroid Build Coastguard Worker    u32 pid = bpf_get_current_pid_tgid();
101*387f9dfdSAndroid Build Coastguard Worker    u8 one = 1;
102*387f9dfdSAndroid Build Coastguard Worker
103*387f9dfdSAndroid Build Coastguard Worker    flag.update(&pid, &one);
104*387f9dfdSAndroid Build Coastguard Worker    return 0;
105*387f9dfdSAndroid Build Coastguard Worker}
106*387f9dfdSAndroid Build Coastguard Worker
107*387f9dfdSAndroid Build Coastguard WorkerKRETFUNC_PROBE(RA_FUNC)
108*387f9dfdSAndroid Build Coastguard Worker{
109*387f9dfdSAndroid Build Coastguard Worker    u32 pid = bpf_get_current_pid_tgid();
110*387f9dfdSAndroid Build Coastguard Worker    u8 zero = 0;
111*387f9dfdSAndroid Build Coastguard Worker
112*387f9dfdSAndroid Build Coastguard Worker    flag.update(&pid, &zero);
113*387f9dfdSAndroid Build Coastguard Worker    return 0;
114*387f9dfdSAndroid Build Coastguard Worker}
115*387f9dfdSAndroid Build Coastguard Worker
116*387f9dfdSAndroid Build Coastguard WorkerKFUNC_PROBE(mark_page_accessed, struct page *arg0)
117*387f9dfdSAndroid Build Coastguard Worker{
118*387f9dfdSAndroid Build Coastguard Worker    u64 ts, delta;
119*387f9dfdSAndroid Build Coastguard Worker    u32 zero = 0; // static key for accessing pages[0]
120*387f9dfdSAndroid Build Coastguard Worker    u64 *bts = birth.lookup(&arg0);
121*387f9dfdSAndroid Build Coastguard Worker
122*387f9dfdSAndroid Build Coastguard Worker    if (bts != NULL) {
123*387f9dfdSAndroid Build Coastguard Worker        delta = bpf_ktime_get_ns() - *bts;
124*387f9dfdSAndroid Build Coastguard Worker        dist.atomic_increment(bpf_log2l(delta/1000000));
125*387f9dfdSAndroid Build Coastguard Worker        pages.atomic_increment(zero, -1);
126*387f9dfdSAndroid Build Coastguard Worker        birth.delete(&arg0); // remove the entry from hashmap
127*387f9dfdSAndroid Build Coastguard Worker    }
128*387f9dfdSAndroid Build Coastguard Worker    return 0;
129*387f9dfdSAndroid Build Coastguard Worker}
130*387f9dfdSAndroid Build Coastguard Worker"""
131*387f9dfdSAndroid Build Coastguard Worker
132*387f9dfdSAndroid Build Coastguard Workerbpf_text_kfunc_cache_alloc_ret_page = """
133*387f9dfdSAndroid Build Coastguard WorkerKRETFUNC_PROBE(__page_cache_alloc, gfp_t gfp, struct page *retval)
134*387f9dfdSAndroid Build Coastguard Worker{
135*387f9dfdSAndroid Build Coastguard Worker    u64 ts;
136*387f9dfdSAndroid Build Coastguard Worker    u32 zero = 0; // static key for accessing pages[0]
137*387f9dfdSAndroid Build Coastguard Worker    u32 pid = bpf_get_current_pid_tgid();
138*387f9dfdSAndroid Build Coastguard Worker    u8 *f = flag.lookup(&pid);
139*387f9dfdSAndroid Build Coastguard Worker
140*387f9dfdSAndroid Build Coastguard Worker    if (f != NULL && *f == 1) {
141*387f9dfdSAndroid Build Coastguard Worker        ts = bpf_ktime_get_ns();
142*387f9dfdSAndroid Build Coastguard Worker        birth.update(&retval, &ts);
143*387f9dfdSAndroid Build Coastguard Worker        pages.atomic_increment(zero);
144*387f9dfdSAndroid Build Coastguard Worker    }
145*387f9dfdSAndroid Build Coastguard Worker    return 0;
146*387f9dfdSAndroid Build Coastguard Worker}
147*387f9dfdSAndroid Build Coastguard Worker"""
148*387f9dfdSAndroid Build Coastguard Worker
149*387f9dfdSAndroid Build Coastguard Workerbpf_text_kfunc_cache_alloc_ret_folio = """
150*387f9dfdSAndroid Build Coastguard WorkerKRETFUNC_PROBE(filemap_alloc_folio, gfp_t gfp, unsigned int order,
151*387f9dfdSAndroid Build Coastguard Worker    struct folio *retval)
152*387f9dfdSAndroid Build Coastguard Worker{
153*387f9dfdSAndroid Build Coastguard Worker    u64 ts;
154*387f9dfdSAndroid Build Coastguard Worker    u32 zero = 0; // static key for accessing pages[0]
155*387f9dfdSAndroid Build Coastguard Worker    u32 pid = bpf_get_current_pid_tgid();
156*387f9dfdSAndroid Build Coastguard Worker    u8 *f = flag.lookup(&pid);
157*387f9dfdSAndroid Build Coastguard Worker    struct page *page = folio_page(retval, 0);
158*387f9dfdSAndroid Build Coastguard Worker
159*387f9dfdSAndroid Build Coastguard Worker    if (f != NULL && *f == 1) {
160*387f9dfdSAndroid Build Coastguard Worker        ts = bpf_ktime_get_ns();
161*387f9dfdSAndroid Build Coastguard Worker        birth.update(&page, &ts);
162*387f9dfdSAndroid Build Coastguard Worker        pages.atomic_increment(zero);
163*387f9dfdSAndroid Build Coastguard Worker    }
164*387f9dfdSAndroid Build Coastguard Worker    return 0;
165*387f9dfdSAndroid Build Coastguard Worker}
166*387f9dfdSAndroid Build Coastguard Worker"""
167*387f9dfdSAndroid Build Coastguard Worker
168*387f9dfdSAndroid Build Coastguard Workerif BPF.support_kfunc():
169*387f9dfdSAndroid Build Coastguard Worker    if BPF.get_kprobe_functions(b"__do_page_cache_readahead"):
170*387f9dfdSAndroid Build Coastguard Worker        ra_func = "__do_page_cache_readahead"
171*387f9dfdSAndroid Build Coastguard Worker    elif BPF.get_kprobe_functions(b"do_page_cache_ra"):
172*387f9dfdSAndroid Build Coastguard Worker        ra_func = "do_page_cache_ra"
173*387f9dfdSAndroid Build Coastguard Worker    elif BPF.get_kprobe_functions(b"page_cache_ra_order"):
174*387f9dfdSAndroid Build Coastguard Worker        ra_func = "page_cache_ra_order"
175*387f9dfdSAndroid Build Coastguard Worker    else:
176*387f9dfdSAndroid Build Coastguard Worker        print("Not found any kfunc.")
177*387f9dfdSAndroid Build Coastguard Worker        exit()
178*387f9dfdSAndroid Build Coastguard Worker    bpf_text += bpf_text_kfunc.replace("RA_FUNC", ra_func)
179*387f9dfdSAndroid Build Coastguard Worker    if BPF.get_kprobe_functions(b"__page_cache_alloc"):
180*387f9dfdSAndroid Build Coastguard Worker        bpf_text += bpf_text_kfunc_cache_alloc_ret_page
181*387f9dfdSAndroid Build Coastguard Worker    else:
182*387f9dfdSAndroid Build Coastguard Worker        bpf_text += bpf_text_kfunc_cache_alloc_ret_folio
183*387f9dfdSAndroid Build Coastguard Worker    b = BPF(text=bpf_text)
184*387f9dfdSAndroid Build Coastguard Workerelse:
185*387f9dfdSAndroid Build Coastguard Worker    bpf_text += bpf_text_kprobe
186*387f9dfdSAndroid Build Coastguard Worker    if BPF.get_kprobe_functions(b"__do_page_cache_readahead"):
187*387f9dfdSAndroid Build Coastguard Worker        ra_event = "__do_page_cache_readahead"
188*387f9dfdSAndroid Build Coastguard Worker    elif BPF.get_kprobe_functions(b"do_page_cache_ra"):
189*387f9dfdSAndroid Build Coastguard Worker        ra_event = "do_page_cache_ra"
190*387f9dfdSAndroid Build Coastguard Worker    elif BPF.get_kprobe_functions(b"page_cache_ra_order"):
191*387f9dfdSAndroid Build Coastguard Worker        ra_event = "page_cache_ra_order"
192*387f9dfdSAndroid Build Coastguard Worker    else:
193*387f9dfdSAndroid Build Coastguard Worker        print("Not found any kprobe.")
194*387f9dfdSAndroid Build Coastguard Worker        exit()
195*387f9dfdSAndroid Build Coastguard Worker    if BPF.get_kprobe_functions(b"__page_cache_alloc"):
196*387f9dfdSAndroid Build Coastguard Worker        cache_func = "__page_cache_alloc"
197*387f9dfdSAndroid Build Coastguard Worker        bpf_text = bpf_text.replace('GET_RETVAL_PAGE', 'PT_REGS_RC(ctx)')
198*387f9dfdSAndroid Build Coastguard Worker    else:
199*387f9dfdSAndroid Build Coastguard Worker        cache_func = "filemap_alloc_folio"
200*387f9dfdSAndroid Build Coastguard Worker        bpf_text = bpf_text.replace('GET_RETVAL_PAGE', 'folio_page((struct folio *)PT_REGS_RC(ctx), 0)')
201*387f9dfdSAndroid Build Coastguard Worker    b = BPF(text=bpf_text)
202*387f9dfdSAndroid Build Coastguard Worker    b.attach_kprobe(event=ra_event, fn_name="entry__do_page_cache_readahead")
203*387f9dfdSAndroid Build Coastguard Worker    b.attach_kretprobe(event=ra_event, fn_name="exit__do_page_cache_readahead")
204*387f9dfdSAndroid Build Coastguard Worker    b.attach_kretprobe(event=cache_func, fn_name="exit__page_cache_alloc")
205*387f9dfdSAndroid Build Coastguard Worker    b.attach_kprobe(event="mark_page_accessed", fn_name="entry_mark_page_accessed")
206*387f9dfdSAndroid Build Coastguard Worker
207*387f9dfdSAndroid Build Coastguard Worker# header
208*387f9dfdSAndroid Build Coastguard Workerprint("Tracing... Hit Ctrl-C to end.")
209*387f9dfdSAndroid Build Coastguard Worker
210*387f9dfdSAndroid Build Coastguard Worker# print
211*387f9dfdSAndroid Build Coastguard Workerdef print_stats():
212*387f9dfdSAndroid Build Coastguard Worker    print()
213*387f9dfdSAndroid Build Coastguard Worker    print("Read-ahead unused pages: %d" % (b["pages"][ct.c_ulong(0)].value))
214*387f9dfdSAndroid Build Coastguard Worker    print("Histogram of read-ahead used page age (ms):")
215*387f9dfdSAndroid Build Coastguard Worker    print("")
216*387f9dfdSAndroid Build Coastguard Worker    b["dist"].print_log2_hist("age (ms)")
217*387f9dfdSAndroid Build Coastguard Worker    b["dist"].clear()
218*387f9dfdSAndroid Build Coastguard Worker    b["pages"].clear()
219*387f9dfdSAndroid Build Coastguard Worker
220*387f9dfdSAndroid Build Coastguard Workerwhile True:
221*387f9dfdSAndroid Build Coastguard Worker    try:
222*387f9dfdSAndroid Build Coastguard Worker        sleep(args.duration)
223*387f9dfdSAndroid Build Coastguard Worker        print_stats()
224*387f9dfdSAndroid Build Coastguard Worker    except KeyboardInterrupt:
225*387f9dfdSAndroid Build Coastguard Worker        print_stats()
226*387f9dfdSAndroid Build Coastguard Worker        break
227