sort.c 8.4 KB
Newer Older
1 2 3
#include "sort.h"

regex_t		parent_regex;
4 5 6 7
const char	default_parent_pattern[] = "^sys_|^do_page_fault";
const char	*parent_pattern = default_parent_pattern;
const char	default_sort_order[] = "comm,dso,symbol";
const char	*sort_order = default_sort_order;
8 9
int		sort__need_collapse = 0;
int		sort__has_parent = 0;
10 11

enum sort_type	sort__first_dimension;
12 13 14 15

unsigned int dsos__col_width;
unsigned int comms__col_width;
unsigned int threads__col_width;
A
Arun Sharma 已提交
16
unsigned int cpus__col_width;
17 18 19 20 21
static unsigned int parent_symbol__col_width;
char * field_sep;

LIST_HEAD(hist_entry__sort_list);

22 23 24 25 26 27 28 29 30 31
static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
				       size_t size, unsigned int width);
static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
				     size_t size, unsigned int width);
static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
				    size_t size, unsigned int width);
static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
				    size_t size, unsigned int width);
static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
				       size_t size, unsigned int width);
A
Arun Sharma 已提交
32 33
static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
				    size_t size, unsigned int width);
34

35
struct sort_entry sort_thread = {
36 37 38 39
	.se_header	= "Command:  Pid",
	.se_cmp		= sort__thread_cmp,
	.se_snprintf	= hist_entry__thread_snprintf,
	.se_width	= &threads__col_width,
40 41 42
};

struct sort_entry sort_comm = {
43 44 45 46 47
	.se_header	= "Command",
	.se_cmp		= sort__comm_cmp,
	.se_collapse	= sort__comm_collapse,
	.se_snprintf	= hist_entry__comm_snprintf,
	.se_width	= &comms__col_width,
48 49 50
};

struct sort_entry sort_dso = {
51 52 53 54
	.se_header	= "Shared Object",
	.se_cmp		= sort__dso_cmp,
	.se_snprintf	= hist_entry__dso_snprintf,
	.se_width	= &dsos__col_width,
55 56 57
};

struct sort_entry sort_sym = {
58 59 60
	.se_header	= "Symbol",
	.se_cmp		= sort__sym_cmp,
	.se_snprintf	= hist_entry__sym_snprintf,
61 62 63
};

struct sort_entry sort_parent = {
64 65 66 67
	.se_header	= "Parent symbol",
	.se_cmp		= sort__parent_cmp,
	.se_snprintf	= hist_entry__parent_snprintf,
	.se_width	= &parent_symbol__col_width,
68
};
A
Arun Sharma 已提交
69 70 71 72 73 74 75
 
struct sort_entry sort_cpu = {
	.se_header      = "CPU",
	.se_cmp	        = sort__cpu_cmp,
	.se_snprintf    = hist_entry__cpu_snprintf,
	.se_width	= &cpus__col_width,
};
76 77 78 79 80 81 82 83 84 85 86 87 88

struct sort_dimension {
	const char		*name;
	struct sort_entry	*entry;
	int			taken;
};

static struct sort_dimension sort_dimensions[] = {
	{ .name = "pid",	.entry = &sort_thread,	},
	{ .name = "comm",	.entry = &sort_comm,	},
	{ .name = "dso",	.entry = &sort_dso,	},
	{ .name = "symbol",	.entry = &sort_sym,	},
	{ .name = "parent",	.entry = &sort_parent,	},
A
Arun Sharma 已提交
89
	{ .name = "cpu",	.entry = &sort_cpu,	},
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
};

int64_t cmp_null(void *l, void *r)
{
	if (!l && !r)
		return 0;
	else if (!l)
		return -1;
	else
		return 1;
}

/* --sort pid */

int64_t
sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
{
	return right->thread->pid - left->thread->pid;
}

110
static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
111 112 113 114 115
{
	int n;
	va_list ap;

	va_start(ap, fmt);
116 117 118 119 120 121 122 123 124
	n = vsnprintf(bf, size, fmt, ap);
	if (field_sep && n > 0) {
		char *sep = bf;

		while (1) {
			sep = strchr(sep, *field_sep);
			if (sep == NULL)
				break;
			*sep = '.';
125 126 127 128 129 130
		}
	}
	va_end(ap);
	return n;
}

131 132
static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
				       size_t size, unsigned int width)
133
{
134
	return repsep_snprintf(bf, size, "%*s:%5d", width,
135 136 137
			      self->thread->comm ?: "", self->thread->pid);
}

138 139
static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
				     size_t size, unsigned int width)
140
{
141
	return repsep_snprintf(bf, size, "%*s", width, self->thread->comm);
142 143 144 145 146 147 148
}

/* --sort dso */

int64_t
sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
{
149 150
	struct dso *dso_l = left->ms.map ? left->ms.map->dso : NULL;
	struct dso *dso_r = right->ms.map ? right->ms.map->dso : NULL;
151
	const char *dso_name_l, *dso_name_r;
152 153 154 155

	if (!dso_l || !dso_r)
		return cmp_null(dso_l, dso_r);

156 157 158 159 160 161 162 163 164
	if (verbose) {
		dso_name_l = dso_l->long_name;
		dso_name_r = dso_r->long_name;
	} else {
		dso_name_l = dso_l->short_name;
		dso_name_r = dso_r->short_name;
	}

	return strcmp(dso_name_l, dso_name_r);
165 166
}

