Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf hist: Set levels in output_field_add()

It turns out that the output fields didn't consider the hierarchy mode
and put all the fields in the same level. To support hierarchy, each
non-output field should be in a separate level.

Pass a pointer to level to output_field_add() and make it increase the
level when it sees non-output fields.

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20250331073722.4695-4-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Namhyung Kim and committed by
Arnaldo Carvalho de Melo
390627dd b09124e2

+26 -15
+2 -1
tools/perf/builtin-c2c.c
··· 1969 1969 static int c2c_hists__init_output(struct perf_hpp_list *hpp_list, char *name) 1970 1970 { 1971 1971 struct c2c_fmt *c2c_fmt = get_format(name); 1972 + int level = 0; 1972 1973 1973 1974 if (!c2c_fmt) { 1974 1975 reset_dimensions(); 1975 - return output_field_add(hpp_list, name); 1976 + return output_field_add(hpp_list, name, &level); 1976 1977 } 1977 1978 1978 1979 perf_hpp_list__column_register(hpp_list, &c2c_fmt->fmt);
+23 -13
tools/perf/util/sort.c
··· 2884 2884 } 2885 2885 2886 2886 static int __sort_dimension__add_hpp_output(struct sort_dimension *sd, 2887 - struct perf_hpp_list *list) 2887 + struct perf_hpp_list *list, 2888 + int level) 2888 2889 { 2889 - struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd, 0); 2890 + struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd, level); 2890 2891 2891 2892 if (hse == NULL) 2892 2893 return -1; ··· 3496 3495 } 3497 3496 3498 3497 static int __sort_dimension__add_output(struct perf_hpp_list *list, 3499 - struct sort_dimension *sd) 3498 + struct sort_dimension *sd, 3499 + int level) 3500 3500 { 3501 3501 if (sd->taken) 3502 3502 return 0; 3503 3503 3504 - if (__sort_dimension__add_hpp_output(sd, list) < 0) 3504 + if (__sort_dimension__add_hpp_output(sd, list, level) < 0) 3505 3505 return -1; 3506 3506 3507 3507 sd->taken = 1; ··· 3510 3508 } 3511 3509 3512 3510 static int __hpp_dimension__add_output(struct perf_hpp_list *list, 3513 - struct hpp_dimension *hd) 3511 + struct hpp_dimension *hd, 3512 + int level) 3514 3513 { 3515 3514 struct perf_hpp_fmt *fmt; 3516 3515 3517 3516 if (hd->taken) 3518 3517 return 0; 3519 3518 3520 - fmt = __hpp_dimension__alloc_hpp(hd, 0); 3519 + fmt = __hpp_dimension__alloc_hpp(hd, level); 3521 3520 if (!fmt) 3522 3521 return -1; 3523 3522 ··· 3535 3532 hd = &hpp_sort_dimensions[col]; 3536 3533 if (implicit && !hd->was_taken) 3537 3534 return 0; 3538 - return __hpp_dimension__add_output(&perf_hpp_list, hd); 3535 + return __hpp_dimension__add_output(&perf_hpp_list, hd, /*level=*/0); 3539 3536 } 3540 3537 3541 3538 int sort_dimension__add(struct perf_hpp_list *list, const char *tok, ··· 4003 4000 } 4004 4001 } 4005 4002 4006 - int output_field_add(struct perf_hpp_list *list, const char *tok) 4003 + int output_field_add(struct perf_hpp_list *list, const char *tok, int *level) 4007 4004 { 4008 4005 unsigned int i; 4009 4006 ··· 4016 4013 if (!strcasecmp(tok, "weight")) 4017 4014 ui__warning("--fields weight shows the average value unlike in the --sort key.\n"); 4018 4015 4019 - return __hpp_dimension__add_output(list, hd); 4016 + return __hpp_dimension__add_output(list, hd, *level); 4020 4017 } 4018 + 4019 + /* 4020 + * A non-output field will increase level so that it can be in a 4021 + * different hierarchy. 4022 + */ 4023 + (*level)++; 4021 4024 4022 4025 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) { 4023 4026 struct sort_dimension *sd = &common_sort_dimensions[i]; ··· 4031 4022 if (!sd->name || strncasecmp(tok, sd->name, strlen(tok))) 4032 4023 continue; 4033 4024 4034 - return __sort_dimension__add_output(list, sd); 4025 + return __sort_dimension__add_output(list, sd, *level); 4035 4026 } 4036 4027 4037 4028 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) { ··· 4043 4034 if (sort__mode != SORT_MODE__BRANCH) 4044 4035 return -EINVAL; 4045 4036 4046 - return __sort_dimension__add_output(list, sd); 4037 + return __sort_dimension__add_output(list, sd, *level); 4047 4038 } 4048 4039 4049 4040 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) { ··· 4055 4046 if (sort__mode != SORT_MODE__MEMORY) 4056 4047 return -EINVAL; 4057 4048 4058 - return __sort_dimension__add_output(list, sd); 4049 + return __sort_dimension__add_output(list, sd, *level); 4059 4050 } 4060 4051 4061 4052 return -ESRCH; ··· 4065 4056 { 4066 4057 char *tmp, *tok; 4067 4058 int ret = 0; 4059 + int level = 0; 4068 4060 4069 4061 for (tok = strtok_r(str, ", ", &tmp); 4070 4062 tok; tok = strtok_r(NULL, ", ", &tmp)) { 4071 - ret = output_field_add(list, tok); 4063 + ret = output_field_add(list, tok, &level); 4072 4064 if (ret == -EINVAL) { 4073 4065 ui__error("Invalid --fields key: `%s'", tok); 4074 4066 break;
+1 -1
tools/perf/util/sort.h
··· 146 146 int sort_dimension__add(struct perf_hpp_list *list, const char *tok, 147 147 struct evlist *evlist, 148 148 int level); 149 - int output_field_add(struct perf_hpp_list *list, const char *tok); 149 + int output_field_add(struct perf_hpp_list *list, const char *tok, int *level); 150 150 int64_t 151 151 sort__iaddr_cmp(struct hist_entry *left, struct hist_entry *right); 152 152 int64_t