Skip to content

Commit

Permalink
tools/virtiostat: add filter
Browse files Browse the repository at this point in the history
Add device driver/name filter for virtiostat.

Suggested by Yonghong, also use bpf_probe_read_kernel_str to copy
string from kernel.

Signed-off-by: zhenwei pi <[email protected]>
  • Loading branch information
pizhenwei authored and yonghong-song committed Mar 14, 2021
1 parent 00b72fd commit fa7bec9
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 19 deletions.
12 changes: 11 additions & 1 deletion man/man8/virtiostat.8
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
.SH NAME
virtiostat \- Trace VIRTIO devices input/output statistics. Uses Linux eBPF/bcc.
.SH SYNOPSIS
.B virtiostat [\-h] [\-T] [\-D] [INTERVAL] [COUNT]
.B virtiostat [\-h] [\-T] [\-D] [-d DRIVER] [-n DEVNAME] [INTERVAL] [COUNT]
.SH DESCRIPTION
This tool traces VIRTIO devices input/output statistics. It works in lower
layer of VIRTIO base driver, so it could trace all the devices of VIRTIO
Expand All @@ -25,6 +25,12 @@ Include a time column on output (HH:MM:SS).
\-D
Show debug infomation of bpf text.
.TP
\-d DRIVER
Filter for driver name.
.TP
\-n DEVNAME
Filter for device name.
.TP
INTERVAL
Print output every interval seconds.
.TP
Expand All @@ -35,6 +41,10 @@ Total count of trace in seconds.
Trace virtio device statistics and print 1 second summaries, 10 times:
#
.B virtiostat 1 10
.TP
Trace virtio block deivces only:
#
.B virtiostat -d virtio_blk
.SH OVERHEAD
This traces the kernel virtqueue_add_sgs, virtqueue_add_outbuf,
virtqueue_add_inbuf, virtqueue_add_inbuf_ctx functions.
Expand Down
67 changes: 59 additions & 8 deletions tools/virtiostat.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# virtiostat Show virtio devices input/output statistics.
# For Linux, uses BCC, eBPF.
#
# USAGE: virtiostat [-h] [-T] [-D] [INTERVAL] [COUNT]
# USAGE: virtiostat [-h] [-T] [-D] [-d DRIVER] [-n DEVNAME] [INTERVAL] [COUNT]
#
# Copyright (c) 2021 zhenwei pi
# Licensed under the Apache License, Version 2.0 (the "License")
Expand All @@ -18,10 +18,12 @@