167 168
static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
				    size_t size, unsigned int width)
169
{
170 171 172
	if (self->ms.map && self->ms.map->dso) {
		const char *dso_name = !verbose ? self->ms.map->dso->short_name :
						  self->ms.map->dso->long_name;
173
		return repsep_snprintf(bf, size, "%-*s", width, dso_name);
174
	}
175

176
	return repsep_snprintf(bf, size, "%*Lx", width, self->ip);
177 178 179 180 181 182 183 184 185
}

/* --sort symbol */

int64_t
sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
{
	u64 ip_l, ip_r;

186
	if (left->ms.sym == right->ms.sym)
187 188
		return 0;

189 190
	ip_l = left->ms.sym ? left->ms.sym->start : left->ip;
	ip_r = right->ms.sym ? right->ms.sym->start : right->ip;
191 192 193 194

	return (int64_t)(ip_r - ip_l);
}

195 196
static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
				    size_t size, unsigned int width __used)
197 198 199
{
	size_t ret = 0;

200
	if (verbose) {
201
		char o = self->ms.map ? dso__symtab_origin(self->ms.map->dso) : '!';
202
		ret += repsep_snprintf(bf, size, "%#018llx %c ", self->ip, o);
203
	}
204

205
	ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", self->level);
206
	if (self->ms.sym)
207 208
		ret += repsep_snprintf(bf + ret, size - ret, "%s",
				       self->ms.sym->name);
209
	else
210
		ret += repsep_snprintf(bf + ret, size - ret, "%#016llx", self->ip);
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248

	return ret;
}

/* --sort comm */

int64_t
sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
{
	return right->thread->pid - left->thread->pid;
}

int64_t
sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
{
	char *comm_l = left->thread->comm;
	char *comm_r = right->thread->comm;

	if (!comm_l || !comm_r)
		return cmp_null(comm_l, comm_r);

	return strcmp(comm_l, comm_r);
}

/* --sort parent */

int64_t
sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
{
	struct symbol *sym_l = left->parent;
	struct symbol *sym_r = right->parent;

	if (!sym_l || !sym_r)
		return cmp_null(sym_l, sym_r);

	return strcmp(sym_l->name, sym_r->name);
}

249 250
static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
				       size_t size, unsigned int width)
251
{
252
	return repsep_snprintf(bf, size, "%-*s", width,
253 254 255
			      self->parent ? self->parent->name : "[other]");
}

A
Arun Sharma 已提交
256 257 258 259 260 261 262 263 264 265 266 267 268 269
/* --sort cpu */

int64_t
sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
{
	return right->cpu - left->cpu;
}

static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
				       size_t size, unsigned int width)
{
	return repsep_snprintf(bf, size, "%-*d", width, self->cpu);
}

270 271 272 273 274 275 276 277 278 279 280 281 282
int sort_dimension__add(const char *tok)
{
	unsigned int i;

	for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
		struct sort_dimension *sd = &sort_dimensions[i];

		if (sd->taken)
			continue;

		if (strncasecmp(tok, sd->name, strlen(tok)))
			continue;

283
		if (sd->entry->se_collapse)
284 285 286 287 288 289 290 291
			sort__need_collapse = 1;

		if (sd->entry == &sort_parent) {
			int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
			if (ret) {
				char err[BUFSIZ];

				regerror(ret, &parent_regex, err, sizeof(err));
292 293
				pr_err("Invalid regex: %s\n%s", parent_pattern, err);
				return -EINVAL;
294 295 296 297
			}
			sort__has_parent = 1;
		}

298 299 300 301 302 303 304 305 306 307 308
		if (list_empty(&hist_entry__sort_list)) {
			if (!strcmp(sd->name, "pid"))
				sort__first_dimension = SORT_PID;
			else if (!strcmp(sd->name, "comm"))
				sort__first_dimension = SORT_COMM;
			else if (!strcmp(sd->name, "dso"))
				sort__first_dimension = SORT_DSO;
			else if (!strcmp(sd->name, "symbol"))
				sort__first_dimension = SORT_SYM;
			else if (!strcmp(sd->name, "parent"))
				sort__first_dimension = SORT_PARENT;
A
Arun Sharma 已提交
309 310
			else if (!strcmp(sd->name, "cpu"))
				sort__first_dimension = SORT_CPU;
311
		}
312

313 314 315 316 317 318 319 320
		list_add_tail(&sd->entry->list, &hist_entry__sort_list);
		sd->taken = 1;

		return 0;
	}

	return -ESRCH;
}
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335

void setup_sorting(const char * const usagestr[], const struct option *opts)
{
	char *tmp, *tok, *str = strdup(sort_order);

	for (tok = strtok_r(str, ", ", &tmp);
			tok; tok = strtok_r(NULL, ", ", &tmp)) {
		if (sort_dimension__add(tok) < 0) {
			error("Unknown --sort key: `%s'", tok);
			usage_with_options(usagestr, opts);
		}
	}

	free(str);
}
336 337 338 339 340 341 342 343 344 345 346

void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
			     const char *list_name, FILE *fp)
{
	if (list && strlist__nr_entries(list) == 1) {
		if (fp != NULL)
			fprintf(fp, "# %s: %s\n", list_name,
				strlist__entry(list, 0)->s);
		self->elide = true;
	}
}