xref: /linux/tools/tracing/rtla/src/trace.c (revision 20e92ac8c189049d9f72d60fdf1562a42cc82357)
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 	ssize_t n_read;
77 	ssize_t n_written;
78 
79 	if (!inst || !filename)
80 		return 0;
81 
82 	in_fd = tracefs_instance_file_open(inst, file, O_RDONLY);
83 	if (in_fd < 0) {
84 		err_msg("Failed to open trace file\n");
85 		return -1;
86 	}
87 
88 	printf("  Saving trace to %s\n", filename);
89 	out_fd = creat(filename, mode);
90 	if (out_fd < 0) {
91 		err_msg("Failed to create output file %s\n", filename);
92 		goto out_close_in;
93 	}
94 
95 	for (;;) {
96 		n_read = read(in_fd, buffer, sizeof(buffer));
97 		if (n_read < 0) {
98 			if (errno == EINTR)
99 				continue;
100 			err_msg("Error reading trace file: %s\n", strerror(errno));
101 			goto out_close;
102 		}
103 		if (n_read == 0)
104 			break;
105 
106 		n_written = 0;
107 		while (n_written < n_read) {
108 			const ssize_t w = write(out_fd, buffer + n_written, n_read - n_written);
109 
110 			if (w < 0) {
111 				if (errno == EINTR)
112 					continue;
113 				err_msg("Error writing trace file: %s\n", strerror(errno));
114 				goto out_close;
115 			}
116 			n_written += w;
117 		}
118 	}
119 
120 	retval = 0;
121 out_close:
122 	close(out_fd);
123 out_close_in:
124 	close(in_fd);
125 	return retval;
126 }
127 
128 /*
129  * collect_registered_events - call the existing callback function for the event
130  *
131  * If an event has a registered callback function, call it.
132  * Otherwise, ignore the event.
133  */
134 int
135 collect_registered_events(struct tep_event *event, struct tep_record *record,
136 			  int cpu, void *context)
137 {
138 	struct trace_instance *trace = context;
139 	struct trace_seq *s = trace->seq;
140 
141 	if (cpu >= nr_cpus) {
142 		/* Kernel reports event on CPU we don't see, corrupt data? */
143 		trace->invalid_events++;
144 		return 0;
145 	}
146 
147 	trace->processed_events++;
148 
149 	if (!event->handler)
150 		return 0;
151 
152 	event->handler(s, record, event, context);
153 
154 	return 0;
155 }
156 
157 /*
158  * collect_missed_events - record number of missed events
159  *
160  * If rtla cannot keep up with events generated by tracer, events are going
161  * to fall out of the ring buffer.
162  * Collect how many events were missed so it can be reported to the user.
163  */
164 static int
165 collect_missed_events(struct tep_event *event, struct tep_record *record,
166 		      int cpu, void *context)
167 {
168 	struct trace_instance *trace = context;
169 
170 	if (trace->missed_events == UINT64_MAX)
171 		return 0;
172 
173 	if (record->missed_events > 0)
174 		trace->missed_events += record->missed_events;
175 	else
176 		/* Events missed but no data on how many */
177 		trace->missed_events = UINT64_MAX;
178 
179 	return 0;
180 }
181 
182 /*
183  * trace_instance_destroy - destroy and free a rtla trace instance
184  */
185 void trace_instance_destroy(struct trace_instance *trace)
186 {
187 	if (trace->inst) {
188 		disable_tracer(trace->inst);
189 		destroy_instance(trace->inst);
190 		trace->inst = NULL;
191 	}
192 
193 	if (trace->seq) {
194 		free(trace->seq);
195 		trace->seq = NULL;
196 	}
197 
198 	if (trace->tep) {
199 		tep_free(trace->tep);
200 		trace->tep = NULL;
201 	}
202 }
203 
204 /*
205  * trace_instance_init - create an rtla trace instance
206  *
207  * It is more than the tracefs instance, as it contains other
208  * things required for the tracing, such as the local events and
209  * a seq file.
210  *
211  * Note that the trace instance is returned disabled. This allows
212  * the tool to apply some other configs, like setting priority
213  * to the kernel threads, before starting generating trace entries.
214  */
215 int trace_instance_init(struct trace_instance *trace, char *tool_name)
216 {
217 	trace->seq = calloc_fatal(1, sizeof(*trace->seq));
218 
219 	trace_seq_init(trace->seq);
220 
221 	trace->inst = create_instance(tool_name);
222 	if (!trace->inst)
223 		goto out_err;
224 
225 	trace->tep = tracefs_local_events(NULL);
226 	if (!trace->tep)
227 		goto out_err;
228 
229 	/*
230 	 * Let the main enable the record after setting some other
231 	 * things such as the priority of the tracer's threads.
232 	 */
233 	tracefs_trace_off(trace->inst);
234 
235 	/*
236 	 * Collect the number of events missed due to tracefs buffer
237 	 * overflow.
238 	 */
239 	trace->missed_events = 0;
240 	tracefs_follow_missed_events(trace->inst,
241 				     collect_missed_events,
242 				     trace);
243 
244 	trace->processed_events = 0;
245 	trace->invalid_events = 0;
246 
247 	return 0;
248 
249 out_err:
250 	trace_instance_destroy(trace);
251 	return 1;
252 }
253 
254 /*
255  * trace_instance_start - start tracing a given rtla instance
256  */
257 int trace_instance_start(struct trace_instance *trace)
258 {
259 	return tracefs_trace_on(trace->inst);
260 }
261 
262 /*
263  * trace_instance_stop - stop tracing a given rtla instance
264  */
265 int trace_instance_stop(struct trace_instance *trace)
266 {
267 	return tracefs_trace_off(trace->inst);
268 }
269 
270 /*
271  * trace_events_free - free a list of trace events
272  */
273 static void trace_events_free(struct trace_events *events)
274 {
275 	struct trace_events *tevent = events;
276 	struct trace_events *free_event;
277 
278 	while (tevent) {
279 		free_event = tevent;
280 
281 		tevent = tevent->next;
282 
283 		if (free_event->filter)
284 			free(free_event->filter);
285 		if (free_event->trigger)
286 			free(free_event->trigger);
287 		free(free_event->system);
288 		free(free_event);
289 	}
290 }
291 
292 /*
293  * trace_event_alloc - alloc and parse a single trace event
294  */
295 struct trace_events *trace_event_alloc(const char *event_string)
296 {
297 	struct trace_events *tevent;
298 
299 	tevent = calloc_fatal(1, sizeof(*tevent));
300 
301 	tevent->system = strdup_fatal(event_string);
302 
303 	tevent->event = strstr(tevent->system, ":");
304 	if (tevent->event) {
305 		*tevent->event = '\0';
306 		tevent->event = &tevent->event[1];
307 	}
308 
309 	return tevent;
310 }
311 
312 /*
313  * trace_event_add_filter - record an event filter
314  */
315 void trace_event_add_filter(struct trace_events *event, char *filter)
316 {
317 	if (event->filter)
318 		free(event->filter);
319 
320 	event->filter = strdup_fatal(filter);
321 }
322 
323 /*
324  * trace_event_add_trigger - record an event trigger action
325  */
326 void trace_event_add_trigger(struct trace_events *event, char *trigger)
327 {
328 	if (event->trigger)
329 		free(event->trigger);
330 
331 	event->trigger = strdup_fatal(trigger);
332 }
333 
334 /*
335  * trace_event_disable_filter - disable an event filter
336  */
337 static void trace_event_disable_filter(struct trace_instance *instance,
338 				       struct trace_events *tevent)
339 {
340 	char filter[MAX_PATH];
341 	int retval;
342 
343 	if (!tevent->filter)
344 		return;
345 
346 	if (!tevent->filter_enabled)
347 		return;
348 
349 	debug_msg("Disabling %s:%s filter %s\n", tevent->system,
350 		  tevent->event ? : "*", tevent->filter);
351 
352 	snprintf(filter, ARRAY_SIZE(filter), "!%s\n", tevent->filter);
353 
354 	retval = tracefs_event_file_write(instance->inst, tevent->system,
355 					  tevent->event, "filter", filter);
356 	if (retval < 0)
357 		err_msg("Error disabling %s:%s filter %s\n", tevent->system,
358 			tevent->event ? : "*", tevent->filter);
359 }
360 
361 /*
362  * trace_event_save_hist - save the content of an event hist
363  *
364  * If the trigger is a hist: one, save the content of the hist file.
365  */
366 static void trace_event_save_hist(struct trace_instance *instance,
367 				  struct trace_events *tevent)
368 {
369 	size_t index, hist_len;
370 	mode_t mode = 0644;
371 	char path[MAX_PATH];
372 	char *hist;
373 	int out_fd;
374 
375 	if (!tevent)
376 		return;
377 
378 	/* trigger enables hist */
379 	if (!tevent->trigger)
380 		return;
381 
382 	/* is this a hist: trigger? */
383 	if (!str_has_prefix(tevent->trigger, "hist:"))
384 		return;
385 
386 	snprintf(path, ARRAY_SIZE(path), "%s_%s_hist.txt", tevent->system, tevent->event);
387 
388 	printf("  Saving event %s:%s hist to %s\n", tevent->system, tevent->event, path);
389 
390 	out_fd = creat(path, mode);
391 	if (out_fd < 0) {
392 		err_msg("  Failed to create %s output file\n", path);
393 		return;
394 	}
395 
396 	hist = tracefs_event_file_read(instance->inst, tevent->system, tevent->event, "hist", 0);
397 	if (!hist) {
398 		err_msg("  Failed to read %s:%s hist file\n", tevent->system, tevent->event);
399 		goto out_close;
400 	}
401 
402 	index = 0;
403 	hist_len = strlen(hist);
404 	do {
405 		const ssize_t written = write(out_fd, &hist[index], hist_len - index);
406 
407 		if (written < 0) {
408 			if (errno == EINTR)
409 				continue;
410 			err_msg("  Error writing hist file: %s\n", strerror(errno));
411 			break;
412 		}
413 		index += written;
414 	} while (index < hist_len);
415 
416 	free(hist);
417 out_close:
418 	close(out_fd);
419 }
420 
421 /*
422  * trace_event_disable_trigger - disable an event trigger
423  */
424 static void trace_event_disable_trigger(struct trace_instance *instance,
425 					struct trace_events *tevent)
426 {
427 	char trigger[MAX_PATH];
428 	int retval;
429 
430 	if (!tevent->trigger)
431 		return;
432 
433 	if (!tevent->trigger_enabled)
434 		return;
435 
436 	debug_msg("Disabling %s:%s trigger %s\n", tevent->system,
437 		  tevent->event ? : "*", tevent->trigger);
438 
439 	trace_event_save_hist(instance, tevent);
440 
441 	snprintf(trigger, ARRAY_SIZE(trigger), "!%s\n", tevent->trigger);
442 
443 	retval = tracefs_event_file_write(instance->inst, tevent->system,
444 					  tevent->event, "trigger", trigger);
445 	if (retval < 0)
446 		err_msg("Error disabling %s:%s trigger %s\n", tevent->system,
447 			tevent->event ? : "*", tevent->trigger);
448 }
449 
450 static inline struct trace_events *trace_events_tail(struct trace_events *tevent)
451 {
452 	while (tevent && tevent->next)
453 		tevent = tevent->next;
454 
455 	return tevent;
456 }
457 
458 /*
459  * Events are stashed in LIFO order; flip that to FIFO to process them in the
460  * same order as they are defined by the user on the command line.
461  */
462 #define for_each_trace_event(tevent) \
463 	for (tevent = trace_events_tail(tevent); tevent; tevent = tevent->prev)
464 
465 /*
466  * trace_events_disable - disable all trace events
467  */
468 void trace_events_disable(struct trace_instance *instance,
469 			  struct trace_events *events)
470 {
471 	struct trace_events *tevent = events;
472 
473 	if (!events)
474 		return;
475 
476 	for_each_trace_event(tevent) {
477 		debug_msg("Disabling event %s:%s\n", tevent->system, tevent->event ? : "*");
478 		if (tevent->enabled) {
479 			trace_event_disable_filter(instance, tevent);
480 			trace_event_disable_trigger(instance, tevent);
481 			tracefs_event_disable(instance->inst, tevent->system, tevent->event);
482 		}
483 
484 		tevent->enabled = 0;
485 	}
486 }
487 
488 /*
489  * trace_event_enable_filter - enable an event filter associated with an event
490  */
491 static int trace_event_enable_filter(struct trace_instance *instance,
492 				     struct trace_events *tevent)
493 {
494 	char filter[MAX_PATH];
495 	int retval;
496 
497 	/* Unconditionally clean any pre-existing filters */
498 	tracefs_event_file_write(instance->inst, tevent->system,
499 				 tevent->event, "filter", "0");
500 
501 	if (!tevent->filter)
502 		return 0;
503 
504 	if (!tevent->event) {
505 		err_msg("Filter %s applies only for single events, not for all %s:* events\n",
506 			tevent->filter, tevent->system);
507 		return 1;
508 	}
509 
510 	snprintf(filter, ARRAY_SIZE(filter), "%s\n", tevent->filter);
511 
512 	debug_msg("Enabling %s:%s filter %s\n", tevent->system,
513 		  tevent->event ? : "*", tevent->filter);
514 
515 	retval = tracefs_event_file_write(instance->inst, tevent->system,
516 					  tevent->event, "filter", filter);
517 	if (retval < 0) {
518 		err_msg("Error enabling %s:%s filter %s\n", tevent->system,
519 			tevent->event ? : "*", tevent->filter);
520 		return 1;
521 	}
522 
523 	tevent->filter_enabled = 1;
524 	return 0;
525 }
526 
527 /*
528  * trace_event_enable_trigger - enable an event trigger associated with an event
529  */
530 static int trace_event_enable_trigger(struct trace_instance *instance,
531 				      struct trace_events *tevent)
532 {
533 	char trigger[MAX_PATH];
534 	int retval;
535 
536 	if (!tevent->trigger)
537 		return 0;
538 
539 	if (!tevent->event) {
540 		err_msg("Trigger %s applies only for single events, not for all %s:* events\n",
541 			tevent->trigger, tevent->system);
542 		return 1;
543 	}
544 
545 	snprintf(trigger, ARRAY_SIZE(trigger), "%s\n", tevent->trigger);
546 
547 	debug_msg("Enabling %s:%s trigger %s\n", tevent->system,
548 		  tevent->event ? : "*", tevent->trigger);
549 
550 	retval = tracefs_event_file_write(instance->inst, tevent->system,
551 					  tevent->event, "trigger", trigger);
552 	if (retval < 0) {
553 		err_msg("Error enabling %s:%s trigger %s\n", tevent->system,
554 			tevent->event ? : "*", tevent->trigger);
555 		return 1;
556 	}
557 
558 	tevent->trigger_enabled = 1;
559 
560 	return 0;
561 }
562 
563 /*
564  * trace_events_enable - enable all events
565  */
566 int trace_events_enable(struct trace_instance *instance,
567 			struct trace_events *events)
568 {
569 	struct trace_events *tevent = events;
570 	int retval;
571 
572 	if (!events)
573 		return 0;
574 
575 	for_each_trace_event(tevent) {
576 		debug_msg("Enabling event %s:%s\n", tevent->system, tevent->event ? : "*");
577 		retval = tracefs_event_enable(instance->inst, tevent->system, tevent->event);
578 		if (retval < 0) {
579 			err_msg("Error enabling event %s:%s\n", tevent->system,
580 				tevent->event ? : "*");
581 			return 1;
582 		}
583 
584 		retval = trace_event_enable_filter(instance, tevent);
585 		if (retval)
586 			return 1;
587 
588 		retval = trace_event_enable_trigger(instance, tevent);
589 		if (retval)
590 			return 1;
591 
592 		tevent->enabled = 1;
593 	}
594 
595 	return 0;
596 }
597 
598 /*
599  * trace_events_destroy - disable and free all trace events
600  */
601 void trace_events_destroy(struct trace_instance *instance,
602 			  struct trace_events *events)
603 {
604 	if (!events)
605 		return;
606 
607 	trace_events_disable(instance, events);
608 	trace_events_free(events);
609 }
610 
611 /*
612  * trace_set_buffer_size - set the per-cpu tracing buffer size.
613  */
614 int trace_set_buffer_size(struct trace_instance *trace, int size)
615 {
616 	int retval;
617 
618 	debug_msg("Setting trace buffer size to %d Kb\n", size);
619 	retval = tracefs_instance_set_buffer_size(trace->inst, size, -1);
620 	if (retval)
621 		err_msg("Error setting trace buffer size\n");
622 
623 	return retval;
624 }
625