xref: /openbmc/linux/tools/perf/util/db-export.c (revision 64d85cc9)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * db-export.c: Support for exporting data suitable for import to a database
4  * Copyright (c) 2014, Intel Corporation.
5  */
6 
7 #include <errno.h>
8 
9 #include "evsel.h"
10 #include "machine.h"
11 #include "thread.h"
12 #include "comm.h"
13 #include "symbol.h"
14 #include "map.h"
15 #include "event.h"
16 #include "util.h"
17 #include "thread-stack.h"
18 #include "callchain.h"
19 #include "call-path.h"
20 #include "db-export.h"
21 
22 struct deferred_export {
23 	struct list_head node;
24 	struct comm *comm;
25 };
26 
27 static int db_export__deferred(struct db_export *dbe)
28 {
29 	struct deferred_export *de;
30 	int err;
31 
32 	while (!list_empty(&dbe->deferred)) {
33 		de = list_entry(dbe->deferred.next, struct deferred_export,
34 				node);
35 		err = dbe->export_comm(dbe, de->comm);
36 		list_del(&de->node);
37 		free(de);
38 		if (err)
39 			return err;
40 	}
41 
42 	return 0;
43 }
44 
45 static void db_export__free_deferred(struct db_export *dbe)
46 {
47 	struct deferred_export *de;
48 
49 	while (!list_empty(&dbe->deferred)) {
50 		de = list_entry(dbe->deferred.next, struct deferred_export,
51 				node);
52 		list_del(&de->node);
53 		free(de);
54 	}
55 }
56 
57 static int db_export__defer_comm(struct db_export *dbe, struct comm *comm)
58 {
59 	struct deferred_export *de;
60 
61 	de = zalloc(sizeof(struct deferred_export));
62 	if (!de)
63 		return -ENOMEM;
64 
65 	de->comm = comm;
66 	list_add_tail(&de->node, &dbe->deferred);
67 
68 	return 0;
69 }
70 
71 int db_export__init(struct db_export *dbe)
72 {
73 	memset(dbe, 0, sizeof(struct db_export));
74 	INIT_LIST_HEAD(&dbe->deferred);
75 	return 0;
76 }
77 
78 int db_export__flush(struct db_export *dbe)
79 {
80 	return db_export__deferred(dbe);
81 }
82 
83 void db_export__exit(struct db_export *dbe)
84 {
85 	db_export__free_deferred(dbe);
86 	call_return_processor__free(dbe->crp);
87 	dbe->crp = NULL;
88 }
89 
90 int db_export__evsel(struct db_export *dbe, struct perf_evsel *evsel)
91 {
92 	if (evsel->db_id)
93 		return 0;
94 
95 	evsel->db_id = ++dbe->evsel_last_db_id;
96 
97 	if (dbe->export_evsel)
98 		return dbe->export_evsel(dbe, evsel);
99 
100 	return 0;
101 }
102 
103 int db_export__machine(struct db_export *dbe, struct machine *machine)
104 {
105 	if (machine->db_id)
106 		return 0;
107 
108 	machine->db_id = ++dbe->machine_last_db_id;
109 
110 	if (dbe->export_machine)
111 		return dbe->export_machine(dbe, machine);
112 
113 	return 0;
114 }
115 
116 int db_export__thread(struct db_export *dbe, struct thread *thread,
117 		      struct machine *machine, struct comm *comm)
118 {
119 	struct thread *main_thread;
120 	u64 main_thread_db_id = 0;
121 	int err;
122 
123 	if (thread->db_id)
124 		return 0;
125 
126 	thread->db_id = ++dbe->thread_last_db_id;
127 
128 	if (thread->pid_ != -1) {
129 		if (thread->pid_ == thread->tid) {
130 			main_thread = thread;
131 		} else {
132 			main_thread = machine__findnew_thread(machine,
133 							      thread->pid_,
134 							      thread->pid_);
135 			if (!main_thread)
136 				return -ENOMEM;
137 			err = db_export__thread(dbe, main_thread, machine,
138 						comm);
139 			if (err)
140 				goto out_put;
141 			if (comm) {
142 				err = db_export__comm_thread(dbe, comm, thread);
143 				if (err)
144 					goto out_put;
145 			}
146 		}
147 		main_thread_db_id = main_thread->db_id;
148 		if (main_thread != thread)
149 			thread__put(main_thread);
150 	}
151 
152 	if (dbe->export_thread)
153 		return dbe->export_thread(dbe, thread, main_thread_db_id,
154 					  machine);
155 
156 	return 0;
157 
158 out_put:
159 	thread__put(main_thread);
160 	return err;
161 }
162 
163 int db_export__comm(struct db_export *dbe, struct comm *comm,
164 		    struct thread *main_thread)
165 {
166 	int err;
167 
168 	if (comm->db_id)
169 		return 0;
170 
171 	comm->db_id = ++dbe->comm_last_db_id;
172 
173 	if (dbe->export_comm) {
174 		if (main_thread->comm_set)
175 			err = dbe->export_comm(dbe, comm);
176 		else
177 			err = db_export__defer_comm(dbe, comm);
178 		if (err)
179 			return err;
180 	}
181 
182 	return db_export__comm_thread(dbe, comm, main_thread);
183 }
184 
185 int db_export__comm_thread(struct db_export *dbe, struct comm *comm,
186 			   struct thread *thread)
187 {
188 	u64 db_id;
189 
190 	db_id = ++dbe->comm_thread_last_db_id;
191 
192 	if (dbe->export_comm_thread)
193 		return dbe->export_comm_thread(dbe, db_id, comm, thread);
194 
195 	return 0;
196 }
197 
198 int db_export__dso(struct db_export *dbe, struct dso *dso,
199 		   struct machine *machine)
200 {
201 	if (dso->db_id)
202 		return 0;
203 
204 	dso->db_id = ++dbe->dso_last_db_id;
205 
206 	if (dbe->export_dso)
207 		return dbe->export_dso(dbe, dso, machine);
208 
209 	return 0;
210 }
211 
212 int db_export__symbol(struct db_export *dbe, struct symbol *sym,
213 		      struct dso *dso)
214 {
215 	u64 *sym_db_id = symbol__priv(sym);
216 
217 	if (*sym_db_id)
218 		return 0;
219 
220 	*sym_db_id = ++dbe->symbol_last_db_id;
221 
222 	if (dbe->export_symbol)
223 		return dbe->export_symbol(dbe, sym, dso);
224 
225 	return 0;
226 }
227 
228 static int db_ids_from_al(struct db_export *dbe, struct addr_location *al,
229 			  u64 *dso_db_id, u64 *sym_db_id, u64 *offset)
230 {
231 	int err;
232 
233 	if (al->map) {
234 		struct dso *dso = al->map->dso;
235 
236 		err = db_export__dso(dbe, dso, al->machine);
237 		if (err)
238 			return err;
239 		*dso_db_id = dso->db_id;
240 
241 		if (!al->sym) {
242 			al->sym = symbol__new(al->addr, 0, 0, 0, "unknown");
243 			if (al->sym)
244 				dso__insert_symbol(dso, al->sym);
245 		}
246 
247 		if (al->sym) {
248 			u64 *db_id = symbol__priv(al->sym);
249 
250 			err = db_export__symbol(dbe, al->sym, dso);
251 			if (err)
252 				return err;
253 			*sym_db_id = *db_id;
254 			*offset = al->addr - al->sym->start;
255 		}
256 	}
257 
258 	return 0;
259 }
260 
261 static struct call_path *call_path_from_sample(struct db_export *dbe,
262 					       struct machine *machine,
263 					       struct thread *thread,
264 					       struct perf_sample *sample,
265 					       struct perf_evsel *evsel)
266 {
267 	u64 kernel_start = machine__kernel_start(machine);
268 	struct call_path *current = &dbe->cpr->call_path;
269 	enum chain_order saved_order = callchain_param.order;
270 	int err;
271 
272 	if (!symbol_conf.use_callchain || !sample->callchain)
273 		return NULL;
274 
275 	/*
276 	 * Since the call path tree must be built starting with the root, we
277 	 * must use ORDER_CALL for call chain resolution, in order to process
278 	 * the callchain starting with the root node and ending with the leaf.
279 	 */
280 	callchain_param.order = ORDER_CALLER;
281 	err = thread__resolve_callchain(thread, &callchain_cursor, evsel,
282 					sample, NULL, NULL, PERF_MAX_STACK_DEPTH);
283 	if (err) {
284 		callchain_param.order = saved_order;
285 		return NULL;
286 	}
287 	callchain_cursor_commit(&callchain_cursor);
288 
289 	while (1) {
290 		struct callchain_cursor_node *node;
291 		struct addr_location al;
292 		u64 dso_db_id = 0, sym_db_id = 0, offset = 0;
293 
294 		memset(&al, 0, sizeof(al));
295 
296 		node = callchain_cursor_current(&callchain_cursor);
297 		if (!node)
298 			break;
299 		/*
300 		 * Handle export of symbol and dso for this node by
301 		 * constructing an addr_location struct and then passing it to
302 		 * db_ids_from_al() to perform the export.
303 		 */
304 		al.sym = node->sym;
305 		al.map = node->map;
306 		al.machine = machine;
307 		al.addr = node->ip;
308 
309 		if (al.map && !al.sym)
310 			al.sym = dso__find_symbol(al.map->dso, al.addr);
311 
312 		db_ids_from_al(dbe, &al, &dso_db_id, &sym_db_id, &offset);
313 
314 		/* add node to the call path tree if it doesn't exist */
315 		current = call_path__findnew(dbe->cpr, current,
316 					     al.sym, node->ip,
317 					     kernel_start);
318 
319 		callchain_cursor_advance(&callchain_cursor);
320 	}
321 
322 	/* Reset the callchain order to its prior value. */
323 	callchain_param.order = saved_order;
324 
325 	if (current == &dbe->cpr->call_path) {
326 		/* Bail because the callchain was empty. */
327 		return NULL;
328 	}
329 
330 	return current;
331 }
332 
333 int db_export__branch_type(struct db_export *dbe, u32 branch_type,
334 			   const char *name)
335 {
336 	if (dbe->export_branch_type)
337 		return dbe->export_branch_type(dbe, branch_type, name);
338 
339 	return 0;
340 }
341 
342 int db_export__sample(struct db_export *dbe, union perf_event *event,
343 		      struct perf_sample *sample, struct perf_evsel *evsel,
344 		      struct addr_location *al)
345 {
346 	struct thread* thread = al->thread;
347 	struct export_sample es = {
348 		.event = event,
349 		.sample = sample,
350 		.evsel = evsel,
351 		.al = al,
352 	};
353 	struct thread *main_thread;
354 	struct comm *comm = NULL;
355 	int err;
356 
357 	err = db_export__evsel(dbe, evsel);
358 	if (err)
359 		return err;
360 
361 	err = db_export__machine(dbe, al->machine);
362 	if (err)
363 		return err;
364 
365 	main_thread = thread__main_thread(al->machine, thread);
366 	if (main_thread)
367 		comm = machine__thread_exec_comm(al->machine, main_thread);
368 
369 	err = db_export__thread(dbe, thread, al->machine, comm);
370 	if (err)
371 		goto out_put;
372 
373 	if (comm) {
374 		err = db_export__comm(dbe, comm, main_thread);
375 		if (err)
376 			goto out_put;
377 		es.comm_db_id = comm->db_id;
378 	}
379 
380 	es.db_id = ++dbe->sample_last_db_id;
381 
382 	err = db_ids_from_al(dbe, al, &es.dso_db_id, &es.sym_db_id, &es.offset);
383 	if (err)
384 		goto out_put;
385 
386 	if (dbe->cpr) {
387 		struct call_path *cp = call_path_from_sample(dbe, al->machine,
388 							     thread, sample,
389 							     evsel);
390 		if (cp) {
391 			db_export__call_path(dbe, cp);
392 			es.call_path_id = cp->db_id;
393 		}
394 	}
395 
396 	if ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) &&
397 	    sample_addr_correlates_sym(&evsel->attr)) {
398 		struct addr_location addr_al;
399 
400 		thread__resolve(thread, &addr_al, sample);
401 		err = db_ids_from_al(dbe, &addr_al, &es.addr_dso_db_id,
402 				     &es.addr_sym_db_id, &es.addr_offset);
403 		if (err)
404 			goto out_put;
405 		if (dbe->crp) {
406 			err = thread_stack__process(thread, comm, sample, al,
407 						    &addr_al, es.db_id,
408 						    dbe->crp);
409 			if (err)
410 				goto out_put;
411 		}
412 	}
413 
414 	if (dbe->export_sample)
415 		err = dbe->export_sample(dbe, &es);
416 
417 out_put:
418 	thread__put(main_thread);
419 	return err;
420 }
421 
422 static struct {
423 	u32 branch_type;
424 	const char *name;
425 } branch_types[] = {
426 	{0, "no branch"},
427 	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL, "call"},
428 	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN, "return"},
429 	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL, "conditional jump"},
430 	{PERF_IP_FLAG_BRANCH, "unconditional jump"},
431 	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_INTERRUPT,
432 	 "software interrupt"},
433 	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_INTERRUPT,
434 	 "return from interrupt"},
435 	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_SYSCALLRET,
436 	 "system call"},
437 	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_SYSCALLRET,
438 	 "return from system call"},
439 	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_ASYNC, "asynchronous branch"},
440 	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC |
441 	 PERF_IP_FLAG_INTERRUPT, "hardware interrupt"},
442 	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TX_ABORT, "transaction abort"},
443 	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_BEGIN, "trace begin"},
444 	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_END, "trace end"},
445 	{0, NULL}
446 };
447 
448 int db_export__branch_types(struct db_export *dbe)
449 {
450 	int i, err = 0;
451 
452 	for (i = 0; branch_types[i].name ; i++) {
453 		err = db_export__branch_type(dbe, branch_types[i].branch_type,
454 					     branch_types[i].name);
455 		if (err)
456 			break;
457 	}
458 
459 	/* Add trace begin / end variants */
460 	for (i = 0; branch_types[i].name ; i++) {
461 		const char *name = branch_types[i].name;
462 		u32 type = branch_types[i].branch_type;
463 		char buf[64];
464 
465 		if (type == PERF_IP_FLAG_BRANCH ||
466 		    (type & (PERF_IP_FLAG_TRACE_BEGIN | PERF_IP_FLAG_TRACE_END)))
467 			continue;
468 
469 		snprintf(buf, sizeof(buf), "trace begin / %s", name);
470 		err = db_export__branch_type(dbe, type | PERF_IP_FLAG_TRACE_BEGIN, buf);
471 		if (err)
472 			break;
473 
474 		snprintf(buf, sizeof(buf), "%s / trace end", name);
475 		err = db_export__branch_type(dbe, type | PERF_IP_FLAG_TRACE_END, buf);
476 		if (err)
477 			break;
478 	}
479 
480 	return err;
481 }
482 
483 int db_export__call_path(struct db_export *dbe, struct call_path *cp)
484 {
485 	int err;
486 
487 	if (cp->db_id)
488 		return 0;
489 
490 	if (cp->parent) {
491 		err = db_export__call_path(dbe, cp->parent);
492 		if (err)
493 			return err;
494 	}
495 
496 	cp->db_id = ++dbe->call_path_last_db_id;
497 
498 	if (dbe->export_call_path)
499 		return dbe->export_call_path(dbe, cp);
500 
501 	return 0;
502 }
503 
504 int db_export__call_return(struct db_export *dbe, struct call_return *cr,
505 			   u64 *parent_db_id)
506 {
507 	int err;
508 
509 	err = db_export__call_path(dbe, cr->cp);
510 	if (err)
511 		return err;
512 
513 	if (!cr->db_id)
514 		cr->db_id = ++dbe->call_return_last_db_id;
515 
516 	if (parent_db_id) {
517 		if (!*parent_db_id)
518 			*parent_db_id = ++dbe->call_return_last_db_id;
519 		cr->parent_db_id = *parent_db_id;
520 	}
521 
522 	if (dbe->export_call_return)
523 		return dbe->export_call_return(dbe, cr);
524 
525 	return 0;
526 }
527