Commit 3ce27b5d authored by 4ast's avatar 4ast

Merge pull request #417 from iovisor/funccount_alternate

Remove use of update() in funccount
parents e58ed9f1 95728834
...@@ -33,8 +33,8 @@ open_uprobes = {} ...@@ -33,8 +33,8 @@ open_uprobes = {}
tracefile = None tracefile = None
TRACEFS = "/sys/kernel/debug/tracing" TRACEFS = "/sys/kernel/debug/tracing"
KALLSYMS = "/proc/kallsyms" KALLSYMS = "/proc/kallsyms"
ksym_addrs = [] ksyms = []
ksym_names = [] ksym_names = {}
ksym_loaded = 0 ksym_loaded = 0
_kprobe_limit = 1000 _kprobe_limit = 1000
...@@ -642,7 +642,7 @@ class BPF(object): ...@@ -642,7 +642,7 @@ class BPF(object):
@staticmethod @staticmethod
def _load_kallsyms(): def _load_kallsyms():
global ksym_loaded, ksym_addrs, ksym_names global ksym_loaded, ksyms, ksym_names
if ksym_loaded: if ksym_loaded:
return return
try: try:
...@@ -654,19 +654,20 @@ class BPF(object): ...@@ -654,19 +654,20 @@ class BPF(object):
cols = line.split() cols = line.split()
name = cols[2] name = cols[2]
addr = int(cols[0], 16) addr = int(cols[0], 16)
ksym_addrs.append(addr) # keep a mapping of names to ksyms index
ksym_names.append(name) ksym_names[name] = len(ksyms)
ksyms.append((name, addr))
syms.close() syms.close()
ksym_loaded = 1 ksym_loaded = 1
@staticmethod @staticmethod
def _ksym_addr2index(addr): def _ksym_addr2index(addr):
global ksym_addrs global ksyms
start = -1 start = -1
end = len(ksym_addrs) end = len(ksyms)
while end != start + 1: while end != start + 1:
mid = int((start + end) / 2) mid = int((start + end) / 2)
if addr < ksym_addrs[mid]: if addr < ksyms[mid][1]:
end = mid end = mid
else: else:
start = mid start = mid
...@@ -679,12 +680,12 @@ class BPF(object): ...@@ -679,12 +680,12 @@ class BPF(object):
Translate a kernel memory address into a kernel function name, which is Translate a kernel memory address into a kernel function name, which is
returned. This is a simple translator that uses /proc/kallsyms. returned. This is a simple translator that uses /proc/kallsyms.
""" """
global ksym_names global ksyms
BPF._load_kallsyms() BPF._load_kallsyms()
idx = BPF._ksym_addr2index(addr) idx = BPF._ksym_addr2index(addr)
if idx == -1: if idx == -1:
return "[unknown]" return "[unknown]"
return ksym_names[idx] return ksyms[idx][0]
@staticmethod @staticmethod
def ksymaddr(addr): def ksymaddr(addr):
...@@ -694,13 +695,27 @@ class BPF(object): ...@@ -694,13 +695,27 @@ class BPF(object):
instruction offset as a hexidecimal number, which is returned as a instruction offset as a hexidecimal number, which is returned as a
string. This is a simple translator that uses /proc/kallsyms. string. This is a simple translator that uses /proc/kallsyms.
""" """
global ksym_addrs, ksym_names global ksyms
BPF._load_kallsyms() BPF._load_kallsyms()
idx = BPF._ksym_addr2index(addr) idx = BPF._ksym_addr2index(addr)
if idx == -1: if idx == -1:
return "[unknown]" return "[unknown]"
offset = int(addr - ksym_addrs[idx]) offset = int(addr - ksyms[idx][1])
return ksym_names[idx] + hex(offset) return ksyms[idx][0] + hex(offset)
@staticmethod
def ksymname(name):
"""ksymname(name)
Translate a kernel name into an address. This is the reverse of
ksymaddr. Returns -1 when the function name is unknown."""
global ksyms, ksym_names
BPF._load_kallsyms()
idx = ksym_names.get(name, -1)
if idx == -1:
return 0
return ksyms[idx][1]
@staticmethod @staticmethod
def num_open_kprobes(): def num_open_kprobes():
......
...@@ -186,6 +186,10 @@ class TableBase(MutableMapping): ...@@ -186,6 +186,10 @@ class TableBase(MutableMapping):
for k in self.keys(): for k in self.keys():
self.__delitem__(k) self.__delitem__(k)
def zero(self):
for k in self.keys():
self[k] = self.Leaf()
def __iter__(self): def __iter__(self):
return TableBase.Iter(self, self.Key) return TableBase.Iter(self, self.Key)
......
...@@ -65,9 +65,13 @@ BPF_HASH(counts, struct key_t); ...@@ -65,9 +65,13 @@ BPF_HASH(counts, struct key_t);
int trace_count(struct pt_regs *ctx) { int trace_count(struct pt_regs *ctx) {
FILTER FILTER
struct key_t key = {}; struct key_t key = {};
u64 zero = 0, *val; u64 *val;
key.ip = ctx->ip; // the kprobe pc is slightly after the function starting address, align
val = counts.lookup_or_init(&key, &zero); // back to the start (4 byte alignment) in order to match /proc/kallsyms
key.ip = ctx->ip & ~3ull;
val = counts.lookup(&key);
if (!val)
return 0;
(*val)++; (*val)++;
return 0; return 0;
} }
...@@ -81,6 +85,16 @@ else: ...@@ -81,6 +85,16 @@ else:
if debug: if debug:
print(bpf_text) print(bpf_text)
b = BPF(text=bpf_text) b = BPF(text=bpf_text)
counts = b.get_table("counts")
# pre-insert the function addresses into the counts table
fns = b._get_kprobe_functions(pattern)
for fn in fns:
addr = b.ksymname(fn)
if addr == -1:
raise Exception("Unknown symbol name %s" % fn)
counts[counts.Key(addr)] = counts.Leaf()
b.attach_kprobe(event_re=pattern, fn_name="trace_count") b.attach_kprobe(event_re=pattern, fn_name="trace_count")
matched = b.num_open_kprobes() matched = b.num_open_kprobes()
if matched == 0: if matched == 0:
...@@ -106,10 +120,10 @@ while (1): ...@@ -106,10 +120,10 @@ while (1):
print("%-8s\n" % strftime("%H:%M:%S"), end="") print("%-8s\n" % strftime("%H:%M:%S"), end="")
print("%-16s %-26s %8s" % ("ADDR", "FUNC", "COUNT")) print("%-16s %-26s %8s" % ("ADDR", "FUNC", "COUNT"))
counts = b.get_table("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 v.value == 0: continue
print("%-16x %-26s %8d" % (k.ip, b.ksym(k.ip), v.value)) print("%-16x %-26s %8d" % (k.ip, b.ksym(k.ip), v.value))
counts.clear() counts.zero()
if exiting: if exiting:
print("Detaching...") print("Detaching...")
......
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