Linux Audio

Check our new training course

Loading...
v3.1
  1#include "sort.h"
  2#include "hist.h"
  3
  4regex_t		parent_regex;
  5const char	default_parent_pattern[] = "^sys_|^do_page_fault";
  6const char	*parent_pattern = default_parent_pattern;
  7const char	default_sort_order[] = "comm,dso,symbol";
  8const char	*sort_order = default_sort_order;
  9int		sort__need_collapse = 0;
 10int		sort__has_parent = 0;
 
 11
 12enum sort_type	sort__first_dimension;
 13
 14char * field_sep;
 15
 16LIST_HEAD(hist_entry__sort_list);
 17
 18static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
 19{
 20	int n;
 21	va_list ap;
 22
 23	va_start(ap, fmt);
 24	n = vsnprintf(bf, size, fmt, ap);
 25	if (field_sep && n > 0) {
 26		char *sep = bf;
 27
 28		while (1) {
 29			sep = strchr(sep, *field_sep);
 30			if (sep == NULL)
 31				break;
 32			*sep = '.';
 33		}
 34	}
 35	va_end(ap);
 
 
 
 36	return n;
 37}
 38
 39static int64_t cmp_null(void *l, void *r)
 40{
 41	if (!l && !r)
 42		return 0;
 43	else if (!l)
 44		return -1;
 45	else
 46		return 1;
 47}
 48
 49/* --sort pid */
 50
 51static int64_t
 52sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
 53{
 54	return right->thread->pid - left->thread->pid;
 55}
 56
 57static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
 58				       size_t size, unsigned int width)
 59{
 60	return repsep_snprintf(bf, size, "%*s:%5d", width,
 61			      self->thread->comm ?: "", self->thread->pid);
 62}
 63
 64struct sort_entry sort_thread = {
 65	.se_header	= "Command:  Pid",
 66	.se_cmp		= sort__thread_cmp,
 67	.se_snprintf	= hist_entry__thread_snprintf,
 68	.se_width_idx	= HISTC_THREAD,
 69};
 70
 71/* --sort comm */
 72
 73static int64_t
 74sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
 75{
 76	return right->thread->pid - left->thread->pid;
 77}
 78
 79static int64_t
 80sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
 81{
 82	char *comm_l = left->thread->comm;
 83	char *comm_r = right->thread->comm;
 84
 85	if (!comm_l || !comm_r)
 86		return cmp_null(comm_l, comm_r);
 87
 88	return strcmp(comm_l, comm_r);
 89}
 90
 91static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
 92				     size_t size, unsigned int width)
 93{
 94	return repsep_snprintf(bf, size, "%*s", width, self->thread->comm);
 95}
 96
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 97struct sort_entry sort_comm = {
 98	.se_header	= "Command",
 99	.se_cmp		= sort__comm_cmp,
100	.se_collapse	= sort__comm_collapse,
101	.se_snprintf	= hist_entry__comm_snprintf,
102	.se_width_idx	= HISTC_COMM,
103};
104
105/* --sort dso */
106
107static int64_t
108sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
109{
110	struct dso *dso_l = left->ms.map ? left->ms.map->dso : NULL;
111	struct dso *dso_r = right->ms.map ? right->ms.map->dso : NULL;
112	const char *dso_name_l, *dso_name_r;
113
114	if (!dso_l || !dso_r)
115		return cmp_null(dso_l, dso_r);
116
117	if (verbose) {
118		dso_name_l = dso_l->long_name;
119		dso_name_r = dso_r->long_name;
120	} else {
121		dso_name_l = dso_l->short_name;
122		dso_name_r = dso_r->short_name;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123	}
124
125	return strcmp(dso_name_l, dso_name_r);
126}
127
128static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
129				    size_t size, unsigned int width)
130{
131	if (self->ms.map && self->ms.map->dso) {
132		const char *dso_name = !verbose ? self->ms.map->dso->short_name :
133						  self->ms.map->dso->long_name;
134		return repsep_snprintf(bf, size, "%-*s", width, dso_name);
 
 
 
 
 
 
 
 
 
135	}
136
137	return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
 
 
 
 
 
 
 
 
 
 
 
 
 
138}
139
 
140struct sort_entry sort_dso = {
141	.se_header	= "Shared Object",
142	.se_cmp		= sort__dso_cmp,
143	.se_snprintf	= hist_entry__dso_snprintf,
144	.se_width_idx	= HISTC_DSO,
145};
146
147/* --sort symbol */
 
 
 
 
 
