Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
B
bcc
Manage
Activity
Members
Plan
Wiki
Code
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Deploy
Releases
Package Registry
Container Registry
Model registry
Operate
Terraform modules
Analyze
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
CodeLinaro
la
platform
external
bcc
Commits
c76cd926
Commit
c76cd926
authored
3 years ago
by
chenyue.zhou
Committed by
yonghong-song
3 years ago
Browse files
Options
Downloads
Patches
Plain Diff
tools/funclatency: support nested or recursive functions
parent
21d866e2
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
tools/funclatency.py
+156
-23
156 additions, 23 deletions
tools/funclatency.py
with
156 additions
and
23 deletions
tools/funclatency.py
+
156
−
23
View file @
c76cd926
...
...
@@ -12,11 +12,6 @@
# The pattern is a string with optional '*' wildcards, similar to file
# globbing. If you'd prefer to use regular expressions, use the -r option.
#
# Currently nested or recursive functions are not supported properly, and
# timestamps will be overwritten, creating dubious output. Try to match single
# functions, or groups of functions that run at the same stack layer, and
# don't ultimately call each other.
#
# Copyright (c) 2015 Brendan Gregg.
# Licensed under the Apache License, Version 2.0 (the "License")
#
...
...
@@ -62,6 +57,8 @@ parser.add_argument("-F", "--function", action="store_true",
help
=
"
show a separate histogram per function
"
)
parser
.
add_argument
(
"
-r
"
,
"
--regexp
"
,
action
=
"
store_true
"
,
help
=
"
use regular expressions. Default is
\"
*
\"
wildcards only.
"
)
parser
.
add_argument
(
"
-l
"
,
"
--level
"
,
type
=
int
,
help
=
"
set the level of nested or recursive functions
"
)
parser
.
add_argument
(
"
-v
"
,
"
--verbose
"
,
action
=
"
store_true
"
,
help
=
"
print the BPF program (for debugging purposes)
"
)
parser
.
add_argument
(
"
pattern
"
,
...
...
@@ -110,9 +107,11 @@ typedef struct hist_key {
u64 slot;
} hist_key_t;
BPF_HASH(start, u32);
TYPEDEF
BPF_ARRAY(avg, u64, 2);
STORAGE
FUNCTION
int trace_func_entry(struct pt_regs *ctx)
{
...
...
@@ -123,7 +122,6 @@ int trace_func_entry(struct pt_regs *ctx)
FILTER
ENTRYSTORE
start.update(&pid, &ts);
return 0;
}
...
...
@@ -136,12 +134,7 @@ int trace_func_return(struct pt_regs *ctx)
u32 tgid = pid_tgid >> 32;
// calculate delta time
tsp = start.lookup(&pid);
if (tsp == 0) {
return 0; // missed start
}
delta = bpf_ktime_get_ns() - *tsp;
start.delete(&pid);
CALCULATE
u32 lat = 0;
u32 cnt = 1;
...
...
@@ -178,14 +171,140 @@ else:
bpf_text
=
bpf_text
.
replace
(
'
FACTOR
'
,
''
)
label
=
"
nsecs
"
if
need_key
:
bpf_text
=
bpf_text
.
replace
(
'
STORAGE
'
,
'
BPF_HASH(ipaddr, u32);
\n
'
+
'
BPF_HISTOGRAM(dist, hist_key_t);
'
)
# stash the IP on entry, as on return it's kretprobe_trampoline:
bpf_text
=
bpf_text
.
replace
(
'
ENTRYSTORE
'
,
'
u64 ip = PT_REGS_IP(ctx); ipaddr.update(&pid, &ip);
'
)
pid
=
'
-1
'
if
not
library
else
'
tgid
'
bpf_text
=
bpf_text
.
replace
(
'
STORE
'
,
"""
if
args
.
level
>
1
:
bpf_text
=
bpf_text
.
replace
(
'
TYPEDEF
'
,
"""
#define STACK_DEPTH %s
typedef struct {
u64 ip;
u64 start_ts;
} func_cache_t;
/* LIFO */
typedef struct {
u32 head;
func_cache_t cache[STACK_DEPTH];
} func_stack_t;
"""
%
args
.
level
)
bpf_text
=
bpf_text
.
replace
(
'
STORAGE
'
,
"""
BPF_HASH(func_stack, u32, func_stack_t);
BPF_HISTOGRAM(dist, hist_key_t);
"""
)
bpf_text
=
bpf_text
.
replace
(
'
FUNCTION
'
,
"""
static inline int stack_pop(func_stack_t *stack, func_cache_t *cache) {
if (stack->head <= 0) {
return -1;
}
u32 index = --stack->head;
if (index < STACK_DEPTH) {
/* bound check */
cache->ip = stack->cache[index].ip;
cache->start_ts = stack->cache[index].start_ts;
}
return 0;
}
static inline int stack_push(func_stack_t *stack, func_cache_t *cache) {
u32 index = stack->head;
if (index > STACK_DEPTH - 1) {
/* bound check */
return -1;
}
stack->head++;
stack->cache[index].ip = cache->ip;
stack->cache[index].start_ts = cache->start_ts;
return 0;
}
"""
)
bpf_text
=
bpf_text
.
replace
(
'
ENTRYSTORE
'
,
"""
u64 ip = PT_REGS_IP(ctx);
func_cache_t cache = {
.ip = ip,
.start_ts = ts,
};
func_stack_t *stack = func_stack.lookup(&pid);
if (!stack) {
func_stack_t new_stack = {
.head = 0,
};
if (!stack_push(&new_stack, &cache)) {
func_stack.update(&pid, &new_stack);
}
return 0;
}
if (!stack_push(stack, &cache)) {
func_stack.update(&pid, stack);
}
"""
)
bpf_text
=
bpf_text
.
replace
(
'
CALCULATE
'
,
"""
u64 ip, start_ts;
func_stack_t *stack = func_stack.lookup(&pid);
if (!stack) {
/* miss start */
return 0;
}
func_cache_t cache = {};
if (stack_pop(stack, &cache)) {
func_stack.delete(&pid);
return 0;
}
ip = cache.ip;
start_ts = cache.start_ts;
delta = bpf_ktime_get_ns() - start_ts;
"""
)
bpf_text
=
bpf_text
.
replace
(
'
STORE
'
,
"""
hist_key_t key;
key.key.ip = ip;
key.key.pid = %s;
key.slot = bpf_log2l(delta);
dist.increment(key);
if (stack->head == 0) {
/* empty */
func_stack.delete(&pid);
}
"""
%
pid
)
else
:
bpf_text
=
bpf_text
.
replace
(
'
STORAGE
'
,
'
BPF_HASH(ipaddr, u32);
\n
'
\
'
BPF_HISTOGRAM(dist, hist_key_t);
\n
'
\
'
BPF_HASH(start, u32);
'
)
# stash the IP on entry, as on return it's kretprobe_trampoline:
bpf_text
=
bpf_text
.
replace
(
'
ENTRYSTORE
'
,
'
u64 ip = PT_REGS_IP(ctx); ipaddr.update(&pid, &ip);
'
\
'
start.update(&pid, &ts);
'
)
bpf_text
=
bpf_text
.
replace
(
'
STORE
'
,
"""
u64 ip, *ipp = ipaddr.lookup(&pid);
if (ipp) {
ip = *ipp;
...
...
@@ -196,12 +315,26 @@ if need_key:
dist.increment(key);
ipaddr.delete(&pid);
}
"""
%
pid
)
"""
%
pid
)
else
:
bpf_text
=
bpf_text
.
replace
(
'
STORAGE
'
,
'
BPF_HISTOGRAM(dist);
'
)
bpf_text
=
bpf_text
.
replace
(
'
ENTRYSTORE
'
,
''
)
bpf_text
=
bpf_text
.
replace
(
'
STORAGE
'
,
'
BPF_HISTOGRAM(dist);
\n
'
\
'
BPF_HASH(start, u32);
'
)
bpf_text
=
bpf_text
.
replace
(
'
ENTRYSTORE
'
,
'
start.update(&pid, &ts);
'
)
bpf_text
=
bpf_text
.
replace
(
'
STORE
'
,
'
dist.increment(bpf_log2l(delta));
'
)
bpf_text
=
bpf_text
.
replace
(
'
TYPEDEF
'
,
''
)
bpf_text
=
bpf_text
.
replace
(
'
FUNCTION
'
,
''
)
bpf_text
=
bpf_text
.
replace
(
'
CALCULATE
'
,
"""
tsp = start.lookup(&pid);
if (tsp == 0) {
return 0; // missed start
}
delta = bpf_ktime_get_ns() - *tsp;
start.delete(&pid);
"""
)
if
args
.
verbose
or
args
.
ebpf
:
print
(
bpf_text
)
if
args
.
ebpf
:
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment