diff options
Diffstat (limited to 'tools/perf/builtin-annotate.c')
| -rw-r--r-- | tools/perf/builtin-annotate.c | 211 |
1 files changed, 7 insertions, 204 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index a33087328bd4..059c565b31ea 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
| @@ -22,12 +22,10 @@ | |||
| 22 | #include "util/parse-options.h" | 22 | #include "util/parse-options.h" |
| 23 | #include "util/parse-events.h" | 23 | #include "util/parse-events.h" |
| 24 | #include "util/thread.h" | 24 | #include "util/thread.h" |
| 25 | #include "util/sort.h" | ||
| 25 | 26 | ||
| 26 | static char const *input_name = "perf.data"; | 27 | static char const *input_name = "perf.data"; |
| 27 | 28 | ||
| 28 | static char default_sort_order[] = "comm,symbol"; | ||
| 29 | static char *sort_order = default_sort_order; | ||
| 30 | |||
| 31 | static int force; | 29 | static int force; |
| 32 | static int input; | 30 | static int input; |
| 33 | static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV; | 31 | static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV; |
| @@ -55,207 +53,6 @@ struct sym_ext { | |||
| 55 | 53 | ||
| 56 | static struct rb_root hist; | 54 | static struct rb_root hist; |
| 57 | 55 | ||
| 58 | struct hist_entry { | ||
| 59 | struct rb_node rb_node; | ||
| 60 | |||
| 61 | struct thread *thread; | ||
| 62 | struct map *map; | ||
| 63 | struct dso *dso; | ||
| 64 | struct symbol *sym; | ||
| 65 | u64 ip; | ||
| 66 | char level; | ||
| 67 | |||
| 68 | uint32_t count; | ||
| 69 | }; | ||
| 70 | |||
| 71 | /* | ||
| 72 | * configurable sorting bits | ||
| 73 | */ | ||
| 74 | |||
| 75 | struct sort_entry { | ||
| 76 | struct list_head list; | ||
| 77 | |||
| 78 | const char *header; | ||
| 79 | |||
| 80 | int64_t (*cmp)(struct hist_entry *, struct hist_entry *); | ||
| 81 | int64_t (*collapse)(struct hist_entry *, struct hist_entry *); | ||
| 82 | size_t (*print)(FILE *fp, struct hist_entry *); | ||
| 83 | }; | ||
| 84 | |||
| 85 | static int64_t cmp_null(void *l, void *r) | ||
| 86 | { | ||
| 87 | if (!l && !r) | ||
| 88 | return 0; | ||
| 89 | else if (!l) | ||
| 90 | return -1; | ||
| 91 | else | ||
| 92 | return 1; | ||
| 93 | } | ||
| 94 | |||
| 95 | /* --sort pid */ | ||
| 96 | |||
| 97 | static int64_t | ||
| 98 | sort__thread_cmp(struct hist_entry *left, struct hist_entry *right) | ||
| 99 | { | ||
| 100 | return right->thread->pid - left->thread->pid; | ||
| 101 | } | ||
| 102 | |||
| 103 | static size_t | ||
| 104 | sort__thread_print(FILE *fp, struct hist_entry *self) | ||
| 105 | { | ||
| 106 | return fprintf(fp, "%16s:%5d", self->thread->comm ?: "", self->thread->pid); | ||
| 107 | } | ||
| 108 | |||
| 109 | static struct sort_entry sort_thread = { | ||
| 110 | .header = " Command: Pid", | ||
| 111 | .cmp = sort__thread_cmp, | ||
| 112 | .print = sort__thread_print, | ||
| 113 | }; | ||
| 114 | |||
| 115 | /* --sort comm */ | ||
| 116 | |||
| 117 | static int64_t | ||
| 118 | sort__comm_cmp(struct hist_entry *left, struct hist_entry *right) | ||
| 119 | { | ||
| 120 | return right->thread->pid - left->thread->pid; | ||
| 121 | } | ||
| 122 | |||
| 123 | static int64_t | ||
| 124 | sort__comm_collapse(struct hist_entry *left, struct hist_entry *right) | ||
| 125 | { | ||
| 126 | char *comm_l = left->thread->comm; | ||
| 127 | char *comm_r = right->thread->comm; | ||
| 128 | |||
| 129 | if (!comm_l || !comm_r) | ||
| 130 | return cmp_null(comm_l, comm_r); | ||
| 131 | |||
| 132 | return strcmp(comm_l, comm_r); | ||
| 133 | } | ||
| 134 | |||
| 135 | static size_t | ||
| 136 | sort__comm_print(FILE *fp, struct hist_entry *self) | ||
| 137 | { | ||
| 138 | return fprintf(fp, "%16s", self->thread->comm); | ||
| 139 | } | ||
| 140 | |||
| 141 | static struct sort_entry sort_comm = { | ||
| 142 | .header = " Command", | ||
| 143 | .cmp = sort__comm_cmp, | ||
| 144 | .collapse = sort__comm_collapse, | ||
| 145 | .print = sort__comm_print, | ||
| 146 | }; | ||
| 147 | |||
| 148 | /* --sort dso */ | ||
| 149 | |||
| 150 | static int64_t | ||
| 151 | sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) | ||
| 152 | { | ||
| 153 | struct dso *dso_l = left->dso; | ||
| 154 | struct dso *dso_r = right->dso; | ||
| 155 | |||
| 156 | if (!dso_l || !dso_r) | ||
| 157 | return cmp_null(dso_l, dso_r); | ||
| 158 | |||
| 159 | return strcmp(dso_l->name, dso_r->name); | ||
| 160 | } | ||
| 161 | |||
| 162 | static size_t | ||
| 163 | sort__dso_print(FILE *fp, struct hist_entry *self) | ||
| 164 | { | ||
| 165 | if (self->dso) | ||
| 166 | return fprintf(fp, "%-25s", self->dso->name); | ||
| 167 | |||
| 168 | return fprintf(fp, "%016llx ", (u64)self->ip); | ||
| 169 | } | ||
| 170 | |||
| 171 | static struct sort_entry sort_dso = { | ||
| 172 | .header = "Shared Object ", | ||
| 173 | .cmp = sort__dso_cmp, | ||
| 174 | .print = sort__dso_print, | ||
| 175 | }; | ||
| 176 | |||
| 177 | /* --sort symbol */ | ||
| 178 | |||
| 179 | static int64_t | ||
| 180 | sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) | ||
| 181 | { | ||
| 182 | u64 ip_l, ip_r; | ||
| 183 | |||
| 184 | if (left->sym == right->sym) | ||
| 185 | return 0; | ||
| 186 | |||
| 187 | ip_l = left->sym ? left->sym->start : left->ip; | ||
| 188 | ip_r = right->sym ? right->sym->start : right->ip; | ||
| 189 | |||
| 190 | return (int64_t)(ip_r - ip_l); | ||
| 191 | } | ||
| 192 | |||
| 193 | static size_t | ||
| 194 | sort__sym_print(FILE *fp, struct hist_entry *self) | ||
| 195 | { | ||
| 196 | size_t ret = 0; | ||
| 197 | |||
| 198 | if (verbose) | ||
| 199 | ret += fprintf(fp, "%#018llx ", (u64)self->ip); | ||
| 200 | |||
| 201 | if (self->sym) { | ||
| 202 | ret += fprintf(fp, "[%c] %s", | ||
| 203 | self->dso == kernel_dso ? 'k' : '.', self->sym->name); | ||
| 204 | } else { | ||
| 205 | ret += fprintf(fp, "%#016llx", (u64)self->ip); | ||
| 206 | } | ||
| 207 | |||
| 208 | return ret; | ||
| 209 | } | ||
| 210 | |||
| 211 | static struct sort_entry sort_sym = { | ||
| 212 | .header = "Symbol", | ||
| 213 | .cmp = sort__sym_cmp, | ||
| 214 | .print = sort__sym_print, | ||
| 215 | }; | ||
| 216 | |||
| 217 | static int sort__need_collapse = 0; | ||
| 218 | |||
| 219 | struct sort_dimension { | ||
| 220 | const char *name; | ||
| 221 | struct sort_entry *entry; | ||
| 222 | int taken; | ||
| 223 | }; | ||
| 224 | |||
| 225 | static struct sort_dimension sort_dimensions[] = { | ||
| 226 | { .name = "pid", .entry = &sort_thread, }, | ||
| 227 | { .name = "comm", .entry = &sort_comm, }, | ||
| 228 | { .name = "dso", .entry = &sort_dso, }, | ||
| 229 | { .name = "symbol", .entry = &sort_sym, }, | ||
| 230 | }; | ||
| 231 | |||
| 232 | static LIST_HEAD(hist_entry__sort_list); | ||
| 233 | |||
| 234 | static int sort_dimension__add(char *tok) | ||
| 235 | { | ||
| 236 | unsigned int i; | ||
| 237 | |||
| 238 | for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { | ||
| 239 | struct sort_dimension *sd = &sort_dimensions[i]; | ||
| 240 | |||
| 241 | if (sd->taken) | ||
| 242 | continue; | ||
| 243 | |||
| 244 | if (strncasecmp(tok, sd->name, strlen(tok))) | ||
| 245 | continue; | ||
| 246 | |||
| 247 | if (sd->entry->collapse) | ||
| 248 | sort__need_collapse = 1; | ||
| 249 | |||
| 250 | list_add_tail(&sd->entry->list, &hist_entry__sort_list); | ||
| 251 | sd->taken = 1; | ||
| 252 | |||
| 253 | return 0; | ||
| 254 | } | ||
| 255 | |||
| 256 | return -ESRCH; | ||
| 257 | } | ||
| 258 | |||
| 259 | static int64_t | 56 | static int64_t |
| 260 | hist_entry__cmp(struct hist_entry *left, struct hist_entry *right) | 57 | hist_entry__cmp(struct hist_entry *left, struct hist_entry *right) |
| 261 | { | 58 | { |
| @@ -1137,5 +934,11 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used) | |||
| 1137 | 934 | ||
| 1138 | setup_pager(); | 935 | setup_pager(); |
| 1139 | 936 | ||
| 937 | if (field_sep && *field_sep == '.') { | ||
| 938 | fputs("'.' is the only non valid --field-separator argument\n", | ||
| 939 | stderr); | ||
| 940 | exit(129); | ||
| 941 | } | ||
| 942 | |||
| 1140 | return __cmd_annotate(); | 943 | return __cmd_annotate(); |
| 1141 | } | 944 | } |