148
 
149static int64_t
150sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
151{
152	u64 ip_l, ip_r;
153
154	if (!left->ms.sym && !right->ms.sym)
155		return right->level - left->level;
156
157	if (!left->ms.sym || !right->ms.sym)
158		return cmp_null(left->ms.sym, right->ms.sym);
159
160	if (left->ms.sym == right->ms.sym)
161		return 0;
162
163	ip_l = left->ms.sym->start;
164	ip_r = right->ms.sym->start;
165
166	return (int64_t)(ip_r - ip_l);
167}
168
169static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
170				    size_t size, unsigned int width __used)
171{
172	size_t ret = 0;
173
174	if (verbose) {
175		char o = self->ms.map ? dso__symtab_origin(self->ms.map->dso) : '!';
176		ret += repsep_snprintf(bf, size, "%-#*llx %c ",
177				       BITS_PER_LONG / 4, self->ip, o);
178	}
179
180	ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", self->level);
181	if (self->ms.sym)
182		ret += repsep_snprintf(bf + ret, size - ret, "%s",
183				       self->ms.sym->name);
184	else
185		ret += repsep_snprintf(bf + ret, size - ret, "%-#*llx",
186				       BITS_PER_LONG / 4, self->ip);
187
188	return ret;
189}
190
191struct sort_entry sort_sym = {
192	.se_header	= "Symbol",
193	.se_cmp		= sort__sym_cmp,
194	.se_snprintf	= hist_entry__sym_snprintf,
195	.se_width_idx	= HISTC_SYMBOL,
196};
197
198/* --sort parent */
199
200static int64_t
201sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
202{
203	struct symbol *sym_l = left->parent;
204	struct symbol *sym_r = right->parent;
205
206	if (!sym_l || !sym_r)
207		return cmp_null(sym_l, sym_r);
208
209	return strcmp(sym_l->name, sym_r->name);
210}
211
212static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
213				       size_t size, unsigned int width)
214{
215	return repsep_snprintf(bf, size, "%-*s", width,
216			      self->parent ? self->parent->name : "[other]");
217}
218
219struct sort_entry sort_parent = {
220	.se_header	= "Parent symbol",
221	.se_cmp		= sort__parent_cmp,
222	.se_snprintf	= hist_entry__parent_snprintf,
223	.se_width_idx	= HISTC_PARENT,
224};
225
226/* --sort cpu */
227
228static int64_t
229sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
230{
231	return right->cpu - left->cpu;
232}
233
234static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
235				       size_t size, unsigned int width)
236{
237	return repsep_snprintf(bf, size, "%-*d", width, self->cpu);
238}
239
240struct sort_entry sort_cpu = {
241	.se_header      = "CPU",
242	.se_cmp	        = sort__cpu_cmp,
243	.se_snprintf    = hist_entry__cpu_snprintf,
244	.se_width_idx	= HISTC_CPU,
245};
246
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
247struct sort_dimension {
248	const char		*name;
249	struct sort_entry	*entry;
250	int			taken;
251};
252
 
 
253static struct sort_dimension sort_dimensions[] = {
254	{ .name = "pid",	.entry = &sort_thread,	},
255	{ .name = "comm",	.entry = &sort_comm,	},
256	{ .name = "dso",	.entry = &sort_dso,	},
257	{ .name = "symbol",	.entry = &sort_sym,	},
258	{ .name = "parent",	.entry = &sort_parent,	},
259	{ .name = "cpu",	.entry = &sort_cpu,	},
 
 
 
 
 
260};
261
262int sort_dimension__add(const char *tok)
263{
264	unsigned int i;
265
266	for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
267		struct sort_dimension *sd = &sort_dimensions[i];
268
269		if (strncasecmp(tok, sd->name, strlen(tok)))
270			continue;
271
272		if (sd->entry == &sort_parent) {
273			int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
274			if (ret) {
275				char err[BUFSIZ];
276
277				regerror(ret, &parent_regex, err, sizeof(err));
278				pr_err("Invalid regex: %s\n%s", parent_pattern, err);
279				return -EINVAL;
280			}
281			sort__has_parent = 1;
282		}
283
284		if (sd->taken)
285			return 0;
286
287		if (sd->entry->se_collapse)
288			sort__need_collapse = 1;
289
290		if (list_empty(&hist_entry__sort_list)) {
291			if (!strcmp(sd->name, "pid"))
292				sort__first_dimension = SORT_PID;
293			else if (!strcmp(sd->name, "comm"))
294				sort__first_dimension = SORT_COMM;
295			else if (!strcmp(sd->name, "dso"))
296				sort__first_dimension = SORT_DSO;
297			else if (!strcmp(sd->name, "symbol"))
298				sort__first_dimension = SORT_SYM;
299			else if (!strcmp(sd->name, "parent"))
300				sort__first_dimension = SORT_PARENT;
301			else if (!strcmp(sd->name, "cpu"))
302				sort__first_dimension = SORT_CPU;
 
 
 
 
 
 
 
 
 
 
303		}
304
305		list_add_tail(&sd->entry->list, &hist_entry__sort_list);
306		sd->taken = 1;
307
308		return 0;
309	}
310
311	return -ESRCH;
312}
313
314void setup_sorting(const char * const usagestr[], const struct option *opts)
315{
316	char *tmp, *tok, *str = strdup(sort_order);
317
318	for (tok = strtok_r(str, ", ", &tmp);
319			tok; tok = strtok_r(NULL, ", ", &tmp)) {
320		if (sort_dimension__add(tok) < 0) {
321			error("Unknown --sort key: `%s'", tok);
322			usage_with_options(usagestr, opts);
323		}
324	}
325
326	free(str);
327}
328
329void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
330			     const char *list_name, FILE *fp)
331{
332	if (list && strlist__nr_entries(list) == 1) {
333		if (fp != NULL)
334			fprintf(fp, "# %s: %s\n", list_name,
335				strlist__entry(list, 0)->s);
336		self->elide = true;
337	}
338}
v3.5.6
  1#include "sort.h"
  2#include "hist.h"
  3
  4regex_t		parent_regex;
  5const char	default_parent_pattern[] = "^sys_|^do_page_fault";
  6const char	*parent_pattern = default_parent_pattern;
  7const char	default_sort_order[] = "comm,dso,symbol";
  8const char	*sort_order = default_sort_order;
  9int		sort__need_collapse = 0;
 10int		sort__has_parent = 0;
 11int		sort__branch_mode = -1; /* -1 = means not set */
 12
 13enum sort_type	sort__first_dimension;
 14
 15char * field_sep;
 16
 17LIST_HEAD(hist_entry__sort_list);
 18
 19static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
 20{
 21	int n;
 22	va_list ap;
 23
 24	va_start(ap, fmt);
 25	n = vsnprintf(bf, size, fmt, ap);
 26	if (field_sep && n > 0) {
 27		char *sep = bf;
 28
 29		while (1) {
 30			sep = strchr(sep, *field_sep);
 31			if (sep == NULL)
 32				break;
 33			*sep = '.';
 34		}
 35	}
 36	va_end(ap);
 37
 38	if (n >= (int)size)
 39		return size - 1;
 40	return n;
 41}
 42
 43static int64_t cmp_null(void *l, void *r)
 44{
 45	if (!l && !r)
 46		return 0;
 47	else if (!l)
 48		return -1;
 49	else
 50		return 1;
 51}
 52
 53/* --sort pid */
 54
 55static int64_t
 56sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
 57{
 58	return right->thread->pid - left->thread->pid;
 59}
 60
 61static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
 62				       size_t size, unsigned int width)
 63{
 64	return repsep_snprintf(bf, size, "%*s:%5d", width,
 65			      self->thread->comm ?: "", self->thread->pid);
 66}
 67
 68struct sort_entry sort_thread = {
 69	.se_header	= "Command:  Pid",
 70	.se_cmp		= sort__thread_cmp,
 71	.se_snprintf	= hist_entry__thread_snprintf,
 72	.se_width_idx	= HISTC_THREAD,
 73};
 74
 75/* --sort comm */
 76
 77static int64_t
 78sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
 79{
 80	return right->thread->pid - left->thread->pid;
 81}
 82
 83static int64_t
 84sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
 85{
 86	char *comm_l = left->thread->comm;
 87	char *comm_r = right->thread->comm;
 88
 89	if (!comm_l || !comm_r)
 90		return cmp_null(comm_l, comm_r);
 91
 92	return strcmp(comm_l, comm_r);
 93}
 94
 95static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
 96				     size_t size, unsigned int width)
 97{
 98	return repsep_snprintf(bf, size, "%*s", width, self->thread->comm);
 99}
