File Index
Files and directories
Sign in
FILE

trace.c

File preview with syntax highlighting.

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