# arguments
examples = """examples:
./virtiostat # print 3(default) second summaries
./virtiostat 1 10 # print 1 second summaries, 10 times
./virtiostat -T # show timestamps
./virtiostat -D # show debug bpf text
./virtiostat # print 3(default) second summaries
./virtiostat 1 10 # print 1 second summaries, 10 times
./virtiostat -T # show timestamps
./virtiostat -d virtio_blk # only show virtio block devices
./virtiostat -n virtio0 # only show virtio0 device
./virtiostat -D # show debug bpf text
"""
parser = argparse.ArgumentParser(
description="Show virtio devices input/output statistics",
Expand All @@ -33,6 +35,10 @@
help="number of outputs")
parser.add_argument("-T", "--timestamp", action="store_true",
help="show timestamp on output")
parser.add_argument("-d", "--driver",
help="filter for driver name")
parser.add_argument("-n", "--devname",
help="filter for device name")
parser.add_argument("-D", "--debug", action="store_true",
help="print BPF program before starting (for debugging purposes)")
parser.add_argument("--ebpf", action="store_true",
Expand All @@ -52,6 +58,25 @@
/* typically virtio blk has max SEG of 128 */
#define SG_MAX 128
/* local strcmp function, max length 16 to protect instruction loops */
#define CMPMAX 16
static int local_strcmp(const char *cs, const char *ct)
{
int len = 0;
unsigned char c1, c2;
while (len++ < CMPMAX) {
c1 = *cs++;
c2 = *ct++;
if (c1 != c2)
return c1 < c2 ? -1 : 1;
if (!c1)
break;
}
return 0;
}
typedef struct virtio_stat {
char driver[16];
char dev[12];
Expand Down Expand Up @@ -128,6 +153,9 @@
u64 key = (u64)vq;
u64 in_bw = 0;
DRIVERFILTER
DEVNAMEFILTER
/* Workaround: separate two count_len() calls, one here and the
* other below. Otherwise, compiler may generate some spills which
* harms verifier pruning. This happens in llvm12, but not llvm4.
Expand All @@ -138,9 +166,9 @@
vs = stats.lookup(&key);
if (!vs) {
bpf_probe_read_kernel(newvs.driver, sizeof(newvs.driver), vq->vdev->dev.driver->name);
bpf_probe_read_kernel(newvs.dev, sizeof(newvs.dev), vq->vdev->dev.kobj.name);
bpf_probe_read_kernel(newvs.vqname, sizeof(newvs.vqname), vq->name);
bpf_probe_read_kernel_str(newvs.driver, sizeof(newvs.driver), vq->vdev->dev.driver->name);
bpf_probe_read_kernel_str(newvs.dev, sizeof(newvs.dev), vq->vdev->dev.kobj.name);
bpf_probe_read_kernel_str(newvs.vqname, sizeof(newvs.vqname), vq->name);
newvs.out_sgs = out_sgs;
newvs.in_sgs = in_sgs;
if (out_sgs)
Expand Down Expand Up @@ -194,6 +222,29 @@
}
"""

# filter for driver name
if args.driver:
bpf_text = bpf_text.replace('DRIVERFILTER',
"""char filter_driver[] = \"%s\";
char driver[16];
bpf_probe_read_kernel_str(driver, sizeof(driver), vq->vdev->dev.driver->name);
if (local_strcmp(filter_driver, driver))
return;""" % (args.driver))
else:
bpf_text = bpf_text.replace('DRIVERFILTER', '')

# filter for dev name
if args.devname:
bpf_text = bpf_text.replace('DEVNAMEFILTER',
"""char filter_devname[] = \"%s\";
char devname[16];
bpf_probe_read_kernel_str(devname, sizeof(devname), vq->vdev->dev.kobj.name);
if (local_strcmp(filter_devname, devname))
return;""" % (args.devname))
else:
bpf_text = bpf_text.replace('DEVNAMEFILTER', '')


# debug mode: print bpf text
if args.debug:
print(bpf_text)
Expand Down
37 changes: 27 additions & 10 deletions tools/virtiostat_example.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,41 @@ Tracing virtio devices statistics ... Hit Ctrl-C to end.
9pnet_virtio virtio6 requests 91520 91141 1737364 125320785


Show virtio block devices only:
#./virtiostat.py -d virtio_blk
Tracing virtio devices statistics ... Hit Ctrl-C to end.
--------
Driver Device VQ Name In SGs Out SGs In BW Out BW
virtio_blk virtio4 req.0 4 6 4 24640
virtio_blk virtio5 req.0 678756 339378 1390431666 5430048


Full USAGE:

#./virtiostat -h
usage: virtiostat.py [-h] [-T] [-D] [interval] [count]
usage: virtiostat.py [-h] [-T] [-d DRIVER] [-n DEVNAME] [-D]
[interval] [count]

Show virtio devices input/output statistics

positional arguments:
interval output interval, in seconds
count number of outputs
interval output interval, in seconds
count number of outputs

optional arguments:
-h, --help show this help message and exit
-T, --timestamp show timestamp on output
-D, --debug print BPF program before starting (for debugging purposes)
-h, --help show this help message and exit
-T, --timestamp show timestamp on output
-d DRIVER, --driver DRIVER
filter for driver name
-n DEVNAME, --devname DEVNAME
filter for device name
-D, --debug print BPF program before starting (for debugging
purposes)

examples:
./virtiostat # print 3(default) second summaries
./virtiostat 1 10 # print 1 second summaries, 10 times
./virtiostat -T # show timestamps
./virtiostat -D # show debug bpf text
./virtiostat # print 3(default) second summaries
./virtiostat 1 10 # print 1 second summaries, 10 times
./virtiostat -T # show timestamps
./virtiostat -d virtio_blk # only show virtio block devices
./virtiostat -n virtio0 # only show virtio0 device
./virtiostat -D # show debug bpf text

0 comments on commit fa7bec9

Please sign in to comment.