summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/perf/Documentation/perf-ftrace.txt4
-rw-r--r--tools/perf/builtin-ftrace.c32
-rw-r--r--tools/perf/util/bpf_ftrace.c1
-rw-r--r--tools/perf/util/bpf_skel/func_latency.bpf.c12
-rw-r--r--tools/perf/util/ftrace.h1
5 files changed, 43 insertions, 7 deletions
diff --git a/tools/perf/Documentation/perf-ftrace.txt b/tools/perf/Documentation/perf-ftrace.txt
index e8cc8208e29f..82219e4262c7 100644
--- a/tools/perf/Documentation/perf-ftrace.txt
+++ b/tools/perf/Documentation/perf-ftrace.txt
@@ -151,6 +151,10 @@ OPTIONS for 'perf ftrace latency'
--bucket-range=::
Bucket range in ms or ns (according to -n/--use-nsec), default is log2() mode.
+--min-latency=::
+ Minimum latency for the start of the first bucket, in ms or ns (according to
+ -n/--use-nsec).
+
OPTIONS for 'perf ftrace profile'
---------------------------------
diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c
index e047e5dcda26..d9fbe7a32926 100644
--- a/tools/perf/builtin-ftrace.c
+++ b/tools/perf/builtin-ftrace.c
@@ -729,6 +729,7 @@ out:
static void make_histogram(struct perf_ftrace *ftrace, int buckets[],
char *buf, size_t len, char *linebuf)
{
+ int min_latency = ftrace->min_latency;
char *p, *q;
char *unit;
double num;
@@ -777,6 +778,12 @@ static void make_histogram(struct perf_ftrace *ftrace, int buckets[],
if (ftrace->use_nsec)
num *= 1000;
+ i = 0;
+ if (num < min_latency)
+ goto do_inc;
+
+ num -= min_latency;
+
if (!ftrace->bucket_range) {
i = log2(num);
if (i < 0)
@@ -784,13 +791,13 @@ static void make_histogram(struct perf_ftrace *ftrace, int buckets[],
} else {
// Less than 1 unit (ms or ns), or, in the future,
// than the min latency desired.
- i = 0;
if (num > 0) // 1st entry: [ 1 unit .. bucket_range units ]
i = num / ftrace->bucket_range + 1;
}
if (i >= NUM_BUCKET)
i = NUM_BUCKET - 1;
+do_inc:
buckets[i]++;
next:
@@ -804,6 +811,7 @@ next:
static void display_histogram(struct perf_ftrace *ftrace, int buckets[])
{
+ int min_latency = ftrace->min_latency;
bool use_nsec = ftrace->use_nsec;
int i;
int total = 0;
@@ -825,7 +833,8 @@ static void display_histogram(struct perf_ftrace *ftrace, int buckets[])
bar_len = buckets[0] * bar_total / total;
printf(" %4d - %4d %s | %10d | %.*s%*s |\n",
- 0, 1, use_nsec ? "ns" : "us", buckets[0], bar_len, bar, bar_total - bar_len, "");
+ 0, min_latency, use_nsec ? "ns" : "us",
+ buckets[0], bar_len, bar, bar_total - bar_len, "");
for (i = 1; i < NUM_BUCKET - 1; i++) {
int start, stop;
@@ -841,8 +850,8 @@ static void display_histogram(struct perf_ftrace *ftrace, int buckets[])
unit = use_nsec ? "us" : "ms";
}
} else {
- start = (i - 1) * ftrace->bucket_range + 1;
- stop = i * ftrace->bucket_range + 1;
+ start = (i - 1) * ftrace->bucket_range + min_latency;
+ stop = i * ftrace->bucket_range + min_latency;
if (start >= 1000) {
double dstart = start / 1000.0,
@@ -864,7 +873,7 @@ print_bucket_info:
if (!ftrace->bucket_range) {
printf(" %4d - %-4s %s", 1, "...", use_nsec ? "ms" : "s ");
} else {
- int upper_outlier = (NUM_BUCKET - 2) * ftrace->bucket_range;
+ int upper_outlier = (NUM_BUCKET - 2) * ftrace->bucket_range + min_latency;
if (upper_outlier >= 1000) {
double dstart = upper_outlier / 1000.0;
@@ -1598,6 +1607,8 @@ int cmd_ftrace(int argc, const char **argv)
"Use nano-second histogram"),
OPT_UINTEGER(0, "bucket-range", &ftrace.bucket_range,
"Bucket range in ms or ns (-n/--use-nsec), default is log2() mode"),
+ OPT_UINTEGER(0, "min-latency", &ftrace.min_latency,
+ "Minimum latency (1st bucket). Works only with --bucket-range."),
OPT_PARENT(common_options),
};
const struct option profile_options[] = {
@@ -1693,6 +1704,17 @@ int cmd_ftrace(int argc, const char **argv)
ret = -EINVAL;
goto out_delete_filters;
}
+ if (!ftrace.bucket_range && ftrace.min_latency) {
+ pr_err("--min-latency works only with --bucket-range\n");
+ parse_options_usage(ftrace_usage, options,
+ "min-latency", /*short_opt=*/false);
+ ret = -EINVAL;
+ goto out_delete_filters;
+ }
+ if (!ftrace.min_latency) {
+ /* default min latency should be the bucket range */
+ ftrace.min_latency = ftrace.bucket_range;
+ }
cmd_func = __cmd_latency;
break;
case PERF_FTRACE_PROFILE:
diff --git a/tools/perf/util/bpf_ftrace.c b/tools/perf/util/bpf_ftrace.c
index b3cb68295e56..bc484e65fb8f 100644
--- a/tools/perf/util/bpf_ftrace.c
+++ b/tools/perf/util/bpf_ftrace.c
@@ -37,6 +37,7 @@ int perf_ftrace__latency_prepare_bpf(struct perf_ftrace *ftrace)
}
skel->rodata->bucket_range = ftrace->bucket_range;
+ skel->rodata->min_latency = ftrace->min_latency;
/* don't need to set cpu filter for system-wide mode */
if (ftrace->target.cpu_list) {
diff --git a/tools/perf/util/bpf_skel/func_latency.bpf.c b/tools/perf/util/bpf_skel/func_latency.bpf.c
index 00a340ca1543..a89d2b4c3817 100644
--- a/tools/perf/util/bpf_skel/func_latency.bpf.c
+++ b/tools/perf/util/bpf_skel/func_latency.bpf.c
@@ -42,6 +42,7 @@ const volatile int has_cpu = 0;
const volatile int has_task = 0;
const volatile int use_nsec = 0;
const volatile unsigned int bucket_range;
+const volatile unsigned int min_latency;
SEC("kprobe/func")
int BPF_PROG(func_begin)
@@ -93,7 +94,7 @@ int BPF_PROG(func_end)
start = bpf_map_lookup_elem(&functime, &tid);
if (start) {
__s64 delta = bpf_ktime_get_ns() - *start;
- __u32 key;
+ __u32 key = 0;
__u64 *hist;
bpf_map_delete_elem(&functime, &tid);
@@ -103,9 +104,16 @@ int BPF_PROG(func_end)
if (bucket_range != 0) {
delta /= cmp_base;
+
+ if (min_latency > 0) {
+ if (delta > min_latency)
+ delta -= min_latency;
+ else
+ goto do_lookup;
+ }
+
// Less than 1 unit (ms or ns), or, in the future,
// than the min latency desired.
- key = 0;
if (delta > 0) { // 1st entry: [ 1 unit .. bucket_range units )
key = delta / bucket_range + 1;
if (key >= NUM_BUCKET)
diff --git a/tools/perf/util/ftrace.h b/tools/perf/util/ftrace.h
index 6ac136484349..78d7745d497a 100644
--- a/tools/perf/util/ftrace.h
+++ b/tools/perf/util/ftrace.h
@@ -21,6 +21,7 @@ struct perf_ftrace {
bool inherit;
bool use_nsec;
unsigned int bucket_range;
+ unsigned int min_latency;
int graph_depth;
int func_stack_trace;
int func_irq_info;