xref: /linux/tools/tracing/rtla/src/trace.c (revision f3cc3e4b5116929ebff27c3b0a565b34ae4969b3)
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(1, sizeof(*trace->seq));
195 	if (!trace->seq)
196 		goto out_err;
197 
198 	trace_seq_init(trace->seq);
199 
200 	trace->inst = create_instance(tool_name);
201 	if (!trace->inst)
202 		goto out_err;
203 
204 	trace->tep = tracefs_local_events(NULL);
205 	if (!trace->tep)
206 		goto out_err;
207 
208 	/*
209 	 * Let the main enable the record after setting some other
210 	 * things such as the priority of the tracer's threads.
211 	 */
212 	tracefs_trace_off(trace->inst);
213 
214 	/*
215 	 * Collect the number of events missed due to tracefs buffer
216 	 * overflow.
217 	 */
218 	trace->missed_events = 0;
219 	tracefs_follow_missed_events(trace->inst,
220 				     collect_missed_events,
221 				     trace);
222 
223 	trace->processed_events = 0;
224 
225 	return 0;
226 
227 out_err:
228 	trace_instance_destroy(trace);
229 	return 1;
230 }
231 
232 /*
233  * trace_instance_start - start tracing a given rtla instance
234  */
235 int trace_instance_start(struct trace_instance *trace)
236 {
237 	return tracefs_trace_on(trace->inst);
238 }
239 
240 /*
241  * trace_instance_stop - stop tracing a given rtla instance
242  */
243 int trace_instance_stop(struct trace_instance *trace)
244 {
245 	return tracefs_trace_off(trace->inst);
246 }
247 
248 /*
249  * trace_events_free - free a list of trace events
250  */
251 static void trace_events_free(struct trace_events *events)
252 {
253 	struct trace_events *tevent = events;
254 	struct trace_events *free_event;
255 
256 	while (tevent) {
257 		free_event = tevent;
258 
259 		tevent = tevent->next;
260 
261 		if (free_event->filter)
262 			free(free_event->filter);
263 		if (free_event->trigger)
264 			free(free_event->trigger);
265 		free(free_event->system);
266 		free(free_event);
267 	}
268 }
269 
270 /*
271  * trace_event_alloc - alloc and parse a single trace event
272  */
273 struct trace_events *trace_event_alloc(const char *event_string)
274 {
275 	struct trace_events *tevent;
276 
277 	tevent = calloc(1, sizeof(*tevent));
278 	if (!tevent)
279 		return NULL;
280 
281 	tevent->system = strdup(event_string);
282 	if (!tevent->system) {
283 		free(tevent);
284 		return NULL;
285 	}
286 
287 	tevent->event = strstr(tevent->system, ":");
288 	if (tevent->event) {
289 		*tevent->event = '\0';
290 		tevent->event = &tevent->event[1];
291 	}
292 
293 	return tevent;
294 }
295 
296 /*
297  * trace_event_add_filter - record an event filter
298  */
299 int trace_event_add_filter(struct trace_events *event, char *filter)
300 {
301 	if (event->filter)
302 		free(event->filter);
303 
304 	event->filter = strdup(filter);
305 	if (!event->filter)
306 		return 1;
307 
308 	return 0;
309 }
310 
311 /*
312  * trace_event_add_trigger - record an event trigger action
313  */
314 int trace_event_add_trigger(struct trace_events *event, char *trigger)
315 {
316 	if (event->trigger)
317 		free(event->trigger);
318 
319 	event->trigger = strdup(trigger);
320 	if (!event->trigger)
321 		return 1;
322 
323 	return 0;
324 }
325 
326 /*
327  * trace_event_disable_filter - disable an event filter
328  */
329 static void trace_event_disable_filter(struct trace_instance *instance,
330 				       struct trace_events *tevent)
331 {
332 	char filter[1024];
333 	int retval;
334 
335 	if (!tevent->filter)
336 		return;
337 
338 	if (!tevent->filter_enabled)
339 		return;
340 
341 	debug_msg("Disabling %s:%s filter %s\n", tevent->system,
342 		  tevent->event ? : "*", tevent->filter);
343 
344 	snprintf(filter, 1024, "!%s\n", tevent->filter);
345 
346 	retval = tracefs_event_file_write(instance->inst, tevent->system,
347 					  tevent->event, "filter", filter);
348 	if (retval < 0)
349 		err_msg("Error disabling %s:%s filter %s\n", tevent->system,
350 			tevent->event ? : "*", tevent->filter);
351 }
352 
353 /*
354  * trace_event_save_hist - save the content of an event hist
355  *
356  * If the trigger is a hist: one, save the content of the hist file.
357  */
358 static void trace_event_save_hist(struct trace_instance *instance,
359 				  struct trace_events *tevent)
360 {
361 	int retval, index, out_fd;
362 	mode_t mode = 0644;
363 	char path[1024];
364 	char *hist;
365 
366 	if (!tevent)
367 		return;
368 
369 	/* trigger enables hist */
370 	if (!tevent->trigger)
371 		return;
372 
373 	/* is this a hist: trigger? */
374 	retval = strncmp(tevent->trigger, "hist:", strlen("hist:"));
375 	if (retval)
376 		return;
377 
378 	snprintf(path, 1024, "%s_%s_hist.txt", tevent->system, tevent->event);
379 
380 	printf("  Saving event %s:%s hist to %s\n", tevent->system, tevent->event, path);
381 
382 	out_fd = creat(path, mode);
383 	if (out_fd < 0) {
384 		err_msg("  Failed to create %s output file\n", path);
385 		return;
386 	}
387 
388 	hist = tracefs_event_file_read(instance->inst, tevent->system, tevent->event, "hist", 0);
389 	if (!hist) {
390 		err_msg("  Failed to read %s:%s hist file\n", tevent->system, tevent->event);
391 		goto out_close;
392 	}
393 
394 	index = 0;
395 	do {
396 		index += write(out_fd, &hist[index], strlen(hist) - index);
397 	} while (index < strlen(hist));
398 
399 	free(hist);
400 out_close:
401 	close(out_fd);
402 }
403 
404 /*
405  * trace_event_disable_trigger - disable an event trigger
406  */
407 static void trace_event_disable_trigger(struct trace_instance *instance,
408 					struct trace_events *tevent)
409 {
410 	char trigger[1024];
411 	int retval;
412 
413 	if (!tevent->trigger)
414 		return;
415 
416 	if (!tevent->trigger_enabled)
417 		return;
418 
419 	debug_msg("Disabling %s:%s trigger %s\n", tevent->system,
420 		  tevent->event ? : "*", tevent->trigger);
421 
422 	trace_event_save_hist(instance, tevent);
423 
424 	snprintf(trigger, 1024, "!%s\n", tevent->trigger);
425 
426 	retval = tracefs_event_file_write(instance->inst, tevent->system,
427 					  tevent->event, "trigger", trigger);
428 	if (retval < 0)
429 		err_msg("Error disabling %s:%s trigger %s\n", tevent->system,
430 			tevent->event ? : "*", tevent->trigger);
431 }
432 
433 /*
434  * trace_events_disable - disable all trace events
435  */
436 void trace_events_disable(struct trace_instance *instance,
437 			  struct trace_events *events)
438 {
439 	struct trace_events *tevent = events;
440 
441 	if (!events)
442 		return;
443 
444 	while (tevent) {
445 		debug_msg("Disabling event %s:%s\n", tevent->system, tevent->event ? : "*");
446 		if (tevent->enabled) {
447 			trace_event_disable_filter(instance, tevent);
448 			trace_event_disable_trigger(instance, tevent);
449 			tracefs_event_disable(instance->inst, tevent->system, tevent->event);
450 		}
451 
452 		tevent->enabled = 0;
453 		tevent = tevent->next;
454 	}
455 }
456 
457 /*
458  * trace_event_enable_filter - enable an event filter associated with an event
459  */
460 static int trace_event_enable_filter(struct trace_instance *instance,
461 				     struct trace_events *tevent)
462 {
463 	char filter[1024];
464 	int retval;
465 
466 	if (!tevent->filter)
467 		return 0;
468 
469 	if (!tevent->event) {
470 		err_msg("Filter %s applies only for single events, not for all %s:* events\n",
471 			tevent->filter, tevent->system);
472 		return 1;
473 	}
474 
475 	snprintf(filter, 1024, "%s\n", tevent->filter);
476 
477 	debug_msg("Enabling %s:%s filter %s\n", tevent->system,
478 		  tevent->event ? : "*", tevent->filter);
479 
480 	retval = tracefs_event_file_write(instance->inst, tevent->system,
481 					  tevent->event, "filter", filter);
482 	if (retval < 0) {
483 		err_msg("Error enabling %s:%s filter %s\n", tevent->system,
484 			tevent->event ? : "*", tevent->filter);
485 		return 1;
486 	}
487 
488 	tevent->filter_enabled = 1;
489 	return 0;
490 }
491 
492 /*
493  * trace_event_enable_trigger - enable an event trigger associated with an event
494  */
495 static int trace_event_enable_trigger(struct trace_instance *instance,
496 				      struct trace_events *tevent)
497 {
498 	char trigger[1024];
499 	int retval;
500 
501 	if (!tevent->trigger)
502 		return 0;
503 
504 	if (!tevent->event) {
505 		err_msg("Trigger %s applies only for single events, not for all %s:* events\n",
506 			tevent->trigger, tevent->system);
507 		return 1;
508 	}
509 
510 	snprintf(trigger, 1024, "%s\n", tevent->trigger);
511 
512 	debug_msg("Enabling %s:%s trigger %s\n", tevent->system,
513 		  tevent->event ? : "*", tevent->trigger);
514 
515 	retval = tracefs_event_file_write(instance->inst, tevent->system,
516 					  tevent->event, "trigger", trigger);
517 	if (retval < 0) {
518 		err_msg("Error enabling %s:%s trigger %s\n", tevent->system,
519 			tevent->event ? : "*", tevent->trigger);
520 		return 1;
521 	}
522 
523 	tevent->trigger_enabled = 1;
524 
525 	return 0;
526 }
527 
528 /*
529  * trace_events_enable - enable all events
530  */
531 int trace_events_enable(struct trace_instance *instance,
532 			struct trace_events *events)
533 {
534 	struct trace_events *tevent = events;
535 	int retval;
536 
537 	while (tevent) {
538 		debug_msg("Enabling event %s:%s\n", tevent->system, tevent->event ? : "*");
539 		retval = tracefs_event_enable(instance->inst, tevent->system, tevent->event);
540 		if (retval < 0) {
541 			err_msg("Error enabling event %s:%s\n", tevent->system,
542 				tevent->event ? : "*");
543 			return 1;
544 		}
545 
546 		retval = trace_event_enable_filter(instance, tevent);
547 		if (retval)
548 			return 1;
549 
550 		retval = trace_event_enable_trigger(instance, tevent);
551 		if (retval)
552 			return 1;
553 
554 		tevent->enabled = 1;
555 		tevent = tevent->next;
556 	}
557 
558 	return 0;
559 }
560 
561 /*
562  * trace_events_destroy - disable and free all trace events
563  */
564 void trace_events_destroy(struct trace_instance *instance,
565 			  struct trace_events *events)
566 {
567 	if (!events)
568 		return;
569 
570 	trace_events_disable(instance, events);
571 	trace_events_free(events);
572 }
573 
574 /*
575  * trace_set_buffer_size - set the per-cpu tracing buffer size.
576  */
577 int trace_set_buffer_size(struct trace_instance *trace, int size)
578 {
579 	int retval;
580 
581 	debug_msg("Setting trace buffer size to %d Kb\n", size);
582 	retval = tracefs_instance_set_buffer_size(trace->inst, size, -1);
583 	if (retval)
584 		err_msg("Error setting trace buffer size\n");
585 
586 	return retval;
587 }
588