Skip to content

Commit

Permalink
Add filters to filetop
Browse files Browse the repository at this point in the history
Add filter to reverse the output order of filetop, and filters to trace either
read or write operations at a time

Signed-off-by: Pradyumn Rahar <[email protected]>
  • Loading branch information
Hannibal404 committed May 15, 2024
1 parent 01bd3e4 commit b3a2613
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 23 deletions.
17 changes: 14 additions & 3 deletions man/man8/filetop.8
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ This is top for files.

This traces file reads and writes, and prints a per-file summary every interval
(by default, 1 second). By default the summary is sorted on the highest read
throughput (Kbytes). Sorting order can be changed via -s option. By default only
IO on regular files is shown. The -a option will list all file types (sockets,
FIFOs, etc).
throughput (Kbytes). Sorting order can be changed via -s option and reversed
via -rev option. By default only IO on regular files is shown. The -a option
will list all file types (sockets, FIFOs, etc). Only read or only write
operations can be traced using -ro or -wo options respectively. By default
both are traced.

This uses in-kernel eBPF maps to store per process summaries for efficiency.

Expand Down Expand Up @@ -46,6 +48,15 @@ Sort column. Default is rbytes (read throughput).
\-p PID
Trace this PID only.
.TP
\-rev
Reverse the sorting order
.TP
\-ro
Trace read operations only
.TP
\-wo
Trace write operations only
.TP
interval
Interval between updates, seconds.
.TP
Expand Down
69 changes: 50 additions & 19 deletions tools/filetop.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
# filetop file reads and writes by process.
# For Linux, uses BCC, eBPF.
#
# USAGE: filetop.py [-h] [-C] [-r MAXROWS] [interval] [count]
# USAGE: filetop.py [-h] [-a] [-C] [-r MAXROWS] [-p PID] [-rev] [-ro] [-wo]
# [interval] [count]
#
# This uses in-kernel eBPF maps to store per process summaries for efficiency.
#
Expand All @@ -26,6 +27,9 @@
./filetop -p 181 # PID 181 only
./filetop 5 # 5 second summaries
./filetop 5 10 # 5 second summaries, 10 times only
./filetop 5 -rev # 5 second summaries, sorted in reverse order
./filetop 5 -ro # 5 second summaries, only read operations traced
./filetop 5 -wo # 5 second summaries, only write operations traced
"""
parser = argparse.ArgumentParser(
description="File reads and writes by process",
Expand All @@ -42,6 +46,12 @@
help="sort column, default all")
parser.add_argument("-p", "--pid", type=int, metavar="PID", dest="tgid",
help="trace this PID only")
parser.add_argument("-rev", "--reverse", action="store_true",
help="sort columns in reverse order")
parser.add_argument("-ro", "--readonly", action="store_true",
help="trace only reads")
parser.add_argument("-wo", "--writeonly", action="store_true",
help="trace only writes")
parser.add_argument("interval", nargs="?", default=1,
help="output interval, in seconds")
parser.add_argument("count", nargs="?", default=99999999,
Expand Down Expand Up @@ -164,8 +174,10 @@

# initialize BPF
b = BPF(text=bpf_text)
b.attach_kprobe(event="vfs_read", fn_name="trace_read_entry")
b.attach_kprobe(event="vfs_write", fn_name="trace_write_entry")
if not args.writeonly or args.readonly:
b.attach_kprobe(event="vfs_read", fn_name="trace_read_entry")
if not args.readonly or args.writeonly:
b.attach_kprobe(event="vfs_write", fn_name="trace_write_entry")

# check whether hash table batch ops is supported
htab_batch_ops = True if BPF.kernel_struct_has_field(b'bpf_map_ops',
Expand Down Expand Up @@ -202,22 +214,41 @@ def sort_fn(counts):
# by-TID output
counts = b.get_table("counts")
line = 0
for k, v in reversed(sorted(counts.items_lookup_and_delete_batch()
if htab_batch_ops else counts.items(),
key=sort_fn)):
name = k.name.decode('utf-8', 'replace')
if k.name_len > DNAME_INLINE_LEN:
name = name[:-3] + "..."

# print line
print("%-7d %-16s %-6d %-6d %-7d %-7d %1s %s" % (k.pid,
k.comm.decode('utf-8', 'replace'), v.reads, v.writes,
v.rbytes / 1024, v.wbytes / 1024,
k.type.decode('utf-8', 'replace'), name))

line += 1
if line >= maxrows:
break

if not args.reverse:
for k, v in reversed(sorted(counts.items_lookup_and_delete_batch()
if htab_batch_ops else counts.items(),
key=sort_fn)):
name = k.name.decode('utf-8', 'replace')
if k.name_len > DNAME_INLINE_LEN:
name = name[:-3] + "..."

# print line
print("%-7d %-16s %-6d %-6d %-7d %-7d %1s %s" % (k.pid,
k.comm.decode('utf-8', 'replace'), v.reads, v.writes,
v.rbytes / 1024, v.wbytes / 1024,
k.type.decode('utf-8', 'replace'), name))

line += 1
if line >= maxrows:
break
else:
for k, v in sorted(counts.items_lookup_and_delete_batch()
if htab_batch_ops else counts.items(),
key=sort_fn):
name = k.name.decode('utf-8', 'replace')
if k.name_len > DNAME_INLINE_LEN:
name = name[:-3] + "..."

# print line
print("%-7d %-16s %-6d %-6d %-7d %-7d %1s %s" % (k.pid,
k.comm.decode('utf-8', 'replace'), v.reads, v.writes,
v.rbytes / 1024, v.wbytes / 1024,
k.type.decode('utf-8', 'replace'), name))

line += 1
if line >= maxrows:
break

if not htab_batch_ops:
counts.clear()
Expand Down
27 changes: 26 additions & 1 deletion tools/filetop_example.txt
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,29 @@ socket I/O from an sshd process, showing up as non-regular file types (the "O"
for other, and "S" for socket, in the type column: "T").


# ./filetop 10 -wo -C
Tracing... Output every 10 secs. Hit Ctrl-C to end

08:56:49 loadavg: 0.00 0.00 0.00 1/248 775686

TID COMM READS WRITES R_Kb W_Kb T FILE
638295 gomon 0 1 0 0 R monitoring.log

08:56:59 loadavg: 0.00 0.00 0.00 2/246 775686

TID COMM READS WRITES R_Kb W_Kb T FILE

08:57:09 loadavg: 0.00 0.00 0.00 1/246 775686

TID COMM READS WRITES R_Kb W_Kb T FILE

In this example only write operations are traced


USAGE message:

# ./filetop -h
usage: filetop.py [-h] [-a] [-C] [-r MAXROWS] [-p PID] [interval] [count]
usage: filetop.py [-h] [-a] [-C] [-r MAXROWS] [-p PID] [-rev] [-ro] [-wo] [interval] [count]

File reads and writes by process

Expand All @@ -150,10 +169,16 @@ optional arguments:
-s {reads,writes,rbytes,wbytes}, --sort {reads,writes,rbytes,wbytes}
sort column, default rbytes
-p PID, --pid PID trace this PID only
-rev, --reverse reverse the sorting order
-ro, --readonly trace read operations only
-wo, --writeonly trace write operations only

examples:
./filetop # file I/O top, 1 second refresh
./filetop -C # don't clear the screen
./filetop -p 181 # PID 181 only
./filetop 5 # 5 second summaries
./filetop 5 10 # 5 second summaries, 10 times only
./filetop 5 -rev # 5 second summaries, sorted in reverse order
./filetop 5 -ro # 5 second summaries, only read operations traced
./filetop 5 -wo # 5 second summaries, only write operations traced

0 comments on commit b3a2613

Please sign in to comment.