Commit 27e7aeab authored by Marko Myllynen's avatar Marko Myllynen Committed by yonghong-song

tools: continue adding --ebpf support (#1986)

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.
parent 3d221163
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
from __future__ import print_function from __future__ import print_function
from bcc import BPF from bcc import BPF
from time import sleep, strftime from time import sleep, strftime
import argparse
import signal import signal
import re import re
from sys import argv from sys import argv
...@@ -48,43 +49,25 @@ misses = 0 ...@@ -48,43 +49,25 @@ misses = 0
hits = 0 hits = 0
debug = 0 debug = 0
# args
def usage():
print("USAGE: %s [-T] [ interval [count] ]" % argv[0])
exit()
# arguments # arguments
interval = 5 parser = argparse.ArgumentParser(
count = -1 description="Count cache kernel function calls",
tstamp = 0 formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("-T", "--timestamp", action="store_true",
if len(argv) > 1: help="include timestamp on output")
if str(argv[1]) == '-T': parser.add_argument("interval", nargs="?", default=5,
tstamp = 1 help="output interval, in seconds")
parser.add_argument("count", nargs="?", default=-1,
if len(argv) > 1 and tstamp == 0: help="number of outputs")
try: parser.add_argument("--ebpf", action="store_true",
if int(argv[1]) > 0: help=argparse.SUPPRESS)
interval = int(argv[1]) args = parser.parse_args()
if len(argv) > 2: count = int(args.count)
if int(argv[2]) > 0: tstamp = args.timestamp
count = int(argv[2]) interval = int(args.interval)
except:
usage() # define BPF program
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
bpf_text = """ bpf_text = """
#include <uapi/linux/ptrace.h> #include <uapi/linux/ptrace.h>
struct key_t { struct key_t {
u64 ip; u64 ip;
...@@ -102,6 +85,13 @@ int do_count(struct pt_regs *ctx) { ...@@ -102,6 +85,13 @@ int do_count(struct pt_regs *ctx) {
} }
""" """
if debug or args.ebpf:
print(bpf_text)
if args.ebpf:
exit()
# load BPF program
b = BPF(text=bpf_text) b = BPF(text=bpf_text)
b.attach_kprobe(event="add_to_page_cache_lru", fn_name="do_count") b.attach_kprobe(event="add_to_page_cache_lru", fn_name="do_count")
b.attach_kprobe(event="mark_page_accessed", fn_name="do_count") b.attach_kprobe(event="mark_page_accessed", fn_name="do_count")
...@@ -129,7 +119,7 @@ while 1: ...@@ -129,7 +119,7 @@ while 1:
# as cleanup can take many seconds, trap Ctrl-C: # as cleanup can take many seconds, trap Ctrl-C:
signal.signal(signal.SIGINT, signal_ignore) 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): 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: if re.match(b'mark_page_accessed', b.ksym(k.ip)) is not None:
...@@ -175,7 +165,7 @@ while 1: ...@@ -175,7 +165,7 @@ while 1:
cached = int(mem["Cached"]) / 1024 cached = int(mem["Cached"]) / 1024
buff = int(mem["Buffers"]) / 1024 buff = int(mem["Buffers"]) / 1024
if tstamp == 1: if tstamp:
print("%-8s " % strftime("%H:%M:%S"), end="") print("%-8s " % strftime("%H:%M:%S"), end="")
print("%8d %8d %8d %8d %12.0f %10.0f" % print("%8d %8d %8d %8d %12.0f %10.0f" %
(total, misses, hits, mbd, buff, cached)) (total, misses, hits, mbd, buff, cached))
......
...@@ -49,6 +49,8 @@ parser.add_argument("-v", "--verbose", action="store_true", ...@@ -49,6 +49,8 @@ parser.add_argument("-v", "--verbose", action="store_true",
help="verbose mode: print the BPF program (for debugging purposes)") help="verbose mode: print the BPF program (for debugging purposes)")
parser.add_argument("-m", "--milliseconds", action="store_true", parser.add_argument("-m", "--milliseconds", action="store_true",
help="report times in milliseconds (default is microseconds)") help="report times in milliseconds (default is microseconds)")
parser.add_argument("--ebpf", action="store_true",
help=argparse.SUPPRESS)
args = parser.parse_args() args = parser.parse_args()
language = args.language language = args.language
...@@ -243,10 +245,12 @@ if language: ...@@ -243,10 +245,12 @@ if language:
else: else:
usdt = None usdt = None
if args.verbose: if args.ebpf or args.verbose:
if usdt: if args.verbose and usdt:
print(usdt.get_text()) print(usdt.get_text())
print(program) print(program)
if args.ebpf:
exit()
bpf = BPF(text=program, usdt_contexts=[usdt] if usdt else []) bpf = BPF(text=program, usdt_contexts=[usdt] if usdt else [])
if args.syscalls: if args.syscalls:
......
...@@ -39,6 +39,8 @@ parser.add_argument("-C", "--class", dest="clazz", ...@@ -39,6 +39,8 @@ parser.add_argument("-C", "--class", dest="clazz",
help="trace only calls to classes starting with this prefix") help="trace only calls to classes starting with this prefix")
parser.add_argument("-v", "--verbose", action="store_true", parser.add_argument("-v", "--verbose", action="store_true",
help="verbose mode: print the BPF program (for debugging purposes)") help="verbose mode: print the BPF program (for debugging purposes)")
parser.add_argument("--ebpf", action="store_true",
help=argparse.SUPPRESS)
args = parser.parse_args() args = parser.parse_args()
usdt = USDT(pid=args.pid) usdt = USDT(pid=args.pid)
...@@ -165,9 +167,12 @@ else: ...@@ -165,9 +167,12 @@ else:
print("No language detected; use -l to trace a language.") print("No language detected; use -l to trace a language.")
exit(1) exit(1)
if args.verbose: if args.ebpf or args.verbose:
print(usdt.get_text()) if args.verbose:
print(usdt.get_text())
print(program) print(program)
if args.ebpf:
exit()
bpf = BPF(text=program, usdt_contexts=[usdt]) bpf = BPF(text=program, usdt_contexts=[usdt])
print("Tracing method calls in %s process %d... Ctrl-C to quit." % print("Tracing method calls in %s process %d... Ctrl-C to quit." %
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
# ugc Summarize garbage collection events in high-level languages. # ugc Summarize garbage collection events in high-level languages.
# For Linux, uses BCC, eBPF. # 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 # Copyright 2016 Sasha Goldshtein
# Licensed under the Apache License, Version 2.0 (the "License") # Licensed under the Apache License, Version 2.0 (the "License")
...@@ -18,7 +18,7 @@ import ctypes as ct ...@@ -18,7 +18,7 @@ import ctypes as ct
import time import time
import os import os
languages = ["java", "python", "ruby", "node"] languages = ["java", "node", "python", "ruby"]
examples = """examples: examples = """examples:
./ugc -l java 185 # trace Java GCs in process 185 ./ugc -l java 185 # trace Java GCs in process 185
...@@ -40,6 +40,8 @@ parser.add_argument("-M", "--minimum", type=int, default=0, ...@@ -40,6 +40,8 @@ parser.add_argument("-M", "--minimum", type=int, default=0,
help="display only GCs longer than this many milliseconds") help="display only GCs longer than this many milliseconds")
parser.add_argument("-F", "--filter", type=str, parser.add_argument("-F", "--filter", type=str,
help="display only GCs whose description contains this text") help="display only GCs whose description contains this text")
parser.add_argument("--ebpf", action="store_true",
help=argparse.SUPPRESS)
args = parser.parse_args() args = parser.parse_args()
usdt = USDT(pid=args.pid) usdt = USDT(pid=args.pid)
...@@ -150,6 +152,21 @@ if language == "java": ...@@ -150,6 +152,21 @@ if language == "java":
probes.append(Probe("gc__begin", "gc__end", probes.append(Probe("gc__begin", "gc__end",
"", "", lambda _: "no additional info available")) "", "", 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 # Python
# #
elif language == "python": elif language == "python":
...@@ -179,21 +196,6 @@ elif language == "ruby": ...@@ -179,21 +196,6 @@ elif language == "ruby":
"", "", lambda _: "GC mark stage")) "", "", lambda _: "GC mark stage"))
probes.append(Probe("gc__sweep__begin", "gc__sweep__end", probes.append(Probe("gc__sweep__begin", "gc__sweep__end",
"", "", lambda _: "GC sweep stage")) "", "", 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: else:
print("No language detected; use -l to trace a language.") print("No language detected; use -l to trace a language.")
...@@ -204,9 +206,12 @@ for probe in probes: ...@@ -204,9 +206,12 @@ for probe in probes:
program += probe.generate() program += probe.generate()
probe.attach() probe.attach()
if args.verbose: if args.ebpf or args.verbose:
print(usdt.get_text()) if args.verbose:
print(usdt.get_text())
print(program) print(program)
if args.ebpf:
exit()
bpf = BPF(text=program, usdt_contexts=[usdt]) bpf = BPF(text=program, usdt_contexts=[usdt])
print("Tracing garbage collections in %s process %d... Ctrl-C to quit." % print("Tracing garbage collections in %s process %d... Ctrl-C to quit." %
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
# uobjnew Summarize object allocations in high-level languages. # uobjnew Summarize object allocations in high-level languages.
# For Linux, uses BCC, eBPF. # 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 # Copyright 2016 Sasha Goldshtein
# Licensed under the Apache License, Version 2.0 (the "License") # Licensed under the Apache License, Version 2.0 (the "License")
...@@ -18,7 +18,7 @@ from time import sleep ...@@ -18,7 +18,7 @@ from time import sleep
import os import os
# C needs to be the last language. # C needs to be the last language.
languages = ["java", "ruby", "c"] languages = ["c", "java", "ruby"]
examples = """examples: examples = """examples:
./uobjnew -l java 145 # summarize Java allocations in process 145 ./uobjnew -l java 145 # summarize Java allocations in process 145
...@@ -41,6 +41,8 @@ parser.add_argument("-S", "--top-size", type=int, ...@@ -41,6 +41,8 @@ parser.add_argument("-S", "--top-size", type=int,
help="number of largest types by allocated bytes to print") help="number of largest types by allocated bytes to print")
parser.add_argument("-v", "--verbose", action="store_true", parser.add_argument("-v", "--verbose", action="store_true",
help="verbose mode: print the BPF program (for debugging purposes)") help="verbose mode: print the BPF program (for debugging purposes)")
parser.add_argument("--ebpf", action="store_true",
help=argparse.SUPPRESS)
args = parser.parse_args() args = parser.parse_args()
language = args.language language = args.language
...@@ -68,10 +70,25 @@ BPF_HASH(allocs, struct key_t, struct val_t); ...@@ -68,10 +70,25 @@ BPF_HASH(allocs, struct key_t, struct val_t);
usdt = USDT(pid=args.pid) 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 # Java
# #
if language == "java": elif language == "java":
program += """ program += """
int alloc_entry(struct pt_regs *ctx) { int alloc_entry(struct pt_regs *ctx) {
struct key_t key = {}; struct key_t key = {};
...@@ -120,30 +137,18 @@ int object_alloc_entry(struct pt_regs *ctx) { ...@@ -120,30 +137,18 @@ int object_alloc_entry(struct pt_regs *ctx) {
program += create_template.replace("THETHING", thing) program += create_template.replace("THETHING", thing)
usdt.enable_probe_or_bail("%s__create" % thing, usdt.enable_probe_or_bail("%s__create" % thing,
"%s_alloc_entry" % 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: else:
print("No language detected; use -l to trace a language.") print("No language detected; use -l to trace a language.")
exit(1) exit(1)
if args.verbose: if args.ebpf or args.verbose:
print(usdt.get_text()) if args.verbose:
print(usdt.get_text())
print(program) print(program)
if args.ebpf:
exit()
bpf = BPF(text=program, usdt_contexts=[usdt]) bpf = BPF(text=program, usdt_contexts=[usdt])
if language == "c": if language == "c":
......
...@@ -147,6 +147,8 @@ class Tool(object): ...@@ -147,6 +147,8 @@ class Tool(object):
help="output interval, in seconds") help="output interval, in seconds")
parser.add_argument("count", nargs="?", default=99999999, type=int, parser.add_argument("count", nargs="?", default=99999999, type=int,
help="number of outputs") help="number of outputs")
parser.add_argument("--ebpf", action="store_true",
help=argparse.SUPPRESS)
self.args = parser.parse_args() self.args = parser.parse_args()
def _create_probes(self): def _create_probes(self):
...@@ -197,8 +199,10 @@ class Tool(object): ...@@ -197,8 +199,10 @@ class Tool(object):
def _attach_probes(self): def _attach_probes(self):
program = str.join('\n', [p.get_program() for p in self.probes]) 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) print(program)
if self.args.ebpf:
exit()
for probe in self.probes: for probe in self.probes:
print("Attached to %s processes:" % probe.language, print("Attached to %s processes:" % probe.language,
str.join(', ', map(str, probe.targets))) str.join(', ', map(str, probe.targets)))
......
...@@ -34,6 +34,8 @@ parser.add_argument("-l", "--language", choices=languages + ["none"], ...@@ -34,6 +34,8 @@ parser.add_argument("-l", "--language", choices=languages + ["none"],
parser.add_argument("pid", type=int, help="process id to attach to") parser.add_argument("pid", type=int, help="process id to attach to")
parser.add_argument("-v", "--verbose", action="store_true", parser.add_argument("-v", "--verbose", action="store_true",
help="verbose mode: print the BPF program (for debugging purposes)") help="verbose mode: print the BPF program (for debugging purposes)")
parser.add_argument("--ebpf", action="store_true",
help=argparse.SUPPRESS)
args = parser.parse_args() args = parser.parse_args()
usdt = USDT(pid=args.pid) usdt = USDT(pid=args.pid)
...@@ -88,9 +90,12 @@ int %s(struct pt_regs *ctx) { ...@@ -88,9 +90,12 @@ int %s(struct pt_regs *ctx) {
usdt.enable_probe_or_bail("thread__start", "trace_start") usdt.enable_probe_or_bail("thread__start", "trace_start")
usdt.enable_probe_or_bail("thread__stop", "trace_stop") usdt.enable_probe_or_bail("thread__stop", "trace_stop")
if args.verbose: if args.ebpf or args.verbose:
print(usdt.get_text()) if args.verbose:
print(usdt.get_text())
print(program) print(program)
if args.ebpf:
exit()
bpf = BPF(text=program, usdt_contexts=[usdt]) bpf = BPF(text=program, usdt_contexts=[usdt])
print("Tracing thread events in process %d (language: %s)... Ctrl-C to quit." % print("Tracing thread events in process %d (language: %s)... Ctrl-C to quit." %
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
# tcpsubnet Summarize TCP bytes sent to different subnets. # tcpsubnet Summarize TCP bytes sent to different subnets.
# For Linux, uses BCC, eBPF. Embedded C. # 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 # This uses dynamic tracing of kernel functions, and will need to be updated
# to match kernel changes. # to match kernel changes.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment