Skip to content

Commit

Permalink
tools: continue adding --ebpf support (iovisor#1986)
Browse files Browse the repository at this point in the history
Use argparse in cachestat, add --ebpf support.

Add --ebpf support for u* tools, finalize language sorting.

Remove sole --ebpf string on usage line in tcpsubnet.
  • Loading branch information
myllynen authored and yonghong-song committed Sep 26, 2018
1 parent 3d22116 commit 27e7aea
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 84 deletions.
64 changes: 27 additions & 37 deletions tools/cachestat.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from __future__ import print_function
from bcc import BPF
from time import sleep, strftime
import argparse
import signal
import re
from sys import argv
Expand Down Expand Up @@ -48,43 +49,25 @@ def get_meminfo():
hits = 0
debug = 0

# args
def usage():
print("USAGE: %s [-T] [ interval [count] ]" % argv[0])
exit()

# arguments
interval = 5
count = -1
tstamp = 0

if len(argv) > 1:
if str(argv[1]) == '-T':
tstamp = 1

if len(argv) > 1 and tstamp == 0:
try:
if int(argv[1]) > 0:
interval = int(argv[1])
if len(argv) > 2:
if int(argv[2]) > 0:
count = int(argv[2])
except:
usage()

elif len(argv) > 2 and tstamp == 1:
try:
if int(argv[2]) > 0:
interval = int(argv[2])
if len(argv) >= 4:
if int(argv[3]) > 0:
count = int(argv[3])
except:
usage()

# load BPF program
parser = argparse.ArgumentParser(
description="Count cache kernel function calls",
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("-T", "--timestamp", action="store_true",
help="include timestamp on output")
parser.add_argument("interval", nargs="?", default=5,
help="output interval, in seconds")
parser.add_argument("count", nargs="?", default=-1,
help="number of outputs")
parser.add_argument("--ebpf", action="store_true",
help=argparse.SUPPRESS)
args = parser.parse_args()
count = int(args.count)
tstamp = args.timestamp
interval = int(args.interval)

# define BPF program
bpf_text = """
#include <uapi/linux/ptrace.h>
struct key_t {
u64 ip;
Expand All @@ -102,6 +85,13 @@ def usage():
}
"""

if debug or args.ebpf:
print(bpf_text)
if args.ebpf:
exit()

# load BPF program
b = BPF(text=bpf_text)
b.attach_kprobe(event="add_to_page_cache_lru", fn_name="do_count")
b.attach_kprobe(event="mark_page_accessed", fn_name="do_count")
Expand Down Expand Up @@ -129,7 +119,7 @@ def usage():
# as cleanup can take many seconds, trap Ctrl-C:
signal.signal(signal.SIGINT, signal_ignore)

counts = b.get_table("counts")
counts = b["counts"]
for k, v in sorted(counts.items(), key=lambda counts: counts[1].value):

if re.match(b'mark_page_accessed', b.ksym(k.ip)) is not None:
Expand Down Expand Up @@ -175,7 +165,7 @@ def usage():
cached = int(mem["Cached"]) / 1024
buff = int(mem["Buffers"]) / 1024

if tstamp == 1:
if tstamp:
print("%-8s " % strftime("%H:%M:%S"), end="")
print("%8d %8d %8d %8d %12.0f %10.0f" %
(total, misses, hits, mbd, buff, cached))
Expand Down
8 changes: 6 additions & 2 deletions tools/lib/ucalls.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
help="verbose mode: print the BPF program (for debugging purposes)")
parser.add_argument("-m", "--milliseconds", action="store_true",
help="report times in milliseconds (default is microseconds)")
parser.add_argument("--ebpf", action="store_true",
help=argparse.SUPPRESS)
args = parser.parse_args()

language = args.language
Expand Down Expand Up @@ -243,10 +245,12 @@
else:
usdt = None

if args.verbose:
if usdt:
if args.ebpf or args.verbose:
if args.verbose and usdt:
print(usdt.get_text())
print(program)
if args.ebpf:
exit()

bpf = BPF(text=program, usdt_contexts=[usdt] if usdt else [])
if args.syscalls:
Expand Down
9 changes: 7 additions & 2 deletions tools/lib/uflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
help="trace only calls to classes starting with this prefix")
parser.add_argument("-v", "--verbose", action="store_true",
help="verbose mode: print the BPF program (for debugging purposes)")
parser.add_argument("--ebpf", action="store_true",
help=argparse.SUPPRESS)
args = parser.parse_args()

