xref: /aosp_15_r20/external/bcc/tools/cachetop.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# cachetop      Count cache kernel function calls per processes
5*387f9dfdSAndroid Build Coastguard Worker#               For Linux, uses BCC, eBPF.
6*387f9dfdSAndroid Build Coastguard Worker#
7*387f9dfdSAndroid Build Coastguard Worker# USAGE: cachetop
8*387f9dfdSAndroid Build Coastguard Worker# Taken from cachestat by Brendan Gregg
9*387f9dfdSAndroid Build Coastguard Worker#
10*387f9dfdSAndroid Build Coastguard Worker# Copyright (c) 2016-present, Facebook, Inc.
11*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License")
12*387f9dfdSAndroid Build Coastguard Worker#
13*387f9dfdSAndroid Build Coastguard Worker# 13-Jul-2016   Emmanuel Bretelle first version
14*387f9dfdSAndroid Build Coastguard Worker# 17-Mar-2022   Rocky Xing        Added PID filter support.
15*387f9dfdSAndroid Build Coastguard Worker# 15-Feb-2023   Rong Tao          Add writeback_dirty_{folio,page} tracepoints
16*387f9dfdSAndroid Build Coastguard Worker
17*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import absolute_import
18*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import division
19*387f9dfdSAndroid Build Coastguard Worker# Do not import unicode_literals until #623 is fixed
20*387f9dfdSAndroid Build Coastguard Worker# from __future__ import unicode_literals
21*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function
22*387f9dfdSAndroid Build Coastguard Worker
23*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF
24*387f9dfdSAndroid Build Coastguard Workerfrom collections import defaultdict
25*387f9dfdSAndroid Build Coastguard Workerfrom time import strftime
26*387f9dfdSAndroid Build Coastguard Worker
27*387f9dfdSAndroid Build Coastguard Workerimport argparse
28*387f9dfdSAndroid Build Coastguard Workerimport curses
29*387f9dfdSAndroid Build Coastguard Workerimport pwd
30*387f9dfdSAndroid Build Coastguard Workerimport re
31*387f9dfdSAndroid Build Coastguard Workerimport signal
32*387f9dfdSAndroid Build Coastguard Workerfrom time import sleep
33*387f9dfdSAndroid Build Coastguard Worker
34*387f9dfdSAndroid Build Coastguard WorkerFIELDS = (
35*387f9dfdSAndroid Build Coastguard Worker    "PID",
36*387f9dfdSAndroid Build Coastguard Worker    "UID",
37*387f9dfdSAndroid Build Coastguard Worker    "CMD",
38*387f9dfdSAndroid Build Coastguard Worker    "HITS",
39*387f9dfdSAndroid Build Coastguard Worker    "MISSES",
40*387f9dfdSAndroid Build Coastguard Worker    "DIRTIES",
41*387f9dfdSAndroid Build Coastguard Worker    "READ_HIT%",
42*387f9dfdSAndroid Build Coastguard Worker    "WRITE_HIT%"
43*387f9dfdSAndroid Build Coastguard Worker)
44*387f9dfdSAndroid Build Coastguard WorkerDEFAULT_FIELD = "HITS"
45*387f9dfdSAndroid Build Coastguard WorkerDEFAULT_SORT_FIELD = FIELDS.index(DEFAULT_FIELD)
46*387f9dfdSAndroid Build Coastguard Worker
47*387f9dfdSAndroid Build Coastguard Worker# signal handler
48*387f9dfdSAndroid Build Coastguard Workerdef signal_ignore(signal, frame):
49*387f9dfdSAndroid Build Coastguard Worker    print()
50*387f9dfdSAndroid Build Coastguard Worker
51*387f9dfdSAndroid Build Coastguard Worker
52*387f9dfdSAndroid Build Coastguard Worker# Function to gather data from /proc/meminfo
53*387f9dfdSAndroid Build Coastguard Worker# return dictionary for quicker lookup of both values
54*387f9dfdSAndroid Build Coastguard Workerdef get_meminfo():
55*387f9dfdSAndroid Build Coastguard Worker    result = {}
56*387f9dfdSAndroid Build Coastguard Worker
57*387f9dfdSAndroid Build Coastguard Worker    for line in open('/proc/meminfo'):
58*387f9dfdSAndroid Build Coastguard Worker        k = line.split(':', 3)
59*387f9dfdSAndroid Build Coastguard Worker        v = k[1].split()
60*387f9dfdSAndroid Build Coastguard Worker        result[k[0]] = int(v[0])
61*387f9dfdSAndroid Build Coastguard Worker    return result
62*387f9dfdSAndroid Build Coastguard Worker
63*387f9dfdSAndroid Build Coastguard Worker
64*387f9dfdSAndroid Build Coastguard Workerdef get_processes_stats(
65*387f9dfdSAndroid Build Coastguard Worker        bpf,
66*387f9dfdSAndroid Build Coastguard Worker        sort_field=DEFAULT_SORT_FIELD,
67*387f9dfdSAndroid Build Coastguard Worker        sort_reverse=False):
68*387f9dfdSAndroid Build Coastguard Worker    '''
69*387f9dfdSAndroid Build Coastguard Worker    Return a tuple containing:
70*387f9dfdSAndroid Build Coastguard Worker    buffer
71*387f9dfdSAndroid Build Coastguard Worker    cached
72*387f9dfdSAndroid Build Coastguard Worker    list of tuple with per process cache stats
73*387f9dfdSAndroid Build Coastguard Worker    '''
74*387f9dfdSAndroid Build Coastguard Worker    counts = bpf.get_table("counts")
75*387f9dfdSAndroid Build Coastguard Worker    stats = defaultdict(lambda: defaultdict(int))
76*387f9dfdSAndroid Build Coastguard Worker    for k, v in counts.items():
77*387f9dfdSAndroid Build Coastguard Worker        stats["%d-%d-%s" % (k.pid, k.uid, k.comm.decode('utf-8', 'replace'))][k.nf] = v.value
78*387f9dfdSAndroid Build Coastguard Worker    stats_list = []
79*387f9dfdSAndroid Build Coastguard Worker
80*387f9dfdSAndroid Build Coastguard Worker    for pid, count in sorted(stats.items(), key=lambda stat: stat[0]):
81*387f9dfdSAndroid Build Coastguard Worker        rtaccess = 0
82*387f9dfdSAndroid Build Coastguard Worker        wtaccess = 0
83*387f9dfdSAndroid Build Coastguard Worker        mpa = 0
84*387f9dfdSAndroid Build Coastguard Worker        mbd = 0
85*387f9dfdSAndroid Build Coastguard Worker        apcl = 0
86*387f9dfdSAndroid Build Coastguard Worker        apd = 0
87*387f9dfdSAndroid Build Coastguard Worker        access = 0
88*387f9dfdSAndroid Build Coastguard Worker        misses = 0
89*387f9dfdSAndroid Build Coastguard Worker        rhits = 0
90*387f9dfdSAndroid Build Coastguard Worker        whits = 0
91*387f9dfdSAndroid Build Coastguard Worker
92*387f9dfdSAndroid Build Coastguard Worker        for k, v in count.items():
93*387f9dfdSAndroid Build Coastguard Worker            if k == 0: # NF_APCL
94*387f9dfdSAndroid Build Coastguard Worker                apcl = max(0, v)
95*387f9dfdSAndroid Build Coastguard Worker
96*387f9dfdSAndroid Build Coastguard Worker            if k == 1: # NF_MPA
97*387f9dfdSAndroid Build Coastguard Worker                mpa = max(0, v)
98*387f9dfdSAndroid Build Coastguard Worker
99*387f9dfdSAndroid Build Coastguard Worker            if k == 2: # NF_MBD
100*387f9dfdSAndroid Build Coastguard Worker                mbd = max(0, v)
101*387f9dfdSAndroid Build Coastguard Worker
102*387f9dfdSAndroid Build Coastguard Worker            if k == 3: # NF_APD
103*387f9dfdSAndroid Build Coastguard Worker                apd = max(0, v)
104*387f9dfdSAndroid Build Coastguard Worker
105*387f9dfdSAndroid Build Coastguard Worker            # access = total cache access incl. reads(mpa) and writes(mbd)
106*387f9dfdSAndroid Build Coastguard Worker            # misses = total of add to lru which we do when we write(mbd)
107*387f9dfdSAndroid Build Coastguard Worker            # and also the mark the page dirty(same as mbd)
108*387f9dfdSAndroid Build Coastguard Worker            access = (mpa + mbd)
109*387f9dfdSAndroid Build Coastguard Worker            misses = (apcl + apd)
110*387f9dfdSAndroid Build Coastguard Worker
111*387f9dfdSAndroid Build Coastguard Worker            # rtaccess is the read hit % during the sample period.
112*387f9dfdSAndroid Build Coastguard Worker            # wtaccess is the write hit % during the sample period.
113*387f9dfdSAndroid Build Coastguard Worker            if mpa > 0:
114*387f9dfdSAndroid Build Coastguard Worker                rtaccess = float(mpa) / (access + misses)
115*387f9dfdSAndroid Build Coastguard Worker            if apcl > 0:
116*387f9dfdSAndroid Build Coastguard Worker                wtaccess = float(apcl) / (access + misses)
117*387f9dfdSAndroid Build Coastguard Worker
118*387f9dfdSAndroid Build Coastguard Worker            if wtaccess != 0:
119*387f9dfdSAndroid Build Coastguard Worker                whits = 100 * wtaccess
120*387f9dfdSAndroid Build Coastguard Worker            if rtaccess != 0:
121*387f9dfdSAndroid Build Coastguard Worker                rhits = 100 * rtaccess
122*387f9dfdSAndroid Build Coastguard Worker
123*387f9dfdSAndroid Build Coastguard Worker        _pid, uid, comm = pid.split('-', 2)
124*387f9dfdSAndroid Build Coastguard Worker        stats_list.append(
125*387f9dfdSAndroid Build Coastguard Worker            (int(_pid), uid, comm,
126*387f9dfdSAndroid Build Coastguard Worker             access, misses, mbd,
127*387f9dfdSAndroid Build Coastguard Worker             rhits, whits))
128*387f9dfdSAndroid Build Coastguard Worker
129*387f9dfdSAndroid Build Coastguard Worker    stats_list = sorted(
130*387f9dfdSAndroid Build Coastguard Worker        stats_list, key=lambda stat: stat[sort_field], reverse=sort_reverse
131*387f9dfdSAndroid Build Coastguard Worker    )
132*387f9dfdSAndroid Build Coastguard Worker    counts.clear()
133*387f9dfdSAndroid Build Coastguard Worker    return stats_list
134*387f9dfdSAndroid Build Coastguard Worker
135*387f9dfdSAndroid Build Coastguard Worker
136*387f9dfdSAndroid Build Coastguard Workerdef handle_loop(stdscr, args):
137*387f9dfdSAndroid Build Coastguard Worker    # don't wait on key press
138*387f9dfdSAndroid Build Coastguard Worker    stdscr.nodelay(1)
139*387f9dfdSAndroid Build Coastguard Worker    # set default sorting field
140*387f9dfdSAndroid Build Coastguard Worker    sort_field = FIELDS.index(DEFAULT_FIELD)
141*387f9dfdSAndroid Build Coastguard Worker    sort_reverse = True
142*387f9dfdSAndroid Build Coastguard Worker
143*387f9dfdSAndroid Build Coastguard Worker    # load BPF program
144*387f9dfdSAndroid Build Coastguard Worker    bpf_text = """
145*387f9dfdSAndroid Build Coastguard Worker
146*387f9dfdSAndroid Build Coastguard Worker    #include <uapi/linux/ptrace.h>
147*387f9dfdSAndroid Build Coastguard Worker    struct key_t {
148*387f9dfdSAndroid Build Coastguard Worker        // NF_{APCL,MPA,MBD,APD}
149*387f9dfdSAndroid Build Coastguard Worker        u64 nf;
150*387f9dfdSAndroid Build Coastguard Worker        u32 pid;
151*387f9dfdSAndroid Build Coastguard Worker        u32 uid;
152*387f9dfdSAndroid Build Coastguard Worker        char comm[16];
153*387f9dfdSAndroid Build Coastguard Worker    };
154*387f9dfdSAndroid Build Coastguard Worker    enum {
155*387f9dfdSAndroid Build Coastguard Worker        NF_APCL,
156*387f9dfdSAndroid Build Coastguard Worker        NF_MPA,
157*387f9dfdSAndroid Build Coastguard Worker        NF_MBD,
158*387f9dfdSAndroid Build Coastguard Worker        NF_APD,
159*387f9dfdSAndroid Build Coastguard Worker    };
160*387f9dfdSAndroid Build Coastguard Worker
161*387f9dfdSAndroid Build Coastguard Worker    BPF_HASH(counts, struct key_t);
162*387f9dfdSAndroid Build Coastguard Worker
163*387f9dfdSAndroid Build Coastguard Worker    static int __do_count(void *ctx, u64 nf) {
164*387f9dfdSAndroid Build Coastguard Worker        u32 pid = bpf_get_current_pid_tgid() >> 32;
165*387f9dfdSAndroid Build Coastguard Worker        if (FILTER_PID)
166*387f9dfdSAndroid Build Coastguard Worker            return 0;
167*387f9dfdSAndroid Build Coastguard Worker
168*387f9dfdSAndroid Build Coastguard Worker        struct key_t key = {};
169*387f9dfdSAndroid Build Coastguard Worker        u32 uid = bpf_get_current_uid_gid();
170*387f9dfdSAndroid Build Coastguard Worker
171*387f9dfdSAndroid Build Coastguard Worker        key.nf = nf;
172*387f9dfdSAndroid Build Coastguard Worker        key.pid = pid;
173*387f9dfdSAndroid Build Coastguard Worker        key.uid = uid;
174*387f9dfdSAndroid Build Coastguard Worker        bpf_get_current_comm(&(key.comm), 16);
175*387f9dfdSAndroid Build Coastguard Worker
176*387f9dfdSAndroid Build Coastguard Worker        counts.increment(key);
177*387f9dfdSAndroid Build Coastguard Worker        return 0;
178*387f9dfdSAndroid Build Coastguard Worker    }
179*387f9dfdSAndroid Build Coastguard Worker    int do_count_apcl(struct pt_regs *ctx) {
180*387f9dfdSAndroid Build Coastguard Worker        return __do_count(ctx, NF_APCL);
181*387f9dfdSAndroid Build Coastguard Worker    }
182*387f9dfdSAndroid Build Coastguard Worker    int do_count_mpa(struct pt_regs *ctx) {
183*387f9dfdSAndroid Build Coastguard Worker        return __do_count(ctx, NF_MPA);
184*387f9dfdSAndroid Build Coastguard Worker    }
185*387f9dfdSAndroid Build Coastguard Worker    int do_count_mbd(struct pt_regs *ctx) {
186*387f9dfdSAndroid Build Coastguard Worker        return __do_count(ctx, NF_MBD);
187*387f9dfdSAndroid Build Coastguard Worker    }
188*387f9dfdSAndroid Build Coastguard Worker    int do_count_apd(struct pt_regs *ctx) {
189*387f9dfdSAndroid Build Coastguard Worker        return __do_count(ctx, NF_APD);
190*387f9dfdSAndroid Build Coastguard Worker    }
191*387f9dfdSAndroid Build Coastguard Worker    int do_count_apd_tp(void *ctx) {
192*387f9dfdSAndroid Build Coastguard Worker        return __do_count(ctx, NF_APD);
193*387f9dfdSAndroid Build Coastguard Worker    }
194*387f9dfdSAndroid Build Coastguard Worker
195*387f9dfdSAndroid Build Coastguard Worker    """
196*387f9dfdSAndroid Build Coastguard Worker
197*387f9dfdSAndroid Build Coastguard Worker    if args.pid:
198*387f9dfdSAndroid Build Coastguard Worker        bpf_text = bpf_text.replace('FILTER_PID', 'pid != %d' % args.pid)
199*387f9dfdSAndroid Build Coastguard Worker    else:
200*387f9dfdSAndroid Build Coastguard Worker        bpf_text = bpf_text.replace('FILTER_PID', '0')
201*387f9dfdSAndroid Build Coastguard Worker
202*387f9dfdSAndroid Build Coastguard Worker    b = BPF(text=bpf_text)
203*387f9dfdSAndroid Build Coastguard Worker    b.attach_kprobe(event="add_to_page_cache_lru", fn_name="do_count_apcl")
204*387f9dfdSAndroid Build Coastguard Worker    b.attach_kprobe(event="mark_page_accessed", fn_name="do_count_mpa")
205*387f9dfdSAndroid Build Coastguard Worker    b.attach_kprobe(event="mark_buffer_dirty", fn_name="do_count_mbd")
206*387f9dfdSAndroid Build Coastguard Worker
207*387f9dfdSAndroid Build Coastguard Worker    # Function account_page_dirtied() is changed to folio_account_dirtied() in 5.15.
208*387f9dfdSAndroid Build Coastguard Worker    # Introduce tracepoint writeback_dirty_{page,folio}
209*387f9dfdSAndroid Build Coastguard Worker    if BPF.get_kprobe_functions(b'folio_account_dirtied'):
210*387f9dfdSAndroid Build Coastguard Worker        b.attach_kprobe(event="folio_account_dirtied", fn_name="do_count_apd")
211*387f9dfdSAndroid Build Coastguard Worker    elif BPF.get_kprobe_functions(b'account_page_dirtied'):
212*387f9dfdSAndroid Build Coastguard Worker        b.attach_kprobe(event="account_page_dirtied", fn_name="do_count_apd")
213*387f9dfdSAndroid Build Coastguard Worker    elif BPF.tracepoint_exists("writeback", "writeback_dirty_folio"):
214*387f9dfdSAndroid Build Coastguard Worker        b.attach_tracepoint(tp="writeback:writeback_dirty_folio", fn_name="do_count_apd_tp")
215*387f9dfdSAndroid Build Coastguard Worker    elif BPF.tracepoint_exists("writeback", "writeback_dirty_page"):
216*387f9dfdSAndroid Build Coastguard Worker        b.attach_tracepoint(tp="writeback:writeback_dirty_page", fn_name="do_count_apd_tp")
217*387f9dfdSAndroid Build Coastguard Worker    else:
218*387f9dfdSAndroid Build Coastguard Worker        raise Exception("Failed to attach kprobe %s or %s and any tracepoint" %
219*387f9dfdSAndroid Build Coastguard Worker                        ("folio_account_dirtied", "account_page_dirtied"))
220*387f9dfdSAndroid Build Coastguard Worker
221*387f9dfdSAndroid Build Coastguard Worker    exiting = 0
222*387f9dfdSAndroid Build Coastguard Worker
223*387f9dfdSAndroid Build Coastguard Worker    while 1:
224*387f9dfdSAndroid Build Coastguard Worker        s = stdscr.getch()
225*387f9dfdSAndroid Build Coastguard Worker        if s == ord('q'):
226*387f9dfdSAndroid Build Coastguard Worker            exiting = 1
227*387f9dfdSAndroid Build Coastguard Worker        elif s == ord('r'):
228*387f9dfdSAndroid Build Coastguard Worker            sort_reverse = not sort_reverse
229*387f9dfdSAndroid Build Coastguard Worker        elif s == ord('<'):
230*387f9dfdSAndroid Build Coastguard Worker            sort_field = max(0, sort_field - 1)
231*387f9dfdSAndroid Build Coastguard Worker        elif s == ord('>'):
232*387f9dfdSAndroid Build Coastguard Worker            sort_field = min(len(FIELDS) - 1, sort_field + 1)
233*387f9dfdSAndroid Build Coastguard Worker        try:
234*387f9dfdSAndroid Build Coastguard Worker            sleep(args.interval)
235*387f9dfdSAndroid Build Coastguard Worker        except KeyboardInterrupt:
236*387f9dfdSAndroid Build Coastguard Worker            exiting = 1
237*387f9dfdSAndroid Build Coastguard Worker            # as cleanup can take many seconds, trap Ctrl-C:
238*387f9dfdSAndroid Build Coastguard Worker            signal.signal(signal.SIGINT, signal_ignore)
239*387f9dfdSAndroid Build Coastguard Worker
240*387f9dfdSAndroid Build Coastguard Worker        # Get memory info
241*387f9dfdSAndroid Build Coastguard Worker        mem = get_meminfo()
242*387f9dfdSAndroid Build Coastguard Worker        cached = int(mem["Cached"]) / 1024
243*387f9dfdSAndroid Build Coastguard Worker        buff = int(mem["Buffers"]) / 1024
244*387f9dfdSAndroid Build Coastguard Worker
245*387f9dfdSAndroid Build Coastguard Worker        process_stats = get_processes_stats(
246*387f9dfdSAndroid Build Coastguard Worker            b,
247*387f9dfdSAndroid Build Coastguard Worker            sort_field=sort_field,
248*387f9dfdSAndroid Build Coastguard Worker            sort_reverse=sort_reverse)
249*387f9dfdSAndroid Build Coastguard Worker        stdscr.clear()
250*387f9dfdSAndroid Build Coastguard Worker        stdscr.addstr(
251*387f9dfdSAndroid Build Coastguard Worker            0, 0,
252*387f9dfdSAndroid Build Coastguard Worker            "%-8s Buffers MB: %.0f / Cached MB: %.0f "
253*387f9dfdSAndroid Build Coastguard Worker            "/ Sort: %s / Order: %s" % (
254*387f9dfdSAndroid Build Coastguard Worker                strftime("%H:%M:%S"), buff, cached, FIELDS[sort_field],
255*387f9dfdSAndroid Build Coastguard Worker                sort_reverse and "descending" or "ascending"
256*387f9dfdSAndroid Build Coastguard Worker            )
257*387f9dfdSAndroid Build Coastguard Worker        )
258*387f9dfdSAndroid Build Coastguard Worker
259*387f9dfdSAndroid Build Coastguard Worker        # header
260*387f9dfdSAndroid Build Coastguard Worker        stdscr.addstr(
261*387f9dfdSAndroid Build Coastguard Worker            1, 0,
262*387f9dfdSAndroid Build Coastguard Worker            "{0:8} {1:8} {2:16} {3:8} {4:8} {5:8} {6:10} {7:10}".format(
263*387f9dfdSAndroid Build Coastguard Worker                *FIELDS
264*387f9dfdSAndroid Build Coastguard Worker            ),
265*387f9dfdSAndroid Build Coastguard Worker            curses.A_REVERSE
266*387f9dfdSAndroid Build Coastguard Worker        )
267*387f9dfdSAndroid Build Coastguard Worker        (height, width) = stdscr.getmaxyx()
268*387f9dfdSAndroid Build Coastguard Worker        for i, stat in enumerate(process_stats):
269*387f9dfdSAndroid Build Coastguard Worker            uid = int(stat[1])
270*387f9dfdSAndroid Build Coastguard Worker            try:
271*387f9dfdSAndroid Build Coastguard Worker                username = pwd.getpwuid(uid)[0]
272*387f9dfdSAndroid Build Coastguard Worker            except KeyError:
273*387f9dfdSAndroid Build Coastguard Worker                # `pwd` throws a KeyError if the user cannot be found. This can
274*387f9dfdSAndroid Build Coastguard Worker                # happen e.g. when the process is running in a cgroup that has
275*387f9dfdSAndroid Build Coastguard Worker                # different users from the host.
276*387f9dfdSAndroid Build Coastguard Worker                username = 'UNKNOWN({})'.format(uid)
277*387f9dfdSAndroid Build Coastguard Worker
278*387f9dfdSAndroid Build Coastguard Worker            stdscr.addstr(
279*387f9dfdSAndroid Build Coastguard Worker                i + 2, 0,
280*387f9dfdSAndroid Build Coastguard Worker                "{0:8} {username:8.8} {2:16} {3:8} {4:8} "
281*387f9dfdSAndroid Build Coastguard Worker                "{5:8} {6:9.1f}% {7:9.1f}%".format(
282*387f9dfdSAndroid Build Coastguard Worker                    *stat, username=username
283*387f9dfdSAndroid Build Coastguard Worker                )
284*387f9dfdSAndroid Build Coastguard Worker            )
285*387f9dfdSAndroid Build Coastguard Worker            if i > height - 4:
286*387f9dfdSAndroid Build Coastguard Worker                break
287*387f9dfdSAndroid Build Coastguard Worker        stdscr.refresh()
288*387f9dfdSAndroid Build Coastguard Worker        if exiting:
289*387f9dfdSAndroid Build Coastguard Worker            print("Detaching...")
290*387f9dfdSAndroid Build Coastguard Worker            return
291*387f9dfdSAndroid Build Coastguard Worker
292*387f9dfdSAndroid Build Coastguard Worker
293*387f9dfdSAndroid Build Coastguard Workerdef parse_arguments():
294*387f9dfdSAndroid Build Coastguard Worker    parser = argparse.ArgumentParser(
295*387f9dfdSAndroid Build Coastguard Worker        description='Show Linux page cache hit/miss statistics including read '
296*387f9dfdSAndroid Build Coastguard Worker                    'and write hit % per processes in a UI like top.'
297*387f9dfdSAndroid Build Coastguard Worker    )
298*387f9dfdSAndroid Build Coastguard Worker    parser.add_argument("-p", "--pid", type=int, metavar="PID",
299*387f9dfdSAndroid Build Coastguard Worker        help="trace this PID only")
300*387f9dfdSAndroid Build Coastguard Worker    parser.add_argument(
301*387f9dfdSAndroid Build Coastguard Worker        'interval', type=int, default=5, nargs='?',
302*387f9dfdSAndroid Build Coastguard Worker        help='Interval between probes.'
303*387f9dfdSAndroid Build Coastguard Worker    )
304*387f9dfdSAndroid Build Coastguard Worker
305*387f9dfdSAndroid Build Coastguard Worker    args = parser.parse_args()
306*387f9dfdSAndroid Build Coastguard Worker    return args
307*387f9dfdSAndroid Build Coastguard Worker
308*387f9dfdSAndroid Build Coastguard Workerargs = parse_arguments()
309*387f9dfdSAndroid Build Coastguard Workercurses.wrapper(handle_loop, args)
310