diff --git a/tools/perf/Documentation/perf-ftrace.txt b/tools/perf/Documentation/perf-ftrace.txt index 82219e4262c7..eccc0483f7fa 100644 --- a/tools/perf/Documentation/perf-ftrace.txt +++ b/tools/perf/Documentation/perf-ftrace.txt @@ -155,6 +155,10 @@ OPTIONS for 'perf ftrace latency' Minimum latency for the start of the first bucket, in ms or ns (according to -n/--use-nsec). +--max-latency=:: + Maximum latency for the start of the last bucket, in ms or ns (according to + -n/--use-nsec). The setting is ignored if the value results in more than + 22 buckets. OPTIONS for 'perf ftrace profile' --------------------------------- diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c index d9fbe7a32926..cea7bc284f2f 100644 --- a/tools/perf/builtin-ftrace.c +++ b/tools/perf/builtin-ftrace.c @@ -730,6 +730,7 @@ static void make_histogram(struct perf_ftrace *ftrace, int buckets[], char *buf, size_t len, char *linebuf) { int min_latency = ftrace->min_latency; + int max_latency = ftrace->max_latency; char *p, *q; char *unit; double num; @@ -794,7 +795,7 @@ static void make_histogram(struct perf_ftrace *ftrace, int buckets[], if (num > 0) // 1st entry: [ 1 unit .. bucket_range units ] i = num / ftrace->bucket_range + 1; } - if (i >= NUM_BUCKET) + if (i >= NUM_BUCKET || num >= max_latency - min_latency) i = NUM_BUCKET - 1; do_inc: @@ -837,7 +838,7 @@ static void display_histogram(struct perf_ftrace *ftrace, int buckets[]) buckets[0], bar_len, bar, bar_total - bar_len, ""); for (i = 1; i < NUM_BUCKET - 1; i++) { - int start, stop; + unsigned int start, stop; const char *unit = use_nsec ? "ns" : "us"; if (!ftrace->bucket_range) { @@ -853,6 +854,11 @@ static void display_histogram(struct perf_ftrace *ftrace, int buckets[]) start = (i - 1) * ftrace->bucket_range + min_latency; stop = i * ftrace->bucket_range + min_latency; + if (start >= ftrace->max_latency) + break; + if (stop > ftrace->max_latency) + stop = ftrace->max_latency; + if (start >= 1000) { double dstart = start / 1000.0, dstop = stop / 1000.0; @@ -873,7 +879,9 @@ static void display_histogram(struct perf_ftrace *ftrace, int buckets[]) if (!ftrace->bucket_range) { printf(" %4d - %-4s %s", 1, "...", use_nsec ? "ms" : "s "); } else { - int upper_outlier = (NUM_BUCKET - 2) * ftrace->bucket_range + min_latency; + unsigned int upper_outlier = (NUM_BUCKET - 2) * ftrace->bucket_range + min_latency; + if (upper_outlier > ftrace->max_latency) + upper_outlier = ftrace->max_latency; if (upper_outlier >= 1000) { double dstart = upper_outlier / 1000.0; @@ -1609,6 +1617,8 @@ int cmd_ftrace(int argc, const char **argv) "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_UINTEGER(0, "max-latency", &ftrace.max_latency, + "Maximum latency (last bucket). Works only with --bucket-range and total buckets less than 22."), OPT_PARENT(common_options), }; const struct option profile_options[] = { @@ -1715,6 +1725,18 @@ int cmd_ftrace(int argc, const char **argv) /* default min latency should be the bucket range */ ftrace.min_latency = ftrace.bucket_range; } + if (!ftrace.bucket_range && ftrace.max_latency) { + pr_err("--max-latency works only with --bucket-range\n"); + parse_options_usage(ftrace_usage, options, + "max-latency", /*short_opt=*/false); + ret = -EINVAL; + goto out_delete_filters; + } + if (!ftrace.max_latency) { + /* default max latency should depend on bucket range and num_buckets */ + ftrace.max_latency = (NUM_BUCKET - 2) * ftrace.bucket_range + + ftrace.min_latency; + } cmd_func = __cmd_latency; break; case PERF_FTRACE_PROFILE: diff --git a/tools/perf/util/bpf_skel/func_latency.bpf.c b/tools/perf/util/bpf_skel/func_latency.bpf.c index a89d2b4c3817..50ae153bf26e 100644 --- a/tools/perf/util/bpf_skel/func_latency.bpf.c +++ b/tools/perf/util/bpf_skel/func_latency.bpf.c @@ -43,6 +43,7 @@ const volatile int has_task = 0; const volatile int use_nsec = 0; const volatile unsigned int bucket_range; const volatile unsigned int min_latency; +const volatile unsigned int max_latency; SEC("kprobe/func") int BPF_PROG(func_begin) @@ -116,7 +117,8 @@ int BPF_PROG(func_end) // than the min latency desired. if (delta > 0) { // 1st entry: [ 1 unit .. bucket_range units ) key = delta / bucket_range + 1; - if (key >= NUM_BUCKET) + if (key >= NUM_BUCKET || + delta >= max_latency - min_latency) key = NUM_BUCKET - 1; } goto do_lookup; diff --git a/tools/perf/util/ftrace.h b/tools/perf/util/ftrace.h index 78d7745d497a..f218703063f7 100644 --- a/tools/perf/util/ftrace.h +++ b/tools/perf/util/ftrace.h @@ -22,6 +22,7 @@ struct perf_ftrace { bool use_nsec; unsigned int bucket_range; unsigned int min_latency; + unsigned int max_latency; int graph_depth; int func_stack_trace; int func_irq_info;