xref: /linux/tools/tracing/rtla/src/trace.c (revision f79720e25b793691dcc46e1f1cd64d01578075c2)
1 // SPDX-License-Identifier: GPL-2.0
2 #define _GNU_SOURCE
3 #include <sys/sendfile.h>
4 #include <tracefs.h>
5 #include <stdlib.h>
6 #include <unistd.h>
7 #include <errno.h>
8 
9 #include "trace.h"
10 #include "utils.h"
11 
12 /*
13  * enable_tracer_by_name - enable a tracer on the given instance
14  */
15 int enable_tracer_by_name(struct tracefs_instance *inst, const char *tracer_name)
16 {
17 	enum tracefs_tracers tracer;
18 	int retval;
19 
20 	tracer = TRACEFS_TRACER_CUSTOM;
21 
22 	debug_msg("Enabling %s tracer\n", tracer_name);
23 
24 	retval = tracefs_tracer_set(inst, tracer, tracer_name);
25 	if (retval < 0) {
26 		if (errno == ENODEV)
27 			err_msg("Tracer %s not found!\n", tracer_name);
28 
29 		err_msg("Failed to enable the %s tracer\n", tracer_name);
30 		return -1;
31 	}
32 
33 	return 0;
34 }
35 
36 /*
37  * disable_tracer - set nop tracer to the insta
38  */
39 void disable_tracer(struct tracefs_instance *inst)
40 {
41 	enum tracefs_tracers t = TRACEFS_TRACER_NOP;
42 	int retval;
43 
44 	retval = tracefs_tracer_set(inst, t);
45 	if (retval < 0)
46 		err_msg("Oops, error disabling tracer\n");
47 }
48 
49 /*
50  * create_instance - create a trace instance with *instance_name
51  */
52 struct tracefs_instance *create_instance(char *instance_name)
53 {
54 	return tracefs_instance_create(instance_name);
55 }
56 
57 /*
58  * destroy_instance - remove a trace instance and free the data
59  */
60 void destroy_instance(struct tracefs_instance *inst)
61 {
62 	tracefs_instance_destroy(inst);
63 	tracefs_instance_free(inst);
64 }
65 
66 /*
67  * save_trace_to_file - save the trace output of the instance to the file
68  */
69 int save_trace_to_file(struct tracefs_instance *inst, const char *filename)
70 {
71 	const char *file = "trace";
72 	mode_t mode = 0644;
73 	char buffer[4096];
74 	int out_fd, in_fd;
75 	int retval = -1;
76 
77 	if (!inst || !filename)
78 		return 0;
79 
80 	in_fd = tracefs_instance_file_open(inst, file, O_RDONLY);
81 	if (in_fd < 0) {
82 		err_msg("Failed to open trace file\n");
83 		return -1;
84 	}
85 
86 	printf("  Saving trace to %s\n", filename);
87 	out_fd = creat(filename, mode);
88 	if (out_fd < 0) {
89 		err_msg("Failed to create output file %s\n", filename);
90 		goto out_close_in;
91 	}
92 
93 	do {
94 		retval = read(in_fd, buffer, sizeof(buffer));
95 		if (retval <= 0)
96 			goto out_close;
97 
98 		retval = write(out_fd, buffer, retval);
99 		if (retval < 0)
100 			goto out_close;
101 	} while (retval > 0);
102 
103 	retval = 0;
104 out_close:
105 	close(out_fd);
106 out_close_in:
107 	close(in_fd);
108 	return retval;
109 }
110 
111 /*
112  * collect_registered_events - call the existing callback function for the event
113  *
114  * If an event has a registered callback function, call it.
115  * Otherwise, ignore the event.
116  */
117 int
118 collect_registered_events(struct tep_event *event, struct tep_record *record,
119 			  int cpu, void *context)
120 {
121 	struct trace_instance *trace = context;
122 	struct trace_seq *s = trace->seq;
123 
124 	trace->processed_events++;
125 
126 	if (!event->handler)
127 		return 0;
128 
129 	event->handler(s, record, event, context);
130 
131 	return 0;
132 }
133 
134 /*
135  * collect_missed_events - record number of missed events
136  *
137  * If rtla cannot keep up with events generated by tracer, events are going
138  * to fall out of the ring buffer.
139  * Collect how many events were missed so it can be reported to the user.
140  */
141 static int
142 collect_missed_events(struct tep_event *event, struct tep_record *record,
143 		      int cpu, void *context)
144 {
145 	struct trace_instance *trace = context;
146 
147 	if (trace->missed_events == UINT64_MAX)
148 		return 0;
149 
150 	if (record->missed_events > 0)
151 		trace->missed_events += record->missed_events;
152 	else
153 		/* Events missed but no data on how many */
154 		trace->missed_events = UINT64_MAX;
155 
156 	return 0;
157 }
158 
159 /*
160  * trace_instance_destroy - destroy and free a rtla trace instance
161  */
162 void trace_instance_destroy(struct trace_instance *trace)
163 {
164 	if (trace->inst) {
165 		disable_tracer(trace->inst);
166 		destroy_instance(trace->inst);
167 		trace->inst = NULL;
168 	}
169 
170 	if (trace->seq) {
171 		free(trace->seq);
172 		trace->seq = NULL;
173 	}
174 
175 	if (trace->tep) {
176 		tep_free(trace->tep);
177 		trace->tep = NULL;
178 	}
179 }
180 
181 /*
182  * trace_instance_init - create an rtla trace instance
183  *
184  * It is more than the tracefs instance, as it contains other
185  * things required for the tracing, such as the local events and
186  * a seq file.
187  *
188  * Note that the trace instance is returned disabled. This allows
189  * the tool to apply some other configs, like setting priority
190  * to the kernel threads, before starting generating trace entries.
191  */
192 int trace_instance_init(struct trace_instance *trace, char *tool_name)
193 {
194 	trace->seq = calloc_fatal(1, sizeof(*trace->seq));
195 
196 	trace_seq_init(trace->seq);
197 
198 	trace->inst = create_instance(tool_name);
199 	if (!trace->inst)
200 		goto out_err;
201 
202 	trace->tep = tracefs_local_events(NULL);
203 	if (!trace->tep)
204 		goto out_err;
205 
206 	/*
207 	 * Let the main enable the record after setting some other
208 	 * things such as the priority of the tracer's threads.
209 	 */
210 	tracefs_trace_off(trace->inst);
211 
212 	/*
213 	 * Collect the number of events missed due to tracefs buffer
214 	 * overflow.
215 	 */
216 	trace->missed_events = 0;
217 	tracefs_follow_missed_events(trace->inst,
218 				     collect_missed_events,
219 				     trace);
220 
221 	trace->processed_events = 0;
222 
223 	return 0;
224 
225 out_err:
226 	trace_instance_destroy(trace);
227 	return 1;
228 }
229 
230 /*
231  * trace_instance_start - start tracing a given rtla instance
232  */
233 int trace_instance_start(struct trace_instance *trace)
234 {
235 	return tracefs_trace_on(trace->inst);
236 }
237 
238 /*
239  * trace_instance_stop - stop tracing a given rtla instance
240  */
241 int trace_instance_stop(struct trace_instance *trace)
242 {
243 	return tracefs_trace_off(trace->inst);
244 }
245 
246 /*
247  * trace_events_free - free a list of trace events
248  */
249 static void trace_events_free(struct trace_events *events)
250 {
251 	struct trace_events *tevent = events;
252 	struct trace_events *free_event;
253 
254 	while (tevent) {
255 		free_event = tevent;
256 
257 		tevent = tevent->next;
258 
259 		if (free_event->filter)
260 			free(free_event->filter);
261 		if (free_event->trigger)
262 			free(free_event->trigger);
263 		free(free_event->system);
264 		free(free_event);
265 	}
266 }
267 
268 /*
269  * trace_event_alloc - alloc and parse a single trace event
270  */
271 struct trace_events *trace_event_alloc(const char *event_string)
272 {
273 	struct trace_events *tevent;
274 
275 	tevent = calloc_fatal(1, sizeof(*tevent));
276 
277 	tevent->system = strdup_fatal(event_string);
278 
279 	tevent->event = strstr(tevent->system, ":");
280 	if (tevent->event) {
281 		*tevent->event = '\0';
282 		tevent->event = &tevent->event[1];
283 	}
284 
285 	return tevent;
286 }
287 
288 /*
289  * trace_event_add_filter - record an event filter
290  */
291 void trace_event_add_filter(struct trace_events *event, char *filter)
292 {
293 	if (event->filter)
294 		free(event->filter);
295 
296 	event->filter = strdup_fatal(filter);
297 }
298 
299 /*
300  * trace_event_add_trigger - record an event trigger action
301  */
302 void trace_event_add_trigger(struct trace_events *event, char *trigger)
303 {
304 	if (event->trigger)
305 		free(event->trigger);
306 
307 	event->trigger = strdup_fatal(trigger);
308 }
309 
310 /*
311  * trace_event_disable_filter - disable an event filter
312  */
313 static void trace_event_disable_filter(struct trace_instance *instance,
314 				       struct trace_events *tevent)
315 {
316 	char filter[MAX_PATH];
317 	int retval;
318 
319 	if (!tevent->filter)
320 		return;
321 
322 	if (!tevent->filter_enabled)
323 		return;
324 
325 	debug_msg("Disabling %s:%s filter %s\n", tevent->system,
326 		  tevent->event ? : "*", tevent->filter);
327 
328 	snprintf(filter, ARRAY_SIZE(filter), "!%s\n", tevent->filter);
329 
330 	retval = tracefs_event_file_write(instance->inst, tevent->system,
331 					  tevent->event, "filter", filter);
332 	if (retval < 0)
333 		err_msg("Error disabling %s:%s filter %s\n", tevent->system,
334 			tevent->event ? : "*", tevent->filter);
335 }
336 
337 /*
338  * trace_event_save_hist - save the content of an event hist
339  *
340  * If the trigger is a hist: one, save the content of the hist file.
341  */
342 static void trace_event_save_hist(struct trace_instance *instance,
343 				  struct trace_events *tevent)
344 {
345 	int retval, index, out_fd;
346 	mode_t mode = 0644;
347 	char path[MAX_PATH];
348 	char *hist;
349 	size_t hist_len;
350 
351 	if (!tevent)
352 		return;
353 
354 	/* trigger enables hist */
355 	if (!tevent->trigger)
356 		return;
357 
358 	/* is this a hist: trigger? */
359 	retval = strncmp(tevent->trigger, "hist:", strlen("hist:"));
360 	if (retval)
361 		return;
362 
363 	snprintf(path, ARRAY_SIZE(path), "%s_%s_hist.txt", tevent->system, tevent->event);
364 
365 	printf("  Saving event %s:%s hist to %s\n", tevent->system, tevent->event, path);
366 
367 	out_fd = creat(path, mode);
368 	if (out_fd < 0) {
369 		err_msg("  Failed to create %s output file\n", path);
370 		return;
371 	}
372 
373 	hist = tracefs_event_file_read(instance->inst, tevent->system, tevent->event, "hist", 0);
374 	if (!hist) {
375 		err_msg("  Failed to read %s:%s hist file\n", tevent->system, tevent->event);
376 		goto out_close;
377 	}
378 
379 	index = 0;
380 	hist_len = strlen(hist);
381 	do {
382 		index += write(out_fd, &hist[index], hist_len - index);
383 	} while (index < hist_len);
384 
385 	free(hist);
386 out_close:
387 	close(out_fd);
388 }
389 
390 /*
391  * trace_event_disable_trigger - disable an event trigger
392  */
393 static void trace_event_disable_trigger(struct trace_instance *instance,
394 					struct trace_events *tevent)
395 {
396 	char trigger[MAX_PATH];
397 	int retval;
398 
399 	if (!tevent->trigger)
400 		return;
401 
402 	if (!tevent->trigger_enabled)
403 		return;
404 
405 	debug_msg("Disabling %s:%s trigger %s\n", tevent->system,
406 		  tevent->event ? : "*", tevent->trigger);
407 
408 	trace_event_save_hist(instance, tevent);
409 
410 	snprintf(trigger, ARRAY_SIZE(trigger), "!%s\n", tevent->trigger);
411 
412 	retval = tracefs_event_file_write(instance->inst, tevent->system,
413 					  tevent->event, "trigger", trigger);
414 	if (retval < 0)
415 		err_msg("Error disabling %s:%s trigger %s\n", tevent->system,
416 			tevent->event ? : "*", tevent->trigger);
417 }
418 
419 /*
420  * trace_events_disable - disable all trace events
421  */
422 void trace_events_disable(struct trace_instance *instance,
423 			  struct trace_events *events)
424 {
425 	struct trace_events *tevent = events;
426 
427 	if (!events)
428 		return;
429 
430 	while (tevent) {
431 		debug_msg("Disabling event %s:%s\n", tevent->system, tevent->event ? : "*");
432 		if (tevent->enabled) {
433 			trace_event_disable_filter(instance, tevent);
434 			trace_event_disable_trigger(instance, tevent);
435 			tracefs_event_disable(instance->inst, tevent->system, tevent->event);
436 		}
437 
438 		tevent->enabled = 0;
439 		tevent = tevent->next;
440 	}
441 }
442 
443 /*
444  * trace_event_enable_filter - enable an event filter associated with an event
445  */
446 static int trace_event_enable_filter(struct trace_instance *instance,
447 				     struct trace_events *tevent)
448 {
449 	char filter[MAX_PATH];
450 	int retval;
451 
452 	if (!tevent->filter)
453 		return 0;
454 
455 	if (!tevent->event) {
456 		err_msg("Filter %s applies only for single events, not for all %s:* events\n",
457 			tevent->filter, tevent->system);
458 		return 1;
459 	}
460 
461 	snprintf(filter, ARRAY_SIZE(filter), "%s\n", tevent->filter);
462 
463 	debug_msg("Enabling %s:%s filter %s\n", tevent->system,
464 		  tevent->event ? : "*", tevent->filter);
465 
466 	retval = tracefs_event_file_write(instance->inst, tevent->system,
467 					  tevent->event, "filter", filter);
468 	if (retval < 0) {
469 		err_msg("Error enabling %s:%s filter %s\n", tevent->system,
470 			tevent->event ? : "*", tevent->filter);
471 		return 1;
472 	}
473 
474 	tevent->filter_enabled = 1;
475 	return 0;
476 }
477 
478 /*
479  * trace_event_enable_trigger - enable an event trigger associated with an event
480  */
481 static int trace_event_enable_trigger(struct trace_instance *instance,
482 				      struct trace_events *tevent)
483 {
484 	char trigger[MAX_PATH];
485 	int retval;
486 
487 	if (!tevent->trigger)
488 		return 0;
489 
490 	if (!tevent->event) {
491 		err_msg("Trigger %s applies only for single events, not for all %s:* events\n",
492 			tevent->trigger, tevent->system);
493 		return 1;
494 	}
495 
496 	snprintf(trigger, ARRAY_SIZE(trigger), "%s\n", tevent->trigger);
497 
498 	debug_msg("Enabling %s:%s trigger %s\n", tevent->system,
499 		  tevent->event ? : "*", tevent->trigger);
500 
501 	retval = tracefs_event_file_write(instance->inst, tevent->system,
502 					  tevent->event, "trigger", trigger);
503 	if (retval < 0) {
504 		err_msg("Error enabling %s:%s trigger %s\n", tevent->system,
505 			tevent->event ? : "*", tevent->trigger);
506 		return 1;
507 	}
508 
509 	tevent->trigger_enabled = 1;
510 
511 	return 0;
512 }
513 
514 /*
515  * trace_events_enable - enable all events
516  */
517 int trace_events_enable(struct trace_instance *instance,
518 			struct trace_events *events)
519 {
520 	struct trace_events *tevent = events;
521 	int retval;
522 
523 	while (tevent) {
524 		debug_msg("Enabling event %s:%s\n", tevent->system, tevent->event ? : "*");
525 		retval = tracefs_event_enable(instance->inst, tevent->system, tevent->event);
526 		if (retval < 0) {
527 			err_msg("Error enabling event %s:%s\n", tevent->system,
528 				tevent->event ? : "*");
529 			return 1;
530 		}
531 
532 		retval = trace_event_enable_filter(instance, tevent);
533 		if (retval)
534 			return 1;
535 
536 		retval = trace_event_enable_trigger(instance, tevent);
537 		if (retval)
538 			return 1;
539 
540 		tevent->enabled = 1;
541 		tevent = tevent->next;
542 	}
543 
544 	return 0;
545 }
546 
547 /*
548  * trace_events_destroy - disable and free all trace events
549  */
550 void trace_events_destroy(struct trace_instance *instance,
551 			  struct trace_events *events)
552 {
553 	if (!events)
554 		return;
555 
556 	trace_events_disable(instance, events);
557 	trace_events_free(events);
558 }
559 
560 /*
561  * trace_set_buffer_size - set the per-cpu tracing buffer size.
562  */
563 int trace_set_buffer_size(struct trace_instance *trace, int size)
564 {
565 	int retval;
566 
567 	debug_msg("Setting trace buffer size to %d Kb\n", size);
568 	retval = tracefs_instance_set_buffer_size(trace->inst, size, -1);
569 	if (retval)
570 		err_msg("Error setting trace buffer size\n");
571 
572 	return retval;
573 }
574