100
101static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
102{
103	struct dso *dso_l = map_l ? map_l->dso : NULL;
104	struct dso *dso_r = map_r ? map_r->dso : NULL;
105	const char *dso_name_l, *dso_name_r;
106
107	if (!dso_l || !dso_r)
108		return cmp_null(dso_l, dso_r);
109
110	if (verbose) {
111		dso_name_l = dso_l->long_name;
112		dso_name_r = dso_r->long_name;
113	} else {
114		dso_name_l = dso_l->short_name;
115		dso_name_r = dso_r->short_name;
116	}
117
118	return strcmp(dso_name_l, dso_name_r);
119}
120
121struct sort_entry sort_comm = {
122	.se_header	= "Command",
123	.se_cmp		= sort__comm_cmp,
124	.se_collapse	= sort__comm_collapse,
125	.se_snprintf	= hist_entry__comm_snprintf,
126	.se_width_idx	= HISTC_COMM,
127};
128
129/* --sort dso */
130
131static int64_t
132sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
133{
134	return _sort__dso_cmp(left->ms.map, right->ms.map);
135}
 
136
 
 
137
138static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r,
139			      u64 ip_l, u64 ip_r)
140{
141	if (!sym_l || !sym_r)
142		return cmp_null(sym_l, sym_r);
143
144	if (sym_l == sym_r)
145		return 0;
146
147	if (sym_l)
148		ip_l = sym_l->start;
149	if (sym_r)
150		ip_r = sym_r->start;
151
152	return (int64_t)(ip_r - ip_l);
153}
154
155static int _hist_entry__dso_snprintf(struct map *map, char *bf,
156				     size_t size, unsigned int width)
157{
158	if (map && map->dso) {
159		const char *dso_name = !verbose ? map->dso->short_name :
160			map->dso->long_name;
161		return repsep_snprintf(bf, size, "%-*s", width, dso_name);
162	}
163
164	return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
165}
166
167static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
168				    size_t size, unsigned int width)
169{
170	return _hist_entry__dso_snprintf(self->ms.map, bf, size, width);
171}
172
173static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
174				     u64 ip, char level, char *bf, size_t size,
175				     unsigned int width __used)
176{
177	size_t ret = 0;
178
179	if (verbose) {
180		char o = map ? dso__symtab_origin(map->dso) : '!';
181		ret += repsep_snprintf(bf, size, "%-#*llx %c ",
182				       BITS_PER_LONG / 4, ip, o);
183	}
184
185	ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
186	if (sym)
187		ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
188				       width - ret,
189				       sym->name);
190	else {
191		size_t len = BITS_PER_LONG / 4;
192		ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
193				       len, ip);
194		ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
195				       width - ret, "");
196	}
197
198	return ret;
199}
200
201
202struct sort_entry sort_dso = {
203	.se_header	= "Shared Object",
204	.se_cmp		= sort__dso_cmp,
205	.se_snprintf	= hist_entry__dso_snprintf,
206	.se_width_idx	= HISTC_DSO,
207};
208
209static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
210				    size_t size, unsigned int width __used)
211{
212	return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip,
213					 self->level, bf, size, width);
214}
215
216/* --sort symbol */
217static int64_t
218sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
219{
220	u64 ip_l, ip_r;
221
222	if (!left->ms.sym && !right->ms.sym)
223		return right->level - left->level;
224
225	if (!left->ms.sym || !right->ms.sym)
226		return cmp_null(left->ms.sym, right->ms.sym);
227
228	if (left->ms.sym == right->ms.sym)
229		return 0;
230
231	ip_l = left->ms.sym->start;
232	ip_r = right->ms.sym->start;
233
234	return _sort__sym_cmp(left->ms.sym, right->ms.sym, ip_l, ip_r);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235}
236
237struct sort_entry sort_sym = {
238	.se_header	= "Symbol",
239	.se_cmp		= sort__sym_cmp,
240	.se_snprintf	= hist_entry__sym_snprintf,
241	.se_width_idx	= HISTC_SYMBOL,
242};
243
244/* --sort parent */
245
246static int64_t
247sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
248{
249	struct symbol *sym_l = left->parent;
250	struct symbol *sym_r = right->parent;
251
252	if (!sym_l || !sym_r)
253		return cmp_null(sym_l, sym_r);
254
255	return strcmp(sym_l->name, sym_r->name);
256}
257
258static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
259				       size_t size, unsigned int width)
260{
261	return repsep_snprintf(bf, size, "%-*s", width,
262			      self->parent ? self->parent->name : "[other]");
263}
264
265struct sort_entry sort_parent = {
266	.se_header	= "Parent symbol",
267	.se_cmp		= sort__parent_cmp,
268	.se_snprintf	= hist_entry__parent_snprintf,
269	.se_width_idx	= HISTC_PARENT,
270};
271
272/* --sort cpu */
273
274static int64_t
275sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
276{
277	return right->cpu - left->cpu;
278}
279
280static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
281				       size_t size, unsigned int width)
282{
283	return repsep_snprintf(bf, size, "%-*d", width, self->cpu);
284}
285
286struct sort_entry sort_cpu = {
287	.se_header      = "CPU",
288	.se_cmp	        = sort__cpu_cmp,
289	.se_snprintf    = hist_entry__cpu_snprintf,
290	.se_width_idx	= HISTC_CPU,
291};
292
293static int64_t
294sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
295{
296	return _sort__dso_cmp(left->branch_info->from.map,
297			      right->branch_info->from.map);
298}
299
300static int hist_entry__dso_from_snprintf(struct hist_entry *self, char *bf,
301				    size_t size, unsigned int width)
302{
303	return _hist_entry__dso_snprintf(self->branch_info->from.map,
304					 bf, size, width);
305}
306
307struct sort_entry sort_dso_from = {
308	.se_header	= "Source Shared Object",
309	.se_cmp		= sort__dso_from_cmp,
310	.se_snprintf	= hist_entry__dso_from_snprintf,
311	.se_width_idx	= HISTC_DSO_FROM,
312};
313
314static int64_t
315sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
316{
317	return _sort__dso_cmp(left->branch_info->to.map,
318			      right->branch_info->to.map);
319}
320
321static int hist_entry__dso_to_snprintf(struct hist_entry *self, char *bf,
322				       size_t size, unsigned int width)
323{
324	return _hist_entry__dso_snprintf(self->branch_info->to.map,
325					 bf, size, width);
326}
327
328static int64_t
329sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
330{
331	struct addr_map_symbol *from_l = &left->branch_info->from;
332	struct addr_map_symbol *from_r = &right->branch_info->from;
333
334	if (!from_l->sym && !from_r->sym)
335		return right->level - left->level;
336
337	return _sort__sym_cmp(from_l->sym, from_r->sym, from_l->addr,
338			     from_r->addr);
339}
340
341static int64_t
342sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
343{
344	struct addr_map_symbol *to_l = &left->branch_info->to;
345	struct addr_map_symbol *to_r = &right->branch_info->to;
346
347	if (!to_l->sym && !to_r->sym)
348		return right->level - left->level;
349
350	return _sort__sym_cmp(to_l->sym, to_r->sym, to_l->addr, to_r->addr);
351}
352
353static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf,
354				    size_t size, unsigned int width __used)
355{
356	struct addr_map_symbol *from = &self->branch_info->from;
357	return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
358					 self->level, bf, size, width);
359
360}
361
362static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf,
363				    size_t size, unsigned int width __used)
364{
365	struct addr_map_symbol *to = &self->branch_info->to;
366	return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
367					 self->level, bf, size, width);
368
369}
370
371struct sort_entry sort_dso_to = {
372	.se_header	= "Target Shared Object",
373	.se_cmp		= sort__dso_to_cmp,
374	.se_snprintf	= hist_entry__dso_to_snprintf,
375	.se_width_idx	= HISTC_DSO_TO,
376};
377
378struct sort_entry sort_sym_from = {
379	.se_header	= "Source Symbol",
380	.se_cmp		= sort__sym_from_cmp,
381	.se_snprintf	= hist_entry__sym_from_snprintf,
382	.se_width_idx	= HISTC_SYMBOL_FROM,
383};
384
385struct sort_entry sort_sym_to = {
386	.se_header	= "Target Symbol",
387	.se_cmp		= sort__sym_to_cmp,
388	.se_snprintf	= hist_entry__sym_to_snprintf,
389	.se_width_idx	= HISTC_SYMBOL_TO,
390};
391
392static int64_t
393sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
394{
395	const unsigned char mp = left->branch_info->flags.mispred !=
396					right->branch_info->flags.mispred;
397	const unsigned char p = left->branch_info->flags.predicted !=
398					right->branch_info->flags.predicted;
399
400	return mp || p;
401}
402
403static int hist_entry__mispredict_snprintf(struct hist_entry *self, char *bf,
404				    size_t size, unsigned int width){
405	static const char *out = "N/A";
406
407	if (self->branch_info->flags.predicted)
408		out = "N";
409	else if (self->branch_info->flags.mispred)
410		out = "Y";
411
412	return repsep_snprintf(bf, size, "%-*s", width, out);
413}
414
415struct sort_entry sort_mispredict = {
416	.se_header	= "Branch Mispredicted",
417	.se_cmp		= sort__mispredict_cmp,
418	.se_snprintf	= hist_entry__mispredict_snprintf,
419	.se_width_idx	= HISTC_MISPREDICT,
420};
421
422struct sort_dimension {
423	const char		*name;
424	struct sort_entry	*entry;
425	int			taken;
426};
427
428#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
429
430static struct sort_dimension sort_dimensions[] = {
431	DIM(SORT_PID, "pid", sort_thread),
432	DIM(SORT_COMM, "comm", sort_comm),
433	DIM(SORT_DSO, "dso", sort_dso),
434	DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
435	DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
436	DIM(SORT_SYM, "symbol", sort_sym),
437	DIM(SORT_SYM_TO, "symbol_from", sort_sym_from),
438	DIM(SORT_SYM_FROM, "symbol_to", sort_sym_to),
439	DIM(SORT_PARENT, "parent", sort_parent),
440	DIM(SORT_CPU, "cpu", sort_cpu),
441	DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
442};
443
444int sort_dimension__add(const char *tok)
445{
446	unsigned int i;
447
448	for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
449		struct sort_dimension *sd = &sort_dimensions[i];
450
451		if (strncasecmp(tok, sd->name, strlen(tok)))
452			continue;
 
453		if (sd->entry == &sort_parent) {
454			int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
455			if (ret) {
456				char err[BUFSIZ];
457
458				regerror(ret, &parent_regex, err, sizeof(err));
459				pr_err("Invalid regex: %s\n%s", parent_pattern, err);
460				return -EINVAL;
461			}
462			sort__has_parent = 1;
463		}
464
465		if (sd->taken)
466			return 0;
467
468		if (sd->entry->se_collapse)
469			sort__need_collapse = 1;
470
471		if (list_empty(&hist_entry__sort_list)) {
472			if (!strcmp(sd->name, "pid"))
473				sort__first_dimension = SORT_PID;
474			else if (!strcmp(sd->name, "comm"))
475				sort__first_dimension = SORT_COMM;
476			else if (!strcmp(sd->name, "dso"))
477				sort__first_dimension = SORT_DSO;
478			else if (!strcmp(sd->name, "symbol"))
479				sort__first_dimension = SORT_SYM;
480			else if (!strcmp(sd->name, "parent"))
481				sort__first_dimension = SORT_PARENT;
482			else if (!strcmp(sd->name, "cpu"))
483				sort__first_dimension = SORT_CPU;
484			else if (!strcmp(sd->name, "symbol_from"))
485				sort__first_dimension = SORT_SYM_FROM;
486			else if (!strcmp(sd->name, "symbol_to"))
487				sort__first_dimension = SORT_SYM_TO;
488			else if (!strcmp(sd->name, "dso_from"))
489				sort__first_dimension = SORT_DSO_FROM;
490			else if (!strcmp(sd->name, "dso_to"))
491				sort__first_dimension = SORT_DSO_TO;
492			else if (!strcmp(sd->name, "mispredict"))
493				sort__first_dimension = SORT_MISPREDICT;
494		}
495
496		list_add_tail(&sd->entry->list, &hist_entry__sort_list);
497		sd->taken = 1;
498
499		return 0;
500	}
 
501	return -ESRCH;
502}
503
504void setup_sorting(const char * const usagestr[], const struct option *opts)
505{
506	char *tmp, *tok, *str = strdup(sort_order);
507
508	for (tok = strtok_r(str, ", ", &tmp);
509			tok; tok = strtok_r(NULL, ", ", &tmp)) {
510		if (sort_dimension__add(tok) < 0) {
511			error("Unknown --sort key: `%s'", tok);
512			usage_with_options(usagestr, opts);
513		}
514	}
515
516	free(str);
517}
518
519void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
520			     const char *list_name, FILE *fp)
521{
522	if (list && strlist__nr_entries(list) == 1) {
523		if (fp != NULL)
524			fprintf(fp, "# %s: %s\n", list_name,
525				strlist__entry(list, 0)->s);
526		self->elide = true;
527	}
528}