xref: /openbmc/linux/tools/tracing/rtla/src/trace.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1b1696371SDaniel Bristot de Oliveira // SPDX-License-Identifier: GPL-2.0
2b1696371SDaniel Bristot de Oliveira #define _GNU_SOURCE
3b1696371SDaniel Bristot de Oliveira #include <sys/sendfile.h>
4b1696371SDaniel Bristot de Oliveira #include <tracefs.h>
5b1696371SDaniel Bristot de Oliveira #include <signal.h>
6b1696371SDaniel Bristot de Oliveira #include <stdlib.h>
7b1696371SDaniel Bristot de Oliveira #include <unistd.h>
8b1696371SDaniel Bristot de Oliveira #include <errno.h>
9b1696371SDaniel Bristot de Oliveira 
10b1696371SDaniel Bristot de Oliveira #include "trace.h"
11b1696371SDaniel Bristot de Oliveira #include "utils.h"
12b1696371SDaniel Bristot de Oliveira 
13b1696371SDaniel Bristot de Oliveira /*
14b1696371SDaniel Bristot de Oliveira  * enable_tracer_by_name - enable a tracer on the given instance
15b1696371SDaniel Bristot de Oliveira  */
enable_tracer_by_name(struct tracefs_instance * inst,const char * tracer_name)16b1696371SDaniel Bristot de Oliveira int enable_tracer_by_name(struct tracefs_instance *inst, const char *tracer_name)
17b1696371SDaniel Bristot de Oliveira {
18b1696371SDaniel Bristot de Oliveira 	enum tracefs_tracers tracer;
19b1696371SDaniel Bristot de Oliveira 	int retval;
20b1696371SDaniel Bristot de Oliveira 
21b1696371SDaniel Bristot de Oliveira 	tracer = TRACEFS_TRACER_CUSTOM;
22b1696371SDaniel Bristot de Oliveira 
231a622909SDaniel Bristot de Oliveira 	debug_msg("Enabling %s tracer\n", tracer_name);
24b1696371SDaniel Bristot de Oliveira 
25b1696371SDaniel Bristot de Oliveira 	retval = tracefs_tracer_set(inst, tracer, tracer_name);
26b1696371SDaniel Bristot de Oliveira 	if (retval < 0) {
27b1696371SDaniel Bristot de Oliveira 		if (errno == ENODEV)
281a622909SDaniel Bristot de Oliveira 			err_msg("Tracer %s not found!\n", tracer_name);
29b1696371SDaniel Bristot de Oliveira 
301a622909SDaniel Bristot de Oliveira 		err_msg("Failed to enable the %s tracer\n", tracer_name);
31b1696371SDaniel Bristot de Oliveira 		return -1;
32b1696371SDaniel Bristot de Oliveira 	}
33b1696371SDaniel Bristot de Oliveira 
34b1696371SDaniel Bristot de Oliveira 	return 0;
35b1696371SDaniel Bristot de Oliveira }
36b1696371SDaniel Bristot de Oliveira 
37b1696371SDaniel Bristot de Oliveira /*
38b1696371SDaniel Bristot de Oliveira  * disable_tracer - set nop tracer to the insta
39b1696371SDaniel Bristot de Oliveira  */
disable_tracer(struct tracefs_instance * inst)40b1696371SDaniel Bristot de Oliveira void disable_tracer(struct tracefs_instance *inst)
41b1696371SDaniel Bristot de Oliveira {
42b1696371SDaniel Bristot de Oliveira 	enum tracefs_tracers t = TRACEFS_TRACER_NOP;
43b1696371SDaniel Bristot de Oliveira 	int retval;
44b1696371SDaniel Bristot de Oliveira 
45b1696371SDaniel Bristot de Oliveira 	retval = tracefs_tracer_set(inst, t);
46b1696371SDaniel Bristot de Oliveira 	if (retval < 0)
471a622909SDaniel Bristot de Oliveira 		err_msg("Oops, error disabling tracer\n");
48b1696371SDaniel Bristot de Oliveira }
49b1696371SDaniel Bristot de Oliveira 
50b1696371SDaniel Bristot de Oliveira /*
51b1696371SDaniel Bristot de Oliveira  * create_instance - create a trace instance with *instance_name
52b1696371SDaniel Bristot de Oliveira  */
create_instance(char * instance_name)53b1696371SDaniel Bristot de Oliveira struct tracefs_instance *create_instance(char *instance_name)
54b1696371SDaniel Bristot de Oliveira {
55b1696371SDaniel Bristot de Oliveira 	return tracefs_instance_create(instance_name);
56b1696371SDaniel Bristot de Oliveira }
57b1696371SDaniel Bristot de Oliveira 
58b1696371SDaniel Bristot de Oliveira /*
59b1696371SDaniel Bristot de Oliveira  * destroy_instance - remove a trace instance and free the data
60b1696371SDaniel Bristot de Oliveira  */
destroy_instance(struct tracefs_instance * inst)61b1696371SDaniel Bristot de Oliveira void destroy_instance(struct tracefs_instance *inst)
62b1696371SDaniel Bristot de Oliveira {
63b1696371SDaniel Bristot de Oliveira 	tracefs_instance_destroy(inst);
64b1696371SDaniel Bristot de Oliveira 	tracefs_instance_free(inst);
65b1696371SDaniel Bristot de Oliveira }
66b1696371SDaniel Bristot de Oliveira 
67b1696371SDaniel Bristot de Oliveira /*
68b1696371SDaniel Bristot de Oliveira  * save_trace_to_file - save the trace output of the instance to the file
69b1696371SDaniel Bristot de Oliveira  */
save_trace_to_file(struct tracefs_instance * inst,const char * filename)70b1696371SDaniel Bristot de Oliveira int save_trace_to_file(struct tracefs_instance *inst, const char *filename)
71b1696371SDaniel Bristot de Oliveira {
72b1696371SDaniel Bristot de Oliveira 	const char *file = "trace";
73b1696371SDaniel Bristot de Oliveira 	mode_t mode = 0644;
74b1696371SDaniel Bristot de Oliveira 	char buffer[4096];
75b1696371SDaniel Bristot de Oliveira 	int out_fd, in_fd;
76b1696371SDaniel Bristot de Oliveira 	int retval = -1;
77b1696371SDaniel Bristot de Oliveira 
78b1696371SDaniel Bristot de Oliveira 	in_fd = tracefs_instance_file_open(inst, file, O_RDONLY);
79b1696371SDaniel Bristot de Oliveira 	if (in_fd < 0) {
80b1696371SDaniel Bristot de Oliveira 		err_msg("Failed to open trace file\n");
81b1696371SDaniel Bristot de Oliveira 		return -1;
82b1696371SDaniel Bristot de Oliveira 	}
83b1696371SDaniel Bristot de Oliveira 
84b1696371SDaniel Bristot de Oliveira 	out_fd = creat(filename, mode);
85b1696371SDaniel Bristot de Oliveira 	if (out_fd < 0) {
86b1696371SDaniel Bristot de Oliveira 		err_msg("Failed to create output file %s\n", filename);
87b1696371SDaniel Bristot de Oliveira 		goto out_close_in;
88b1696371SDaniel Bristot de Oliveira 	}
89b1696371SDaniel Bristot de Oliveira 
90b1696371SDaniel Bristot de Oliveira 	do {
91b1696371SDaniel Bristot de Oliveira 		retval = read(in_fd, buffer, sizeof(buffer));
92b1696371SDaniel Bristot de Oliveira 		if (retval <= 0)
93b1696371SDaniel Bristot de Oliveira 			goto out_close;
94b1696371SDaniel Bristot de Oliveira 
95b1696371SDaniel Bristot de Oliveira 		retval = write(out_fd, buffer, retval);
96b1696371SDaniel Bristot de Oliveira 		if (retval < 0)
97b1696371SDaniel Bristot de Oliveira 			goto out_close;
98b1696371SDaniel Bristot de Oliveira 	} while (retval > 0);
99b1696371SDaniel Bristot de Oliveira 
100b1696371SDaniel Bristot de Oliveira 	retval = 0;
101b1696371SDaniel Bristot de Oliveira out_close:
102b1696371SDaniel Bristot de Oliveira 	close(out_fd);
103b1696371SDaniel Bristot de Oliveira out_close_in:
104b1696371SDaniel Bristot de Oliveira 	close(in_fd);
105b1696371SDaniel Bristot de Oliveira 	return retval;
106b1696371SDaniel Bristot de Oliveira }
107b1696371SDaniel Bristot de Oliveira 
108b1696371SDaniel Bristot de Oliveira /*
109b1696371SDaniel Bristot de Oliveira  * collect_registered_events - call the existing callback function for the event
110b1696371SDaniel Bristot de Oliveira  *
111b1696371SDaniel Bristot de Oliveira  * If an event has a registered callback function, call it.
112b1696371SDaniel Bristot de Oliveira  * Otherwise, ignore the event.
113b1696371SDaniel Bristot de Oliveira  */
114b1696371SDaniel Bristot de Oliveira int
collect_registered_events(struct tep_event * event,struct tep_record * record,int cpu,void * context)115b1696371SDaniel Bristot de Oliveira collect_registered_events(struct tep_event *event, struct tep_record *record,
116b1696371SDaniel Bristot de Oliveira 			  int cpu, void *context)
117b1696371SDaniel Bristot de Oliveira {
118b1696371SDaniel Bristot de Oliveira 	struct trace_instance *trace = context;
119b1696371SDaniel Bristot de Oliveira 	struct trace_seq *s = trace->seq;
120b1696371SDaniel Bristot de Oliveira 
121b1696371SDaniel Bristot de Oliveira 	if (!event->handler)
122b1696371SDaniel Bristot de Oliveira 		return 0;
123b1696371SDaniel Bristot de Oliveira 
124b1696371SDaniel Bristot de Oliveira 	event->handler(s, record, event, context);
125b1696371SDaniel Bristot de Oliveira 
126b1696371SDaniel Bristot de Oliveira 	return 0;
127b1696371SDaniel Bristot de Oliveira }
128b1696371SDaniel Bristot de Oliveira 
129b1696371SDaniel Bristot de Oliveira /*
130b1696371SDaniel Bristot de Oliveira  * trace_instance_destroy - destroy and free a rtla trace instance
131b1696371SDaniel Bristot de Oliveira  */
trace_instance_destroy(struct trace_instance * trace)132b1696371SDaniel Bristot de Oliveira void trace_instance_destroy(struct trace_instance *trace)
133b1696371SDaniel Bristot de Oliveira {
134b1696371SDaniel Bristot de Oliveira 	if (trace->inst) {
135b1696371SDaniel Bristot de Oliveira 		disable_tracer(trace->inst);
136b1696371SDaniel Bristot de Oliveira 		destroy_instance(trace->inst);
137*4f753c3bSAndreas Schwab 		trace->inst = NULL;
138b1696371SDaniel Bristot de Oliveira 	}
139b1696371SDaniel Bristot de Oliveira 
140*4f753c3bSAndreas Schwab 	if (trace->seq) {
141b1696371SDaniel Bristot de Oliveira 		free(trace->seq);
142*4f753c3bSAndreas Schwab 		trace->seq = NULL;
143*4f753c3bSAndreas Schwab 	}
144b1696371SDaniel Bristot de Oliveira 
145*4f753c3bSAndreas Schwab 	if (trace->tep) {
146b1696371SDaniel Bristot de Oliveira 		tep_free(trace->tep);
147*4f753c3bSAndreas Schwab 		trace->tep = NULL;
148*4f753c3bSAndreas Schwab 	}
149b1696371SDaniel Bristot de Oliveira }
150b1696371SDaniel Bristot de Oliveira 
151b1696371SDaniel Bristot de Oliveira /*
152b1696371SDaniel Bristot de Oliveira  * trace_instance_init - create an rtla trace instance
153b1696371SDaniel Bristot de Oliveira  *
154b1696371SDaniel Bristot de Oliveira  * It is more than the tracefs instance, as it contains other
155b1696371SDaniel Bristot de Oliveira  * things required for the tracing, such as the local events and
156b1696371SDaniel Bristot de Oliveira  * a seq file.
157b1696371SDaniel Bristot de Oliveira  *
158b1696371SDaniel Bristot de Oliveira  * Note that the trace instance is returned disabled. This allows
159b1696371SDaniel Bristot de Oliveira  * the tool to apply some other configs, like setting priority
160b1696371SDaniel Bristot de Oliveira  * to the kernel threads, before starting generating trace entries.
161b1696371SDaniel Bristot de Oliveira  */
trace_instance_init(struct trace_instance * trace,char * tool_name)162b1696371SDaniel Bristot de Oliveira int trace_instance_init(struct trace_instance *trace, char *tool_name)
163b1696371SDaniel Bristot de Oliveira {
164b1696371SDaniel Bristot de Oliveira 	trace->seq = calloc(1, sizeof(*trace->seq));
165b1696371SDaniel Bristot de Oliveira 	if (!trace->seq)
166b1696371SDaniel Bristot de Oliveira 		goto out_err;
167b1696371SDaniel Bristot de Oliveira 
168b1696371SDaniel Bristot de Oliveira 	trace_seq_init(trace->seq);
169b1696371SDaniel Bristot de Oliveira 
170b1696371SDaniel Bristot de Oliveira 	trace->inst = create_instance(tool_name);
171b1696371SDaniel Bristot de Oliveira 	if (!trace->inst)
172b1696371SDaniel Bristot de Oliveira 		goto out_err;
173b1696371SDaniel Bristot de Oliveira 
174b1696371SDaniel Bristot de Oliveira 	trace->tep = tracefs_local_events(NULL);
175b1696371SDaniel Bristot de Oliveira 	if (!trace->tep)
176b1696371SDaniel Bristot de Oliveira 		goto out_err;
177b1696371SDaniel Bristot de Oliveira 
178b1696371SDaniel Bristot de Oliveira 	/*
179b1696371SDaniel Bristot de Oliveira 	 * Let the main enable the record after setting some other
180b1696371SDaniel Bristot de Oliveira 	 * things such as the priority of the tracer's threads.
181b1696371SDaniel Bristot de Oliveira 	 */
182b1696371SDaniel Bristot de Oliveira 	tracefs_trace_off(trace->inst);
183b1696371SDaniel Bristot de Oliveira 
184b1696371SDaniel Bristot de Oliveira 	return 0;
185b1696371SDaniel Bristot de Oliveira 
186b1696371SDaniel Bristot de Oliveira out_err:
187b1696371SDaniel Bristot de Oliveira 	trace_instance_destroy(trace);
188b1696371SDaniel Bristot de Oliveira 	return 1;
189b1696371SDaniel Bristot de Oliveira }
190b1696371SDaniel Bristot de Oliveira 
191b1696371SDaniel Bristot de Oliveira /*
192b1696371SDaniel Bristot de Oliveira  * trace_instance_start - start tracing a given rtla instance
193b1696371SDaniel Bristot de Oliveira  */
trace_instance_start(struct trace_instance * trace)194b1696371SDaniel Bristot de Oliveira int trace_instance_start(struct trace_instance *trace)
195b1696371SDaniel Bristot de Oliveira {
196b1696371SDaniel Bristot de Oliveira 	return tracefs_trace_on(trace->inst);
197b1696371SDaniel Bristot de Oliveira }
198b5aa0be2SDaniel Bristot de Oliveira 
199b5aa0be2SDaniel Bristot de Oliveira /*
200b5aa0be2SDaniel Bristot de Oliveira  * trace_events_free - free a list of trace events
201b5aa0be2SDaniel Bristot de Oliveira  */
trace_events_free(struct trace_events * events)202b5aa0be2SDaniel Bristot de Oliveira static void trace_events_free(struct trace_events *events)
203b5aa0be2SDaniel Bristot de Oliveira {
204b5aa0be2SDaniel Bristot de Oliveira 	struct trace_events *tevent = events;
205b5aa0be2SDaniel Bristot de Oliveira 	struct trace_events *free_event;
206b5aa0be2SDaniel Bristot de Oliveira 
207b5aa0be2SDaniel Bristot de Oliveira 	while (tevent) {
208b5aa0be2SDaniel Bristot de Oliveira 		free_event = tevent;
209b5aa0be2SDaniel Bristot de Oliveira 
210b5aa0be2SDaniel Bristot de Oliveira 		tevent = tevent->next;
211b5aa0be2SDaniel Bristot de Oliveira 
2125487b6ceSDaniel Bristot de Oliveira 		if (free_event->filter)
2135487b6ceSDaniel Bristot de Oliveira 			free(free_event->filter);
214336c92b2SDaniel Bristot de Oliveira 		if (free_event->trigger)
215336c92b2SDaniel Bristot de Oliveira 			free(free_event->trigger);
216b5aa0be2SDaniel Bristot de Oliveira 		free(free_event->system);
217b5aa0be2SDaniel Bristot de Oliveira 		free(free_event);
218b5aa0be2SDaniel Bristot de Oliveira 	}
219b5aa0be2SDaniel Bristot de Oliveira }
220b5aa0be2SDaniel Bristot de Oliveira 
221b5aa0be2SDaniel Bristot de Oliveira /*
222b5aa0be2SDaniel Bristot de Oliveira  * trace_event_alloc - alloc and parse a single trace event
223b5aa0be2SDaniel Bristot de Oliveira  */
trace_event_alloc(const char * event_string)224b5aa0be2SDaniel Bristot de Oliveira struct trace_events *trace_event_alloc(const char *event_string)
225b5aa0be2SDaniel Bristot de Oliveira {
226b5aa0be2SDaniel Bristot de Oliveira 	struct trace_events *tevent;
227b5aa0be2SDaniel Bristot de Oliveira 
228b5aa0be2SDaniel Bristot de Oliveira 	tevent = calloc(1, sizeof(*tevent));
229b5aa0be2SDaniel Bristot de Oliveira 	if (!tevent)
230b5aa0be2SDaniel Bristot de Oliveira 		return NULL;
231b5aa0be2SDaniel Bristot de Oliveira 
232b5aa0be2SDaniel Bristot de Oliveira 	tevent->system = strdup(event_string);
233b5aa0be2SDaniel Bristot de Oliveira 	if (!tevent->system) {
234b5aa0be2SDaniel Bristot de Oliveira 		free(tevent);
235b5aa0be2SDaniel Bristot de Oliveira 		return NULL;
236b5aa0be2SDaniel Bristot de Oliveira 	}
237b5aa0be2SDaniel Bristot de Oliveira 
238b5aa0be2SDaniel Bristot de Oliveira 	tevent->event = strstr(tevent->system, ":");
239b5aa0be2SDaniel Bristot de Oliveira 	if (tevent->event) {
240b5aa0be2SDaniel Bristot de Oliveira 		*tevent->event = '\0';
241b5aa0be2SDaniel Bristot de Oliveira 		tevent->event = &tevent->event[1];
242b5aa0be2SDaniel Bristot de Oliveira 	}
243b5aa0be2SDaniel Bristot de Oliveira 
244b5aa0be2SDaniel Bristot de Oliveira 	return tevent;
245b5aa0be2SDaniel Bristot de Oliveira }
246b5aa0be2SDaniel Bristot de Oliveira 
247b5aa0be2SDaniel Bristot de Oliveira /*
2485487b6ceSDaniel Bristot de Oliveira  * trace_event_add_filter - record an event filter
2495487b6ceSDaniel Bristot de Oliveira  */
trace_event_add_filter(struct trace_events * event,char * filter)2505487b6ceSDaniel Bristot de Oliveira int trace_event_add_filter(struct trace_events *event, char *filter)
2515487b6ceSDaniel Bristot de Oliveira {
2525487b6ceSDaniel Bristot de Oliveira 	if (event->filter)
2535487b6ceSDaniel Bristot de Oliveira 		free(event->filter);
2545487b6ceSDaniel Bristot de Oliveira 
2555487b6ceSDaniel Bristot de Oliveira 	event->filter = strdup(filter);
2565487b6ceSDaniel Bristot de Oliveira 	if (!event->filter)
2575487b6ceSDaniel Bristot de Oliveira 		return 1;
2585487b6ceSDaniel Bristot de Oliveira 
2595487b6ceSDaniel Bristot de Oliveira 	return 0;
2605487b6ceSDaniel Bristot de Oliveira }
2615487b6ceSDaniel Bristot de Oliveira 
2625487b6ceSDaniel Bristot de Oliveira /*
263336c92b2SDaniel Bristot de Oliveira  * trace_event_add_trigger - record an event trigger action
264336c92b2SDaniel Bristot de Oliveira  */
trace_event_add_trigger(struct trace_events * event,char * trigger)265336c92b2SDaniel Bristot de Oliveira int trace_event_add_trigger(struct trace_events *event, char *trigger)
266336c92b2SDaniel Bristot de Oliveira {
267336c92b2SDaniel Bristot de Oliveira 	if (event->trigger)
268336c92b2SDaniel Bristot de Oliveira 		free(event->trigger);
269336c92b2SDaniel Bristot de Oliveira 
270336c92b2SDaniel Bristot de Oliveira 	event->trigger = strdup(trigger);
271336c92b2SDaniel Bristot de Oliveira 	if (!event->trigger)
272336c92b2SDaniel Bristot de Oliveira 		return 1;
273336c92b2SDaniel Bristot de Oliveira 
274336c92b2SDaniel Bristot de Oliveira 	return 0;
275336c92b2SDaniel Bristot de Oliveira }
276336c92b2SDaniel Bristot de Oliveira 
277336c92b2SDaniel Bristot de Oliveira /*
2785487b6ceSDaniel Bristot de Oliveira  * trace_event_disable_filter - disable an event filter
2795487b6ceSDaniel Bristot de Oliveira  */
trace_event_disable_filter(struct trace_instance * instance,struct trace_events * tevent)2805487b6ceSDaniel Bristot de Oliveira static void trace_event_disable_filter(struct trace_instance *instance,
2815487b6ceSDaniel Bristot de Oliveira 				       struct trace_events *tevent)
2825487b6ceSDaniel Bristot de Oliveira {
2835487b6ceSDaniel Bristot de Oliveira 	char filter[1024];
2845487b6ceSDaniel Bristot de Oliveira 	int retval;
2855487b6ceSDaniel Bristot de Oliveira 
2865487b6ceSDaniel Bristot de Oliveira 	if (!tevent->filter)
2875487b6ceSDaniel Bristot de Oliveira 		return;
2885487b6ceSDaniel Bristot de Oliveira 
2895487b6ceSDaniel Bristot de Oliveira 	if (!tevent->filter_enabled)
2905487b6ceSDaniel Bristot de Oliveira 		return;
2915487b6ceSDaniel Bristot de Oliveira 
2925487b6ceSDaniel Bristot de Oliveira 	debug_msg("Disabling %s:%s filter %s\n", tevent->system,
2935487b6ceSDaniel Bristot de Oliveira 		  tevent->event ? : "*", tevent->filter);
2945487b6ceSDaniel Bristot de Oliveira 
2955487b6ceSDaniel Bristot de Oliveira 	snprintf(filter, 1024, "!%s\n", tevent->filter);
2965487b6ceSDaniel Bristot de Oliveira 
2975487b6ceSDaniel Bristot de Oliveira 	retval = tracefs_event_file_write(instance->inst, tevent->system,
2985487b6ceSDaniel Bristot de Oliveira 					  tevent->event, "filter", filter);
2995487b6ceSDaniel Bristot de Oliveira 	if (retval < 0)
3005487b6ceSDaniel Bristot de Oliveira 		err_msg("Error disabling %s:%s filter %s\n", tevent->system,
3015487b6ceSDaniel Bristot de Oliveira 			tevent->event ? : "*", tevent->filter);
3025487b6ceSDaniel Bristot de Oliveira }
3035487b6ceSDaniel Bristot de Oliveira 
3045487b6ceSDaniel Bristot de Oliveira /*
305761916fdSDaniel Bristot de Oliveira  * trace_event_save_hist - save the content of an event hist
306761916fdSDaniel Bristot de Oliveira  *
307761916fdSDaniel Bristot de Oliveira  * If the trigger is a hist: one, save the content of the hist file.
308761916fdSDaniel Bristot de Oliveira  */
trace_event_save_hist(struct trace_instance * instance,struct trace_events * tevent)309761916fdSDaniel Bristot de Oliveira static void trace_event_save_hist(struct trace_instance *instance,
310761916fdSDaniel Bristot de Oliveira 				  struct trace_events *tevent)
311761916fdSDaniel Bristot de Oliveira {
312761916fdSDaniel Bristot de Oliveira 	int retval, index, out_fd;
313761916fdSDaniel Bristot de Oliveira 	mode_t mode = 0644;
314761916fdSDaniel Bristot de Oliveira 	char path[1024];
315761916fdSDaniel Bristot de Oliveira 	char *hist;
316761916fdSDaniel Bristot de Oliveira 
317761916fdSDaniel Bristot de Oliveira 	if (!tevent)
318761916fdSDaniel Bristot de Oliveira 		return;
319761916fdSDaniel Bristot de Oliveira 
320761916fdSDaniel Bristot de Oliveira 	/* trigger enables hist */
321761916fdSDaniel Bristot de Oliveira 	if (!tevent->trigger)
322761916fdSDaniel Bristot de Oliveira 		return;
323761916fdSDaniel Bristot de Oliveira 
324761916fdSDaniel Bristot de Oliveira 	/* is this a hist: trigger? */
325761916fdSDaniel Bristot de Oliveira 	retval = strncmp(tevent->trigger, "hist:", strlen("hist:"));
326761916fdSDaniel Bristot de Oliveira 	if (retval)
327761916fdSDaniel Bristot de Oliveira 		return;
328761916fdSDaniel Bristot de Oliveira 
329761916fdSDaniel Bristot de Oliveira 	snprintf(path, 1024, "%s_%s_hist.txt", tevent->system, tevent->event);
330761916fdSDaniel Bristot de Oliveira 
331761916fdSDaniel Bristot de Oliveira 	printf("  Saving event %s:%s hist to %s\n", tevent->system, tevent->event, path);
332761916fdSDaniel Bristot de Oliveira 
333761916fdSDaniel Bristot de Oliveira 	out_fd = creat(path, mode);
334761916fdSDaniel Bristot de Oliveira 	if (out_fd < 0) {
335761916fdSDaniel Bristot de Oliveira 		err_msg("  Failed to create %s output file\n", path);
336761916fdSDaniel Bristot de Oliveira 		return;
337761916fdSDaniel Bristot de Oliveira 	}
338761916fdSDaniel Bristot de Oliveira 
339761916fdSDaniel Bristot de Oliveira 	hist = tracefs_event_file_read(instance->inst, tevent->system, tevent->event, "hist", 0);
340761916fdSDaniel Bristot de Oliveira 	if (!hist) {
341761916fdSDaniel Bristot de Oliveira 		err_msg("  Failed to read %s:%s hist file\n", tevent->system, tevent->event);
342761916fdSDaniel Bristot de Oliveira 		goto out_close;
343761916fdSDaniel Bristot de Oliveira 	}
344761916fdSDaniel Bristot de Oliveira 
345761916fdSDaniel Bristot de Oliveira 	index = 0;
346761916fdSDaniel Bristot de Oliveira 	do {
347761916fdSDaniel Bristot de Oliveira 		index += write(out_fd, &hist[index], strlen(hist) - index);
348761916fdSDaniel Bristot de Oliveira 	} while (index < strlen(hist));
349761916fdSDaniel Bristot de Oliveira 
350761916fdSDaniel Bristot de Oliveira 	free(hist);
351761916fdSDaniel Bristot de Oliveira out_close:
352761916fdSDaniel Bristot de Oliveira 	close(out_fd);
353761916fdSDaniel Bristot de Oliveira }
354761916fdSDaniel Bristot de Oliveira 
355761916fdSDaniel Bristot de Oliveira /*
356336c92b2SDaniel Bristot de Oliveira  * trace_event_disable_trigger - disable an event trigger
357336c92b2SDaniel Bristot de Oliveira  */
trace_event_disable_trigger(struct trace_instance * instance,struct trace_events * tevent)358336c92b2SDaniel Bristot de Oliveira static void trace_event_disable_trigger(struct trace_instance *instance,
359336c92b2SDaniel Bristot de Oliveira 					struct trace_events *tevent)
360336c92b2SDaniel Bristot de Oliveira {
361336c92b2SDaniel Bristot de Oliveira 	char trigger[1024];
362336c92b2SDaniel Bristot de Oliveira 	int retval;
363336c92b2SDaniel Bristot de Oliveira 
364336c92b2SDaniel Bristot de Oliveira 	if (!tevent->trigger)
365336c92b2SDaniel Bristot de Oliveira 		return;
366336c92b2SDaniel Bristot de Oliveira 
367336c92b2SDaniel Bristot de Oliveira 	if (!tevent->trigger_enabled)
368336c92b2SDaniel Bristot de Oliveira 		return;
369336c92b2SDaniel Bristot de Oliveira 
370336c92b2SDaniel Bristot de Oliveira 	debug_msg("Disabling %s:%s trigger %s\n", tevent->system,
371336c92b2SDaniel Bristot de Oliveira 		  tevent->event ? : "*", tevent->trigger);
372336c92b2SDaniel Bristot de Oliveira 
373761916fdSDaniel Bristot de Oliveira 	trace_event_save_hist(instance, tevent);
374761916fdSDaniel Bristot de Oliveira 
375336c92b2SDaniel Bristot de Oliveira 	snprintf(trigger, 1024, "!%s\n", tevent->trigger);
376336c92b2SDaniel Bristot de Oliveira 
377336c92b2SDaniel Bristot de Oliveira 	retval = tracefs_event_file_write(instance->inst, tevent->system,
378336c92b2SDaniel Bristot de Oliveira 					  tevent->event, "trigger", trigger);
379336c92b2SDaniel Bristot de Oliveira 	if (retval < 0)
380336c92b2SDaniel Bristot de Oliveira 		err_msg("Error disabling %s:%s trigger %s\n", tevent->system,
381336c92b2SDaniel Bristot de Oliveira 			tevent->event ? : "*", tevent->trigger);
382336c92b2SDaniel Bristot de Oliveira }
383336c92b2SDaniel Bristot de Oliveira 
384336c92b2SDaniel Bristot de Oliveira /*
385b5aa0be2SDaniel Bristot de Oliveira  * trace_events_disable - disable all trace events
386b5aa0be2SDaniel Bristot de Oliveira  */
trace_events_disable(struct trace_instance * instance,struct trace_events * events)387b5aa0be2SDaniel Bristot de Oliveira void trace_events_disable(struct trace_instance *instance,
388b5aa0be2SDaniel Bristot de Oliveira 			  struct trace_events *events)
389b5aa0be2SDaniel Bristot de Oliveira {
390b5aa0be2SDaniel Bristot de Oliveira 	struct trace_events *tevent = events;
391b5aa0be2SDaniel Bristot de Oliveira 
392b5aa0be2SDaniel Bristot de Oliveira 	if (!events)
393b5aa0be2SDaniel Bristot de Oliveira 		return;
394b5aa0be2SDaniel Bristot de Oliveira 
395b5aa0be2SDaniel Bristot de Oliveira 	while (tevent) {
396b5aa0be2SDaniel Bristot de Oliveira 		debug_msg("Disabling event %s:%s\n", tevent->system, tevent->event ? : "*");
397336c92b2SDaniel Bristot de Oliveira 		if (tevent->enabled) {
3985487b6ceSDaniel Bristot de Oliveira 			trace_event_disable_filter(instance, tevent);
399336c92b2SDaniel Bristot de Oliveira 			trace_event_disable_trigger(instance, tevent);
400b5aa0be2SDaniel Bristot de Oliveira 			tracefs_event_disable(instance->inst, tevent->system, tevent->event);
401336c92b2SDaniel Bristot de Oliveira 		}
402b5aa0be2SDaniel Bristot de Oliveira 
403b5aa0be2SDaniel Bristot de Oliveira 		tevent->enabled = 0;
404b5aa0be2SDaniel Bristot de Oliveira 		tevent = tevent->next;
405b5aa0be2SDaniel Bristot de Oliveira 	}
406b5aa0be2SDaniel Bristot de Oliveira }
407b5aa0be2SDaniel Bristot de Oliveira 
408b5aa0be2SDaniel Bristot de Oliveira /*
4095487b6ceSDaniel Bristot de Oliveira  * trace_event_enable_filter - enable an event filter associated with an event
4105487b6ceSDaniel Bristot de Oliveira  */
trace_event_enable_filter(struct trace_instance * instance,struct trace_events * tevent)4115487b6ceSDaniel Bristot de Oliveira static int trace_event_enable_filter(struct trace_instance *instance,
4125487b6ceSDaniel Bristot de Oliveira 				     struct trace_events *tevent)
4135487b6ceSDaniel Bristot de Oliveira {
4145487b6ceSDaniel Bristot de Oliveira 	char filter[1024];
4155487b6ceSDaniel Bristot de Oliveira 	int retval;
4165487b6ceSDaniel Bristot de Oliveira 
4175487b6ceSDaniel Bristot de Oliveira 	if (!tevent->filter)
4185487b6ceSDaniel Bristot de Oliveira 		return 0;
4195487b6ceSDaniel Bristot de Oliveira 
4205487b6ceSDaniel Bristot de Oliveira 	if (!tevent->event) {
4215487b6ceSDaniel Bristot de Oliveira 		err_msg("Filter %s applies only for single events, not for all %s:* events\n",
4225487b6ceSDaniel Bristot de Oliveira 			tevent->filter, tevent->system);
4235487b6ceSDaniel Bristot de Oliveira 		return 1;
4245487b6ceSDaniel Bristot de Oliveira 	}
4255487b6ceSDaniel Bristot de Oliveira 
4265487b6ceSDaniel Bristot de Oliveira 	snprintf(filter, 1024, "%s\n", tevent->filter);
4275487b6ceSDaniel Bristot de Oliveira 
4285487b6ceSDaniel Bristot de Oliveira 	debug_msg("Enabling %s:%s filter %s\n", tevent->system,
4295487b6ceSDaniel Bristot de Oliveira 		  tevent->event ? : "*", tevent->filter);
4305487b6ceSDaniel Bristot de Oliveira 
4315487b6ceSDaniel Bristot de Oliveira 	retval = tracefs_event_file_write(instance->inst, tevent->system,
4325487b6ceSDaniel Bristot de Oliveira 					  tevent->event, "filter", filter);
4335487b6ceSDaniel Bristot de Oliveira 	if (retval < 0) {
4345487b6ceSDaniel Bristot de Oliveira 		err_msg("Error enabling %s:%s filter %s\n", tevent->system,
4355487b6ceSDaniel Bristot de Oliveira 			tevent->event ? : "*", tevent->filter);
4365487b6ceSDaniel Bristot de Oliveira 		return 1;
4375487b6ceSDaniel Bristot de Oliveira 	}
4385487b6ceSDaniel Bristot de Oliveira 
4395487b6ceSDaniel Bristot de Oliveira 	tevent->filter_enabled = 1;
4405487b6ceSDaniel Bristot de Oliveira 	return 0;
4415487b6ceSDaniel Bristot de Oliveira }
4425487b6ceSDaniel Bristot de Oliveira 
4435487b6ceSDaniel Bristot de Oliveira /*
444336c92b2SDaniel Bristot de Oliveira  * trace_event_enable_trigger - enable an event trigger associated with an event
445336c92b2SDaniel Bristot de Oliveira  */
trace_event_enable_trigger(struct trace_instance * instance,struct trace_events * tevent)446336c92b2SDaniel Bristot de Oliveira static int trace_event_enable_trigger(struct trace_instance *instance,
447336c92b2SDaniel Bristot de Oliveira 				      struct trace_events *tevent)
448336c92b2SDaniel Bristot de Oliveira {
449336c92b2SDaniel Bristot de Oliveira 	char trigger[1024];
450336c92b2SDaniel Bristot de Oliveira 	int retval;
451336c92b2SDaniel Bristot de Oliveira 
452336c92b2SDaniel Bristot de Oliveira 	if (!tevent->trigger)
453336c92b2SDaniel Bristot de Oliveira 		return 0;
454336c92b2SDaniel Bristot de Oliveira 
455336c92b2SDaniel Bristot de Oliveira 	if (!tevent->event) {
456336c92b2SDaniel Bristot de Oliveira 		err_msg("Trigger %s applies only for single events, not for all %s:* events\n",
457336c92b2SDaniel Bristot de Oliveira 			tevent->trigger, tevent->system);
458336c92b2SDaniel Bristot de Oliveira 		return 1;
459336c92b2SDaniel Bristot de Oliveira 	}
460336c92b2SDaniel Bristot de Oliveira 
461336c92b2SDaniel Bristot de Oliveira 	snprintf(trigger, 1024, "%s\n", tevent->trigger);
462336c92b2SDaniel Bristot de Oliveira 
463336c92b2SDaniel Bristot de Oliveira 	debug_msg("Enabling %s:%s trigger %s\n", tevent->system,
464336c92b2SDaniel Bristot de Oliveira 		  tevent->event ? : "*", tevent->trigger);
465336c92b2SDaniel Bristot de Oliveira 
466336c92b2SDaniel Bristot de Oliveira 	retval = tracefs_event_file_write(instance->inst, tevent->system,
467336c92b2SDaniel Bristot de Oliveira 					  tevent->event, "trigger", trigger);
468336c92b2SDaniel Bristot de Oliveira 	if (retval < 0) {
469336c92b2SDaniel Bristot de Oliveira 		err_msg("Error enabling %s:%s trigger %s\n", tevent->system,
470336c92b2SDaniel Bristot de Oliveira 			tevent->event ? : "*", tevent->trigger);
471336c92b2SDaniel Bristot de Oliveira 		return 1;
472336c92b2SDaniel Bristot de Oliveira 	}
473336c92b2SDaniel Bristot de Oliveira 
474336c92b2SDaniel Bristot de Oliveira 	tevent->trigger_enabled = 1;
475336c92b2SDaniel Bristot de Oliveira 
476336c92b2SDaniel Bristot de Oliveira 	return 0;
477336c92b2SDaniel Bristot de Oliveira }
478336c92b2SDaniel Bristot de Oliveira 
479336c92b2SDaniel Bristot de Oliveira /*
480b5aa0be2SDaniel Bristot de Oliveira  * trace_events_enable - enable all events
481b5aa0be2SDaniel Bristot de Oliveira  */
trace_events_enable(struct trace_instance * instance,struct trace_events * events)482b5aa0be2SDaniel Bristot de Oliveira int trace_events_enable(struct trace_instance *instance,
483b5aa0be2SDaniel Bristot de Oliveira 			struct trace_events *events)
484b5aa0be2SDaniel Bristot de Oliveira {
485b5aa0be2SDaniel Bristot de Oliveira 	struct trace_events *tevent = events;
486b5aa0be2SDaniel Bristot de Oliveira 	int retval;
487b5aa0be2SDaniel Bristot de Oliveira 
488b5aa0be2SDaniel Bristot de Oliveira 	while (tevent) {
489b5aa0be2SDaniel Bristot de Oliveira 		debug_msg("Enabling event %s:%s\n", tevent->system, tevent->event ? : "*");
490b5aa0be2SDaniel Bristot de Oliveira 		retval = tracefs_event_enable(instance->inst, tevent->system, tevent->event);
491b5aa0be2SDaniel Bristot de Oliveira 		if (retval < 0) {
492b5aa0be2SDaniel Bristot de Oliveira 			err_msg("Error enabling event %s:%s\n", tevent->system,
493b5aa0be2SDaniel Bristot de Oliveira 				tevent->event ? : "*");
494b5aa0be2SDaniel Bristot de Oliveira 			return 1;
495b5aa0be2SDaniel Bristot de Oliveira 		}
496b5aa0be2SDaniel Bristot de Oliveira 
4975487b6ceSDaniel Bristot de Oliveira 		retval = trace_event_enable_filter(instance, tevent);
4985487b6ceSDaniel Bristot de Oliveira 		if (retval)
4995487b6ceSDaniel Bristot de Oliveira 			return 1;
500b5aa0be2SDaniel Bristot de Oliveira 
501336c92b2SDaniel Bristot de Oliveira 		retval = trace_event_enable_trigger(instance, tevent);
502336c92b2SDaniel Bristot de Oliveira 		if (retval)
503336c92b2SDaniel Bristot de Oliveira 			return 1;
504336c92b2SDaniel Bristot de Oliveira 
505b5aa0be2SDaniel Bristot de Oliveira 		tevent->enabled = 1;
506b5aa0be2SDaniel Bristot de Oliveira 		tevent = tevent->next;
507b5aa0be2SDaniel Bristot de Oliveira 	}
508b5aa0be2SDaniel Bristot de Oliveira 
509b5aa0be2SDaniel Bristot de Oliveira 	return 0;
510b5aa0be2SDaniel Bristot de Oliveira }
511b5aa0be2SDaniel Bristot de Oliveira 
512b5aa0be2SDaniel Bristot de Oliveira /*
513b5aa0be2SDaniel Bristot de Oliveira  * trace_events_destroy - disable and free all trace events
514b5aa0be2SDaniel Bristot de Oliveira  */
trace_events_destroy(struct trace_instance * instance,struct trace_events * events)515b5aa0be2SDaniel Bristot de Oliveira void trace_events_destroy(struct trace_instance *instance,
516b5aa0be2SDaniel Bristot de Oliveira 			  struct trace_events *events)
517b5aa0be2SDaniel Bristot de Oliveira {
518b5aa0be2SDaniel Bristot de Oliveira 	if (!events)
519b5aa0be2SDaniel Bristot de Oliveira 		return;
520b5aa0be2SDaniel Bristot de Oliveira 
521b5aa0be2SDaniel Bristot de Oliveira 	trace_events_disable(instance, events);
522b5aa0be2SDaniel Bristot de Oliveira 	trace_events_free(events);
523b5aa0be2SDaniel Bristot de Oliveira }
52428d2160cSDaniel Bristot de Oliveira 
trace_is_off(struct trace_instance * tool,struct trace_instance * trace)52528d2160cSDaniel Bristot de Oliveira int trace_is_off(struct trace_instance *tool, struct trace_instance *trace)
52628d2160cSDaniel Bristot de Oliveira {
52728d2160cSDaniel Bristot de Oliveira 	/*
52828d2160cSDaniel Bristot de Oliveira 	 * The tool instance is always present, it is the one used to collect
52928d2160cSDaniel Bristot de Oliveira 	 * data.
53028d2160cSDaniel Bristot de Oliveira 	 */
53128d2160cSDaniel Bristot de Oliveira 	if (!tracefs_trace_is_on(tool->inst))
53228d2160cSDaniel Bristot de Oliveira 		return 1;
53328d2160cSDaniel Bristot de Oliveira 
53428d2160cSDaniel Bristot de Oliveira 	/*
53528d2160cSDaniel Bristot de Oliveira 	 * The trace instance is only enabled when -t is set. IOW, when the system
53628d2160cSDaniel Bristot de Oliveira 	 * is tracing.
53728d2160cSDaniel Bristot de Oliveira 	 */
53828d2160cSDaniel Bristot de Oliveira 	if (trace && !tracefs_trace_is_on(trace->inst))
53928d2160cSDaniel Bristot de Oliveira 		return 1;
54028d2160cSDaniel Bristot de Oliveira 
54128d2160cSDaniel Bristot de Oliveira 	return 0;
54228d2160cSDaniel Bristot de Oliveira }
543