xref: /linux/tools/tracing/rtla/src/trace.c (revision a29430c2bc86b00e62f74299b866216390c7e418)
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 
350 	if (!tevent)
351 		return;
352 
353 	/* trigger enables hist */
354 	if (!tevent->trigger)
355 		return;
356 
357 	/* is this a hist: trigger? */
358 	retval = strncmp(tevent->trigger, "hist:", strlen("hist:"));
359 	if (retval)
360 		return;
361 
362 	snprintf(path, ARRAY_SIZE(path), "%s_%s_hist.txt", tevent->system, tevent->event);
363 
364 	printf("  Saving event %s:%s hist to %s\n", tevent->system, tevent->event, path);
365 
366 	out_fd = creat(path, mode);
367 	if (out_fd < 0) {
368 		err_msg("  Failed to create %s output file\n", path);
369 		return;
370 	}
371 
372 	hist = tracefs_event_file_read(instance->inst, tevent->system, tevent->event, "hist", 0);
373 	if (!hist) {
374 		err_msg("  Failed to read %s:%s hist file\n", tevent->system, tevent->event);
375 		goto out_close;
376 	}
377 
378 	index = 0;
379 	do {
380 		index += write(out_fd, &hist[index], strlen(hist) - index);
381 	} while (index < strlen(hist));
382 
383 	free(hist);
384 out_close:
385 	close(out_fd);
386 }
387 
388 /*
389  * trace_event_disable_trigger - disable an event trigger
390  */
391 static void trace_event_disable_trigger(struct trace_instance *instance,
392 					struct trace_events *tevent)
393 {
394 	char trigger[MAX_PATH];
395 	int retval;
396 
397 	if (!tevent->trigger)
398 		return;
399 
400 	if (!tevent->trigger_enabled)
401 		return;
402 
403 	debug_msg("Disabling %s:%s trigger %s\n", tevent->system,
404 		  tevent->event ? : "*", tevent->trigger);
405 
406 	trace_event_save_hist(instance, tevent);
407 
408 	snprintf(trigger, ARRAY_SIZE(trigger), "!%s\n", tevent->trigger);
409 
410 	retval = tracefs_event_file_write(instance->inst, tevent->system,
411 					  tevent->event, "trigger", trigger);
412 	if (retval < 0)
413 		err_msg("Error disabling %s:%s trigger %s\n", tevent->system,
414 			tevent->event ? : "*", tevent->trigger);
415 }
416 
417 /*
418  * trace_events_disable - disable all trace events
419  */
420 void trace_events_disable(struct trace_instance *instance,
421 			  struct trace_events *events)
422 {
423 	struct trace_events *tevent = events;
424 
425 	if (!events)
426 		return;
427 
428 	while (tevent) {
429 		debug_msg("Disabling event %s:%s\n", tevent->system, tevent->event ? : "*");
430 		if (tevent->enabled) {
431 			trace_event_disable_filter(instance, tevent);
432 			trace_event_disable_trigger(instance, tevent);
433 			tracefs_event_disable(instance->inst, tevent->system, tevent->event);
434 		}
435 
436 		tevent->enabled = 0;
437 		tevent = tevent->next;
438 	}
439 }
440 
441 /*
442  * trace_event_enable_filter - enable an event filter associated with an event
443  */
444 static int trace_event_enable_filter(struct trace_instance *instance,
445 				     struct trace_events *tevent)
446 {
447 	char filter[MAX_PATH];
448 	int retval;
449 
450 	if (!tevent->filter)
451 		return 0;
452 
453 	if (!tevent->event) {
454 		err_msg("Filter %s applies only for single events, not for all %s:* events\n",
455 			tevent->filter, tevent->system);
456 		return 1;
457 	}
458 
459 	snprintf(filter, ARRAY_SIZE(filter), "%s\n", tevent->filter);
460 
461 	debug_msg("Enabling %s:%s filter %s\n", tevent->system,
462 		  tevent->event ? : "*", tevent->filter);
463 
464 	retval = tracefs_event_file_write(instance->inst, tevent->system,
465 					  tevent->event, "filter", filter);
466 	if (retval < 0) {
467 		err_msg("Error enabling %s:%s filter %s\n", tevent->system,
468 			tevent->event ? : "*", tevent->filter);
469 		return 1;
470 	}
471 
472 	tevent->filter_enabled = 1;
473 	return 0;
474 }
475 
476 /*
477  * trace_event_enable_trigger - enable an event trigger associated with an event
478  */
479 static int trace_event_enable_trigger(struct trace_instance *instance,
480 				      struct trace_events *tevent)
481 {
482 	char trigger[MAX_PATH];
483 	int retval;
484 
485 	if (!tevent->trigger)
486 		return 0;
487 
488 	if (!tevent->event) {
489 		err_msg("Trigger %s applies only for single events, not for all %s:* events\n",
490 			tevent->trigger, tevent->system);
491 		return 1;
492 	}
493 
494 	snprintf(trigger, ARRAY_SIZE(trigger), "%s\n", tevent->trigger);
495 
496 	debug_msg("Enabling %s:%s trigger %s\n", tevent->system,
497 		  tevent->event ? : "*", tevent->trigger);
498 
499 	retval = tracefs_event_file_write(instance->inst, tevent->system,
500 					  tevent->event, "trigger", trigger);
501 	if (retval < 0) {
502 		err_msg("Error enabling %s:%s trigger %s\n", tevent->system,
503 			tevent->event ? : "*", tevent->trigger);
504 		return 1;
505 	}
506 
507 	tevent->trigger_enabled = 1;
508 
509 	return 0;
510 }
511 
512 /*
513  * trace_events_enable - enable all events
514  */
515 int trace_events_enable(struct trace_instance *instance,
516 			struct trace_events *events)
517 {
518 	struct trace_events *tevent = events;
519 	int retval;
520 
521 	while (tevent) {
522 		debug_msg("Enabling event %s:%s\n", tevent->system, tevent->event ? : "*");
523 		retval = tracefs_event_enable(instance->inst, tevent->system, tevent->event);
524 		if (retval < 0) {
525 			err_msg("Error enabling event %s:%s\n", tevent->system,
526 				tevent->event ? : "*");
527 			return 1;
528 		}
529 
530 		retval = trace_event_enable_filter(instance, tevent);
531 		if (retval)
532 			return 1;
533 
534 		retval = trace_event_enable_trigger(instance, tevent);
535 		if (retval)
536 			return 1;
537 
538 		tevent->enabled = 1;
539 		tevent = tevent->next;
540 	}
541 
542 	return 0;
543 }
544 
545 /*
546  * trace_events_destroy - disable and free all trace events
547  */
548 void trace_events_destroy(struct trace_instance *instance,
549 			  struct trace_events *events)
550 {
551 	if (!events)
552 		return;
553 
554 	trace_events_disable(instance, events);
555 	trace_events_free(events);
556 }
557 
558 /*
559  * trace_set_buffer_size - set the per-cpu tracing buffer size.
560  */
561 int trace_set_buffer_size(struct trace_instance *trace, int size)
562 {
563 	int retval;
564 
565 	debug_msg("Setting trace buffer size to %d Kb\n", size);
566 	retval = tracefs_instance_set_buffer_size(trace->inst, size, -1);
567 	if (retval)
568 		err_msg("Error setting trace buffer size\n");
569 
570 	return retval;
571 }
572