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