xref: /openbmc/linux/tools/tracing/rtla/src/trace.c (revision 1a6229096bb501495442ab47761d746c1ae791e1)
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 
23*1a622909SDaniel 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)
28*1a622909SDaniel Bristot de Oliveira 			err_msg("Tracer %s not found!\n", tracer_name);
29b1696371SDaniel Bristot de Oliveira 
30*1a622909SDaniel 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)
47*1a622909SDaniel 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