xref: /linux/tools/tracing/rtla/src/trace.c (revision 5c8166419acf468b5bc3e48f928a040485d3e0c2)
1 // SPDX-License-Identifier: GPL-2.0
2 #define _GNU_SOURCE
3 #include <sys/sendfile.h>
4 #include <tracefs.h>
5 #include <signal.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <errno.h>
9 
10 #include "trace.h"
11 #include "utils.h"
12 
13 /*
14  * enable_tracer_by_name - enable a tracer on the given instance
15  */
16 int enable_tracer_by_name(struct tracefs_instance *inst, const char *tracer_name)
17 {
18 	enum tracefs_tracers tracer;
19 	int retval;
20 
21 	tracer = TRACEFS_TRACER_CUSTOM;
22 
23 	debug_msg("Enabling %s tracer\n", tracer_name);
24 
25 	retval = tracefs_tracer_set(inst, tracer, tracer_name);
26 	if (retval < 0) {
27 		if (errno == ENODEV)
28 			err_msg("Tracer %s not found!\n", tracer_name);
29 
30 		err_msg("Failed to enable the %s tracer\n", tracer_name);
31 		return -1;
32 	}
33 
34 	return 0;
35 }
36 
37 /*
38  * disable_tracer - set nop tracer to the insta
39  */
40 void disable_tracer(struct tracefs_instance *inst)
41 {
42 	enum tracefs_tracers t = TRACEFS_TRACER_NOP;
43 	int retval;
44 
45 	retval = tracefs_tracer_set(inst, t);
46 	if (retval < 0)
47 		err_msg("Oops, error disabling tracer\n");
48 }
49 
50 /*
51  * create_instance - create a trace instance with *instance_name
52  */
53 struct tracefs_instance *create_instance(char *instance_name)
54 {
55 	return tracefs_instance_create(instance_name);
56 }
57 
58 /*
59  * destroy_instance - remove a trace instance and free the data
60  */
61 void destroy_instance(struct tracefs_instance *inst)
62 {
63 	tracefs_instance_destroy(inst);
64 	tracefs_instance_free(inst);
65 }
66 
67 /*
68  * save_trace_to_file - save the trace output of the instance to the file
69  */
70 int save_trace_to_file(struct tracefs_instance *inst, const char *filename)
71 {
72 	const char *file = "trace";
73 	mode_t mode = 0644;
74 	char buffer[4096];
75 	int out_fd, in_fd;
76 	int retval = -1;
77 
78 	in_fd = tracefs_instance_file_open(inst, file, O_RDONLY);
79 	if (in_fd < 0) {
80 		err_msg("Failed to open trace file\n");
81 		return -1;
82 	}
83 
84 	out_fd = creat(filename, mode);
85 	if (out_fd < 0) {
86 		err_msg("Failed to create output file %s\n", filename);
87 		goto out_close_in;
88 	}
89 
90 	do {
91 		retval = read(in_fd, buffer, sizeof(buffer));
92 		if (retval <= 0)
93 			goto out_close;
94 
95 		retval = write(out_fd, buffer, retval);
96 		if (retval < 0)
97 			goto out_close;
98 	} while (retval > 0);
99 
100 	retval = 0;
101 out_close:
102 	close(out_fd);
103 out_close_in:
104 	close(in_fd);
105 	return retval;
106 }
107 
108 /*
109  * collect_registered_events - call the existing callback function for the event
110  *
111  * If an event has a registered callback function, call it.
112  * Otherwise, ignore the event.
113  */
114 int
115 collect_registered_events(struct tep_event *event, struct tep_record *record,
116 			  int cpu, void *context)
117 {
118 	struct trace_instance *trace = context;
119 	struct trace_seq *s = trace->seq;
120 
121 	if (!event->handler)
122 		return 0;
123 
124 	event->handler(s, record, event, context);
125 
126 	return 0;
127 }
128 
129 /*
130  * trace_instance_destroy - destroy and free a rtla trace instance
131  */
132 void trace_instance_destroy(struct trace_instance *trace)
133 {
134 	if (trace->inst) {
135 		disable_tracer(trace->inst);
136 		destroy_instance(trace->inst);
137 	}
138 
139 	if (trace->seq)
140 		free(trace->seq);
141 
142 	if (trace->tep)
143 		tep_free(trace->tep);
144 }
145 
146 /*
147  * trace_instance_init - create an rtla trace instance
148  *
149  * It is more than the tracefs instance, as it contains other
150  * things required for the tracing, such as the local events and
151  * a seq file.
152  *
153  * Note that the trace instance is returned disabled. This allows
154  * the tool to apply some other configs, like setting priority
155  * to the kernel threads, before starting generating trace entries.
156  */
157 int trace_instance_init(struct trace_instance *trace, char *tool_name)
158 {
159 	trace->seq = calloc(1, sizeof(*trace->seq));
160 	if (!trace->seq)
161 		goto out_err;
162 
163 	trace_seq_init(trace->seq);
164 
165 	trace->inst = create_instance(tool_name);
166 	if (!trace->inst)
167 		goto out_err;
168 
169 	trace->tep = tracefs_local_events(NULL);
170 	if (!trace->tep)
171 		goto out_err;
172 
173 	/*
174 	 * Let the main enable the record after setting some other
175 	 * things such as the priority of the tracer's threads.
176 	 */
177 	tracefs_trace_off(trace->inst);
178 
179 	return 0;
180 
181 out_err:
182 	trace_instance_destroy(trace);
183 	return 1;
184 }
185 
186 /*
187  * trace_instance_start - start tracing a given rtla instance
188  */
189 int trace_instance_start(struct trace_instance *trace)
190 {
191 	return tracefs_trace_on(trace->inst);
192 }
193