1 #include "sort.h" 2 3 regex_t parent_regex; 4 char default_parent_pattern[] = "^sys_|^do_page_fault"; 5 char *parent_pattern = default_parent_pattern; 6 char default_sort_order[] = "comm,dso,symbol"; 7 char *sort_order = default_sort_order; 8 int sort__need_collapse = 0; 9 int sort__has_parent = 0; 10 11 enum sort_type sort__first_dimension; 12 13 unsigned int dsos__col_width; 14 unsigned int comms__col_width; 15 unsigned int threads__col_width; 16 static unsigned int parent_symbol__col_width; 17 char * field_sep; 18 19 LIST_HEAD(hist_entry__sort_list); 20 21 struct sort_entry sort_thread = { 22 .header = "Command: Pid", 23 .cmp = sort__thread_cmp, 24 .print = sort__thread_print, 25 .width = &threads__col_width, 26 }; 27 28 struct sort_entry sort_comm = { 29 .header = "Command", 30 .cmp = sort__comm_cmp, 31 .collapse = sort__comm_collapse, 32 .print = sort__comm_print, 33 .width = &comms__col_width, 34 }; 35 36 struct sort_entry sort_dso = { 37 .header = "Shared Object", 38 .cmp = sort__dso_cmp, 39 .print = sort__dso_print, 40 .width = &dsos__col_width, 41 }; 42 43 struct sort_entry sort_sym = { 44 .header = "Symbol", 45 .cmp = sort__sym_cmp, 46 .print = sort__sym_print, 47 }; 48 49 struct sort_entry sort_parent = { 50 .header = "Parent symbol", 51 .cmp = sort__parent_cmp, 52 .print = sort__parent_print, 53 .width = &parent_symbol__col_width, 54 }; 55 56 struct sort_dimension { 57 const char *name; 58 struct sort_entry *entry; 59 int taken; 60 }; 61 62 static struct sort_dimension sort_dimensions[] = { 63 { .name = "pid", .entry = &sort_thread, }, 64 { .name = "comm", .entry = &sort_comm, }, 65 { .name = "dso", .entry = &sort_dso, }, 66 { .name = "symbol", .entry = &sort_sym, }, 67 { .name = "parent", .entry = &sort_parent, }, 68 }; 69 70 int64_t cmp_null(void *l, void *r) 71 { 72 if (!l && !r) 73 return 0; 74 else if (!l) 75 return -1; 76 else 77 return 1; 78 } 79 80 /* --sort pid */ 81 82 int64_t 83 sort__thread_cmp(struct hist_entry *left, struct hist_entry *right) 84 { 85 return right->thread->pid - left->thread->pid; 86 } 87 88 int repsep_fprintf(FILE *fp, const char *fmt, ...) 89 { 90 int n; 91 va_list ap; 92 93 va_start(ap, fmt); 94 if (!field_sep) 95 n = vfprintf(fp, fmt, ap); 96 else { 97 char *bf = NULL; 98 n = vasprintf(&bf, fmt, ap); 99 if (n > 0) { 100 char *sep = bf; 101 102 while (1) { 103 sep = strchr(sep, *field_sep); 104 if (sep == NULL) 105 break; 106 *sep = '.'; 107 } 108 } 109 fputs(bf, fp); 110 free(bf); 111 } 112 va_end(ap); 113 return n; 114 } 115 116 size_t 117 sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width) 118 { 119 return repsep_fprintf(fp, "%*s:%5d", width - 6, 120 self->thread->comm ?: "", self->thread->pid); 121 } 122 123 size_t 124 sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width) 125 { 126 return repsep_fprintf(fp, "%*s", width, self->thread->comm); 127 } 128 129 /* --sort dso */ 130 131 int64_t 132 sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) 133 { 134 struct dso *dso_l = left->map ? left->map->dso : NULL; 135 struct dso *dso_r = right->map ? right->map->dso : NULL; 136 const char *dso_name_l, *dso_name_r; 137 138 if (!dso_l || !dso_r) 139 return cmp_null(dso_l, dso_r); 140 141 if (verbose) { 142 dso_name_l = dso_l->long_name; 143 dso_name_r = dso_r->long_name; 144 } else { 145 dso_name_l = dso_l->short_name; 146 dso_name_r = dso_r->short_name; 147 } 148 149 return strcmp(dso_name_l, dso_name_r); 150 } 151 152 size_t 153 sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width) 154 { 155 if (self->map && self->map->dso) { 156 const char *dso_name = !verbose ? self->map->dso->short_name : 157 self->map->dso->long_name; 158 return repsep_fprintf(fp, "%-*s", width, dso_name); 159 } 160 161 return repsep_fprintf(fp, "%*llx", width, (u64)self->ip); 162 } 163 164 /* --sort symbol */ 165 166 int64_t 167 sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) 168 { 169 u64 ip_l, ip_r; 170 171 if (left->sym == right->sym) 172 return 0; 173 174 ip_l = left->sym ? left->sym->start : left->ip; 175 ip_r = right->sym ? right->sym->start : right->ip; 176 177 return (int64_t)(ip_r - ip_l); 178 } 179 180 181 size_t 182 sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used) 183 { 184 size_t ret = 0; 185 186 if (verbose) { 187 char o = self->map ? dso__symtab_origin(self->map->dso) : '!'; 188 ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip, o); 189 } 190 191 ret += repsep_fprintf(fp, "[%c] ", self->level); 192 if (self->sym) 193 ret += repsep_fprintf(fp, "%s", self->sym->name); 194 else 195 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip); 196 197 return ret; 198 } 199 200 /* --sort comm */ 201 202 int64_t 203 sort__comm_cmp(struct hist_entry *left, struct hist_entry *right) 204 { 205 return right->thread->pid - left->thread->pid; 206 } 207 208 int64_t 209 sort__comm_collapse(struct hist_entry *left, struct hist_entry *right) 210 { 211 char *comm_l = left->thread->comm; 212 char *comm_r = right->thread->comm; 213 214 if (!comm_l || !comm_r) 215 return cmp_null(comm_l, comm_r); 216 217 return strcmp(comm_l, comm_r); 218 } 219 220 /* --sort parent */ 221 222 int64_t 223 sort__parent_cmp(struct hist_entry *left, struct hist_entry *right) 224 { 225 struct symbol *sym_l = left->parent; 226 struct symbol *sym_r = right->parent; 227 228 if (!sym_l || !sym_r) 229 return cmp_null(sym_l, sym_r); 230 231 return strcmp(sym_l->name, sym_r->name); 232 } 233 234 size_t 235 sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width) 236 { 237 return repsep_fprintf(fp, "%-*s", width, 238 self->parent ? self->parent->name : "[other]"); 239 } 240 241 int sort_dimension__add(const char *tok) 242 { 243 unsigned int i; 244 245 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { 246 struct sort_dimension *sd = &sort_dimensions[i]; 247 248 if (sd->taken) 249 continue; 250 251 if (strncasecmp(tok, sd->name, strlen(tok))) 252 continue; 253 254 if (sd->entry->collapse) 255 sort__need_collapse = 1; 256 257 if (sd->entry == &sort_parent) { 258 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED); 259 if (ret) { 260 char err[BUFSIZ]; 261 262 regerror(ret, &parent_regex, err, sizeof(err)); 263 fprintf(stderr, "Invalid regex: %s\n%s", 264 parent_pattern, err); 265 exit(-1); 266 } 267 sort__has_parent = 1; 268 } 269 270 if (list_empty(&hist_entry__sort_list)) { 271 if (!strcmp(sd->name, "pid")) 272 sort__first_dimension = SORT_PID; 273 else if (!strcmp(sd->name, "comm")) 274 sort__first_dimension = SORT_COMM; 275 else if (!strcmp(sd->name, "dso")) 276 sort__first_dimension = SORT_DSO; 277 else if (!strcmp(sd->name, "symbol")) 278 sort__first_dimension = SORT_SYM; 279 else if (!strcmp(sd->name, "parent")) 280 sort__first_dimension = SORT_PARENT; 281 } 282 283 list_add_tail(&sd->entry->list, &hist_entry__sort_list); 284 sd->taken = 1; 285 286 return 0; 287 } 288 289 return -ESRCH; 290 } 291