usdt = USDT(pid=args.pid)
Expand Down Expand Up @@ -165,9 +167,12 @@ def enable_probe(probe_name, func_name, read_class, read_method, is_return):
print("No language detected; use -l to trace a language.")
exit(1)

if args.verbose:
print(usdt.get_text())
if args.ebpf or args.verbose:
if args.verbose:
print(usdt.get_text())
print(program)
if args.ebpf:
exit()

bpf = BPF(text=program, usdt_contexts=[usdt])
print("Tracing method calls in %s process %d... Ctrl-C to quit." %
Expand Down
43 changes: 24 additions & 19 deletions tools/lib/ugc.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# ugc Summarize garbage collection events in high-level languages.
# For Linux, uses BCC, eBPF.
#
# USAGE: ugc [-v] [-m] [-M MSEC] [-F FILTER] {java,python,ruby,node} pid
# USAGE: ugc [-v] [-m] [-M MSEC] [-F FILTER] {java,node,python,ruby} pid
#
# Copyright 2016 Sasha Goldshtein
# Licensed under the Apache License, Version 2.0 (the "License")
Expand All @@ -18,7 +18,7 @@
import time
import os

languages = ["java", "python", "ruby", "node"]
languages = ["java", "node", "python", "ruby"]

examples = """examples:
./ugc -l java 185 # trace Java GCs in process 185
Expand All @@ -40,6 +40,8 @@
help="display only GCs longer than this many milliseconds")
parser.add_argument("-F", "--filter", type=str,
help="display only GCs whose description contains this text")
parser.add_argument("--ebpf", action="store_true",
help=argparse.SUPPRESS)
args = parser.parse_args()

usdt = USDT(pid=args.pid)
Expand Down Expand Up @@ -150,6 +152,21 @@ def formatter(e):
probes.append(Probe("gc__begin", "gc__end",
"", "", lambda _: "no additional info available"))
#
# Node
#
elif language == "node":
end_save = """
u32 gc_type = 0;
bpf_usdt_readarg(1, ctx, &gc_type);
event.field1 = gc_type;
"""
descs = {"GC scavenge": 1, "GC mark-sweep-compact": 2,
"GC incremental mark": 4, "GC weak callbacks": 8}
probes.append(Probe("gc__start", "gc__done", "", end_save,
lambda e: str.join(", ",
[desc for desc, val in descs.items()
if e.field1 & val != 0])))
#
# Python
#
elif language == "python":
Expand Down Expand Up @@ -179,21 +196,6 @@ def formatter(event):
"", "", lambda _: "GC mark stage"))
probes.append(Probe("gc__sweep__begin", "gc__sweep__end",
"", "", lambda _: "GC sweep stage"))
#
# Node
#
elif language == "node":
end_save = """
u32 gc_type = 0;
bpf_usdt_readarg(1, ctx, &gc_type);
event.field1 = gc_type;
"""
descs = {"GC scavenge": 1, "GC mark-sweep-compact": 2,
"GC incremental mark": 4, "GC weak callbacks": 8}
probes.append(Probe("gc__start", "gc__done", "", end_save,
lambda e: str.join(", ",
[desc for desc, val in descs.items()
if e.field1 & val != 0])))

else:
print("No language detected; use -l to trace a language.")
Expand All @@ -204,9 +206,12 @@ def formatter(event):
program += probe.generate()
probe.attach()

if args.verbose:
print(usdt.get_text())
if args.ebpf or args.verbose:
if args.verbose:
print(usdt.get_text())
print(program)
if args.ebpf:
exit()

bpf = BPF(text=program, usdt_contexts=[usdt])
print("Tracing garbage collections in %s process %d... Ctrl-C to quit." %
Expand Down
45 changes: 25 additions & 20 deletions tools/lib/uobjnew.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# uobjnew Summarize object allocations in high-level languages.
# For Linux, uses BCC, eBPF.
#
# USAGE: uobjnew [-h] [-T TOP] [-v] {java,ruby,c} pid [interval]
# USAGE: uobjnew [-h] [-T TOP] [-v] {c,java,ruby} pid [interval]
#
# Copyright 2016 Sasha Goldshtein
# Licensed under the Apache License, Version 2.0 (the "License")
Expand All @@ -18,7 +18,7 @@
import os

# C needs to be the last language.
languages = ["java", "ruby", "c"]
languages = ["c", "java", "ruby"]

examples = """examples:
./uobjnew -l java 145 # summarize Java allocations in process 145
Expand All @@ -41,6 +41,8 @@
help="number of largest types by allocated bytes to print")
parser.add_argument("-v", "--verbose", action="store_true",
help="verbose mode: print the BPF program (for debugging purposes)")
parser.add_argument("--ebpf", action="store_true",
help=argparse.SUPPRESS)
args = parser.parse_args()

