xref: /openbmc/linux/tools/tracing/rtla/src/trace.c (revision b5aa0be25c27a7f21d9a28f0e0057915552d3c1b)
1b1696371SDaniel Bristot de Oliveira // SPDX-License-Identifier: GPL-2.0
2b1696371SDaniel Bristot de Oliveira #define _GNU_SOURCE
3b1696371SDaniel Bristot de Oliveira #include <sys/sendfile.h>
4b1696371SDaniel Bristot de Oliveira #include <tracefs.h>
5b1696371SDaniel Bristot de Oliveira #include <signal.h>
6b1696371SDaniel Bristot de Oliveira #include <stdlib.h>
7b1696371SDaniel Bristot de Oliveira #include <unistd.h>
8b1696371SDaniel Bristot de Oliveira #include <errno.h>
9b1696371SDaniel Bristot de Oliveira 
10b1696371SDaniel Bristot de Oliveira #include "trace.h"
11b1696371SDaniel Bristot de Oliveira #include "utils.h"
12b1696371SDaniel Bristot de Oliveira 
13b1696371SDaniel Bristot de Oliveira /*
14b1696371SDaniel Bristot de Oliveira  * enable_tracer_by_name - enable a tracer on the given instance
15b1696371SDaniel Bristot de Oliveira  */
16b1696371SDaniel Bristot de Oliveira int enable_tracer_by_name(struct tracefs_instance *inst, const char *tracer_name)
17b1696371SDaniel Bristot de Oliveira {
18b1696371SDaniel Bristot de Oliveira 	enum tracefs_tracers tracer;
19b1696371SDaniel Bristot de Oliveira 	int retval;
20b1696371SDaniel Bristot de Oliveira 
21b1696371SDaniel Bristot de Oliveira 	tracer = TRACEFS_TRACER_CUSTOM;
22b1696371SDaniel Bristot de Oliveira 
231a622909SDaniel Bristot de Oliveira 	debug_msg("Enabling %s tracer\n", tracer_name);
24b1696371SDaniel Bristot de Oliveira 
25b1696371SDaniel Bristot de Oliveira 	retval = tracefs_tracer_set(inst, tracer, tracer_name);
26b1696371SDaniel Bristot de Oliveira 	if (retval < 0) {
27b1696371SDaniel Bristot de Oliveira 		if (errno == ENODEV)
281a622909SDaniel Bristot de Oliveira 			err_msg("Tracer %s not found!\n", tracer_name);
29b1696371SDaniel Bristot de Oliveira 
301a622909SDaniel Bristot de Oliveira 		err_msg("Failed to enable the %s tracer\n", tracer_name);
31b1696371SDaniel Bristot de Oliveira 		return -1;
32b1696371SDaniel Bristot de Oliveira 	}
33b1696371SDaniel Bristot de Oliveira 
34b1696371SDaniel Bristot de Oliveira 	return 0;
35b1696371SDaniel Bristot de Oliveira }
36b1696371SDaniel Bristot de Oliveira 
37b1696371SDaniel Bristot de Oliveira /*
38b1696371SDaniel Bristot de Oliveira  * disable_tracer - set nop tracer to the insta
39b1696371SDaniel Bristot de Oliveira  */
40b1696371SDaniel Bristot de Oliveira void disable_tracer(struct tracefs_instance *inst)
41b1696371SDaniel Bristot de Oliveira {
42b1696371SDaniel Bristot de Oliveira 	enum tracefs_tracers t = TRACEFS_TRACER_NOP;
43b1696371SDaniel Bristot de Oliveira 	int retval;
44b1696371SDaniel Bristot de Oliveira 
45b1696371SDaniel Bristot de Oliveira 	retval = tracefs_tracer_set(inst, t);
46b1696371SDaniel Bristot de Oliveira 	if (retval < 0)
471a622909SDaniel Bristot de Oliveira 		err_msg("Oops, error disabling tracer\n");
48b1696371SDaniel Bristot de Oliveira }
49b1696371SDaniel Bristot de Oliveira 
50b1696371SDaniel Bristot de Oliveira /*
51b1696371SDaniel Bristot de Oliveira  * create_instance - create a trace instance with *instance_name
52b1696371SDaniel Bristot de Oliveira  */
53b1696371SDaniel Bristot de Oliveira struct tracefs_instance *create_instance(char *instance_name)
54b1696371SDaniel Bristot de Oliveira {
55b1696371SDaniel Bristot de Oliveira 	return tracefs_instance_create(instance_name);
56b1696371SDaniel Bristot de Oliveira }
57b1696371SDaniel Bristot de Oliveira 
58b1696371SDaniel Bristot de Oliveira /*
59b1696371SDaniel Bristot de Oliveira  * destroy_instance - remove a trace instance and free the data
60b1696371SDaniel Bristot de Oliveira  */
61b1696371SDaniel Bristot de Oliveira void destroy_instance(struct tracefs_instance *inst)
62b1696371SDaniel Bristot de Oliveira {
63b1696371SDaniel Bristot de Oliveira 	tracefs_instance_destroy(inst);
64b1696371SDaniel Bristot de Oliveira 	tracefs_instance_free(inst);
65b1696371SDaniel Bristot de Oliveira }
66b1696371SDaniel Bristot de Oliveira 
67b1696371SDaniel Bristot de Oliveira /*
68b1696371SDaniel Bristot de Oliveira  * save_trace_to_file - save the trace output of the instance to the file
69b1696371SDaniel Bristot de Oliveira  */
70b1696371SDaniel Bristot de Oliveira int save_trace_to_file(struct tracefs_instance *inst, const char *filename)
71b1696371SDaniel Bristot de Oliveira {
72b1696371SDaniel Bristot de Oliveira 	const char *file = "trace";
73b1696371SDaniel Bristot de Oliveira 	mode_t mode = 0644;
74b1696371SDaniel Bristot de Oliveira 	char buffer[4096];
75b1696371SDaniel Bristot de Oliveira 	int out_fd, in_fd;
76b1696371SDaniel Bristot de Oliveira 	int retval = -1;
77b1696371SDaniel Bristot de Oliveira 
78b1696371SDaniel Bristot de Oliveira 	in_fd = tracefs_instance_file_open(inst, file, O_RDONLY);
79b1696371SDaniel Bristot de Oliveira 	if (in_fd < 0) {
80b1696371SDaniel Bristot de Oliveira 		err_msg("Failed to open trace file\n");
81b1696371SDaniel Bristot de Oliveira 		return -1;
82b1696371SDaniel Bristot de Oliveira 	}
83b1696371SDaniel Bristot de Oliveira 
84b1696371SDaniel Bristot de Oliveira 	out_fd = creat(filename, mode);
85b1696371SDaniel Bristot de Oliveira 	if (out_fd < 0) {
86b1696371SDaniel Bristot de Oliveira 		err_msg("Failed to create output file %s\n", filename);
87b1696371SDaniel Bristot de Oliveira 		goto out_close_in;
88b1696371SDaniel Bristot de Oliveira 	}
89b1696371SDaniel Bristot de Oliveira 
90b1696371SDaniel Bristot de Oliveira 	do {
91b1696371SDaniel Bristot de Oliveira 		retval = read(in_fd, buffer, sizeof(buffer));
92b1696371SDaniel Bristot de Oliveira 		if (retval <= 0)
93b1696371SDaniel Bristot de Oliveira 			goto out_close;
94b1696371SDaniel Bristot de Oliveira 
95b1696371SDaniel Bristot de Oliveira 		retval = write(out_fd, buffer, retval);
96b1696371SDaniel Bristot de Oliveira 		if (retval < 0)
97b1696371SDaniel Bristot de Oliveira 			goto out_close;
98b1696371SDaniel Bristot de Oliveira 	} while (retval > 0);
99b1696371SDaniel Bristot de Oliveira 
100b1696371SDaniel Bristot de Oliveira 	retval = 0;
101b1696371SDaniel Bristot de Oliveira out_close:
102b1696371SDaniel Bristot de Oliveira 	close(out_fd);
103b1696371SDaniel Bristot de Oliveira out_close_in:
104b1696371SDaniel Bristot de Oliveira 	close(in_fd);
105b1696371SDaniel Bristot de Oliveira 	return retval;
106b1696371SDaniel Bristot de Oliveira }
107b1696371SDaniel Bristot de Oliveira 
108b1696371SDaniel Bristot de Oliveira /*
109b1696371SDaniel Bristot de Oliveira  * collect_registered_events - call the existing callback function for the event
110b1696371SDaniel Bristot de Oliveira  *
111b1696371SDaniel Bristot de Oliveira  * If an event has a registered callback function, call it.
112b1696371SDaniel Bristot de Oliveira  * Otherwise, ignore the event.
113b1696371SDaniel Bristot de Oliveira  */
114b1696371SDaniel Bristot de Oliveira int
115b1696371SDaniel Bristot de Oliveira collect_registered_events(struct tep_event *event, struct tep_record *record,
116b1696371SDaniel Bristot de Oliveira 			  int cpu, void *context)
117b1696371SDaniel Bristot de Oliveira {
118b1696371SDaniel Bristot de Oliveira 	struct trace_instance *trace = context;
119b1696371SDaniel Bristot de Oliveira 	struct trace_seq *s = trace->seq;
120b1696371SDaniel Bristot de Oliveira 
121b1696371SDaniel Bristot de Oliveira 	if (!event->handler)
122b1696371SDaniel Bristot de Oliveira 		return 0;
123b1696371SDaniel Bristot de Oliveira 
124b1696371SDaniel Bristot de Oliveira 	event->handler(s, record, event, context);
125b1696371SDaniel Bristot de Oliveira 
126b1696371SDaniel Bristot de Oliveira 	return 0;
127b1696371SDaniel Bristot de Oliveira }
128b1696371SDaniel Bristot de Oliveira 
129b1696371SDaniel Bristot de Oliveira /*
130b1696371SDaniel Bristot de Oliveira  * trace_instance_destroy - destroy and free a rtla trace instance
131b1696371SDaniel Bristot de Oliveira  */
132b1696371SDaniel Bristot de Oliveira void trace_instance_destroy(struct trace_instance *trace)
133b1696371SDaniel Bristot de Oliveira {
134b1696371SDaniel Bristot de Oliveira 	if (trace->inst) {
135b1696371SDaniel Bristot de Oliveira 		disable_tracer(trace->inst);
136b1696371SDaniel Bristot de Oliveira 		destroy_instance(trace->inst);
137b1696371SDaniel Bristot de Oliveira 	}
138b1696371SDaniel Bristot de Oliveira 
139b1696371SDaniel Bristot de Oliveira 	if (trace->seq)
140b1696371SDaniel Bristot de Oliveira 		free(trace->seq);
141b1696371SDaniel Bristot de Oliveira 
142b1696371SDaniel Bristot de Oliveira 	if (trace->tep)
143b1696371SDaniel Bristot de Oliveira 		tep_free(trace->tep);
144b1696371SDaniel Bristot de Oliveira }
145b1696371SDaniel Bristot de Oliveira 
146b1696371SDaniel Bristot de Oliveira /*
147b1696371SDaniel Bristot de Oliveira  * trace_instance_init - create an rtla trace instance
148b1696371SDaniel Bristot de Oliveira  *
149b1696371SDaniel Bristot de Oliveira  * It is more than the tracefs instance, as it contains other
150b1696371SDaniel Bristot de Oliveira  * things required for the tracing, such as the local events and
151b1696371SDaniel Bristot de Oliveira  * a seq file.
152b1696371SDaniel Bristot de Oliveira  *
153b1696371SDaniel Bristot de Oliveira  * Note that the trace instance is returned disabled. This allows
154b1696371SDaniel Bristot de Oliveira  * the tool to apply some other configs, like setting priority
155b1696371SDaniel Bristot de Oliveira  * to the kernel threads, before starting generating trace entries.
156b1696371SDaniel Bristot de Oliveira  */
157b1696371SDaniel Bristot de Oliveira int trace_instance_init(struct trace_instance *trace, char *tool_name)
158b1696371SDaniel Bristot de Oliveira {
159b1696371SDaniel Bristot de Oliveira 	trace->seq = calloc(1, sizeof(*trace->seq));
160b1696371SDaniel Bristot de Oliveira 	if (!trace->seq)
161b1696371SDaniel Bristot de Oliveira 		goto out_err;
162b1696371SDaniel Bristot de Oliveira 
163b1696371SDaniel Bristot de Oliveira 	trace_seq_init(trace->seq);
164b1696371SDaniel Bristot de Oliveira 
165b1696371SDaniel Bristot de Oliveira 	trace->inst = create_instance(tool_name);
166b1696371SDaniel Bristot de Oliveira 	if (!trace->inst)
167b1696371SDaniel Bristot de Oliveira 		goto out_err;
168b1696371SDaniel Bristot de Oliveira 
169b1696371SDaniel Bristot de Oliveira 	trace->tep = tracefs_local_events(NULL);
170b1696371SDaniel Bristot de Oliveira 	if (!trace->tep)
171b1696371SDaniel Bristot de Oliveira 		goto out_err;
172b1696371SDaniel Bristot de Oliveira 
173b1696371SDaniel Bristot de Oliveira 	/*
174b1696371SDaniel Bristot de Oliveira 	 * Let the main enable the record after setting some other
175b1696371SDaniel Bristot de Oliveira 	 * things such as the priority of the tracer's threads.
176b1696371SDaniel Bristot de Oliveira 	 */
177b1696371SDaniel Bristot de Oliveira 	tracefs_trace_off(trace->inst);
178b1696371SDaniel Bristot de Oliveira 
179b1696371SDaniel Bristot de Oliveira 	return 0;
180b1696371SDaniel Bristot de Oliveira 
181b1696371SDaniel Bristot de Oliveira out_err:
182b1696371SDaniel Bristot de Oliveira 	trace_instance_destroy(trace);
183b1696371SDaniel Bristot de Oliveira 	return 1;
184b1696371SDaniel Bristot de Oliveira }
185b1696371SDaniel Bristot de Oliveira 
186b1696371SDaniel Bristot de Oliveira /*
187b1696371SDaniel Bristot de Oliveira  * trace_instance_start - start tracing a given rtla instance
188b1696371SDaniel Bristot de Oliveira  */
189b1696371SDaniel Bristot de Oliveira int trace_instance_start(struct trace_instance *trace)
190b1696371SDaniel Bristot de Oliveira {
191b1696371SDaniel Bristot de Oliveira 	return tracefs_trace_on(trace->inst);
192b1696371SDaniel Bristot de Oliveira }
193*b5aa0be2SDaniel Bristot de Oliveira 
194*b5aa0be2SDaniel Bristot de Oliveira /*
195*b5aa0be2SDaniel Bristot de Oliveira  * trace_events_free - free a list of trace events
196*b5aa0be2SDaniel Bristot de Oliveira  */
197*b5aa0be2SDaniel Bristot de Oliveira static void trace_events_free(struct trace_events *events)
198*b5aa0be2SDaniel Bristot de Oliveira {
199*b5aa0be2SDaniel Bristot de Oliveira 	struct trace_events *tevent = events;
200*b5aa0be2SDaniel Bristot de Oliveira 	struct trace_events *free_event;
201*b5aa0be2SDaniel Bristot de Oliveira 
202*b5aa0be2SDaniel Bristot de Oliveira 	while (tevent) {
203*b5aa0be2SDaniel Bristot de Oliveira 		free_event = tevent;
204*b5aa0be2SDaniel Bristot de Oliveira 
205*b5aa0be2SDaniel Bristot de Oliveira 		tevent = tevent->next;
206*b5aa0be2SDaniel Bristot de Oliveira 
207*b5aa0be2SDaniel Bristot de Oliveira 		free(free_event->system);
208*b5aa0be2SDaniel Bristot de Oliveira 		free(free_event);
209*b5aa0be2SDaniel Bristot de Oliveira 	}
210*b5aa0be2SDaniel Bristot de Oliveira }
211*b5aa0be2SDaniel Bristot de Oliveira 
212*b5aa0be2SDaniel Bristot de Oliveira /*
213*b5aa0be2SDaniel Bristot de Oliveira  * trace_event_alloc - alloc and parse a single trace event
214*b5aa0be2SDaniel Bristot de Oliveira  */
215*b5aa0be2SDaniel Bristot de Oliveira struct trace_events *trace_event_alloc(const char *event_string)
216*b5aa0be2SDaniel Bristot de Oliveira {
217*b5aa0be2SDaniel Bristot de Oliveira 	struct trace_events *tevent;
218*b5aa0be2SDaniel Bristot de Oliveira 
219*b5aa0be2SDaniel Bristot de Oliveira 	tevent = calloc(1, sizeof(*tevent));
220*b5aa0be2SDaniel Bristot de Oliveira 	if (!tevent)
221*b5aa0be2SDaniel Bristot de Oliveira 		return NULL;
222*b5aa0be2SDaniel Bristot de Oliveira 
223*b5aa0be2SDaniel Bristot de Oliveira 	tevent->system = strdup(event_string);
224*b5aa0be2SDaniel Bristot de Oliveira 	if (!tevent->system) {
225*b5aa0be2SDaniel Bristot de Oliveira 		free(tevent);
226*b5aa0be2SDaniel Bristot de Oliveira 		return NULL;
227*b5aa0be2SDaniel Bristot de Oliveira 	}
228*b5aa0be2SDaniel Bristot de Oliveira 
229*b5aa0be2SDaniel Bristot de Oliveira 	tevent->event = strstr(tevent->system, ":");
230*b5aa0be2SDaniel Bristot de Oliveira 	if (tevent->event) {
231*b5aa0be2SDaniel Bristot de Oliveira 		*tevent->event = '\0';
232*b5aa0be2SDaniel Bristot de Oliveira 		tevent->event = &tevent->event[1];
233*b5aa0be2SDaniel Bristot de Oliveira 	}
234*b5aa0be2SDaniel Bristot de Oliveira 
235*b5aa0be2SDaniel Bristot de Oliveira 	return tevent;
236*b5aa0be2SDaniel Bristot de Oliveira }
237*b5aa0be2SDaniel Bristot de Oliveira 
238*b5aa0be2SDaniel Bristot de Oliveira /*
239*b5aa0be2SDaniel Bristot de Oliveira  * trace_events_disable - disable all trace events
240*b5aa0be2SDaniel Bristot de Oliveira  */
241*b5aa0be2SDaniel Bristot de Oliveira void trace_events_disable(struct trace_instance *instance,
242*b5aa0be2SDaniel Bristot de Oliveira 			  struct trace_events *events)
243*b5aa0be2SDaniel Bristot de Oliveira {
244*b5aa0be2SDaniel Bristot de Oliveira 	struct trace_events *tevent = events;
245*b5aa0be2SDaniel Bristot de Oliveira 
246*b5aa0be2SDaniel Bristot de Oliveira 	if (!events)
247*b5aa0be2SDaniel Bristot de Oliveira 		return;
248*b5aa0be2SDaniel Bristot de Oliveira 
249*b5aa0be2SDaniel Bristot de Oliveira 	while (tevent) {
250*b5aa0be2SDaniel Bristot de Oliveira 		debug_msg("Disabling event %s:%s\n", tevent->system, tevent->event ? : "*");
251*b5aa0be2SDaniel Bristot de Oliveira 		if (tevent->enabled)
252*b5aa0be2SDaniel Bristot de Oliveira 			tracefs_event_disable(instance->inst, tevent->system, tevent->event);
253*b5aa0be2SDaniel Bristot de Oliveira 
254*b5aa0be2SDaniel Bristot de Oliveira 		tevent->enabled = 0;
255*b5aa0be2SDaniel Bristot de Oliveira 		tevent = tevent->next;
256*b5aa0be2SDaniel Bristot de Oliveira 	}
257*b5aa0be2SDaniel Bristot de Oliveira }
258*b5aa0be2SDaniel Bristot de Oliveira 
259*b5aa0be2SDaniel Bristot de Oliveira /*
260*b5aa0be2SDaniel Bristot de Oliveira  * trace_events_enable - enable all events
261*b5aa0be2SDaniel Bristot de Oliveira  */
262*b5aa0be2SDaniel Bristot de Oliveira int trace_events_enable(struct trace_instance *instance,
263*b5aa0be2SDaniel Bristot de Oliveira 			struct trace_events *events)
264*b5aa0be2SDaniel Bristot de Oliveira {
265*b5aa0be2SDaniel Bristot de Oliveira 	struct trace_events *tevent = events;
266*b5aa0be2SDaniel Bristot de Oliveira 	int retval;
267*b5aa0be2SDaniel Bristot de Oliveira 
268*b5aa0be2SDaniel Bristot de Oliveira 	while (tevent) {
269*b5aa0be2SDaniel Bristot de Oliveira 		debug_msg("Enabling event %s:%s\n", tevent->system, tevent->event ? : "*");
270*b5aa0be2SDaniel Bristot de Oliveira 		retval = tracefs_event_enable(instance->inst, tevent->system, tevent->event);
271*b5aa0be2SDaniel Bristot de Oliveira 		if (retval < 0) {
272*b5aa0be2SDaniel Bristot de Oliveira 			err_msg("Error enabling event %s:%s\n", tevent->system,
273*b5aa0be2SDaniel Bristot de Oliveira 				tevent->event ? : "*");
274*b5aa0be2SDaniel Bristot de Oliveira 			return 1;
275*b5aa0be2SDaniel Bristot de Oliveira 		}
276*b5aa0be2SDaniel Bristot de Oliveira 
277*b5aa0be2SDaniel Bristot de Oliveira 
278*b5aa0be2SDaniel Bristot de Oliveira 		tevent->enabled = 1;
279*b5aa0be2SDaniel Bristot de Oliveira 		tevent = tevent->next;
280*b5aa0be2SDaniel Bristot de Oliveira 	}
281*b5aa0be2SDaniel Bristot de Oliveira 
282*b5aa0be2SDaniel Bristot de Oliveira 	return 0;
283*b5aa0be2SDaniel Bristot de Oliveira }
284*b5aa0be2SDaniel Bristot de Oliveira 
285*b5aa0be2SDaniel Bristot de Oliveira /*
286*b5aa0be2SDaniel Bristot de Oliveira  * trace_events_destroy - disable and free all trace events
287*b5aa0be2SDaniel Bristot de Oliveira  */
288*b5aa0be2SDaniel Bristot de Oliveira void trace_events_destroy(struct trace_instance *instance,
289*b5aa0be2SDaniel Bristot de Oliveira 			  struct trace_events *events)
290*b5aa0be2SDaniel Bristot de Oliveira {
291*b5aa0be2SDaniel Bristot de Oliveira 	if (!events)
292*b5aa0be2SDaniel Bristot de Oliveira 		return;
293*b5aa0be2SDaniel Bristot de Oliveira 
294*b5aa0be2SDaniel Bristot de Oliveira 	trace_events_disable(instance, events);
295*b5aa0be2SDaniel Bristot de Oliveira 	trace_events_free(events);
296*b5aa0be2SDaniel Bristot de Oliveira }
297