language = args.language
Expand Down Expand Up @@ -68,10 +70,25 @@

usdt = USDT(pid=args.pid)

#
# C
#
if language == "c":
program += """
int alloc_entry(struct pt_regs *ctx, size_t size) {
struct key_t key = {};
struct val_t *valp, zero = {};
key.size = size;
valp = allocs.lookup_or_init(&key, &zero);
valp->total_size += size;
valp->num_allocs += 1;
return 0;
}
"""
#
# Java
#
if language == "java":
elif language == "java":
program += """
int alloc_entry(struct pt_regs *ctx) {
struct key_t key = {};
Expand Down Expand Up @@ -120,30 +137,18 @@
program += create_template.replace("THETHING", thing)
usdt.enable_probe_or_bail("%s__create" % thing,
"%s_alloc_entry" % thing)
#
# C
#
elif language == "c":
program += """
int alloc_entry(struct pt_regs *ctx, size_t size) {
struct key_t key = {};
struct val_t *valp, zero = {};
key.size = size;
valp = allocs.lookup_or_init(&key, &zero);
valp->total_size += size;
valp->num_allocs += 1;
return 0;
}
"""

else:
print("No language detected; use -l to trace a language.")
exit(1)


if args.verbose:
print(usdt.get_text())
if args.ebpf or args.verbose:
if args.verbose:
print(usdt.get_text())
print(program)
if args.ebpf:
exit()

bpf = BPF(text=program, usdt_contexts=[usdt])
if language == "c":
Expand Down
6 changes: 5 additions & 1 deletion tools/lib/ustat.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ def _parse_args(self):
help="output interval, in seconds")
parser.add_argument("count", nargs="?", default=99999999, type=int,
help="number of outputs")
parser.add_argument("--ebpf", action="store_true",
help=argparse.SUPPRESS)
self.args = parser.parse_args()

def _create_probes(self):
Expand Down Expand Up @@ -197,8 +199,10 @@ def _create_probes(self):

def _attach_probes(self):
program = str.join('\n', [p.get_program() for p in self.probes])
if self.args.debug:
if self.args.debug or self.args.ebpf:
print(program)
if self.args.ebpf:
exit()
for probe in self.probes:
print("Attached to %s processes:" % probe.language,
str.join(', ', map(str, probe.targets)))
Expand Down
9 changes: 7 additions & 2 deletions tools/lib/uthreads.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
parser.add_argument("pid", type=int, help="process id to attach to")
parser.add_argument("-v", "--verbose", action="store_true",
help="verbose mode: print the BPF program (for debugging purposes)")
parser.add_argument("--ebpf", action="store_true",
help=argparse.SUPPRESS)
args = parser.parse_args()

usdt = USDT(pid=args.pid)
Expand Down Expand Up @@ -88,9 +90,12 @@
usdt.enable_probe_or_bail("thread__start", "trace_start")
usdt.enable_probe_or_bail("thread__stop", "trace_stop")

if args.verbose:
print(usdt.get_text())
if args.ebpf or args.verbose:
if args.verbose:
print(usdt.get_text())
print(program)
if args.ebpf:
exit()

bpf = BPF(text=program, usdt_contexts=[usdt])
print("Tracing thread events in process %d (language: %s)... Ctrl-C to quit." %
Expand Down
2 changes: 1 addition & 1 deletion tools/tcpsubnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# tcpsubnet Summarize TCP bytes sent to different subnets.
# For Linux, uses BCC, eBPF. Embedded C.
#
# USAGE: tcpsubnet [-h] [-v] [--ebpf] [-J] [-f FORMAT] [-i INTERVAL] [subnets]
# USAGE: tcpsubnet [-h] [-v] [-J] [-f FORMAT] [-i INTERVAL] [subnets]
#
# This uses dynamic tracing of kernel functions, and will need to be updated
# to match kernel changes.
Expand Down

0 comments on commit 27e7aea

Please sign in to comment.