xref: /aosp_15_r20/external/libtracefs/src/tracefs-hist.c (revision 287e80b3a36113050663245e7f2c00d274188f18)
1*287e80b3SSadaf Ebrahimi // SPDX-License-Identifier: LGPL-2.1
2*287e80b3SSadaf Ebrahimi /*
3*287e80b3SSadaf Ebrahimi  * Copyright (C) 2021 VMware Inc, Steven Rostedt <[email protected]>
4*287e80b3SSadaf Ebrahimi  *
5*287e80b3SSadaf Ebrahimi  * Updates:
6*287e80b3SSadaf Ebrahimi  * Copyright (C) 2021, VMware, Tzvetomir Stoyanov <[email protected]>
7*287e80b3SSadaf Ebrahimi  *
8*287e80b3SSadaf Ebrahimi  */
9*287e80b3SSadaf Ebrahimi #include <stdio.h>
10*287e80b3SSadaf Ebrahimi #include <stdlib.h>
11*287e80b3SSadaf Ebrahimi #include <dirent.h>
12*287e80b3SSadaf Ebrahimi #include <unistd.h>
13*287e80b3SSadaf Ebrahimi #include <errno.h>
14*287e80b3SSadaf Ebrahimi #include <fcntl.h>
15*287e80b3SSadaf Ebrahimi #include <limits.h>
16*287e80b3SSadaf Ebrahimi #include <sys/time.h>
17*287e80b3SSadaf Ebrahimi #include <sys/types.h>
18*287e80b3SSadaf Ebrahimi 
19*287e80b3SSadaf Ebrahimi #include "tracefs.h"
20*287e80b3SSadaf Ebrahimi #include "tracefs-local.h"
21*287e80b3SSadaf Ebrahimi 
22*287e80b3SSadaf Ebrahimi #define HIST_FILE "hist"
23*287e80b3SSadaf Ebrahimi 
24*287e80b3SSadaf Ebrahimi #define ASCENDING ".ascending"
25*287e80b3SSadaf Ebrahimi #define DESCENDING ".descending"
26*287e80b3SSadaf Ebrahimi 
27*287e80b3SSadaf Ebrahimi #define SYNTHETIC_GROUP "synthetic"
28*287e80b3SSadaf Ebrahimi 
29*287e80b3SSadaf Ebrahimi struct tracefs_hist {
30*287e80b3SSadaf Ebrahimi 	struct tep_handle	*tep;
31*287e80b3SSadaf Ebrahimi 	struct tep_event	*event;
32*287e80b3SSadaf Ebrahimi 	char			*system;
33*287e80b3SSadaf Ebrahimi 	char			*event_name;
34*287e80b3SSadaf Ebrahimi 	char			*name;
35*287e80b3SSadaf Ebrahimi 	char			**keys;
36*287e80b3SSadaf Ebrahimi 	char			**values;
37*287e80b3SSadaf Ebrahimi 	char			**sort;
38*287e80b3SSadaf Ebrahimi 	char			*filter;
39*287e80b3SSadaf Ebrahimi 	int			size;
40*287e80b3SSadaf Ebrahimi 	unsigned int		filter_parens;
41*287e80b3SSadaf Ebrahimi 	unsigned int		filter_state;
42*287e80b3SSadaf Ebrahimi };
43*287e80b3SSadaf Ebrahimi 
44*287e80b3SSadaf Ebrahimi /*
45*287e80b3SSadaf Ebrahimi  * tracefs_hist_get_name - get the name of the histogram
46*287e80b3SSadaf Ebrahimi  * @hist: The histogram to get the name for
47*287e80b3SSadaf Ebrahimi  *
48*287e80b3SSadaf Ebrahimi  * Returns name string owned by @hist on success, or NULL on error.
49*287e80b3SSadaf Ebrahimi  */
tracefs_hist_get_name(struct tracefs_hist * hist)50*287e80b3SSadaf Ebrahimi const char *tracefs_hist_get_name(struct tracefs_hist *hist)
51*287e80b3SSadaf Ebrahimi {
52*287e80b3SSadaf Ebrahimi 	return hist ? hist->name : NULL;
53*287e80b3SSadaf Ebrahimi }
54*287e80b3SSadaf Ebrahimi 
55*287e80b3SSadaf Ebrahimi /*
56*287e80b3SSadaf Ebrahimi  * tracefs_hist_get_event - get the event name of the histogram
57*287e80b3SSadaf Ebrahimi  * @hist: The histogram to get the event name for
58*287e80b3SSadaf Ebrahimi  *
59*287e80b3SSadaf Ebrahimi  * Returns event name string owned by @hist on success, or NULL on error.
60*287e80b3SSadaf Ebrahimi  */
tracefs_hist_get_event(struct tracefs_hist * hist)61*287e80b3SSadaf Ebrahimi const char *tracefs_hist_get_event(struct tracefs_hist *hist)
62*287e80b3SSadaf Ebrahimi {
63*287e80b3SSadaf Ebrahimi 	return hist ? hist->event_name : NULL;
64*287e80b3SSadaf Ebrahimi }
65*287e80b3SSadaf Ebrahimi 
66*287e80b3SSadaf Ebrahimi /*
67*287e80b3SSadaf Ebrahimi  * tracefs_hist_get_system - get the system name of the histogram
68*287e80b3SSadaf Ebrahimi  * @hist: The histogram to get the system name for
69*287e80b3SSadaf Ebrahimi  *
70*287e80b3SSadaf Ebrahimi  * Returns system name string owned by @hist on success, or NULL on error.
71*287e80b3SSadaf Ebrahimi  */
tracefs_hist_get_system(struct tracefs_hist * hist)72*287e80b3SSadaf Ebrahimi const char *tracefs_hist_get_system(struct tracefs_hist *hist)
73*287e80b3SSadaf Ebrahimi {
74*287e80b3SSadaf Ebrahimi 	return hist ? hist->system : NULL;
75*287e80b3SSadaf Ebrahimi }
76*287e80b3SSadaf Ebrahimi 
add_list(struct trace_seq * seq,const char * start,char ** list)77*287e80b3SSadaf Ebrahimi static void add_list(struct trace_seq *seq, const char *start,
78*287e80b3SSadaf Ebrahimi 		     char **list)
79*287e80b3SSadaf Ebrahimi {
80*287e80b3SSadaf Ebrahimi 	int i;
81*287e80b3SSadaf Ebrahimi 
82*287e80b3SSadaf Ebrahimi 	trace_seq_puts(seq, start);
83*287e80b3SSadaf Ebrahimi 	for (i = 0; list[i]; i++) {
84*287e80b3SSadaf Ebrahimi 		if (i)
85*287e80b3SSadaf Ebrahimi 			trace_seq_putc(seq, ',');
86*287e80b3SSadaf Ebrahimi 		trace_seq_puts(seq, list[i]);
87*287e80b3SSadaf Ebrahimi 	}
88*287e80b3SSadaf Ebrahimi }
89*287e80b3SSadaf Ebrahimi 
add_hist_commands(struct trace_seq * seq,struct tracefs_hist * hist,enum tracefs_hist_command command)90*287e80b3SSadaf Ebrahimi static void add_hist_commands(struct trace_seq *seq, struct tracefs_hist *hist,
91*287e80b3SSadaf Ebrahimi 			     enum tracefs_hist_command command)
92*287e80b3SSadaf Ebrahimi {
93*287e80b3SSadaf Ebrahimi 	if (command == TRACEFS_HIST_CMD_DESTROY)
94*287e80b3SSadaf Ebrahimi 		trace_seq_putc(seq, '!');
95*287e80b3SSadaf Ebrahimi 
96*287e80b3SSadaf Ebrahimi 	add_list(seq, "hist:keys=", hist->keys);
97*287e80b3SSadaf Ebrahimi 
98*287e80b3SSadaf Ebrahimi 	if (hist->values)
99*287e80b3SSadaf Ebrahimi 		add_list(seq, ":vals=", hist->values);
100*287e80b3SSadaf Ebrahimi 
101*287e80b3SSadaf Ebrahimi 	if (hist->sort)
102*287e80b3SSadaf Ebrahimi 		add_list(seq, ":sort=", hist->sort);
103*287e80b3SSadaf Ebrahimi 
104*287e80b3SSadaf Ebrahimi 	if (hist->size)
105*287e80b3SSadaf Ebrahimi 		trace_seq_printf(seq, ":size=%d", hist->size);
106*287e80b3SSadaf Ebrahimi 
107*287e80b3SSadaf Ebrahimi 	switch(command) {
108*287e80b3SSadaf Ebrahimi 	case TRACEFS_HIST_CMD_START: break;
109*287e80b3SSadaf Ebrahimi 	case TRACEFS_HIST_CMD_PAUSE: trace_seq_puts(seq, ":pause"); break;
110*287e80b3SSadaf Ebrahimi 	case TRACEFS_HIST_CMD_CONT: trace_seq_puts(seq, ":cont"); break;
111*287e80b3SSadaf Ebrahimi 	case TRACEFS_HIST_CMD_CLEAR: trace_seq_puts(seq, ":clear"); break;
112*287e80b3SSadaf Ebrahimi 	default: break;
113*287e80b3SSadaf Ebrahimi 	}
114*287e80b3SSadaf Ebrahimi 
115*287e80b3SSadaf Ebrahimi 	if (hist->name)
116*287e80b3SSadaf Ebrahimi 		trace_seq_printf(seq, ":name=%s", hist->name);
117*287e80b3SSadaf Ebrahimi 
118*287e80b3SSadaf Ebrahimi 	if (hist->filter)
119*287e80b3SSadaf Ebrahimi 		trace_seq_printf(seq, " if %s", hist->filter);
120*287e80b3SSadaf Ebrahimi 
121*287e80b3SSadaf Ebrahimi }
122*287e80b3SSadaf Ebrahimi 
123*287e80b3SSadaf Ebrahimi /*
124*287e80b3SSadaf Ebrahimi  * trace_hist_echo_cmd - show how to start the histogram
125*287e80b3SSadaf Ebrahimi  * @seq: A trace_seq to store the commands to create
126*287e80b3SSadaf Ebrahimi  * @hist: The histogram to write into the trigger file
127*287e80b3SSadaf Ebrahimi  * @command: If not zero, can pause, continue or clear the histogram
128*287e80b3SSadaf Ebrahimi  *
129*287e80b3SSadaf Ebrahimi  * This shows the echo commands to create the histogram for an event
130*287e80b3SSadaf Ebrahimi  * with the given fields.
131*287e80b3SSadaf Ebrahimi  *
132*287e80b3SSadaf Ebrahimi  * Returns 0 on succes -1 on error.
133*287e80b3SSadaf Ebrahimi  */
134*287e80b3SSadaf Ebrahimi int
tracefs_hist_echo_cmd(struct trace_seq * seq,struct tracefs_instance * instance,struct tracefs_hist * hist,enum tracefs_hist_command command)135*287e80b3SSadaf Ebrahimi tracefs_hist_echo_cmd(struct trace_seq *seq, struct tracefs_instance *instance,
136*287e80b3SSadaf Ebrahimi 		      struct tracefs_hist *hist,
137*287e80b3SSadaf Ebrahimi 		      enum tracefs_hist_command command)
138*287e80b3SSadaf Ebrahimi {
139*287e80b3SSadaf Ebrahimi 	const char *system = hist->system;
140*287e80b3SSadaf Ebrahimi 	const char *event = hist->event_name;
141*287e80b3SSadaf Ebrahimi 	char *path;
142*287e80b3SSadaf Ebrahimi 
143*287e80b3SSadaf Ebrahimi 	if (!hist->keys) {
144*287e80b3SSadaf Ebrahimi 		errno = -EINVAL;
145*287e80b3SSadaf Ebrahimi 		return -1;
146*287e80b3SSadaf Ebrahimi 	}
147*287e80b3SSadaf Ebrahimi 
148*287e80b3SSadaf Ebrahimi 	path = tracefs_event_get_file(instance, system, event, "trigger");
149*287e80b3SSadaf Ebrahimi 	if (!path)
150*287e80b3SSadaf Ebrahimi 		return -1;
151*287e80b3SSadaf Ebrahimi 
152*287e80b3SSadaf Ebrahimi 	trace_seq_puts(seq, "echo '");
153*287e80b3SSadaf Ebrahimi 
154*287e80b3SSadaf Ebrahimi 	add_hist_commands(seq, hist, command);
155*287e80b3SSadaf Ebrahimi 
156*287e80b3SSadaf Ebrahimi 	trace_seq_printf(seq, "' > %s\n", path);
157*287e80b3SSadaf Ebrahimi 
158*287e80b3SSadaf Ebrahimi 	tracefs_put_tracing_file(path);
159*287e80b3SSadaf Ebrahimi 
160*287e80b3SSadaf Ebrahimi 	return 0;
161*287e80b3SSadaf Ebrahimi }
162*287e80b3SSadaf Ebrahimi 
163*287e80b3SSadaf Ebrahimi /*
164*287e80b3SSadaf Ebrahimi  * tracefs_hist_command - Create, start, pause, destroy a histogram for an event
165*287e80b3SSadaf Ebrahimi  * @instance: The instance the histogram will be in (NULL for toplevel)
166*287e80b3SSadaf Ebrahimi  * @hist: The histogram to write into the trigger file
167*287e80b3SSadaf Ebrahimi  * @command: Command to perform on a histogram.
168*287e80b3SSadaf Ebrahimi  *
169*287e80b3SSadaf Ebrahimi  * Creates, pause, continue, clears, or destroys a histogram.
170*287e80b3SSadaf Ebrahimi  *
171*287e80b3SSadaf Ebrahimi  * Returns 0 on succes -1 on error.
172*287e80b3SSadaf Ebrahimi  */
tracefs_hist_command(struct tracefs_instance * instance,struct tracefs_hist * hist,enum tracefs_hist_command command)173*287e80b3SSadaf Ebrahimi int tracefs_hist_command(struct tracefs_instance *instance,
174*287e80b3SSadaf Ebrahimi 			 struct tracefs_hist *hist,
175*287e80b3SSadaf Ebrahimi 			 enum tracefs_hist_command command)
176*287e80b3SSadaf Ebrahimi {
177*287e80b3SSadaf Ebrahimi 	const char *system = hist->system;
178*287e80b3SSadaf Ebrahimi 	const char *event = hist->event_name;
179*287e80b3SSadaf Ebrahimi 	struct trace_seq seq;
180*287e80b3SSadaf Ebrahimi 	int ret;
181*287e80b3SSadaf Ebrahimi 
182*287e80b3SSadaf Ebrahimi 	if (!tracefs_event_file_exists(instance, system, event, HIST_FILE))
183*287e80b3SSadaf Ebrahimi 		return -1;
184*287e80b3SSadaf Ebrahimi 
185*287e80b3SSadaf Ebrahimi 	errno = -EINVAL;
186*287e80b3SSadaf Ebrahimi 	if (!hist->keys)
187*287e80b3SSadaf Ebrahimi 		return -1;
188*287e80b3SSadaf Ebrahimi 
189*287e80b3SSadaf Ebrahimi 	trace_seq_init(&seq);
190*287e80b3SSadaf Ebrahimi 
191*287e80b3SSadaf Ebrahimi 	add_hist_commands(&seq, hist, command);
192*287e80b3SSadaf Ebrahimi 
193*287e80b3SSadaf Ebrahimi 	trace_seq_putc(&seq, '\n');
194*287e80b3SSadaf Ebrahimi 	trace_seq_terminate(&seq);
195*287e80b3SSadaf Ebrahimi 
196*287e80b3SSadaf Ebrahimi 	ret = -1;
197*287e80b3SSadaf Ebrahimi 	if (seq.state == TRACE_SEQ__GOOD)
198*287e80b3SSadaf Ebrahimi 		ret = tracefs_event_file_append(instance, system, event,
199*287e80b3SSadaf Ebrahimi 						"trigger", seq.buffer);
200*287e80b3SSadaf Ebrahimi 
201*287e80b3SSadaf Ebrahimi 	trace_seq_destroy(&seq);
202*287e80b3SSadaf Ebrahimi 
203*287e80b3SSadaf Ebrahimi 	return ret < 0 ? -1 : 0;
204*287e80b3SSadaf Ebrahimi }
205*287e80b3SSadaf Ebrahimi 
206*287e80b3SSadaf Ebrahimi /**
207*287e80b3SSadaf Ebrahimi  * tracefs_hist_free - free a tracefs_hist element
208*287e80b3SSadaf Ebrahimi  * @hist: The histogram to free
209*287e80b3SSadaf Ebrahimi  */
tracefs_hist_free(struct tracefs_hist * hist)210*287e80b3SSadaf Ebrahimi void tracefs_hist_free(struct tracefs_hist *hist)
211*287e80b3SSadaf Ebrahimi {
212*287e80b3SSadaf Ebrahimi 	if (!hist)
213*287e80b3SSadaf Ebrahimi 		return;
214*287e80b3SSadaf Ebrahimi 
215*287e80b3SSadaf Ebrahimi 	tep_unref(hist->tep);
216*287e80b3SSadaf Ebrahimi 	free(hist->system);
217*287e80b3SSadaf Ebrahimi 	free(hist->event_name);
218*287e80b3SSadaf Ebrahimi 	free(hist->name);
219*287e80b3SSadaf Ebrahimi 	free(hist->filter);
220*287e80b3SSadaf Ebrahimi 	tracefs_list_free(hist->keys);
221*287e80b3SSadaf Ebrahimi 	tracefs_list_free(hist->values);
222*287e80b3SSadaf Ebrahimi 	tracefs_list_free(hist->sort);
223*287e80b3SSadaf Ebrahimi 	free(hist);
224*287e80b3SSadaf Ebrahimi }
225*287e80b3SSadaf Ebrahimi 
226*287e80b3SSadaf Ebrahimi /**
227*287e80b3SSadaf Ebrahimi  * tracefs_hist_alloc - Initialize one-dimensional histogram
228*287e80b3SSadaf Ebrahimi  * @tep: The tep handle that has the @system and @event.
229*287e80b3SSadaf Ebrahimi  * @system: The system the histogram event is in.
230*287e80b3SSadaf Ebrahimi  * @event_name: The name of the event that the histogram will be attached to.
231*287e80b3SSadaf Ebrahimi  * @key: The primary key the histogram will use
232*287e80b3SSadaf Ebrahimi  * @type: The format type of the key.
233*287e80b3SSadaf Ebrahimi  *
234*287e80b3SSadaf Ebrahimi  * Will initialize a histogram descriptor that will be attached to
235*287e80b3SSadaf Ebrahimi  * the @system/@event with the given @key as the primary. This only
236*287e80b3SSadaf Ebrahimi  * initializes the descriptor, it does not start the histogram
237*287e80b3SSadaf Ebrahimi  * in the kernel.
238*287e80b3SSadaf Ebrahimi  *
239*287e80b3SSadaf Ebrahimi  * Returns an initialized histogram on success.
240*287e80b3SSadaf Ebrahimi  * NULL on failure.
241*287e80b3SSadaf Ebrahimi  */
242*287e80b3SSadaf Ebrahimi struct tracefs_hist *
tracefs_hist_alloc(struct tep_handle * tep,const char * system,const char * event_name,const char * key,enum tracefs_hist_key_type type)243*287e80b3SSadaf Ebrahimi tracefs_hist_alloc(struct tep_handle *tep,
244*287e80b3SSadaf Ebrahimi 		   const char *system, const char *event_name,
245*287e80b3SSadaf Ebrahimi 		   const char *key, enum tracefs_hist_key_type type)
246*287e80b3SSadaf Ebrahimi {
247*287e80b3SSadaf Ebrahimi 	struct tracefs_hist_axis axis[] = {{key, type}, {NULL, 0}};
248*287e80b3SSadaf Ebrahimi 
249*287e80b3SSadaf Ebrahimi 	return tracefs_hist_alloc_nd(tep, system, event_name, axis);
250*287e80b3SSadaf Ebrahimi }
251*287e80b3SSadaf Ebrahimi 
252*287e80b3SSadaf Ebrahimi /**
253*287e80b3SSadaf Ebrahimi  * tracefs_hist_alloc_2d - Initialize two-dimensional histogram
254*287e80b3SSadaf Ebrahimi  * @tep: The tep handle that has the @system and @event.
255*287e80b3SSadaf Ebrahimi  * @system: The system the histogram event is in.
256*287e80b3SSadaf Ebrahimi  * @event: The event that the histogram will be attached to.
257*287e80b3SSadaf Ebrahimi  * @key1: The first primary key the histogram will use
258*287e80b3SSadaf Ebrahimi  * @type1: The format type of the first key.
259*287e80b3SSadaf Ebrahimi  * @key2: The second primary key the histogram will use
260*287e80b3SSadaf Ebrahimi  * @type2: The format type of the second key.
261*287e80b3SSadaf Ebrahimi  *
262*287e80b3SSadaf Ebrahimi  * Will initialize a histogram descriptor that will be attached to
263*287e80b3SSadaf Ebrahimi  * the @system/@event with the given @key1 and @key2 as the primaries.
264*287e80b3SSadaf Ebrahimi  * This only initializes the descriptor, it does not start the histogram
265*287e80b3SSadaf Ebrahimi  * in the kernel.
266*287e80b3SSadaf Ebrahimi  *
267*287e80b3SSadaf Ebrahimi  * Returns an initialized histogram on success.
268*287e80b3SSadaf Ebrahimi  * NULL on failure.
269*287e80b3SSadaf Ebrahimi  */
270*287e80b3SSadaf Ebrahimi struct tracefs_hist *
tracefs_hist_alloc_2d(struct tep_handle * tep,const char * system,const char * event_name,const char * key1,enum tracefs_hist_key_type type1,const char * key2,enum tracefs_hist_key_type type2)271*287e80b3SSadaf Ebrahimi tracefs_hist_alloc_2d(struct tep_handle *tep,
272*287e80b3SSadaf Ebrahimi 		      const char *system, const char *event_name,
273*287e80b3SSadaf Ebrahimi 		      const char *key1, enum tracefs_hist_key_type type1,
274*287e80b3SSadaf Ebrahimi 		      const char *key2, enum tracefs_hist_key_type type2)
275*287e80b3SSadaf Ebrahimi {
276*287e80b3SSadaf Ebrahimi 	struct tracefs_hist_axis axis[] = {{key1, type1},
277*287e80b3SSadaf Ebrahimi 					   {key2, type2},
278*287e80b3SSadaf Ebrahimi 					   {NULL, 0}};
279*287e80b3SSadaf Ebrahimi 
280*287e80b3SSadaf Ebrahimi 	return tracefs_hist_alloc_nd(tep, system, event_name, axis);
281*287e80b3SSadaf Ebrahimi }
282*287e80b3SSadaf Ebrahimi 
283*287e80b3SSadaf Ebrahimi static struct tracefs_hist *
hist_alloc_nd(struct tep_handle * tep,const char * system,const char * event_name,struct tracefs_hist_axis * axes,struct tracefs_hist_axis_cnt * axes_cnt)284*287e80b3SSadaf Ebrahimi hist_alloc_nd(struct tep_handle *tep,
285*287e80b3SSadaf Ebrahimi 	      const char *system, const char *event_name,
286*287e80b3SSadaf Ebrahimi 	      struct tracefs_hist_axis *axes,
287*287e80b3SSadaf Ebrahimi 	      struct tracefs_hist_axis_cnt *axes_cnt)
288*287e80b3SSadaf Ebrahimi {
289*287e80b3SSadaf Ebrahimi 	struct tep_event *event;
290*287e80b3SSadaf Ebrahimi 	struct tracefs_hist *hist;
291*287e80b3SSadaf Ebrahimi 
292*287e80b3SSadaf Ebrahimi 	if (!system || !event_name)
293*287e80b3SSadaf Ebrahimi 		return NULL;
294*287e80b3SSadaf Ebrahimi 
295*287e80b3SSadaf Ebrahimi 	event = tep_find_event_by_name(tep, system, event_name);
296*287e80b3SSadaf Ebrahimi 	if (!event)
297*287e80b3SSadaf Ebrahimi 		return NULL;
298*287e80b3SSadaf Ebrahimi 
299*287e80b3SSadaf Ebrahimi 	hist = calloc(1, sizeof(*hist));
300*287e80b3SSadaf Ebrahimi 	if (!hist)
301*287e80b3SSadaf Ebrahimi 		return NULL;
302*287e80b3SSadaf Ebrahimi 
303*287e80b3SSadaf Ebrahimi 	tep_ref(tep);
304*287e80b3SSadaf Ebrahimi 	hist->tep = tep;
305*287e80b3SSadaf Ebrahimi 	hist->event = event;
306*287e80b3SSadaf Ebrahimi 	hist->system = strdup(system);
307*287e80b3SSadaf Ebrahimi 	hist->event_name = strdup(event_name);
308*287e80b3SSadaf Ebrahimi 	if (!hist->system || !hist->event_name)
309*287e80b3SSadaf Ebrahimi 		goto fail;
310*287e80b3SSadaf Ebrahimi 
311*287e80b3SSadaf Ebrahimi 	for (; axes && axes->key; axes++)
312*287e80b3SSadaf Ebrahimi 		if (tracefs_hist_add_key(hist, axes->key, axes->type) < 0)
313*287e80b3SSadaf Ebrahimi 			goto fail;
314*287e80b3SSadaf Ebrahimi 
315*287e80b3SSadaf Ebrahimi 	for (; axes_cnt && axes_cnt->key; axes_cnt++)
316*287e80b3SSadaf Ebrahimi 		if (tracefs_hist_add_key_cnt(hist, axes_cnt->key, axes_cnt->type, axes_cnt->cnt) < 0)
317*287e80b3SSadaf Ebrahimi 			goto fail;
318*287e80b3SSadaf Ebrahimi 
319*287e80b3SSadaf Ebrahimi 	return hist;
320*287e80b3SSadaf Ebrahimi 
321*287e80b3SSadaf Ebrahimi  fail:
322*287e80b3SSadaf Ebrahimi 	tracefs_hist_free(hist);
323*287e80b3SSadaf Ebrahimi 	return NULL;
324*287e80b3SSadaf Ebrahimi }
325*287e80b3SSadaf Ebrahimi /**
326*287e80b3SSadaf Ebrahimi  * tracefs_hist_alloc_nd - Initialize N-dimensional histogram
327*287e80b3SSadaf Ebrahimi  * @tep: The tep handle that has the @system and @event.
328*287e80b3SSadaf Ebrahimi  * @system: The system the histogram event is in
329*287e80b3SSadaf Ebrahimi  * @event: The event that the histogram will be attached to
330*287e80b3SSadaf Ebrahimi  * @axes: An array of histogram axes, terminated by a {NULL, 0} entry
331*287e80b3SSadaf Ebrahimi  *
332*287e80b3SSadaf Ebrahimi  * Will initialize a histogram descriptor that will be attached to
333*287e80b3SSadaf Ebrahimi  * the @system/@event. This only initializes the descriptor with the given
334*287e80b3SSadaf Ebrahimi  * @axes keys as primaries. This only initializes the descriptor, it does
335*287e80b3SSadaf Ebrahimi  * not start the histogram in the kernel.
336*287e80b3SSadaf Ebrahimi  *
337*287e80b3SSadaf Ebrahimi  * Returns an initialized histogram on success.
338*287e80b3SSadaf Ebrahimi  * NULL on failure.
339*287e80b3SSadaf Ebrahimi  */
340*287e80b3SSadaf Ebrahimi struct tracefs_hist *
tracefs_hist_alloc_nd(struct tep_handle * tep,const char * system,const char * event_name,struct tracefs_hist_axis * axes)341*287e80b3SSadaf Ebrahimi tracefs_hist_alloc_nd(struct tep_handle *tep,
342*287e80b3SSadaf Ebrahimi 		      const char *system, const char *event_name,
343*287e80b3SSadaf Ebrahimi 		      struct tracefs_hist_axis *axes)
344*287e80b3SSadaf Ebrahimi {
345*287e80b3SSadaf Ebrahimi 	return hist_alloc_nd(tep, system, event_name, axes, NULL);
346*287e80b3SSadaf Ebrahimi }
347*287e80b3SSadaf Ebrahimi 
348*287e80b3SSadaf Ebrahimi /**
349*287e80b3SSadaf Ebrahimi  * tracefs_hist_alloc_nd_cnt - Initialize N-dimensional histogram
350*287e80b3SSadaf Ebrahimi  * @tep: The tep handle that has the @system and @event.
351*287e80b3SSadaf Ebrahimi  * @system: The system the histogram event is in
352*287e80b3SSadaf Ebrahimi  * @event: The event that the histogram will be attached to
353*287e80b3SSadaf Ebrahimi  * @axes: An array of histogram axes, terminated by a {NULL, 0} entry
354*287e80b3SSadaf Ebrahimi  *
355*287e80b3SSadaf Ebrahimi  * Will initialize a histogram descriptor that will be attached to
356*287e80b3SSadaf Ebrahimi  * the @system/@event. This only initializes the descriptor with the given
357*287e80b3SSadaf Ebrahimi  * @axes keys as primaries. This only initializes the descriptor, it does
358*287e80b3SSadaf Ebrahimi  * not start the histogram in the kernel.
359*287e80b3SSadaf Ebrahimi  *
360*287e80b3SSadaf Ebrahimi  * Returns an initialized histogram on success.
361*287e80b3SSadaf Ebrahimi  * NULL on failure.
362*287e80b3SSadaf Ebrahimi  */
363*287e80b3SSadaf Ebrahimi struct tracefs_hist *
tracefs_hist_alloc_nd_cnt(struct tep_handle * tep,const char * system,const char * event_name,struct tracefs_hist_axis_cnt * axes)364*287e80b3SSadaf Ebrahimi tracefs_hist_alloc_nd_cnt(struct tep_handle *tep,
365*287e80b3SSadaf Ebrahimi 			  const char *system, const char *event_name,
366*287e80b3SSadaf Ebrahimi 			  struct tracefs_hist_axis_cnt *axes)
367*287e80b3SSadaf Ebrahimi {
368*287e80b3SSadaf Ebrahimi 	return hist_alloc_nd(tep, system, event_name, NULL, axes);
369*287e80b3SSadaf Ebrahimi }
370*287e80b3SSadaf Ebrahimi 
371*287e80b3SSadaf Ebrahimi /**
372*287e80b3SSadaf Ebrahimi  * tracefs_hist_add_key - add to a key to a histogram
373*287e80b3SSadaf Ebrahimi  * @hist: The histogram to add the key to.
374*287e80b3SSadaf Ebrahimi  * @key: The name of the key field.
375*287e80b3SSadaf Ebrahimi  * @type: The type of the key format.
376*287e80b3SSadaf Ebrahimi  * @cnt: Some types require a counter, for those, this is used
377*287e80b3SSadaf Ebrahimi  *
378*287e80b3SSadaf Ebrahimi  * This adds a secondary or tertiary key to the histogram.
379*287e80b3SSadaf Ebrahimi  *
380*287e80b3SSadaf Ebrahimi  * Returns 0 on success, -1 on error.
381*287e80b3SSadaf Ebrahimi  */
tracefs_hist_add_key_cnt(struct tracefs_hist * hist,const char * key,enum tracefs_hist_key_type type,int cnt)382*287e80b3SSadaf Ebrahimi int tracefs_hist_add_key_cnt(struct tracefs_hist *hist, const char *key,
383*287e80b3SSadaf Ebrahimi 			     enum tracefs_hist_key_type type, int cnt)
384*287e80b3SSadaf Ebrahimi {
385*287e80b3SSadaf Ebrahimi 	bool use_key = false;
386*287e80b3SSadaf Ebrahimi 	char *key_type = NULL;
387*287e80b3SSadaf Ebrahimi 	char **new_list;
388*287e80b3SSadaf Ebrahimi 	int ret = -1;
389*287e80b3SSadaf Ebrahimi 
390*287e80b3SSadaf Ebrahimi 	switch (type) {
391*287e80b3SSadaf Ebrahimi 	case TRACEFS_HIST_KEY_NORMAL:
392*287e80b3SSadaf Ebrahimi 		use_key = true;
393*287e80b3SSadaf Ebrahimi 		ret = 0;
394*287e80b3SSadaf Ebrahimi 		break;
395*287e80b3SSadaf Ebrahimi 	case TRACEFS_HIST_KEY_HEX:
396*287e80b3SSadaf Ebrahimi 		ret = asprintf(&key_type, "%s.hex", key);
397*287e80b3SSadaf Ebrahimi 		break;
398*287e80b3SSadaf Ebrahimi 	case TRACEFS_HIST_KEY_SYM:
399*287e80b3SSadaf Ebrahimi 		ret = asprintf(&key_type, "%s.sym", key);
400*287e80b3SSadaf Ebrahimi 		break;
401*287e80b3SSadaf Ebrahimi 	case TRACEFS_HIST_KEY_SYM_OFFSET:
402*287e80b3SSadaf Ebrahimi 		ret = asprintf(&key_type, "%s.sym-offset", key);
403*287e80b3SSadaf Ebrahimi 		break;
404*287e80b3SSadaf Ebrahimi 	case TRACEFS_HIST_KEY_SYSCALL:
405*287e80b3SSadaf Ebrahimi 		ret = asprintf(&key_type, "%s.syscall", key);
406*287e80b3SSadaf Ebrahimi 		break;
407*287e80b3SSadaf Ebrahimi 	case TRACEFS_HIST_KEY_EXECNAME:
408*287e80b3SSadaf Ebrahimi 		ret = asprintf(&key_type, "%s.execname", key);
409*287e80b3SSadaf Ebrahimi 		break;
410*287e80b3SSadaf Ebrahimi 	case TRACEFS_HIST_KEY_LOG:
411*287e80b3SSadaf Ebrahimi 		ret = asprintf(&key_type, "%s.log2", key);
412*287e80b3SSadaf Ebrahimi 		break;
413*287e80b3SSadaf Ebrahimi 	case TRACEFS_HIST_KEY_USECS:
414*287e80b3SSadaf Ebrahimi 		ret = asprintf(&key_type, "%s.usecs", key);
415*287e80b3SSadaf Ebrahimi 		break;
416*287e80b3SSadaf Ebrahimi 	case TRACEFS_HIST_KEY_BUCKETS:
417*287e80b3SSadaf Ebrahimi 		ret = asprintf(&key_type, "%s.buckets=%d", key, cnt);
418*287e80b3SSadaf Ebrahimi 		break;
419*287e80b3SSadaf Ebrahimi 	case TRACEFS_HIST_KEY_MAX:
420*287e80b3SSadaf Ebrahimi 		/* error */
421*287e80b3SSadaf Ebrahimi 		break;
422*287e80b3SSadaf Ebrahimi 	}
423*287e80b3SSadaf Ebrahimi 
424*287e80b3SSadaf Ebrahimi 	if (ret < 0)
425*287e80b3SSadaf Ebrahimi 		return -1;
426*287e80b3SSadaf Ebrahimi 
427*287e80b3SSadaf Ebrahimi 	new_list = tracefs_list_add(hist->keys, use_key ? key : key_type);
428*287e80b3SSadaf Ebrahimi 	free(key_type);
429*287e80b3SSadaf Ebrahimi 	if (!new_list)
430*287e80b3SSadaf Ebrahimi 		return -1;
431*287e80b3SSadaf Ebrahimi 
432*287e80b3SSadaf Ebrahimi 	hist->keys = new_list;
433*287e80b3SSadaf Ebrahimi 
434*287e80b3SSadaf Ebrahimi 	return 0;
435*287e80b3SSadaf Ebrahimi }
436*287e80b3SSadaf Ebrahimi 
437*287e80b3SSadaf Ebrahimi /**
438*287e80b3SSadaf Ebrahimi  * tracefs_hist_add_key - add to a key to a histogram
439*287e80b3SSadaf Ebrahimi  * @hist: The histogram to add the key to.
440*287e80b3SSadaf Ebrahimi  * @key: The name of the key field.
441*287e80b3SSadaf Ebrahimi  * @type: The type of the key format.
442*287e80b3SSadaf Ebrahimi  *
443*287e80b3SSadaf Ebrahimi  * This adds a secondary or tertiary key to the histogram.
444*287e80b3SSadaf Ebrahimi  *
445*287e80b3SSadaf Ebrahimi  * Returns 0 on success, -1 on error.
446*287e80b3SSadaf Ebrahimi  */
tracefs_hist_add_key(struct tracefs_hist * hist,const char * key,enum tracefs_hist_key_type type)447*287e80b3SSadaf Ebrahimi int tracefs_hist_add_key(struct tracefs_hist *hist, const char *key,
448*287e80b3SSadaf Ebrahimi 			 enum tracefs_hist_key_type type)
449*287e80b3SSadaf Ebrahimi {
450*287e80b3SSadaf Ebrahimi 	return tracefs_hist_add_key_cnt(hist, key, type, 0);
451*287e80b3SSadaf Ebrahimi }
452*287e80b3SSadaf Ebrahimi 
453*287e80b3SSadaf Ebrahimi /**
454*287e80b3SSadaf Ebrahimi  * tracefs_hist_add_value - add to a value to a histogram
455*287e80b3SSadaf Ebrahimi  * @hist: The histogram to add the value to.
456*287e80b3SSadaf Ebrahimi  * @key: The name of the value field.
457*287e80b3SSadaf Ebrahimi  *
458*287e80b3SSadaf Ebrahimi  * This adds a value field to the histogram.
459*287e80b3SSadaf Ebrahimi  *
460*287e80b3SSadaf Ebrahimi  * Returns 0 on success, -1 on error.
461*287e80b3SSadaf Ebrahimi  */
tracefs_hist_add_value(struct tracefs_hist * hist,const char * value)462*287e80b3SSadaf Ebrahimi int tracefs_hist_add_value(struct tracefs_hist *hist, const char *value)
463*287e80b3SSadaf Ebrahimi {
464*287e80b3SSadaf Ebrahimi 	char **new_list;
465*287e80b3SSadaf Ebrahimi 
466*287e80b3SSadaf Ebrahimi 	new_list = tracefs_list_add(hist->values, value);
467*287e80b3SSadaf Ebrahimi 	if (!new_list)
468*287e80b3SSadaf Ebrahimi 		return -1;
469*287e80b3SSadaf Ebrahimi 
470*287e80b3SSadaf Ebrahimi 	hist->values = new_list;
471*287e80b3SSadaf Ebrahimi 
472*287e80b3SSadaf Ebrahimi 	return 0;
473*287e80b3SSadaf Ebrahimi }
474*287e80b3SSadaf Ebrahimi 
475*287e80b3SSadaf Ebrahimi /**
476*287e80b3SSadaf Ebrahimi  * tracefs_hist_add_name - name a histogram
477*287e80b3SSadaf Ebrahimi  * @hist: The histogram to name.
478*287e80b3SSadaf Ebrahimi  * @name: The name of the histogram.
479*287e80b3SSadaf Ebrahimi  *
480*287e80b3SSadaf Ebrahimi  * Adds a name to the histogram. Named histograms will share their
481*287e80b3SSadaf Ebrahimi  * data with other events that have the same name as if it was
482*287e80b3SSadaf Ebrahimi  * a single histogram.
483*287e80b3SSadaf Ebrahimi  *
484*287e80b3SSadaf Ebrahimi  * If the histogram already has a name, this will fail.
485*287e80b3SSadaf Ebrahimi  *
486*287e80b3SSadaf Ebrahimi  * Returns 0 on success, -1 on error.
487*287e80b3SSadaf Ebrahimi  */
tracefs_hist_add_name(struct tracefs_hist * hist,const char * name)488*287e80b3SSadaf Ebrahimi int tracefs_hist_add_name(struct tracefs_hist *hist, const char *name)
489*287e80b3SSadaf Ebrahimi {
490*287e80b3SSadaf Ebrahimi 	if (hist->name)
491*287e80b3SSadaf Ebrahimi 		return -1;
492*287e80b3SSadaf Ebrahimi 
493*287e80b3SSadaf Ebrahimi 	hist->name = strdup(name);
494*287e80b3SSadaf Ebrahimi 
495*287e80b3SSadaf Ebrahimi 	return hist->name ? 0 : -1;
496*287e80b3SSadaf Ebrahimi }
497*287e80b3SSadaf Ebrahimi 
498*287e80b3SSadaf Ebrahimi static char **
add_sort_key(struct tracefs_hist * hist,const char * sort_key,char ** list)499*287e80b3SSadaf Ebrahimi add_sort_key(struct tracefs_hist *hist, const char *sort_key, char **list)
500*287e80b3SSadaf Ebrahimi {
501*287e80b3SSadaf Ebrahimi 	char **key_list = hist->keys;
502*287e80b3SSadaf Ebrahimi 	char **val_list = hist->values;
503*287e80b3SSadaf Ebrahimi 	int i;
504*287e80b3SSadaf Ebrahimi 
505*287e80b3SSadaf Ebrahimi 	if (strcmp(sort_key, TRACEFS_HIST_HITCOUNT) == 0)
506*287e80b3SSadaf Ebrahimi 		goto out;
507*287e80b3SSadaf Ebrahimi 
508*287e80b3SSadaf Ebrahimi 	for (i = 0; key_list[i]; i++) {
509*287e80b3SSadaf Ebrahimi 		if (strcmp(key_list[i], sort_key) == 0)
510*287e80b3SSadaf Ebrahimi 			break;
511*287e80b3SSadaf Ebrahimi 	}
512*287e80b3SSadaf Ebrahimi 
513*287e80b3SSadaf Ebrahimi 	if (!key_list[i] && val_list) {
514*287e80b3SSadaf Ebrahimi 		for (i = 0; val_list[i]; i++) {
515*287e80b3SSadaf Ebrahimi 			if (strcmp(val_list[i], sort_key) == 0)
516*287e80b3SSadaf Ebrahimi 				break;
517*287e80b3SSadaf Ebrahimi 			if (!val_list[i])
518*287e80b3SSadaf Ebrahimi 				return NULL;
519*287e80b3SSadaf Ebrahimi 		}
520*287e80b3SSadaf Ebrahimi 	}
521*287e80b3SSadaf Ebrahimi 
522*287e80b3SSadaf Ebrahimi 
523*287e80b3SSadaf Ebrahimi  out:
524*287e80b3SSadaf Ebrahimi 	return tracefs_list_add(list, sort_key);
525*287e80b3SSadaf Ebrahimi }
526*287e80b3SSadaf Ebrahimi 
527*287e80b3SSadaf Ebrahimi /**
528*287e80b3SSadaf Ebrahimi  * tracefs_hist_add_sort_key - add a key for sorting the histogram
529*287e80b3SSadaf Ebrahimi  * @hist: The histogram to add the sort key to
530*287e80b3SSadaf Ebrahimi  * @sort_key: The key to sort
531*287e80b3SSadaf Ebrahimi  *
532*287e80b3SSadaf Ebrahimi  * Call the function to add to the list of sort keys of the histohram in
533*287e80b3SSadaf Ebrahimi  * the order of priority that the keys would be sorted on output.
534*287e80b3SSadaf Ebrahimi  *
535*287e80b3SSadaf Ebrahimi  * Returns 0 on success, -1 on error.
536*287e80b3SSadaf Ebrahimi  */
tracefs_hist_add_sort_key(struct tracefs_hist * hist,const char * sort_key)537*287e80b3SSadaf Ebrahimi int tracefs_hist_add_sort_key(struct tracefs_hist *hist,
538*287e80b3SSadaf Ebrahimi 			      const char *sort_key)
539*287e80b3SSadaf Ebrahimi {
540*287e80b3SSadaf Ebrahimi 	char **list = hist->sort;
541*287e80b3SSadaf Ebrahimi 
542*287e80b3SSadaf Ebrahimi 	if (!hist || !sort_key)
543*287e80b3SSadaf Ebrahimi 		return -1;
544*287e80b3SSadaf Ebrahimi 
545*287e80b3SSadaf Ebrahimi 	list = add_sort_key(hist, sort_key, hist->sort);
546*287e80b3SSadaf Ebrahimi 	if (!list)
547*287e80b3SSadaf Ebrahimi 		return -1;
548*287e80b3SSadaf Ebrahimi 
549*287e80b3SSadaf Ebrahimi 	hist->sort = list;
550*287e80b3SSadaf Ebrahimi 
551*287e80b3SSadaf Ebrahimi 	return 0;
552*287e80b3SSadaf Ebrahimi }
553*287e80b3SSadaf Ebrahimi 
554*287e80b3SSadaf Ebrahimi /**
555*287e80b3SSadaf Ebrahimi  * tracefs_hist_set_sort_key - set a key for sorting the histogram
556*287e80b3SSadaf Ebrahimi  * @hist: The histogram to set the sort key to
557*287e80b3SSadaf Ebrahimi  * @sort_key: The key to sort (and the strings after it)
558*287e80b3SSadaf Ebrahimi  *  Last one must be NULL.
559*287e80b3SSadaf Ebrahimi  *
560*287e80b3SSadaf Ebrahimi  * Set a list of sort keys in the order of priority that the
561*287e80b3SSadaf Ebrahimi  * keys would be sorted on output. Keys must be added first.
562*287e80b3SSadaf Ebrahimi  *
563*287e80b3SSadaf Ebrahimi  * Returns 0 on success, -1 on error.
564*287e80b3SSadaf Ebrahimi  */
tracefs_hist_set_sort_key(struct tracefs_hist * hist,const char * sort_key,...)565*287e80b3SSadaf Ebrahimi int tracefs_hist_set_sort_key(struct tracefs_hist *hist,
566*287e80b3SSadaf Ebrahimi 			      const char *sort_key, ...)
567*287e80b3SSadaf Ebrahimi {
568*287e80b3SSadaf Ebrahimi 	char **list = NULL;
569*287e80b3SSadaf Ebrahimi 	char **tmp;
570*287e80b3SSadaf Ebrahimi 	va_list ap;
571*287e80b3SSadaf Ebrahimi 
572*287e80b3SSadaf Ebrahimi 	if (!hist || !sort_key)
573*287e80b3SSadaf Ebrahimi 		return -1;
574*287e80b3SSadaf Ebrahimi 
575*287e80b3SSadaf Ebrahimi 	tmp = add_sort_key(hist, sort_key, list);
576*287e80b3SSadaf Ebrahimi 	if (!tmp)
577*287e80b3SSadaf Ebrahimi 		goto fail;
578*287e80b3SSadaf Ebrahimi 	list = tmp;
579*287e80b3SSadaf Ebrahimi 
580*287e80b3SSadaf Ebrahimi 	va_start(ap, sort_key);
581*287e80b3SSadaf Ebrahimi 	for (;;) {
582*287e80b3SSadaf Ebrahimi 		sort_key = va_arg(ap, const char *);
583*287e80b3SSadaf Ebrahimi 		if (!sort_key)
584*287e80b3SSadaf Ebrahimi 			break;
585*287e80b3SSadaf Ebrahimi 		tmp = add_sort_key(hist, sort_key, list);
586*287e80b3SSadaf Ebrahimi 		if (!tmp)
587*287e80b3SSadaf Ebrahimi 			goto fail;
588*287e80b3SSadaf Ebrahimi 		list = tmp;
589*287e80b3SSadaf Ebrahimi 	}
590*287e80b3SSadaf Ebrahimi 	va_end(ap);
591*287e80b3SSadaf Ebrahimi 
592*287e80b3SSadaf Ebrahimi 	tracefs_list_free(hist->sort);
593*287e80b3SSadaf Ebrahimi 	hist->sort = list;
594*287e80b3SSadaf Ebrahimi 
595*287e80b3SSadaf Ebrahimi 	return 0;
596*287e80b3SSadaf Ebrahimi  fail:
597*287e80b3SSadaf Ebrahimi 	tracefs_list_free(list);
598*287e80b3SSadaf Ebrahimi 	return -1;
599*287e80b3SSadaf Ebrahimi }
600*287e80b3SSadaf Ebrahimi 
end_match(const char * sort_key,const char * ending)601*287e80b3SSadaf Ebrahimi static int end_match(const char *sort_key, const char *ending)
602*287e80b3SSadaf Ebrahimi {
603*287e80b3SSadaf Ebrahimi 	int key_len = strlen(sort_key);
604*287e80b3SSadaf Ebrahimi 	int end_len = strlen(ending);
605*287e80b3SSadaf Ebrahimi 
606*287e80b3SSadaf Ebrahimi 	if (key_len <= end_len)
607*287e80b3SSadaf Ebrahimi 		return 0;
608*287e80b3SSadaf Ebrahimi 
609*287e80b3SSadaf Ebrahimi 	sort_key += key_len - end_len;
610*287e80b3SSadaf Ebrahimi 
611*287e80b3SSadaf Ebrahimi 	return strcmp(sort_key, ending) == 0 ? key_len - end_len : 0;
612*287e80b3SSadaf Ebrahimi }
613*287e80b3SSadaf Ebrahimi 
614*287e80b3SSadaf Ebrahimi /**
615*287e80b3SSadaf Ebrahimi  * tracefs_hist_sort_key_direction - set direction of a sort key
616*287e80b3SSadaf Ebrahimi  * @hist: The histogram to modify.
617*287e80b3SSadaf Ebrahimi  * @sort_str: The sort key to set the direction for
618*287e80b3SSadaf Ebrahimi  * @dir: The direction to set the sort key to.
619*287e80b3SSadaf Ebrahimi  *
620*287e80b3SSadaf Ebrahimi  * Returns 0 on success, and -1 on error;
621*287e80b3SSadaf Ebrahimi  */
tracefs_hist_sort_key_direction(struct tracefs_hist * hist,const char * sort_str,enum tracefs_hist_sort_direction dir)622*287e80b3SSadaf Ebrahimi int tracefs_hist_sort_key_direction(struct tracefs_hist *hist,
623*287e80b3SSadaf Ebrahimi 				    const char *sort_str,
624*287e80b3SSadaf Ebrahimi 				    enum tracefs_hist_sort_direction dir)
625*287e80b3SSadaf Ebrahimi {
626*287e80b3SSadaf Ebrahimi 	char **sort = hist->sort;
627*287e80b3SSadaf Ebrahimi 	char *sort_key;
628*287e80b3SSadaf Ebrahimi 	char *direct;
629*287e80b3SSadaf Ebrahimi 	int match;
630*287e80b3SSadaf Ebrahimi 	int i;
631*287e80b3SSadaf Ebrahimi 
632*287e80b3SSadaf Ebrahimi 	if (!sort)
633*287e80b3SSadaf Ebrahimi 		return -1;
634*287e80b3SSadaf Ebrahimi 
635*287e80b3SSadaf Ebrahimi 	for (i = 0; sort[i]; i++) {
636*287e80b3SSadaf Ebrahimi 		if (strcmp(sort[i], sort_str) == 0)
637*287e80b3SSadaf Ebrahimi 			break;
638*287e80b3SSadaf Ebrahimi 	}
639*287e80b3SSadaf Ebrahimi 	if (!sort[i])
640*287e80b3SSadaf Ebrahimi 		return -1;
641*287e80b3SSadaf Ebrahimi 
642*287e80b3SSadaf Ebrahimi 	sort_key = sort[i];
643*287e80b3SSadaf Ebrahimi 
644*287e80b3SSadaf Ebrahimi 	switch (dir) {
645*287e80b3SSadaf Ebrahimi 	case TRACEFS_HIST_SORT_ASCENDING:
646*287e80b3SSadaf Ebrahimi 		direct = ASCENDING;
647*287e80b3SSadaf Ebrahimi 		break;
648*287e80b3SSadaf Ebrahimi 	case TRACEFS_HIST_SORT_DESCENDING:
649*287e80b3SSadaf Ebrahimi 		direct = DESCENDING;
650*287e80b3SSadaf Ebrahimi 		break;
651*287e80b3SSadaf Ebrahimi 	default:
652*287e80b3SSadaf Ebrahimi 		return -1;
653*287e80b3SSadaf Ebrahimi 	}
654*287e80b3SSadaf Ebrahimi 
655*287e80b3SSadaf Ebrahimi 	match = end_match(sort_key, ASCENDING);
656*287e80b3SSadaf Ebrahimi 	if (match) {
657*287e80b3SSadaf Ebrahimi 		/* Already match? */
658*287e80b3SSadaf Ebrahimi 		if (dir == TRACEFS_HIST_SORT_ASCENDING)
659*287e80b3SSadaf Ebrahimi 			return 0;
660*287e80b3SSadaf Ebrahimi 	} else {
661*287e80b3SSadaf Ebrahimi 		match = end_match(sort_key, DESCENDING);
662*287e80b3SSadaf Ebrahimi 		/* Already match? */
663*287e80b3SSadaf Ebrahimi 		if (match && dir == TRACEFS_HIST_SORT_DESCENDING)
664*287e80b3SSadaf Ebrahimi 			return 0;
665*287e80b3SSadaf Ebrahimi 	}
666*287e80b3SSadaf Ebrahimi 
667*287e80b3SSadaf Ebrahimi 	if (match)
668*287e80b3SSadaf Ebrahimi 		/* Clear the original text */
669*287e80b3SSadaf Ebrahimi 		sort_key[match] = '\0';
670*287e80b3SSadaf Ebrahimi 
671*287e80b3SSadaf Ebrahimi 	sort_key = realloc(sort_key, strlen(sort_key) + strlen(direct) + 1);
672*287e80b3SSadaf Ebrahimi 	if (!sort_key) {
673*287e80b3SSadaf Ebrahimi 		/* Failed to alloc, may need to put back the match */
674*287e80b3SSadaf Ebrahimi 		sort_key = sort[i];
675*287e80b3SSadaf Ebrahimi 		if (match)
676*287e80b3SSadaf Ebrahimi 			sort_key[match] = '.';
677*287e80b3SSadaf Ebrahimi 		return -1;
678*287e80b3SSadaf Ebrahimi 	}
679*287e80b3SSadaf Ebrahimi 
680*287e80b3SSadaf Ebrahimi 	strcat(sort_key, direct);
681*287e80b3SSadaf Ebrahimi 	sort[i] = sort_key;
682*287e80b3SSadaf Ebrahimi 	return 0;
683*287e80b3SSadaf Ebrahimi }
684*287e80b3SSadaf Ebrahimi 
tracefs_hist_append_filter(struct tracefs_hist * hist,enum tracefs_filter type,const char * field,enum tracefs_compare compare,const char * val)685*287e80b3SSadaf Ebrahimi int tracefs_hist_append_filter(struct tracefs_hist *hist,
686*287e80b3SSadaf Ebrahimi 			       enum tracefs_filter type,
687*287e80b3SSadaf Ebrahimi 			       const char *field,
688*287e80b3SSadaf Ebrahimi 			       enum tracefs_compare compare,
689*287e80b3SSadaf Ebrahimi 			       const char *val)
690*287e80b3SSadaf Ebrahimi {
691*287e80b3SSadaf Ebrahimi 	return trace_append_filter(&hist->filter, &hist->filter_state,
692*287e80b3SSadaf Ebrahimi 				   &hist->filter_parens,
693*287e80b3SSadaf Ebrahimi 				   hist->event,
694*287e80b3SSadaf Ebrahimi 				   type, field, compare, val);
695*287e80b3SSadaf Ebrahimi }
696*287e80b3SSadaf Ebrahimi 
697*287e80b3SSadaf Ebrahimi enum action_type {
698*287e80b3SSadaf Ebrahimi 	ACTION_NONE,
699*287e80b3SSadaf Ebrahimi 	ACTION_TRACE,
700*287e80b3SSadaf Ebrahimi 	ACTION_SNAPSHOT,
701*287e80b3SSadaf Ebrahimi 	ACTION_SAVE,
702*287e80b3SSadaf Ebrahimi };
703*287e80b3SSadaf Ebrahimi 
704*287e80b3SSadaf Ebrahimi struct action {
705*287e80b3SSadaf Ebrahimi 	struct action			*next;
706*287e80b3SSadaf Ebrahimi 	enum action_type		type;
707*287e80b3SSadaf Ebrahimi 	enum tracefs_synth_handler	handler;
708*287e80b3SSadaf Ebrahimi 	char				*handle_field;
709*287e80b3SSadaf Ebrahimi 	char				*save;
710*287e80b3SSadaf Ebrahimi };
711*287e80b3SSadaf Ebrahimi 
712*287e80b3SSadaf Ebrahimi struct name_hash {
713*287e80b3SSadaf Ebrahimi 	struct name_hash	*next;
714*287e80b3SSadaf Ebrahimi 	char			*name;
715*287e80b3SSadaf Ebrahimi 	char			*hash;
716*287e80b3SSadaf Ebrahimi };
717*287e80b3SSadaf Ebrahimi 
718*287e80b3SSadaf Ebrahimi /*
719*287e80b3SSadaf Ebrahimi  * @name: name of the synthetic event
720*287e80b3SSadaf Ebrahimi  * @start_system: system of the starting event
721*287e80b3SSadaf Ebrahimi  * @start_event: the starting event
722*287e80b3SSadaf Ebrahimi  * @end_system: system of the ending event
723*287e80b3SSadaf Ebrahimi  * @end_event: the ending event
724*287e80b3SSadaf Ebrahimi  * @actions: List of actions to take
725*287e80b3SSadaf Ebrahimi  * @match_names: If a match set is to be a synthetic field, it has a name
726*287e80b3SSadaf Ebrahimi  * @start_match: list of keys in the start event that matches end event
727*287e80b3SSadaf Ebrahimi  * @end_match: list of keys in the end event that matches the start event
728*287e80b3SSadaf Ebrahimi  * @compare_names: The synthetic field names of the compared fields
729*287e80b3SSadaf Ebrahimi  * @start_compare: A list of compare fields in the start to compare to end
730*287e80b3SSadaf Ebrahimi  * @end_compare: A list of compare fields in the end to compare to start
731*287e80b3SSadaf Ebrahimi  * @compare_ops: The type of operations to perform between the start and end
732*287e80b3SSadaf Ebrahimi  * @start_names: The fields in the start event to record
733*287e80b3SSadaf Ebrahimi  * @end_names: The fields in the end event to record
734*287e80b3SSadaf Ebrahimi  * @start_filters: The fields in the end event to record
735*287e80b3SSadaf Ebrahimi  * @end_filters: The fields in the end event to record
736*287e80b3SSadaf Ebrahimi  * @start_parens: Current parenthesis level for start event
737*287e80b3SSadaf Ebrahimi  * @end_parens: Current parenthesis level for end event
738*287e80b3SSadaf Ebrahimi  * @new_format: onmatch().trace(synth_event,..) or onmatch().synth_event(...)
739*287e80b3SSadaf Ebrahimi  */
740*287e80b3SSadaf Ebrahimi struct tracefs_synth {
741*287e80b3SSadaf Ebrahimi 	struct tracefs_instance *instance;
742*287e80b3SSadaf Ebrahimi 	struct tep_handle	*tep;
743*287e80b3SSadaf Ebrahimi 	struct tep_event	*start_event;
744*287e80b3SSadaf Ebrahimi 	struct tep_event	*end_event;
745*287e80b3SSadaf Ebrahimi 	struct action		*actions;
746*287e80b3SSadaf Ebrahimi 	struct action		**next_action;
747*287e80b3SSadaf Ebrahimi 	struct tracefs_dynevent	*dyn_event;
748*287e80b3SSadaf Ebrahimi 	struct name_hash	*name_hash[1 << HASH_BITS];
749*287e80b3SSadaf Ebrahimi 	char			*start_hist;
750*287e80b3SSadaf Ebrahimi 	char			*end_hist;
751*287e80b3SSadaf Ebrahimi 	char			*name;
752*287e80b3SSadaf Ebrahimi 	char			**synthetic_fields;
753*287e80b3SSadaf Ebrahimi 	char			**synthetic_args;
754*287e80b3SSadaf Ebrahimi 	char			**start_selection;
755*287e80b3SSadaf Ebrahimi 	char			**start_keys;
756*287e80b3SSadaf Ebrahimi 	char			**end_keys;
757*287e80b3SSadaf Ebrahimi 	char			**start_vars;
758*287e80b3SSadaf Ebrahimi 	char			**end_vars;
759*287e80b3SSadaf Ebrahimi 	char			*start_filter;
760*287e80b3SSadaf Ebrahimi 	char			*end_filter;
761*287e80b3SSadaf Ebrahimi 	unsigned int		start_parens;
762*287e80b3SSadaf Ebrahimi 	unsigned int		start_state;
763*287e80b3SSadaf Ebrahimi 	unsigned int		end_parens;
764*287e80b3SSadaf Ebrahimi 	unsigned int		end_state;
765*287e80b3SSadaf Ebrahimi 	int			*start_type;
766*287e80b3SSadaf Ebrahimi 	char			arg_name[16];
767*287e80b3SSadaf Ebrahimi 	int			arg_cnt;
768*287e80b3SSadaf Ebrahimi 	bool			new_format;
769*287e80b3SSadaf Ebrahimi };
770*287e80b3SSadaf Ebrahimi 
771*287e80b3SSadaf Ebrahimi  /*
772*287e80b3SSadaf Ebrahimi  * tracefs_synth_get_name - get the name of the synthetic event
773*287e80b3SSadaf Ebrahimi  * @synth: The synthetic event to get the name for
774*287e80b3SSadaf Ebrahimi  *
775*287e80b3SSadaf Ebrahimi  * Returns name string owned by @synth on success, or NULL on error.
776*287e80b3SSadaf Ebrahimi  */
tracefs_synth_get_name(struct tracefs_synth * synth)777*287e80b3SSadaf Ebrahimi const char *tracefs_synth_get_name(struct tracefs_synth *synth)
778*287e80b3SSadaf Ebrahimi {
779*287e80b3SSadaf Ebrahimi 	return synth ? synth->name : NULL;
780*287e80b3SSadaf Ebrahimi }
781*287e80b3SSadaf Ebrahimi 
action_free(struct action * action)782*287e80b3SSadaf Ebrahimi static void action_free(struct action *action)
783*287e80b3SSadaf Ebrahimi {
784*287e80b3SSadaf Ebrahimi 	free(action->handle_field);
785*287e80b3SSadaf Ebrahimi 	free(action->save);
786*287e80b3SSadaf Ebrahimi 	free(action);
787*287e80b3SSadaf Ebrahimi }
788*287e80b3SSadaf Ebrahimi 
free_name_hash(struct name_hash ** hash)789*287e80b3SSadaf Ebrahimi static void free_name_hash(struct name_hash **hash)
790*287e80b3SSadaf Ebrahimi {
791*287e80b3SSadaf Ebrahimi 	struct name_hash *item;
792*287e80b3SSadaf Ebrahimi 	int i;
793*287e80b3SSadaf Ebrahimi 
794*287e80b3SSadaf Ebrahimi 	for (i = 0; i < 1 << HASH_BITS; i++) {
795*287e80b3SSadaf Ebrahimi 		while ((item = hash[i])) {
796*287e80b3SSadaf Ebrahimi 			hash[i] = item->next;
797*287e80b3SSadaf Ebrahimi 			free(item->name);
798*287e80b3SSadaf Ebrahimi 			free(item->hash);
799*287e80b3SSadaf Ebrahimi 			free(item);
800*287e80b3SSadaf Ebrahimi 		}
801*287e80b3SSadaf Ebrahimi 	}
802*287e80b3SSadaf Ebrahimi }
803*287e80b3SSadaf Ebrahimi 
804*287e80b3SSadaf Ebrahimi /**
805*287e80b3SSadaf Ebrahimi  * tracefs_synth_free - free the resources alloced to a synth
806*287e80b3SSadaf Ebrahimi  * @synth: The tracefs_synth descriptor
807*287e80b3SSadaf Ebrahimi  *
808*287e80b3SSadaf Ebrahimi  * Frees the resources allocated for a @synth created with
809*287e80b3SSadaf Ebrahimi  * tracefs_synth_alloc(). It does not touch the system. That is,
810*287e80b3SSadaf Ebrahimi  * any synthetic event created, will not be destroyed by this
811*287e80b3SSadaf Ebrahimi  * function.
812*287e80b3SSadaf Ebrahimi  */
tracefs_synth_free(struct tracefs_synth * synth)813*287e80b3SSadaf Ebrahimi void tracefs_synth_free(struct tracefs_synth *synth)
814*287e80b3SSadaf Ebrahimi {
815*287e80b3SSadaf Ebrahimi 	struct action *action;
816*287e80b3SSadaf Ebrahimi 
817*287e80b3SSadaf Ebrahimi 	if (!synth)
818*287e80b3SSadaf Ebrahimi 		return;
819*287e80b3SSadaf Ebrahimi 
820*287e80b3SSadaf Ebrahimi 	free(synth->name);
821*287e80b3SSadaf Ebrahimi 	free(synth->start_hist);
822*287e80b3SSadaf Ebrahimi 	free(synth->end_hist);
823*287e80b3SSadaf Ebrahimi 	tracefs_list_free(synth->synthetic_fields);
824*287e80b3SSadaf Ebrahimi 	tracefs_list_free(synth->synthetic_args);
825*287e80b3SSadaf Ebrahimi 	tracefs_list_free(synth->start_selection);
826*287e80b3SSadaf Ebrahimi 	tracefs_list_free(synth->start_keys);
827*287e80b3SSadaf Ebrahimi 	tracefs_list_free(synth->end_keys);
828*287e80b3SSadaf Ebrahimi 	tracefs_list_free(synth->start_vars);
829*287e80b3SSadaf Ebrahimi 	tracefs_list_free(synth->end_vars);
830*287e80b3SSadaf Ebrahimi 	free_name_hash(synth->name_hash);
831*287e80b3SSadaf Ebrahimi 	free(synth->start_filter);
832*287e80b3SSadaf Ebrahimi 	free(synth->end_filter);
833*287e80b3SSadaf Ebrahimi 	free(synth->start_type);
834*287e80b3SSadaf Ebrahimi 
835*287e80b3SSadaf Ebrahimi 	tep_unref(synth->tep);
836*287e80b3SSadaf Ebrahimi 
837*287e80b3SSadaf Ebrahimi 	while ((action = synth->actions)) {
838*287e80b3SSadaf Ebrahimi 		synth->actions = action->next;
839*287e80b3SSadaf Ebrahimi 		action_free(action);
840*287e80b3SSadaf Ebrahimi 	}
841*287e80b3SSadaf Ebrahimi 	tracefs_dynevent_free(synth->dyn_event);
842*287e80b3SSadaf Ebrahimi 
843*287e80b3SSadaf Ebrahimi 	free(synth);
844*287e80b3SSadaf Ebrahimi }
845*287e80b3SSadaf Ebrahimi 
verify_event_fields(struct tep_event * start_event,struct tep_event * end_event,const char * start_field_name,const char * end_field_name,const struct tep_format_field ** ptr_start_field)846*287e80b3SSadaf Ebrahimi static bool verify_event_fields(struct tep_event *start_event,
847*287e80b3SSadaf Ebrahimi 				struct tep_event *end_event,
848*287e80b3SSadaf Ebrahimi 				const char *start_field_name,
849*287e80b3SSadaf Ebrahimi 				const char *end_field_name,
850*287e80b3SSadaf Ebrahimi 				const struct tep_format_field **ptr_start_field)
851*287e80b3SSadaf Ebrahimi {
852*287e80b3SSadaf Ebrahimi 	const struct tep_format_field *start_field;
853*287e80b3SSadaf Ebrahimi 	const struct tep_format_field *end_field;
854*287e80b3SSadaf Ebrahimi 	int start_flags, end_flags;
855*287e80b3SSadaf Ebrahimi 
856*287e80b3SSadaf Ebrahimi 	if (!trace_verify_event_field(start_event, start_field_name,
857*287e80b3SSadaf Ebrahimi 				      &start_field))
858*287e80b3SSadaf Ebrahimi 		return false;
859*287e80b3SSadaf Ebrahimi 
860*287e80b3SSadaf Ebrahimi 	if (end_event) {
861*287e80b3SSadaf Ebrahimi 		if (!trace_verify_event_field(end_event, end_field_name,
862*287e80b3SSadaf Ebrahimi 					      &end_field))
863*287e80b3SSadaf Ebrahimi 			return false;
864*287e80b3SSadaf Ebrahimi 
865*287e80b3SSadaf Ebrahimi 		/* A pointer can still match a long */
866*287e80b3SSadaf Ebrahimi 		start_flags = start_field->flags & ~TEP_FIELD_IS_POINTER;
867*287e80b3SSadaf Ebrahimi 		end_flags = end_field->flags & ~TEP_FIELD_IS_POINTER;
868*287e80b3SSadaf Ebrahimi 
869*287e80b3SSadaf Ebrahimi 		if (start_flags != end_flags ||
870*287e80b3SSadaf Ebrahimi 		    start_field->size != end_field->size) {
871*287e80b3SSadaf Ebrahimi 			errno = EBADE;
872*287e80b3SSadaf Ebrahimi 			return false;
873*287e80b3SSadaf Ebrahimi 		}
874*287e80b3SSadaf Ebrahimi 	}
875*287e80b3SSadaf Ebrahimi 
876*287e80b3SSadaf Ebrahimi 	if (ptr_start_field)
877*287e80b3SSadaf Ebrahimi 		*ptr_start_field = start_field;
878*287e80b3SSadaf Ebrahimi 
879*287e80b3SSadaf Ebrahimi 	return true;
880*287e80b3SSadaf Ebrahimi }
881*287e80b3SSadaf Ebrahimi 
append_string(char * str,const char * space,const char * add)882*287e80b3SSadaf Ebrahimi __hidden char *append_string(char *str, const char *space, const char *add)
883*287e80b3SSadaf Ebrahimi {
884*287e80b3SSadaf Ebrahimi 	char *new;
885*287e80b3SSadaf Ebrahimi 	int len;
886*287e80b3SSadaf Ebrahimi 
887*287e80b3SSadaf Ebrahimi 	/* String must already be allocated */
888*287e80b3SSadaf Ebrahimi 	if (!str)
889*287e80b3SSadaf Ebrahimi 		return NULL;
890*287e80b3SSadaf Ebrahimi 
891*287e80b3SSadaf Ebrahimi 	len = strlen(str) + strlen(add) + 2;
892*287e80b3SSadaf Ebrahimi 	if (space)
893*287e80b3SSadaf Ebrahimi 		len += strlen(space);
894*287e80b3SSadaf Ebrahimi 
895*287e80b3SSadaf Ebrahimi 	new = realloc(str, len);
896*287e80b3SSadaf Ebrahimi 	if (!new) {
897*287e80b3SSadaf Ebrahimi 		free(str);
898*287e80b3SSadaf Ebrahimi 		return NULL;
899*287e80b3SSadaf Ebrahimi 	}
900*287e80b3SSadaf Ebrahimi 	str = new;
901*287e80b3SSadaf Ebrahimi 
902*287e80b3SSadaf Ebrahimi 	if (space)
903*287e80b3SSadaf Ebrahimi 		strcat(str, space);
904*287e80b3SSadaf Ebrahimi 	strcat(str, add);
905*287e80b3SSadaf Ebrahimi 
906*287e80b3SSadaf Ebrahimi 	return str;
907*287e80b3SSadaf Ebrahimi }
908*287e80b3SSadaf Ebrahimi 
add_synth_field(const struct tep_format_field * field,const char * name)909*287e80b3SSadaf Ebrahimi static char *add_synth_field(const struct tep_format_field *field,
910*287e80b3SSadaf Ebrahimi 			     const char *name)
911*287e80b3SSadaf Ebrahimi {
912*287e80b3SSadaf Ebrahimi 	const char *type;
913*287e80b3SSadaf Ebrahimi 	char size[64];
914*287e80b3SSadaf Ebrahimi 	char *str;
915*287e80b3SSadaf Ebrahimi 	bool sign;
916*287e80b3SSadaf Ebrahimi 
917*287e80b3SSadaf Ebrahimi 	if (field->flags & TEP_FIELD_IS_ARRAY) {
918*287e80b3SSadaf Ebrahimi 		str = strdup("char");
919*287e80b3SSadaf Ebrahimi 		str = append_string(str, " ", name);
920*287e80b3SSadaf Ebrahimi 		str = append_string(str, NULL, "[");
921*287e80b3SSadaf Ebrahimi 
922*287e80b3SSadaf Ebrahimi 		if (!(field->flags & TEP_FIELD_IS_DYNAMIC)) {
923*287e80b3SSadaf Ebrahimi 			snprintf(size, 64, "%d", field->size);
924*287e80b3SSadaf Ebrahimi 			str = append_string(str, NULL, size);
925*287e80b3SSadaf Ebrahimi 		}
926*287e80b3SSadaf Ebrahimi 		return append_string(str, NULL, "];");
927*287e80b3SSadaf Ebrahimi 	}
928*287e80b3SSadaf Ebrahimi 
929*287e80b3SSadaf Ebrahimi 	/* Synthetic events understand pid_t, gfp_t and bool */
930*287e80b3SSadaf Ebrahimi 	if (strcmp(field->type, "pid_t") == 0 ||
931*287e80b3SSadaf Ebrahimi 	    strcmp(field->type, "gfp_t") == 0 ||
932*287e80b3SSadaf Ebrahimi 	    strcmp(field->type, "bool") == 0) {
933*287e80b3SSadaf Ebrahimi 		str = strdup(field->type);
934*287e80b3SSadaf Ebrahimi 		str = append_string(str, " ", name);
935*287e80b3SSadaf Ebrahimi 		return append_string(str, NULL, ";");
936*287e80b3SSadaf Ebrahimi 	}
937*287e80b3SSadaf Ebrahimi 
938*287e80b3SSadaf Ebrahimi 	sign = field->flags & TEP_FIELD_IS_SIGNED;
939*287e80b3SSadaf Ebrahimi 
940*287e80b3SSadaf Ebrahimi 	switch (field->size) {
941*287e80b3SSadaf Ebrahimi 	case 1:
942*287e80b3SSadaf Ebrahimi 		if (!sign)
943*287e80b3SSadaf Ebrahimi 			type = "unsigned char";
944*287e80b3SSadaf Ebrahimi 		else
945*287e80b3SSadaf Ebrahimi 			type = "char";
946*287e80b3SSadaf Ebrahimi 		break;
947*287e80b3SSadaf Ebrahimi 	case 2:
948*287e80b3SSadaf Ebrahimi 		if (sign)
949*287e80b3SSadaf Ebrahimi 			type = "s16";
950*287e80b3SSadaf Ebrahimi 		else
951*287e80b3SSadaf Ebrahimi 			type = "u16";
952*287e80b3SSadaf Ebrahimi 		break;
953*287e80b3SSadaf Ebrahimi 	case 4:
954*287e80b3SSadaf Ebrahimi 		if (sign)
955*287e80b3SSadaf Ebrahimi 			type = "s32";
956*287e80b3SSadaf Ebrahimi 		else
957*287e80b3SSadaf Ebrahimi 			type = "u32";
958*287e80b3SSadaf Ebrahimi 		break;
959*287e80b3SSadaf Ebrahimi 	case 8:
960*287e80b3SSadaf Ebrahimi 		if (sign)
961*287e80b3SSadaf Ebrahimi 			type = "s64";
962*287e80b3SSadaf Ebrahimi 		else
963*287e80b3SSadaf Ebrahimi 			type = "u64";
964*287e80b3SSadaf Ebrahimi 		break;
965*287e80b3SSadaf Ebrahimi 	default:
966*287e80b3SSadaf Ebrahimi 		errno = EBADF;
967*287e80b3SSadaf Ebrahimi 		return NULL;
968*287e80b3SSadaf Ebrahimi 	}
969*287e80b3SSadaf Ebrahimi 
970*287e80b3SSadaf Ebrahimi 	str = strdup(type);
971*287e80b3SSadaf Ebrahimi 	str = append_string(str, " ", name);
972*287e80b3SSadaf Ebrahimi 	return append_string(str, NULL, ";");
973*287e80b3SSadaf Ebrahimi }
974*287e80b3SSadaf Ebrahimi 
add_var(char *** list,const char * name,const char * var,bool is_var)975*287e80b3SSadaf Ebrahimi static int add_var(char ***list, const char *name, const char *var, bool is_var)
976*287e80b3SSadaf Ebrahimi {
977*287e80b3SSadaf Ebrahimi 	char **new;
978*287e80b3SSadaf Ebrahimi 	char *assign;
979*287e80b3SSadaf Ebrahimi 	int ret;
980*287e80b3SSadaf Ebrahimi 
981*287e80b3SSadaf Ebrahimi 	if (is_var)
982*287e80b3SSadaf Ebrahimi 		ret = asprintf(&assign, "%s=$%s", name, var);
983*287e80b3SSadaf Ebrahimi 	else
984*287e80b3SSadaf Ebrahimi 		ret = asprintf(&assign, "%s=%s", name, var);
985*287e80b3SSadaf Ebrahimi 
986*287e80b3SSadaf Ebrahimi 	if (ret < 0)
987*287e80b3SSadaf Ebrahimi 		return -1;
988*287e80b3SSadaf Ebrahimi 
989*287e80b3SSadaf Ebrahimi 	new = tracefs_list_add(*list, assign);
990*287e80b3SSadaf Ebrahimi 	free(assign);
991*287e80b3SSadaf Ebrahimi 
992*287e80b3SSadaf Ebrahimi 	if (!new)
993*287e80b3SSadaf Ebrahimi 		return -1;
994*287e80b3SSadaf Ebrahimi 	*list = new;
995*287e80b3SSadaf Ebrahimi 	return 0;
996*287e80b3SSadaf Ebrahimi }
997*287e80b3SSadaf Ebrahimi 
998*287e80b3SSadaf Ebrahimi __hidden struct tracefs_synth *
synth_init_from(struct tep_handle * tep,const char * start_system,const char * start_event_name)999*287e80b3SSadaf Ebrahimi synth_init_from(struct tep_handle *tep, const char *start_system,
1000*287e80b3SSadaf Ebrahimi 		const char *start_event_name)
1001*287e80b3SSadaf Ebrahimi {
1002*287e80b3SSadaf Ebrahimi 	struct tep_event *start_event;
1003*287e80b3SSadaf Ebrahimi 	struct tracefs_synth *synth;
1004*287e80b3SSadaf Ebrahimi 
1005*287e80b3SSadaf Ebrahimi 	start_event = tep_find_event_by_name(tep, start_system,
1006*287e80b3SSadaf Ebrahimi 					     start_event_name);
1007*287e80b3SSadaf Ebrahimi 	if (!start_event) {
1008*287e80b3SSadaf Ebrahimi 		errno = ENODEV;
1009*287e80b3SSadaf Ebrahimi 		return NULL;
1010*287e80b3SSadaf Ebrahimi 	}
1011*287e80b3SSadaf Ebrahimi 
1012*287e80b3SSadaf Ebrahimi 	synth = calloc(1, sizeof(*synth));
1013*287e80b3SSadaf Ebrahimi 	if (!synth)
1014*287e80b3SSadaf Ebrahimi 		return NULL;
1015*287e80b3SSadaf Ebrahimi 
1016*287e80b3SSadaf Ebrahimi 	synth->start_event = start_event;
1017*287e80b3SSadaf Ebrahimi 	synth->next_action = &synth->actions;
1018*287e80b3SSadaf Ebrahimi 
1019*287e80b3SSadaf Ebrahimi 	/* Hold onto a reference to this handler */
1020*287e80b3SSadaf Ebrahimi 	tep_ref(tep);
1021*287e80b3SSadaf Ebrahimi 	synth->tep = tep;
1022*287e80b3SSadaf Ebrahimi 
1023*287e80b3SSadaf Ebrahimi 	return synth;
1024*287e80b3SSadaf Ebrahimi }
1025*287e80b3SSadaf Ebrahimi 
alloc_synthetic_event(struct tracefs_synth * synth)1026*287e80b3SSadaf Ebrahimi static int alloc_synthetic_event(struct tracefs_synth *synth)
1027*287e80b3SSadaf Ebrahimi {
1028*287e80b3SSadaf Ebrahimi 	char *format;
1029*287e80b3SSadaf Ebrahimi 	const char *field;
1030*287e80b3SSadaf Ebrahimi 	int i;
1031*287e80b3SSadaf Ebrahimi 
1032*287e80b3SSadaf Ebrahimi 	format = strdup("");
1033*287e80b3SSadaf Ebrahimi 	if (!format)
1034*287e80b3SSadaf Ebrahimi 		return -1;
1035*287e80b3SSadaf Ebrahimi 
1036*287e80b3SSadaf Ebrahimi 	for (i = 0; synth->synthetic_fields && synth->synthetic_fields[i]; i++) {
1037*287e80b3SSadaf Ebrahimi 		field = synth->synthetic_fields[i];
1038*287e80b3SSadaf Ebrahimi 		format = append_string(format, i ? " " : NULL, field);
1039*287e80b3SSadaf Ebrahimi 	}
1040*287e80b3SSadaf Ebrahimi 
1041*287e80b3SSadaf Ebrahimi 	synth->dyn_event = dynevent_alloc(TRACEFS_DYNEVENT_SYNTH, SYNTHETIC_GROUP,
1042*287e80b3SSadaf Ebrahimi 					  synth->name, NULL, format);
1043*287e80b3SSadaf Ebrahimi 	free(format);
1044*287e80b3SSadaf Ebrahimi 
1045*287e80b3SSadaf Ebrahimi 	return synth->dyn_event ? 0 : -1;
1046*287e80b3SSadaf Ebrahimi }
1047*287e80b3SSadaf Ebrahimi 
1048*287e80b3SSadaf Ebrahimi /*
1049*287e80b3SSadaf Ebrahimi  * See if it is onmatch().trace(synth_event,...) or
1050*287e80b3SSadaf Ebrahimi  *   onmatch().synth_event(...)
1051*287e80b3SSadaf Ebrahimi  */
has_new_format()1052*287e80b3SSadaf Ebrahimi static bool has_new_format()
1053*287e80b3SSadaf Ebrahimi {
1054*287e80b3SSadaf Ebrahimi 	char *readme;
1055*287e80b3SSadaf Ebrahimi 	char *p;
1056*287e80b3SSadaf Ebrahimi 	int size;
1057*287e80b3SSadaf Ebrahimi 
1058*287e80b3SSadaf Ebrahimi 	readme = tracefs_instance_file_read(NULL, "README", &size);
1059*287e80b3SSadaf Ebrahimi 	if (!readme)
1060*287e80b3SSadaf Ebrahimi 		return false;
1061*287e80b3SSadaf Ebrahimi 
1062*287e80b3SSadaf Ebrahimi 	p = strstr(readme, "trace(<synthetic_event>,param list)");
1063*287e80b3SSadaf Ebrahimi 	free(readme);
1064*287e80b3SSadaf Ebrahimi 
1065*287e80b3SSadaf Ebrahimi 	return p != NULL;
1066*287e80b3SSadaf Ebrahimi }
1067*287e80b3SSadaf Ebrahimi 
1068*287e80b3SSadaf Ebrahimi /**
1069*287e80b3SSadaf Ebrahimi  * tracefs_synth_alloc - create a new tracefs_synth instance
1070*287e80b3SSadaf Ebrahimi  * @tep: The tep handle that holds the events to work on
1071*287e80b3SSadaf Ebrahimi  * @name: The name of the synthetic event being created
1072*287e80b3SSadaf Ebrahimi  * @start_system: The name of the system of the start event (can be NULL)
1073*287e80b3SSadaf Ebrahimi  * @start_event_name: The name of the start event
1074*287e80b3SSadaf Ebrahimi  * @end_system: The name of the system of the end event (can be NULL)
1075*287e80b3SSadaf Ebrahimi  * @end_event_name: The name of the end event
1076*287e80b3SSadaf Ebrahimi  * @start_match_field: The name of the field in start event to match @end_match_field
1077*287e80b3SSadaf Ebrahimi  * @end_match_field: The name of the field in end event to match @start_match_field
1078*287e80b3SSadaf Ebrahimi  * @match_name: Name to call the fields that match (can be NULL)
1079*287e80b3SSadaf Ebrahimi  *
1080*287e80b3SSadaf Ebrahimi  * Creates a tracefs_synth instance that has the minimum requirements to
1081*287e80b3SSadaf Ebrahimi  * create a synthetic event.
1082*287e80b3SSadaf Ebrahimi  *
1083*287e80b3SSadaf Ebrahimi  * @name is will be the name of the synthetic event that this can create.
1084*287e80b3SSadaf Ebrahimi  *
1085*287e80b3SSadaf Ebrahimi  * The start event is found with @start_system and @start_event_name. If
1086*287e80b3SSadaf Ebrahimi  * @start_system is NULL, then the first event with @start_event_name will
1087*287e80b3SSadaf Ebrahimi  * be used.
1088*287e80b3SSadaf Ebrahimi  *
1089*287e80b3SSadaf Ebrahimi  * The end event is found with @end_system and @end_event_name. If
1090*287e80b3SSadaf Ebrahimi  * @end_system is NULL, then the first event with @end_event_name will
1091*287e80b3SSadaf Ebrahimi  * be used.
1092*287e80b3SSadaf Ebrahimi  *
1093*287e80b3SSadaf Ebrahimi  * The @start_match_field is the field in the start event that will be used
1094*287e80b3SSadaf Ebrahimi  * to match the @end_match_field of the end event.
1095*287e80b3SSadaf Ebrahimi  *
1096*287e80b3SSadaf Ebrahimi  * If @match_name is given, then the field that matched the start and
1097*287e80b3SSadaf Ebrahimi  * end events will be passed an a field to the sythetic event with this
1098*287e80b3SSadaf Ebrahimi  * as the field name.
1099*287e80b3SSadaf Ebrahimi  *
1100*287e80b3SSadaf Ebrahimi  * Returns an allocated tracefs_synth descriptor on success and NULL
1101*287e80b3SSadaf Ebrahimi  * on error, with the following set in errno.
1102*287e80b3SSadaf Ebrahimi  *
1103*287e80b3SSadaf Ebrahimi  * ENOMEM - memory allocation failure.
1104*287e80b3SSadaf Ebrahimi  * ENIVAL - a parameter is passed as NULL that should not be
1105*287e80b3SSadaf Ebrahimi  * ENODEV - could not find an event or field
1106*287e80b3SSadaf Ebrahimi  * EBADE - The start and end fields are not compatible to match
1107*287e80b3SSadaf Ebrahimi  *
1108*287e80b3SSadaf Ebrahimi  * Note, this does not modify the system. That is, the synthetic
1109*287e80b3SSadaf Ebrahimi  * event on the system is not created. That needs to be done with
1110*287e80b3SSadaf Ebrahimi  * tracefs_synth_create().
1111*287e80b3SSadaf Ebrahimi  */
tracefs_synth_alloc(struct tep_handle * tep,const char * name,const char * start_system,const char * start_event_name,const char * end_system,const char * end_event_name,const char * start_match_field,const char * end_match_field,const char * match_name)1112*287e80b3SSadaf Ebrahimi struct tracefs_synth *tracefs_synth_alloc(struct tep_handle *tep,
1113*287e80b3SSadaf Ebrahimi 					  const char *name,
1114*287e80b3SSadaf Ebrahimi 					  const char *start_system,
1115*287e80b3SSadaf Ebrahimi 					  const char *start_event_name,
1116*287e80b3SSadaf Ebrahimi 					  const char *end_system,
1117*287e80b3SSadaf Ebrahimi 					  const char *end_event_name,
1118*287e80b3SSadaf Ebrahimi 					  const char *start_match_field,
1119*287e80b3SSadaf Ebrahimi 					  const char *end_match_field,
1120*287e80b3SSadaf Ebrahimi 					  const char *match_name)
1121*287e80b3SSadaf Ebrahimi {
1122*287e80b3SSadaf Ebrahimi 	struct tep_event *end_event;
1123*287e80b3SSadaf Ebrahimi 	struct tracefs_synth *synth;
1124*287e80b3SSadaf Ebrahimi 	int ret = 0;
1125*287e80b3SSadaf Ebrahimi 
1126*287e80b3SSadaf Ebrahimi 	if (!tep || !name || !start_event_name || !end_event_name ||
1127*287e80b3SSadaf Ebrahimi 	    !start_match_field || !end_match_field) {
1128*287e80b3SSadaf Ebrahimi 		errno = EINVAL;
1129*287e80b3SSadaf Ebrahimi 		return NULL;
1130*287e80b3SSadaf Ebrahimi 	}
1131*287e80b3SSadaf Ebrahimi 
1132*287e80b3SSadaf Ebrahimi 	synth = synth_init_from(tep, start_system, start_event_name);
1133*287e80b3SSadaf Ebrahimi 	if (!synth)
1134*287e80b3SSadaf Ebrahimi 		return NULL;
1135*287e80b3SSadaf Ebrahimi 
1136*287e80b3SSadaf Ebrahimi 	end_event = tep_find_event_by_name(tep, end_system,
1137*287e80b3SSadaf Ebrahimi 					   end_event_name);
1138*287e80b3SSadaf Ebrahimi 	if (!end_event) {
1139*287e80b3SSadaf Ebrahimi 		tep_unref(tep);
1140*287e80b3SSadaf Ebrahimi 		errno = ENODEV;
1141*287e80b3SSadaf Ebrahimi 		return NULL;
1142*287e80b3SSadaf Ebrahimi 	}
1143*287e80b3SSadaf Ebrahimi 
1144*287e80b3SSadaf Ebrahimi 	synth->end_event = end_event;
1145*287e80b3SSadaf Ebrahimi 
1146*287e80b3SSadaf Ebrahimi 	synth->name = strdup(name);
1147*287e80b3SSadaf Ebrahimi 
1148*287e80b3SSadaf Ebrahimi 	ret = tracefs_synth_add_match_field(synth, start_match_field,
1149*287e80b3SSadaf Ebrahimi 					    end_match_field, match_name);
1150*287e80b3SSadaf Ebrahimi 
1151*287e80b3SSadaf Ebrahimi 	if (!synth->name || !synth->start_keys || !synth->end_keys || ret) {
1152*287e80b3SSadaf Ebrahimi 		tracefs_synth_free(synth);
1153*287e80b3SSadaf Ebrahimi 		synth = NULL;
1154*287e80b3SSadaf Ebrahimi 	} else
1155*287e80b3SSadaf Ebrahimi 		synth->new_format = has_new_format();
1156*287e80b3SSadaf Ebrahimi 
1157*287e80b3SSadaf Ebrahimi 	return synth;
1158*287e80b3SSadaf Ebrahimi }
1159*287e80b3SSadaf Ebrahimi 
add_synth_fields(struct tracefs_synth * synth,const struct tep_format_field * field,const char * name,const char * var)1160*287e80b3SSadaf Ebrahimi static int add_synth_fields(struct tracefs_synth *synth,
1161*287e80b3SSadaf Ebrahimi 			    const struct tep_format_field *field,
1162*287e80b3SSadaf Ebrahimi 			    const char *name, const char *var)
1163*287e80b3SSadaf Ebrahimi {
1164*287e80b3SSadaf Ebrahimi 	char **list;
1165*287e80b3SSadaf Ebrahimi 	char *str;
1166*287e80b3SSadaf Ebrahimi 	int ret;
1167*287e80b3SSadaf Ebrahimi 
1168*287e80b3SSadaf Ebrahimi 	str = add_synth_field(field, name ? : field->name);
1169*287e80b3SSadaf Ebrahimi 	if (!str)
1170*287e80b3SSadaf Ebrahimi 		return -1;
1171*287e80b3SSadaf Ebrahimi 
1172*287e80b3SSadaf Ebrahimi 	if (!name)
1173*287e80b3SSadaf Ebrahimi 		name = var;
1174*287e80b3SSadaf Ebrahimi 
1175*287e80b3SSadaf Ebrahimi 	list = tracefs_list_add(synth->synthetic_fields, str);
1176*287e80b3SSadaf Ebrahimi 	free(str);
1177*287e80b3SSadaf Ebrahimi 	if (!list)
1178*287e80b3SSadaf Ebrahimi 		return -1;
1179*287e80b3SSadaf Ebrahimi 	synth->synthetic_fields = list;
1180*287e80b3SSadaf Ebrahimi 
1181*287e80b3SSadaf Ebrahimi 	ret = asprintf(&str, "$%s", var ? : name);
1182*287e80b3SSadaf Ebrahimi 	if (ret < 0) {
1183*287e80b3SSadaf Ebrahimi 		trace_list_pop(synth->synthetic_fields);
1184*287e80b3SSadaf Ebrahimi 		return -1;
1185*287e80b3SSadaf Ebrahimi 	}
1186*287e80b3SSadaf Ebrahimi 
1187*287e80b3SSadaf Ebrahimi 	list = tracefs_list_add(synth->synthetic_args, str);
1188*287e80b3SSadaf Ebrahimi 	free(str);
1189*287e80b3SSadaf Ebrahimi 	if (!list) {
1190*287e80b3SSadaf Ebrahimi 		trace_list_pop(synth->synthetic_fields);
1191*287e80b3SSadaf Ebrahimi 		return -1;
1192*287e80b3SSadaf Ebrahimi 	}
1193*287e80b3SSadaf Ebrahimi 
1194*287e80b3SSadaf Ebrahimi 	synth->synthetic_args = list;
1195*287e80b3SSadaf Ebrahimi 
1196*287e80b3SSadaf Ebrahimi 	return 0;
1197*287e80b3SSadaf Ebrahimi }
1198*287e80b3SSadaf Ebrahimi 
1199*287e80b3SSadaf Ebrahimi /**
1200*287e80b3SSadaf Ebrahimi  * tracefs_synth_add_match_field - add another key to match events
1201*287e80b3SSadaf Ebrahimi  * @synth: The tracefs_synth descriptor
1202*287e80b3SSadaf Ebrahimi  * @start_match_field: The field of the start event to match the end event
1203*287e80b3SSadaf Ebrahimi  * @end_match_field: The field of the end event to match the start event
1204*287e80b3SSadaf Ebrahimi  * @name: The name to show in the synthetic event (NULL is allowed)
1205*287e80b3SSadaf Ebrahimi  *
1206*287e80b3SSadaf Ebrahimi  * This will add another set of keys to use for a match between
1207*287e80b3SSadaf Ebrahimi  * the start event and the end event.
1208*287e80b3SSadaf Ebrahimi  *
1209*287e80b3SSadaf Ebrahimi  * Returns 0 on succes and -1 on error.
1210*287e80b3SSadaf Ebrahimi  * On error, errno is set to:
1211*287e80b3SSadaf Ebrahimi  * ENOMEM - memory allocation failure.
1212*287e80b3SSadaf Ebrahimi  * ENIVAL - a parameter is passed as NULL that should not be
1213*287e80b3SSadaf Ebrahimi  * ENODEV - could not find a field
1214*287e80b3SSadaf Ebrahimi  * EBADE - The start and end fields are not compatible to match
1215*287e80b3SSadaf Ebrahimi  */
tracefs_synth_add_match_field(struct tracefs_synth * synth,const char * start_match_field,const char * end_match_field,const char * name)1216*287e80b3SSadaf Ebrahimi int tracefs_synth_add_match_field(struct tracefs_synth *synth,
1217*287e80b3SSadaf Ebrahimi 				  const char *start_match_field,
1218*287e80b3SSadaf Ebrahimi 				  const char *end_match_field,
1219*287e80b3SSadaf Ebrahimi 				  const char *name)
1220*287e80b3SSadaf Ebrahimi {
1221*287e80b3SSadaf Ebrahimi 	const struct tep_format_field *key_field;
1222*287e80b3SSadaf Ebrahimi 	char **list;
1223*287e80b3SSadaf Ebrahimi 	int ret;
1224*287e80b3SSadaf Ebrahimi 
1225*287e80b3SSadaf Ebrahimi 	if (!synth || !start_match_field || !end_match_field) {
1226*287e80b3SSadaf Ebrahimi 		errno = EINVAL;
1227*287e80b3SSadaf Ebrahimi 		return -1;
1228*287e80b3SSadaf Ebrahimi 	}
1229*287e80b3SSadaf Ebrahimi 
1230*287e80b3SSadaf Ebrahimi 	if (!verify_event_fields(synth->start_event, synth->end_event,
1231*287e80b3SSadaf Ebrahimi 				 start_match_field, end_match_field,
1232*287e80b3SSadaf Ebrahimi 				 &key_field))
1233*287e80b3SSadaf Ebrahimi 		return -1;
1234*287e80b3SSadaf Ebrahimi 
1235*287e80b3SSadaf Ebrahimi 	list = tracefs_list_add(synth->start_keys, start_match_field);
1236*287e80b3SSadaf Ebrahimi 	if (!list)
1237*287e80b3SSadaf Ebrahimi 		return -1;
1238*287e80b3SSadaf Ebrahimi 
1239*287e80b3SSadaf Ebrahimi 	synth->start_keys = list;
1240*287e80b3SSadaf Ebrahimi 
1241*287e80b3SSadaf Ebrahimi 	list = tracefs_list_add(synth->end_keys, end_match_field);
1242*287e80b3SSadaf Ebrahimi 	if (!list) {
1243*287e80b3SSadaf Ebrahimi 		trace_list_pop(synth->start_keys);
1244*287e80b3SSadaf Ebrahimi 		return -1;
1245*287e80b3SSadaf Ebrahimi 	}
1246*287e80b3SSadaf Ebrahimi 	synth->end_keys = list;
1247*287e80b3SSadaf Ebrahimi 
1248*287e80b3SSadaf Ebrahimi 	if (!name)
1249*287e80b3SSadaf Ebrahimi 		return 0;
1250*287e80b3SSadaf Ebrahimi 
1251*287e80b3SSadaf Ebrahimi 	ret = add_var(&synth->end_vars, name, end_match_field, false);
1252*287e80b3SSadaf Ebrahimi 
1253*287e80b3SSadaf Ebrahimi 	if (ret < 0)
1254*287e80b3SSadaf Ebrahimi 		goto pop_lists;
1255*287e80b3SSadaf Ebrahimi 
1256*287e80b3SSadaf Ebrahimi 	ret = add_synth_fields(synth, key_field, name, NULL);
1257*287e80b3SSadaf Ebrahimi 	if (ret < 0)
1258*287e80b3SSadaf Ebrahimi 		goto pop_lists;
1259*287e80b3SSadaf Ebrahimi 
1260*287e80b3SSadaf Ebrahimi 	return 0;
1261*287e80b3SSadaf Ebrahimi 
1262*287e80b3SSadaf Ebrahimi  pop_lists:
1263*287e80b3SSadaf Ebrahimi 	trace_list_pop(synth->start_keys);
1264*287e80b3SSadaf Ebrahimi 	trace_list_pop(synth->end_keys);
1265*287e80b3SSadaf Ebrahimi 	return -1;
1266*287e80b3SSadaf Ebrahimi }
1267*287e80b3SSadaf Ebrahimi 
make_rand(void)1268*287e80b3SSadaf Ebrahimi static unsigned int make_rand(void)
1269*287e80b3SSadaf Ebrahimi {
1270*287e80b3SSadaf Ebrahimi 	struct timeval tv;
1271*287e80b3SSadaf Ebrahimi 	unsigned long seed;
1272*287e80b3SSadaf Ebrahimi 
1273*287e80b3SSadaf Ebrahimi 	gettimeofday(&tv, NULL);
1274*287e80b3SSadaf Ebrahimi 	seed = (tv.tv_sec + tv.tv_usec) + getpid();
1275*287e80b3SSadaf Ebrahimi 
1276*287e80b3SSadaf Ebrahimi 	/* taken from the rand(3) man page */
1277*287e80b3SSadaf Ebrahimi 	seed = seed * 1103515245 + 12345;
1278*287e80b3SSadaf Ebrahimi 	return((unsigned)(seed/65536) % 32768);
1279*287e80b3SSadaf Ebrahimi }
1280*287e80b3SSadaf Ebrahimi 
new_name(struct tracefs_synth * synth,const char * name)1281*287e80b3SSadaf Ebrahimi static char *new_name(struct tracefs_synth *synth, const char *name)
1282*287e80b3SSadaf Ebrahimi {
1283*287e80b3SSadaf Ebrahimi 	int cnt = synth->arg_cnt + 1;
1284*287e80b3SSadaf Ebrahimi 	char *arg;
1285*287e80b3SSadaf Ebrahimi 	int ret;
1286*287e80b3SSadaf Ebrahimi 
1287*287e80b3SSadaf Ebrahimi 	/* Create a unique argument name */
1288*287e80b3SSadaf Ebrahimi 	if (!synth->arg_name[0]) {
1289*287e80b3SSadaf Ebrahimi 		/* make_rand() returns at most 32768 (total 13 bytes in use) */
1290*287e80b3SSadaf Ebrahimi 		sprintf(synth->arg_name, "%u", make_rand());
1291*287e80b3SSadaf Ebrahimi 	}
1292*287e80b3SSadaf Ebrahimi 	ret = asprintf(&arg, "__%s_%s_%d", name, synth->arg_name, cnt);
1293*287e80b3SSadaf Ebrahimi 	if (ret < 0)
1294*287e80b3SSadaf Ebrahimi 		return NULL;
1295*287e80b3SSadaf Ebrahimi 
1296*287e80b3SSadaf Ebrahimi 	synth->arg_cnt = cnt;
1297*287e80b3SSadaf Ebrahimi 	return arg;
1298*287e80b3SSadaf Ebrahimi }
1299*287e80b3SSadaf Ebrahimi 
find_name(struct tracefs_synth * synth,const char * name)1300*287e80b3SSadaf Ebrahimi static struct name_hash *find_name(struct tracefs_synth *synth, const char *name)
1301*287e80b3SSadaf Ebrahimi {
1302*287e80b3SSadaf Ebrahimi 	unsigned int key = quick_hash(name);
1303*287e80b3SSadaf Ebrahimi 	struct name_hash *hash = synth->name_hash[key];
1304*287e80b3SSadaf Ebrahimi 
1305*287e80b3SSadaf Ebrahimi 	for (; hash; hash = hash->next) {
1306*287e80b3SSadaf Ebrahimi 		if (!strcmp(hash->name, name))
1307*287e80b3SSadaf Ebrahimi 			return hash;
1308*287e80b3SSadaf Ebrahimi 	}
1309*287e80b3SSadaf Ebrahimi 	return NULL;
1310*287e80b3SSadaf Ebrahimi }
1311*287e80b3SSadaf Ebrahimi 
hash_name(struct tracefs_synth * synth,const char * name)1312*287e80b3SSadaf Ebrahimi static const char *hash_name(struct tracefs_synth *synth, const char *name)
1313*287e80b3SSadaf Ebrahimi {
1314*287e80b3SSadaf Ebrahimi 	struct name_hash *hash;
1315*287e80b3SSadaf Ebrahimi 	int key;
1316*287e80b3SSadaf Ebrahimi 
1317*287e80b3SSadaf Ebrahimi 	hash = find_name(synth, name);
1318*287e80b3SSadaf Ebrahimi 	if (hash)
1319*287e80b3SSadaf Ebrahimi 		return hash->hash;
1320*287e80b3SSadaf Ebrahimi 
1321*287e80b3SSadaf Ebrahimi 	hash = malloc(sizeof(*hash));
1322*287e80b3SSadaf Ebrahimi 	if (!hash)
1323*287e80b3SSadaf Ebrahimi 		return name;
1324*287e80b3SSadaf Ebrahimi 
1325*287e80b3SSadaf Ebrahimi 	hash->hash = new_name(synth, name);
1326*287e80b3SSadaf Ebrahimi 	if (!hash->hash) {
1327*287e80b3SSadaf Ebrahimi 		free(hash);
1328*287e80b3SSadaf Ebrahimi 		return name;
1329*287e80b3SSadaf Ebrahimi 	}
1330*287e80b3SSadaf Ebrahimi 
1331*287e80b3SSadaf Ebrahimi 	key = quick_hash(name);
1332*287e80b3SSadaf Ebrahimi 	hash->next = synth->name_hash[key];
1333*287e80b3SSadaf Ebrahimi 	synth->name_hash[key] = hash;
1334*287e80b3SSadaf Ebrahimi 
1335*287e80b3SSadaf Ebrahimi 	hash->name = strdup(name);
1336*287e80b3SSadaf Ebrahimi 	if (!hash->name) {
1337*287e80b3SSadaf Ebrahimi 		free(hash->hash);
1338*287e80b3SSadaf Ebrahimi 		free(hash);
1339*287e80b3SSadaf Ebrahimi 		return name;
1340*287e80b3SSadaf Ebrahimi 	}
1341*287e80b3SSadaf Ebrahimi 	return hash->hash;
1342*287e80b3SSadaf Ebrahimi }
1343*287e80b3SSadaf Ebrahimi 
new_arg(struct tracefs_synth * synth)1344*287e80b3SSadaf Ebrahimi static char *new_arg(struct tracefs_synth *synth)
1345*287e80b3SSadaf Ebrahimi {
1346*287e80b3SSadaf Ebrahimi 	return new_name(synth, "arg");
1347*287e80b3SSadaf Ebrahimi }
1348*287e80b3SSadaf Ebrahimi 
1349*287e80b3SSadaf Ebrahimi /**
1350*287e80b3SSadaf Ebrahimi  * tracefs_synth_add_compare_field - add a comparison between start and end
1351*287e80b3SSadaf Ebrahimi  * @synth: The tracefs_synth descriptor
1352*287e80b3SSadaf Ebrahimi  * @start_compare_field: The field of the start event to compare to the end
1353*287e80b3SSadaf Ebrahimi  * @end_compare_field: The field of the end event to compare to the start
1354*287e80b3SSadaf Ebrahimi  * @calc - How to go about the comparing the fields.
1355*287e80b3SSadaf Ebrahimi  * @name: The name to show in the synthetic event (must NOT be NULL)
1356*287e80b3SSadaf Ebrahimi  *
1357*287e80b3SSadaf Ebrahimi  * This will add a way to compare two different fields between the
1358*287e80b3SSadaf Ebrahimi  * start end end events.
1359*287e80b3SSadaf Ebrahimi  *
1360*287e80b3SSadaf Ebrahimi  * The comparing between events is decided by @calc:
1361*287e80b3SSadaf Ebrahimi  *    TRACEFS_SYNTH_DELTA_END       - name = end - start
1362*287e80b3SSadaf Ebrahimi  *    TRACEFS_SYNTH_DELTA_START     - name = start - end
1363*287e80b3SSadaf Ebrahimi  *    TRACEFS_SYNTH_ADD             - name = end + start
1364*287e80b3SSadaf Ebrahimi  *
1365*287e80b3SSadaf Ebrahimi  * Returns 0 on succes and -1 on error.
1366*287e80b3SSadaf Ebrahimi  * On error, errno is set to:
1367*287e80b3SSadaf Ebrahimi  * ENOMEM - memory allocation failure.
1368*287e80b3SSadaf Ebrahimi  * ENIVAL - a parameter is passed as NULL that should not be
1369*287e80b3SSadaf Ebrahimi  * ENODEV - could not find a field
1370*287e80b3SSadaf Ebrahimi  * EBADE - The start and end fields are not compatible to compare
1371*287e80b3SSadaf Ebrahimi  */
tracefs_synth_add_compare_field(struct tracefs_synth * synth,const char * start_compare_field,const char * end_compare_field,enum tracefs_synth_calc calc,const char * name)1372*287e80b3SSadaf Ebrahimi int tracefs_synth_add_compare_field(struct tracefs_synth *synth,
1373*287e80b3SSadaf Ebrahimi 				    const char *start_compare_field,
1374*287e80b3SSadaf Ebrahimi 				    const char *end_compare_field,
1375*287e80b3SSadaf Ebrahimi 				    enum tracefs_synth_calc calc,
1376*287e80b3SSadaf Ebrahimi 				    const char *name)
1377*287e80b3SSadaf Ebrahimi {
1378*287e80b3SSadaf Ebrahimi 	const struct tep_format_field *start_field;
1379*287e80b3SSadaf Ebrahimi 	const char *hname;
1380*287e80b3SSadaf Ebrahimi 	char *start_arg;
1381*287e80b3SSadaf Ebrahimi 	char *compare;
1382*287e80b3SSadaf Ebrahimi 	int ret;
1383*287e80b3SSadaf Ebrahimi 
1384*287e80b3SSadaf Ebrahimi 	/* Compare fields require a name */
1385*287e80b3SSadaf Ebrahimi 	if (!name || !start_compare_field || !end_compare_field) {
1386*287e80b3SSadaf Ebrahimi 		errno = -EINVAL;
1387*287e80b3SSadaf Ebrahimi 		return -1;
1388*287e80b3SSadaf Ebrahimi 	}
1389*287e80b3SSadaf Ebrahimi 
1390*287e80b3SSadaf Ebrahimi 	if (!verify_event_fields(synth->start_event, synth->end_event,
1391*287e80b3SSadaf Ebrahimi 				 start_compare_field, end_compare_field,
1392*287e80b3SSadaf Ebrahimi 				 &start_field))
1393*287e80b3SSadaf Ebrahimi 		return -1;
1394*287e80b3SSadaf Ebrahimi 
1395*287e80b3SSadaf Ebrahimi 	/* Calculations are not allowed on string */
1396*287e80b3SSadaf Ebrahimi 	if (start_field->flags & (TEP_FIELD_IS_ARRAY |
1397*287e80b3SSadaf Ebrahimi 				  TEP_FIELD_IS_DYNAMIC)) {
1398*287e80b3SSadaf Ebrahimi 		errno = -EINVAL;
1399*287e80b3SSadaf Ebrahimi 		return -1;
1400*287e80b3SSadaf Ebrahimi 	}
1401*287e80b3SSadaf Ebrahimi 
1402*287e80b3SSadaf Ebrahimi 	start_arg = new_arg(synth);
1403*287e80b3SSadaf Ebrahimi 	if (!start_arg)
1404*287e80b3SSadaf Ebrahimi 		return -1;
1405*287e80b3SSadaf Ebrahimi 
1406*287e80b3SSadaf Ebrahimi 	ret = add_var(&synth->start_vars, start_arg, start_compare_field, false);
1407*287e80b3SSadaf Ebrahimi 	if (ret < 0) {
1408*287e80b3SSadaf Ebrahimi 		free(start_arg);
1409*287e80b3SSadaf Ebrahimi 		return -1;
1410*287e80b3SSadaf Ebrahimi 	}
1411*287e80b3SSadaf Ebrahimi 
1412*287e80b3SSadaf Ebrahimi 	ret = -1;
1413*287e80b3SSadaf Ebrahimi 	switch (calc) {
1414*287e80b3SSadaf Ebrahimi 	case TRACEFS_SYNTH_DELTA_END:
1415*287e80b3SSadaf Ebrahimi 		ret = asprintf(&compare, "%s-$%s", end_compare_field,
1416*287e80b3SSadaf Ebrahimi 			       start_arg);
1417*287e80b3SSadaf Ebrahimi 		break;
1418*287e80b3SSadaf Ebrahimi 	case TRACEFS_SYNTH_DELTA_START:
1419*287e80b3SSadaf Ebrahimi 		ret = asprintf(&compare, "$%s-%s", start_arg,
1420*287e80b3SSadaf Ebrahimi 			       end_compare_field);
1421*287e80b3SSadaf Ebrahimi 		break;
1422*287e80b3SSadaf Ebrahimi 	case TRACEFS_SYNTH_ADD:
1423*287e80b3SSadaf Ebrahimi 		ret = asprintf(&compare, "%s+$%s", end_compare_field,
1424*287e80b3SSadaf Ebrahimi 			       start_arg);
1425*287e80b3SSadaf Ebrahimi 		break;
1426*287e80b3SSadaf Ebrahimi 	}
1427*287e80b3SSadaf Ebrahimi 	free(start_arg);
1428*287e80b3SSadaf Ebrahimi 	if (ret < 0)
1429*287e80b3SSadaf Ebrahimi 		return -1;
1430*287e80b3SSadaf Ebrahimi 
1431*287e80b3SSadaf Ebrahimi 	hname = hash_name(synth, name);
1432*287e80b3SSadaf Ebrahimi 	ret = add_var(&synth->end_vars, hname, compare, false);
1433*287e80b3SSadaf Ebrahimi 	if (ret < 0)
1434*287e80b3SSadaf Ebrahimi 		goto out_free;
1435*287e80b3SSadaf Ebrahimi 
1436*287e80b3SSadaf Ebrahimi 	ret = add_synth_fields(synth, start_field, name, hname);
1437*287e80b3SSadaf Ebrahimi 	if (ret < 0)
1438*287e80b3SSadaf Ebrahimi 		goto out_free;
1439*287e80b3SSadaf Ebrahimi 
1440*287e80b3SSadaf Ebrahimi  out_free:
1441*287e80b3SSadaf Ebrahimi 	free(compare);
1442*287e80b3SSadaf Ebrahimi 
1443*287e80b3SSadaf Ebrahimi 	return ret ? -1 : 0;
1444*287e80b3SSadaf Ebrahimi }
1445*287e80b3SSadaf Ebrahimi 
synth_add_start_field(struct tracefs_synth * synth,const char * start_field,const char * name,enum tracefs_hist_key_type type,int count)1446*287e80b3SSadaf Ebrahimi __hidden int synth_add_start_field(struct tracefs_synth *synth,
1447*287e80b3SSadaf Ebrahimi 				   const char *start_field,
1448*287e80b3SSadaf Ebrahimi 				   const char *name,
1449*287e80b3SSadaf Ebrahimi 				   enum tracefs_hist_key_type type, int count)
1450*287e80b3SSadaf Ebrahimi {
1451*287e80b3SSadaf Ebrahimi 	const struct tep_format_field *field;
1452*287e80b3SSadaf Ebrahimi 	const char *var;
1453*287e80b3SSadaf Ebrahimi 	char *start_arg;
1454*287e80b3SSadaf Ebrahimi 	char **tmp;
1455*287e80b3SSadaf Ebrahimi 	int *types;
1456*287e80b3SSadaf Ebrahimi 	int len;
1457*287e80b3SSadaf Ebrahimi 	int ret;
1458*287e80b3SSadaf Ebrahimi 
1459*287e80b3SSadaf Ebrahimi 	if (!synth || !start_field) {
1460*287e80b3SSadaf Ebrahimi 		errno = EINVAL;
1461*287e80b3SSadaf Ebrahimi 		return -1;
1462*287e80b3SSadaf Ebrahimi 	}
1463*287e80b3SSadaf Ebrahimi 
1464*287e80b3SSadaf Ebrahimi 	if (!name)
1465*287e80b3SSadaf Ebrahimi 		name = start_field;
1466*287e80b3SSadaf Ebrahimi 
1467*287e80b3SSadaf Ebrahimi 	var = hash_name(synth, name);
1468*287e80b3SSadaf Ebrahimi 
1469*287e80b3SSadaf Ebrahimi 	if (!trace_verify_event_field(synth->start_event, start_field, &field))
1470*287e80b3SSadaf Ebrahimi 		return -1;
1471*287e80b3SSadaf Ebrahimi 
1472*287e80b3SSadaf Ebrahimi 	start_arg = new_arg(synth);
1473*287e80b3SSadaf Ebrahimi 	if (!start_arg)
1474*287e80b3SSadaf Ebrahimi 		return -1;
1475*287e80b3SSadaf Ebrahimi 
1476*287e80b3SSadaf Ebrahimi 	ret = add_var(&synth->start_vars, start_arg, start_field, false);
1477*287e80b3SSadaf Ebrahimi 	if (ret)
1478*287e80b3SSadaf Ebrahimi 		goto out_free;
1479*287e80b3SSadaf Ebrahimi 
1480*287e80b3SSadaf Ebrahimi 	ret = add_var(&synth->end_vars, var, start_arg, true);
1481*287e80b3SSadaf Ebrahimi 	if (ret)
1482*287e80b3SSadaf Ebrahimi 		goto out_free;
1483*287e80b3SSadaf Ebrahimi 
1484*287e80b3SSadaf Ebrahimi 	ret = add_synth_fields(synth, field, name, var);
1485*287e80b3SSadaf Ebrahimi 	if (ret)
1486*287e80b3SSadaf Ebrahimi 		goto out_free;
1487*287e80b3SSadaf Ebrahimi 
1488*287e80b3SSadaf Ebrahimi 	tmp = tracefs_list_add(synth->start_selection, start_field);
1489*287e80b3SSadaf Ebrahimi 	if (!tmp) {
1490*287e80b3SSadaf Ebrahimi 		ret = -1;
1491*287e80b3SSadaf Ebrahimi 		goto out_free;
1492*287e80b3SSadaf Ebrahimi 	}
1493*287e80b3SSadaf Ebrahimi 	synth->start_selection = tmp;
1494*287e80b3SSadaf Ebrahimi 
1495*287e80b3SSadaf Ebrahimi 	len = tracefs_list_size(tmp);
1496*287e80b3SSadaf Ebrahimi 	if (len <= 0) { /* ?? */
1497*287e80b3SSadaf Ebrahimi 		ret = -1;
1498*287e80b3SSadaf Ebrahimi 		goto out_free;
1499*287e80b3SSadaf Ebrahimi 	}
1500*287e80b3SSadaf Ebrahimi 
1501*287e80b3SSadaf Ebrahimi 	types = realloc(synth->start_type, sizeof(*types) * len);
1502*287e80b3SSadaf Ebrahimi 	if (!types) {
1503*287e80b3SSadaf Ebrahimi 		ret = -1;
1504*287e80b3SSadaf Ebrahimi 		goto out_free;
1505*287e80b3SSadaf Ebrahimi 	}
1506*287e80b3SSadaf Ebrahimi 	synth->start_type = types;
1507*287e80b3SSadaf Ebrahimi 	synth->start_type[len - 1] = type;
1508*287e80b3SSadaf Ebrahimi 
1509*287e80b3SSadaf Ebrahimi  out_free:
1510*287e80b3SSadaf Ebrahimi 	free(start_arg);
1511*287e80b3SSadaf Ebrahimi 	return ret;
1512*287e80b3SSadaf Ebrahimi }
1513*287e80b3SSadaf Ebrahimi 
1514*287e80b3SSadaf Ebrahimi /**
1515*287e80b3SSadaf Ebrahimi  * tracefs_synth_add_start_field - add a start field to save
1516*287e80b3SSadaf Ebrahimi  * @synth: The tracefs_synth descriptor
1517*287e80b3SSadaf Ebrahimi  * @start_field: The field of the start event to save
1518*287e80b3SSadaf Ebrahimi  * @name: The name to show in the synthetic event (if NULL @start_field is used)
1519*287e80b3SSadaf Ebrahimi  *
1520*287e80b3SSadaf Ebrahimi  * This adds a field named by @start_field of the start event to
1521*287e80b3SSadaf Ebrahimi  * record in the synthetic event.
1522*287e80b3SSadaf Ebrahimi  *
1523*287e80b3SSadaf Ebrahimi  * Returns 0 on succes and -1 on error.
1524*287e80b3SSadaf Ebrahimi  * On error, errno is set to:
1525*287e80b3SSadaf Ebrahimi  * ENOMEM - memory allocation failure.
1526*287e80b3SSadaf Ebrahimi  * ENIVAL - a parameter is passed as NULL that should not be
1527*287e80b3SSadaf Ebrahimi  * ENODEV - could not find a field
1528*287e80b3SSadaf Ebrahimi  */
tracefs_synth_add_start_field(struct tracefs_synth * synth,const char * start_field,const char * name)1529*287e80b3SSadaf Ebrahimi int tracefs_synth_add_start_field(struct tracefs_synth *synth,
1530*287e80b3SSadaf Ebrahimi 				  const char *start_field,
1531*287e80b3SSadaf Ebrahimi 				  const char *name)
1532*287e80b3SSadaf Ebrahimi {
1533*287e80b3SSadaf Ebrahimi 	return synth_add_start_field(synth, start_field, name, 0, 0);
1534*287e80b3SSadaf Ebrahimi }
1535*287e80b3SSadaf Ebrahimi 
1536*287e80b3SSadaf Ebrahimi /**
1537*287e80b3SSadaf Ebrahimi  * tracefs_synth_add_end_field - add a end field to save
1538*287e80b3SSadaf Ebrahimi  * @synth: The tracefs_synth descriptor
1539*287e80b3SSadaf Ebrahimi  * @end_field: The field of the end event to save
1540*287e80b3SSadaf Ebrahimi  * @name: The name to show in the synthetic event (if NULL @end_field is used)
1541*287e80b3SSadaf Ebrahimi  *
1542*287e80b3SSadaf Ebrahimi  * This adds a field named by @end_field of the start event to
1543*287e80b3SSadaf Ebrahimi  * record in the synthetic event.
1544*287e80b3SSadaf Ebrahimi  *
1545*287e80b3SSadaf Ebrahimi  * Returns 0 on succes and -1 on error.
1546*287e80b3SSadaf Ebrahimi  * On error, errno is set to:
1547*287e80b3SSadaf Ebrahimi  * ENOMEM - memory allocation failure.
1548*287e80b3SSadaf Ebrahimi  * ENIVAL - a parameter is passed as NULL that should not be
1549*287e80b3SSadaf Ebrahimi  * ENODEV - could not find a field
1550*287e80b3SSadaf Ebrahimi  */
tracefs_synth_add_end_field(struct tracefs_synth * synth,const char * end_field,const char * name)1551*287e80b3SSadaf Ebrahimi int tracefs_synth_add_end_field(struct tracefs_synth *synth,
1552*287e80b3SSadaf Ebrahimi 				const char *end_field,
1553*287e80b3SSadaf Ebrahimi 				const char *name)
1554*287e80b3SSadaf Ebrahimi {
1555*287e80b3SSadaf Ebrahimi 	const struct tep_format_field *field;
1556*287e80b3SSadaf Ebrahimi 	const char *hname = NULL;
1557*287e80b3SSadaf Ebrahimi 	char *tmp_var = NULL;
1558*287e80b3SSadaf Ebrahimi 	int ret;
1559*287e80b3SSadaf Ebrahimi 
1560*287e80b3SSadaf Ebrahimi 	if (!synth || !end_field) {
1561*287e80b3SSadaf Ebrahimi 		errno = EINVAL;
1562*287e80b3SSadaf Ebrahimi 		return -1;
1563*287e80b3SSadaf Ebrahimi 	}
1564*287e80b3SSadaf Ebrahimi 
1565*287e80b3SSadaf Ebrahimi 	if (name) {
1566*287e80b3SSadaf Ebrahimi 		if (strncmp(name, "__arg", 5) != 0)
1567*287e80b3SSadaf Ebrahimi 			hname = hash_name(synth, name);
1568*287e80b3SSadaf Ebrahimi 		else
1569*287e80b3SSadaf Ebrahimi 			hname = name;
1570*287e80b3SSadaf Ebrahimi 	}
1571*287e80b3SSadaf Ebrahimi 
1572*287e80b3SSadaf Ebrahimi 	if (!name)
1573*287e80b3SSadaf Ebrahimi 		tmp_var = new_arg(synth);
1574*287e80b3SSadaf Ebrahimi 
1575*287e80b3SSadaf Ebrahimi 	if (!trace_verify_event_field(synth->end_event, end_field, &field))
1576*287e80b3SSadaf Ebrahimi 		return -1;
1577*287e80b3SSadaf Ebrahimi 
1578*287e80b3SSadaf Ebrahimi 	ret = add_var(&synth->end_vars, name ? hname : tmp_var, end_field, false);
1579*287e80b3SSadaf Ebrahimi 	if (ret)
1580*287e80b3SSadaf Ebrahimi 		goto out;
1581*287e80b3SSadaf Ebrahimi 
1582*287e80b3SSadaf Ebrahimi 	ret = add_synth_fields(synth, field, name, hname ? : tmp_var);
1583*287e80b3SSadaf Ebrahimi 	free(tmp_var);
1584*287e80b3SSadaf Ebrahimi  out:
1585*287e80b3SSadaf Ebrahimi 	return ret;
1586*287e80b3SSadaf Ebrahimi }
1587*287e80b3SSadaf Ebrahimi 
1588*287e80b3SSadaf Ebrahimi /**
1589*287e80b3SSadaf Ebrahimi  * tracefs_synth_append_start_filter - create or append a filter
1590*287e80b3SSadaf Ebrahimi  * @synth: The tracefs_synth descriptor
1591*287e80b3SSadaf Ebrahimi  * @type: The type of element to add to the filter
1592*287e80b3SSadaf Ebrahimi  * @field: For @type == TRACEFS_FILTER_COMPARE, the field to compare
1593*287e80b3SSadaf Ebrahimi  * @compare: For @type == TRACEFS_FILTER_COMPARE, how to compare @field to @val
1594*287e80b3SSadaf Ebrahimi  * @val: For @type == TRACEFS_FILTER_COMPARE, what value @field is to be
1595*287e80b3SSadaf Ebrahimi  *
1596*287e80b3SSadaf Ebrahimi  * This will put together a filter string for the starting event
1597*287e80b3SSadaf Ebrahimi  * of @synth. It check to make sure that what is added is correct compared
1598*287e80b3SSadaf Ebrahimi  * to the filter that is already built.
1599*287e80b3SSadaf Ebrahimi  *
1600*287e80b3SSadaf Ebrahimi  * @type can be:
1601*287e80b3SSadaf Ebrahimi  *     TRACEFS_FILTER_COMPARE:        See below
1602*287e80b3SSadaf Ebrahimi  *     TRACEFS_FILTER_AND:            Append "&&" to the filter
1603*287e80b3SSadaf Ebrahimi  *     TRACEFS_FILTER_OR:             Append "||" to the filter
1604*287e80b3SSadaf Ebrahimi  *     TRACEFS_FILTER_NOT:            Append "!" to the filter
1605*287e80b3SSadaf Ebrahimi  *     TRACEFS_FILTER_OPEN_PAREN:     Append "(" to the filter
1606*287e80b3SSadaf Ebrahimi  *     TRACEFS_FILTER_CLOSE_PAREN:    Append ")" to the filter
1607*287e80b3SSadaf Ebrahimi  *
1608*287e80b3SSadaf Ebrahimi  * For all types except TRACEFS_FILTER_COMPARE, the @field, @compare,
1609*287e80b3SSadaf Ebrahimi  * and @val are ignored.
1610*287e80b3SSadaf Ebrahimi  *
1611*287e80b3SSadaf Ebrahimi  * For @type == TRACEFS_FILTER_COMPARE.
1612*287e80b3SSadaf Ebrahimi  *
1613*287e80b3SSadaf Ebrahimi  *  @field is the name of the field for the start event to compare.
1614*287e80b3SSadaf Ebrahimi  *         If it is not a field for the start event, this return an
1615*287e80b3SSadaf Ebrahimi  *         error.
1616*287e80b3SSadaf Ebrahimi  *
1617*287e80b3SSadaf Ebrahimi  *  @compare can be one of:
1618*287e80b3SSadaf Ebrahimi  *     TRACEFS_COMPARE_EQ:       Test @field == @val
1619*287e80b3SSadaf Ebrahimi  *     TRACEFS_COMPARE_NE:       Test @field != @val
1620*287e80b3SSadaf Ebrahimi  *     TRACEFS_COMPARE_GT:       Test @field > @val
1621*287e80b3SSadaf Ebrahimi  *     TRACEFS_COMPARE_GE:       Test @field >= @val
1622*287e80b3SSadaf Ebrahimi  *     TRACEFS_COMPARE_LT:       Test @field < @val
1623*287e80b3SSadaf Ebrahimi  *     TRACEFS_COMPARE_LE:       Test @field <= @val
1624*287e80b3SSadaf Ebrahimi  *     TRACEFS_COMPARE_RE:       Test @field ~ @val
1625*287e80b3SSadaf Ebrahimi  *     TRACEFS_COMPARE_AND:      Test @field & @val
1626*287e80b3SSadaf Ebrahimi  *
1627*287e80b3SSadaf Ebrahimi  * If the @field is of type string, and @compare is not
1628*287e80b3SSadaf Ebrahimi  *   TRACEFS_COMPARE_EQ, TRACEFS_COMPARE_NE or TRACEFS_COMPARE_RE,
1629*287e80b3SSadaf Ebrahimi  *   then this will return an error.
1630*287e80b3SSadaf Ebrahimi  *
1631*287e80b3SSadaf Ebrahimi  * Various other checks are made, for instance, if more CLOSE_PARENs
1632*287e80b3SSadaf Ebrahimi  * are added than existing OPEN_PARENs. Or if AND is added after an
1633*287e80b3SSadaf Ebrahimi  * OPEN_PAREN or another AND or an OR or a NOT.
1634*287e80b3SSadaf Ebrahimi  *
1635*287e80b3SSadaf Ebrahimi  * Returns 0 on success and -1 on failure.
1636*287e80b3SSadaf Ebrahimi  */
tracefs_synth_append_start_filter(struct tracefs_synth * synth,enum tracefs_filter type,const char * field,enum tracefs_compare compare,const char * val)1637*287e80b3SSadaf Ebrahimi int tracefs_synth_append_start_filter(struct tracefs_synth *synth,
1638*287e80b3SSadaf Ebrahimi 				      enum tracefs_filter type,
1639*287e80b3SSadaf Ebrahimi 				      const char *field,
1640*287e80b3SSadaf Ebrahimi 				      enum tracefs_compare compare,
1641*287e80b3SSadaf Ebrahimi 				      const char *val)
1642*287e80b3SSadaf Ebrahimi {
1643*287e80b3SSadaf Ebrahimi 	return trace_append_filter(&synth->start_filter, &synth->start_state,
1644*287e80b3SSadaf Ebrahimi 				   &synth->start_parens,
1645*287e80b3SSadaf Ebrahimi 				   synth->start_event,
1646*287e80b3SSadaf Ebrahimi 				   type, field, compare, val);
1647*287e80b3SSadaf Ebrahimi }
1648*287e80b3SSadaf Ebrahimi 
1649*287e80b3SSadaf Ebrahimi /**
1650*287e80b3SSadaf Ebrahimi  * tracefs_synth_append_end_filter - create or append a filter
1651*287e80b3SSadaf Ebrahimi  * @synth: The tracefs_synth descriptor
1652*287e80b3SSadaf Ebrahimi  * @type: The type of element to add to the filter
1653*287e80b3SSadaf Ebrahimi  * @field: For @type == TRACEFS_FILTER_COMPARE, the field to compare
1654*287e80b3SSadaf Ebrahimi  * @compare: For @type == TRACEFS_FILTER_COMPARE, how to compare @field to @val
1655*287e80b3SSadaf Ebrahimi  * @val: For @type == TRACEFS_FILTER_COMPARE, what value @field is to be
1656*287e80b3SSadaf Ebrahimi  *
1657*287e80b3SSadaf Ebrahimi  * Performs the same thing as tracefs_synth_append_start_filter() but
1658*287e80b3SSadaf Ebrahimi  * for the @synth end event.
1659*287e80b3SSadaf Ebrahimi  */
tracefs_synth_append_end_filter(struct tracefs_synth * synth,enum tracefs_filter type,const char * field,enum tracefs_compare compare,const char * val)1660*287e80b3SSadaf Ebrahimi int tracefs_synth_append_end_filter(struct tracefs_synth *synth,
1661*287e80b3SSadaf Ebrahimi 				    enum tracefs_filter type,
1662*287e80b3SSadaf Ebrahimi 				    const char *field,
1663*287e80b3SSadaf Ebrahimi 				    enum tracefs_compare compare,
1664*287e80b3SSadaf Ebrahimi 				    const char *val)
1665*287e80b3SSadaf Ebrahimi {
1666*287e80b3SSadaf Ebrahimi 	return trace_append_filter(&synth->end_filter, &synth->end_state,
1667*287e80b3SSadaf Ebrahimi 				   &synth->end_parens,
1668*287e80b3SSadaf Ebrahimi 				   synth->end_event,
1669*287e80b3SSadaf Ebrahimi 				   type, field, compare, val);
1670*287e80b3SSadaf Ebrahimi }
1671*287e80b3SSadaf Ebrahimi 
test_max_var(struct tracefs_synth * synth,const char * var)1672*287e80b3SSadaf Ebrahimi static int test_max_var(struct tracefs_synth *synth, const char *var)
1673*287e80b3SSadaf Ebrahimi {
1674*287e80b3SSadaf Ebrahimi 	char **vars = synth->end_vars;
1675*287e80b3SSadaf Ebrahimi 	char *p;
1676*287e80b3SSadaf Ebrahimi 	int len;
1677*287e80b3SSadaf Ebrahimi 	int i;
1678*287e80b3SSadaf Ebrahimi 
1679*287e80b3SSadaf Ebrahimi 	len = strlen(var);
1680*287e80b3SSadaf Ebrahimi 
1681*287e80b3SSadaf Ebrahimi 	/* Make sure the var is defined for the end event */
1682*287e80b3SSadaf Ebrahimi 	for (i = 0; vars[i]; i++) {
1683*287e80b3SSadaf Ebrahimi 		p = strchr(vars[i], '=');
1684*287e80b3SSadaf Ebrahimi 		if (!p)
1685*287e80b3SSadaf Ebrahimi 			continue;
1686*287e80b3SSadaf Ebrahimi 		if (p - vars[i] != len)
1687*287e80b3SSadaf Ebrahimi 			continue;
1688*287e80b3SSadaf Ebrahimi 		if (!strncmp(var, vars[i], len))
1689*287e80b3SSadaf Ebrahimi 			return 0;
1690*287e80b3SSadaf Ebrahimi 	}
1691*287e80b3SSadaf Ebrahimi 	errno = ENODEV;
1692*287e80b3SSadaf Ebrahimi 	return -1;
1693*287e80b3SSadaf Ebrahimi }
1694*287e80b3SSadaf Ebrahimi 
create_action(enum tracefs_synth_handler type,struct tracefs_synth * synth,const char * var)1695*287e80b3SSadaf Ebrahimi static struct action *create_action(enum tracefs_synth_handler type,
1696*287e80b3SSadaf Ebrahimi 				    struct tracefs_synth *synth,
1697*287e80b3SSadaf Ebrahimi 				    const char *var)
1698*287e80b3SSadaf Ebrahimi {
1699*287e80b3SSadaf Ebrahimi 	struct action *action;
1700*287e80b3SSadaf Ebrahimi 	int ret;
1701*287e80b3SSadaf Ebrahimi 
1702*287e80b3SSadaf Ebrahimi 	switch (type) {
1703*287e80b3SSadaf Ebrahimi 	case TRACEFS_SYNTH_HANDLE_MAX:
1704*287e80b3SSadaf Ebrahimi 	case TRACEFS_SYNTH_HANDLE_CHANGE:
1705*287e80b3SSadaf Ebrahimi 		ret = test_max_var(synth, var);
1706*287e80b3SSadaf Ebrahimi 		if (ret < 0)
1707*287e80b3SSadaf Ebrahimi 			return NULL;
1708*287e80b3SSadaf Ebrahimi 		break;
1709*287e80b3SSadaf Ebrahimi 	default:
1710*287e80b3SSadaf Ebrahimi 		break;
1711*287e80b3SSadaf Ebrahimi 	}
1712*287e80b3SSadaf Ebrahimi 
1713*287e80b3SSadaf Ebrahimi 	action = calloc(1, sizeof(*action));
1714*287e80b3SSadaf Ebrahimi 	if (!action)
1715*287e80b3SSadaf Ebrahimi 		return NULL;
1716*287e80b3SSadaf Ebrahimi 
1717*287e80b3SSadaf Ebrahimi 	if (var) {
1718*287e80b3SSadaf Ebrahimi 		ret = asprintf(&action->handle_field, "$%s", var);
1719*287e80b3SSadaf Ebrahimi 		if (!action->handle_field) {
1720*287e80b3SSadaf Ebrahimi 			free(action);
1721*287e80b3SSadaf Ebrahimi 			return NULL;
1722*287e80b3SSadaf Ebrahimi 		}
1723*287e80b3SSadaf Ebrahimi 	}
1724*287e80b3SSadaf Ebrahimi 	return action;
1725*287e80b3SSadaf Ebrahimi }
1726*287e80b3SSadaf Ebrahimi 
add_action(struct tracefs_synth * synth,struct action * action)1727*287e80b3SSadaf Ebrahimi static void add_action(struct tracefs_synth *synth, struct action *action)
1728*287e80b3SSadaf Ebrahimi {
1729*287e80b3SSadaf Ebrahimi 	*synth->next_action = action;
1730*287e80b3SSadaf Ebrahimi 	synth->next_action = &action->next;
1731*287e80b3SSadaf Ebrahimi }
1732*287e80b3SSadaf Ebrahimi 
1733*287e80b3SSadaf Ebrahimi /**
1734*287e80b3SSadaf Ebrahimi  * tracefs_synth_trace - Execute the trace option
1735*287e80b3SSadaf Ebrahimi  * @synth: The tracefs_synth descriptor
1736*287e80b3SSadaf Ebrahimi  * @type: The type of handler to attach the trace action with
1737*287e80b3SSadaf Ebrahimi  * @field: The field for handlers onmax and onchange (ignored otherwise)
1738*287e80b3SSadaf Ebrahimi  *
1739*287e80b3SSadaf Ebrahimi  * Add the action 'trace' for handlers onmatch, onmax and onchange.
1740*287e80b3SSadaf Ebrahimi  *
1741*287e80b3SSadaf Ebrahimi  * Returns 0 on succes, -1 on error.
1742*287e80b3SSadaf Ebrahimi  */
tracefs_synth_trace(struct tracefs_synth * synth,enum tracefs_synth_handler type,const char * field)1743*287e80b3SSadaf Ebrahimi int tracefs_synth_trace(struct tracefs_synth *synth,
1744*287e80b3SSadaf Ebrahimi 			enum tracefs_synth_handler type, const char *field)
1745*287e80b3SSadaf Ebrahimi {
1746*287e80b3SSadaf Ebrahimi 	struct action *action;
1747*287e80b3SSadaf Ebrahimi 
1748*287e80b3SSadaf Ebrahimi 	if (!synth || (!field && (type != TRACEFS_SYNTH_HANDLE_MATCH))) {
1749*287e80b3SSadaf Ebrahimi 		errno = EINVAL;
1750*287e80b3SSadaf Ebrahimi 		return -1;
1751*287e80b3SSadaf Ebrahimi 	}
1752*287e80b3SSadaf Ebrahimi 
1753*287e80b3SSadaf Ebrahimi 	action = create_action(type, synth, field);
1754*287e80b3SSadaf Ebrahimi 	if (!action)
1755*287e80b3SSadaf Ebrahimi 		return -1;
1756*287e80b3SSadaf Ebrahimi 
1757*287e80b3SSadaf Ebrahimi 	action->type = ACTION_TRACE;
1758*287e80b3SSadaf Ebrahimi 	action->handler = type;
1759*287e80b3SSadaf Ebrahimi 	add_action(synth, action);
1760*287e80b3SSadaf Ebrahimi 	return 0;
1761*287e80b3SSadaf Ebrahimi }
1762*287e80b3SSadaf Ebrahimi 
1763*287e80b3SSadaf Ebrahimi /**
1764*287e80b3SSadaf Ebrahimi  * tracefs_synth_snapshot - create a snapshot command to the histogram
1765*287e80b3SSadaf Ebrahimi  * @synth: The tracefs_synth descriptor
1766*287e80b3SSadaf Ebrahimi  * @type: The type of handler to attach the snapshot action with
1767*287e80b3SSadaf Ebrahimi  * @field: The field for handlers onmax and onchange
1768*287e80b3SSadaf Ebrahimi  *
1769*287e80b3SSadaf Ebrahimi  * Add the action to do a snapshot for handlers onmax and onchange.
1770*287e80b3SSadaf Ebrahimi  *
1771*287e80b3SSadaf Ebrahimi  * Returns 0 on succes, -1 on error.
1772*287e80b3SSadaf Ebrahimi  */
tracefs_synth_snapshot(struct tracefs_synth * synth,enum tracefs_synth_handler type,const char * field)1773*287e80b3SSadaf Ebrahimi int tracefs_synth_snapshot(struct tracefs_synth *synth,
1774*287e80b3SSadaf Ebrahimi 			   enum tracefs_synth_handler type, const char *field)
1775*287e80b3SSadaf Ebrahimi {
1776*287e80b3SSadaf Ebrahimi 	struct action *action;
1777*287e80b3SSadaf Ebrahimi 
1778*287e80b3SSadaf Ebrahimi 	if (!synth || !field || (type == TRACEFS_SYNTH_HANDLE_MATCH)) {
1779*287e80b3SSadaf Ebrahimi 		errno = EINVAL;
1780*287e80b3SSadaf Ebrahimi 		return -1;
1781*287e80b3SSadaf Ebrahimi 	}
1782*287e80b3SSadaf Ebrahimi 
1783*287e80b3SSadaf Ebrahimi 	action = create_action(type, synth, field);
1784*287e80b3SSadaf Ebrahimi 	if (!action)
1785*287e80b3SSadaf Ebrahimi 		return -1;
1786*287e80b3SSadaf Ebrahimi 
1787*287e80b3SSadaf Ebrahimi 	action->type = ACTION_SNAPSHOT;
1788*287e80b3SSadaf Ebrahimi 	action->handler = type;
1789*287e80b3SSadaf Ebrahimi 	add_action(synth, action);
1790*287e80b3SSadaf Ebrahimi 	return 0;
1791*287e80b3SSadaf Ebrahimi }
1792*287e80b3SSadaf Ebrahimi 
1793*287e80b3SSadaf Ebrahimi /**
1794*287e80b3SSadaf Ebrahimi  * tracefs_synth_save - create a save command to the histogram
1795*287e80b3SSadaf Ebrahimi  * @synth: The tracefs_synth descriptor
1796*287e80b3SSadaf Ebrahimi  * @type: The type of handler to attach the save action
1797*287e80b3SSadaf Ebrahimi  * @max_field: The field for handlers onmax and onchange
1798*287e80b3SSadaf Ebrahimi  * @fields: The fields to save for the end variable
1799*287e80b3SSadaf Ebrahimi  *
1800*287e80b3SSadaf Ebrahimi  * Add the action to save fields for handlers onmax and onchange.
1801*287e80b3SSadaf Ebrahimi  *
1802*287e80b3SSadaf Ebrahimi  * Returns 0 on succes, -1 on error.
1803*287e80b3SSadaf Ebrahimi  */
tracefs_synth_save(struct tracefs_synth * synth,enum tracefs_synth_handler type,const char * max_field,char ** fields)1804*287e80b3SSadaf Ebrahimi int tracefs_synth_save(struct tracefs_synth *synth,
1805*287e80b3SSadaf Ebrahimi 		       enum tracefs_synth_handler type, const char *max_field,
1806*287e80b3SSadaf Ebrahimi 		       char **fields)
1807*287e80b3SSadaf Ebrahimi {
1808*287e80b3SSadaf Ebrahimi 	struct action *action;
1809*287e80b3SSadaf Ebrahimi 	char *save;
1810*287e80b3SSadaf Ebrahimi 	int i;
1811*287e80b3SSadaf Ebrahimi 
1812*287e80b3SSadaf Ebrahimi 	if (!synth || !max_field || (type == TRACEFS_SYNTH_HANDLE_MATCH)) {
1813*287e80b3SSadaf Ebrahimi 		errno = EINVAL;
1814*287e80b3SSadaf Ebrahimi 		return -1;
1815*287e80b3SSadaf Ebrahimi 	}
1816*287e80b3SSadaf Ebrahimi 
1817*287e80b3SSadaf Ebrahimi 	action = create_action(type, synth, max_field);
1818*287e80b3SSadaf Ebrahimi 	if (!action)
1819*287e80b3SSadaf Ebrahimi 		return -1;
1820*287e80b3SSadaf Ebrahimi 
1821*287e80b3SSadaf Ebrahimi 	action->type = ACTION_SAVE;
1822*287e80b3SSadaf Ebrahimi 	action->handler = type;
1823*287e80b3SSadaf Ebrahimi 	*synth->next_action = action;
1824*287e80b3SSadaf Ebrahimi 	synth->next_action = &action->next;
1825*287e80b3SSadaf Ebrahimi 
1826*287e80b3SSadaf Ebrahimi 	save = strdup(".save(");
1827*287e80b3SSadaf Ebrahimi 	if (!save)
1828*287e80b3SSadaf Ebrahimi 		goto error;
1829*287e80b3SSadaf Ebrahimi 
1830*287e80b3SSadaf Ebrahimi 	for (i = 0; fields[i]; i++) {
1831*287e80b3SSadaf Ebrahimi 		char *delim = i ? "," : NULL;
1832*287e80b3SSadaf Ebrahimi 
1833*287e80b3SSadaf Ebrahimi 		if (!trace_verify_event_field(synth->end_event, fields[i], NULL))
1834*287e80b3SSadaf Ebrahimi 			goto error;
1835*287e80b3SSadaf Ebrahimi 		save = append_string(save, delim, fields[i]);
1836*287e80b3SSadaf Ebrahimi 	}
1837*287e80b3SSadaf Ebrahimi 	save = append_string(save, NULL, ")");
1838*287e80b3SSadaf Ebrahimi 	if (!save)
1839*287e80b3SSadaf Ebrahimi 		goto error;
1840*287e80b3SSadaf Ebrahimi 
1841*287e80b3SSadaf Ebrahimi 	action->save = save;
1842*287e80b3SSadaf Ebrahimi 	add_action(synth, action);
1843*287e80b3SSadaf Ebrahimi 	return 0;
1844*287e80b3SSadaf Ebrahimi  error:
1845*287e80b3SSadaf Ebrahimi 	action_free(action);
1846*287e80b3SSadaf Ebrahimi 	free(save);
1847*287e80b3SSadaf Ebrahimi 	return -1;
1848*287e80b3SSadaf Ebrahimi 	return 0;
1849*287e80b3SSadaf Ebrahimi }
1850*287e80b3SSadaf Ebrahimi 
remove_hist(struct tracefs_instance * instance,struct tep_event * event,const char * hist)1851*287e80b3SSadaf Ebrahimi static int remove_hist(struct tracefs_instance *instance,
1852*287e80b3SSadaf Ebrahimi 		       struct tep_event *event, const char *hist)
1853*287e80b3SSadaf Ebrahimi {
1854*287e80b3SSadaf Ebrahimi 	char *str;
1855*287e80b3SSadaf Ebrahimi 	int ret;
1856*287e80b3SSadaf Ebrahimi 
1857*287e80b3SSadaf Ebrahimi 	ret = asprintf(&str, "!%s", hist);
1858*287e80b3SSadaf Ebrahimi 	if (ret < 0)
1859*287e80b3SSadaf Ebrahimi 		return -1;
1860*287e80b3SSadaf Ebrahimi 
1861*287e80b3SSadaf Ebrahimi 	ret = tracefs_event_file_append(instance, event->system, event->name,
1862*287e80b3SSadaf Ebrahimi 				  "trigger", str);
1863*287e80b3SSadaf Ebrahimi 	free(str);
1864*287e80b3SSadaf Ebrahimi 	return ret < 0 ? -1 : 0;
1865*287e80b3SSadaf Ebrahimi }
1866*287e80b3SSadaf Ebrahimi 
create_hist(char ** keys,char ** vars)1867*287e80b3SSadaf Ebrahimi static char *create_hist(char **keys, char **vars)
1868*287e80b3SSadaf Ebrahimi {
1869*287e80b3SSadaf Ebrahimi 	char *hist = strdup("hist:keys=");
1870*287e80b3SSadaf Ebrahimi 	char *name;
1871*287e80b3SSadaf Ebrahimi 	int i;
1872*287e80b3SSadaf Ebrahimi 
1873*287e80b3SSadaf Ebrahimi 	if (!hist)
1874*287e80b3SSadaf Ebrahimi 		return NULL;
1875*287e80b3SSadaf Ebrahimi 
1876*287e80b3SSadaf Ebrahimi 	for (i = 0; keys[i]; i++) {
1877*287e80b3SSadaf Ebrahimi 		name = keys[i];
1878*287e80b3SSadaf Ebrahimi 		if (i)
1879*287e80b3SSadaf Ebrahimi 			hist = append_string(hist, NULL, ",");
1880*287e80b3SSadaf Ebrahimi 		hist = append_string(hist, NULL, name);
1881*287e80b3SSadaf Ebrahimi 	}
1882*287e80b3SSadaf Ebrahimi 
1883*287e80b3SSadaf Ebrahimi 	if (!vars)
1884*287e80b3SSadaf Ebrahimi 		return hist;
1885*287e80b3SSadaf Ebrahimi 
1886*287e80b3SSadaf Ebrahimi 	hist = append_string(hist, NULL, ":");
1887*287e80b3SSadaf Ebrahimi 
1888*287e80b3SSadaf Ebrahimi 	for (i = 0; vars[i]; i++) {
1889*287e80b3SSadaf Ebrahimi 		name = vars[i];
1890*287e80b3SSadaf Ebrahimi 		if (i)
1891*287e80b3SSadaf Ebrahimi 			hist = append_string(hist, NULL, ",");
1892*287e80b3SSadaf Ebrahimi 		hist = append_string(hist, NULL, name);
1893*287e80b3SSadaf Ebrahimi 	}
1894*287e80b3SSadaf Ebrahimi 
1895*287e80b3SSadaf Ebrahimi 	return hist;
1896*287e80b3SSadaf Ebrahimi }
1897*287e80b3SSadaf Ebrahimi 
create_onmatch(char * hist,struct tracefs_synth * synth)1898*287e80b3SSadaf Ebrahimi static char *create_onmatch(char *hist, struct tracefs_synth *synth)
1899*287e80b3SSadaf Ebrahimi {
1900*287e80b3SSadaf Ebrahimi 	hist = append_string(hist, NULL, ":onmatch(");
1901*287e80b3SSadaf Ebrahimi 	hist = append_string(hist, NULL, synth->start_event->system);
1902*287e80b3SSadaf Ebrahimi 	hist = append_string(hist, NULL, ".");
1903*287e80b3SSadaf Ebrahimi 	hist = append_string(hist, NULL, synth->start_event->name);
1904*287e80b3SSadaf Ebrahimi 	return append_string(hist, NULL, ")");
1905*287e80b3SSadaf Ebrahimi }
1906*287e80b3SSadaf Ebrahimi 
create_trace(char * hist,struct tracefs_synth * synth)1907*287e80b3SSadaf Ebrahimi static char *create_trace(char *hist, struct tracefs_synth *synth)
1908*287e80b3SSadaf Ebrahimi {
1909*287e80b3SSadaf Ebrahimi 	char *name;
1910*287e80b3SSadaf Ebrahimi 	int i;
1911*287e80b3SSadaf Ebrahimi 
1912*287e80b3SSadaf Ebrahimi 	if (synth->new_format) {
1913*287e80b3SSadaf Ebrahimi 		hist = append_string(hist, NULL, ".trace(");
1914*287e80b3SSadaf Ebrahimi 		hist = append_string(hist, NULL, synth->name);
1915*287e80b3SSadaf Ebrahimi 		hist = append_string(hist, NULL, ",");
1916*287e80b3SSadaf Ebrahimi 	} else {
1917*287e80b3SSadaf Ebrahimi 		hist = append_string(hist, NULL, ".");
1918*287e80b3SSadaf Ebrahimi 		hist = append_string(hist, NULL, synth->name);
1919*287e80b3SSadaf Ebrahimi 		hist = append_string(hist, NULL, "(");
1920*287e80b3SSadaf Ebrahimi 	}
1921*287e80b3SSadaf Ebrahimi 
1922*287e80b3SSadaf Ebrahimi 	for (i = 0; synth->synthetic_args && synth->synthetic_args[i]; i++) {
1923*287e80b3SSadaf Ebrahimi 		name = synth->synthetic_args[i];
1924*287e80b3SSadaf Ebrahimi 
1925*287e80b3SSadaf Ebrahimi 		if (i)
1926*287e80b3SSadaf Ebrahimi 			hist = append_string(hist, NULL, ",");
1927*287e80b3SSadaf Ebrahimi 		hist = append_string(hist, NULL, name);
1928*287e80b3SSadaf Ebrahimi 	}
1929*287e80b3SSadaf Ebrahimi 
1930*287e80b3SSadaf Ebrahimi 	return append_string(hist, NULL, ")");
1931*287e80b3SSadaf Ebrahimi }
1932*287e80b3SSadaf Ebrahimi 
create_max(char * hist,struct tracefs_synth * synth,char * field)1933*287e80b3SSadaf Ebrahimi static char *create_max(char *hist, struct tracefs_synth *synth, char *field)
1934*287e80b3SSadaf Ebrahimi {
1935*287e80b3SSadaf Ebrahimi 	hist = append_string(hist, NULL, ":onmax(");
1936*287e80b3SSadaf Ebrahimi 	hist = append_string(hist, NULL, field);
1937*287e80b3SSadaf Ebrahimi 	return append_string(hist, NULL, ")");
1938*287e80b3SSadaf Ebrahimi }
1939*287e80b3SSadaf Ebrahimi 
create_change(char * hist,struct tracefs_synth * synth,char * field)1940*287e80b3SSadaf Ebrahimi static char *create_change(char *hist, struct tracefs_synth *synth, char *field)
1941*287e80b3SSadaf Ebrahimi {
1942*287e80b3SSadaf Ebrahimi 	hist = append_string(hist, NULL, ":onchange(");
1943*287e80b3SSadaf Ebrahimi 	hist = append_string(hist, NULL, field);
1944*287e80b3SSadaf Ebrahimi 	return append_string(hist, NULL, ")");
1945*287e80b3SSadaf Ebrahimi }
1946*287e80b3SSadaf Ebrahimi 
create_actions(char * hist,struct tracefs_synth * synth)1947*287e80b3SSadaf Ebrahimi static char *create_actions(char *hist, struct tracefs_synth *synth)
1948*287e80b3SSadaf Ebrahimi {
1949*287e80b3SSadaf Ebrahimi 	struct action *action;
1950*287e80b3SSadaf Ebrahimi 
1951*287e80b3SSadaf Ebrahimi 	if (!synth->actions) {
1952*287e80b3SSadaf Ebrahimi 		/* Default is "onmatch" and "trace" */
1953*287e80b3SSadaf Ebrahimi 		hist = create_onmatch(hist, synth);
1954*287e80b3SSadaf Ebrahimi 		return create_trace(hist, synth);
1955*287e80b3SSadaf Ebrahimi 	}
1956*287e80b3SSadaf Ebrahimi 
1957*287e80b3SSadaf Ebrahimi 	for (action = synth->actions; action; action = action->next) {
1958*287e80b3SSadaf Ebrahimi 		switch (action->handler) {
1959*287e80b3SSadaf Ebrahimi 		case TRACEFS_SYNTH_HANDLE_MATCH:
1960*287e80b3SSadaf Ebrahimi 			hist = create_onmatch(hist, synth);
1961*287e80b3SSadaf Ebrahimi 			break;
1962*287e80b3SSadaf Ebrahimi 		case TRACEFS_SYNTH_HANDLE_MAX:
1963*287e80b3SSadaf Ebrahimi 			hist = create_max(hist, synth, action->handle_field);
1964*287e80b3SSadaf Ebrahimi 			break;
1965*287e80b3SSadaf Ebrahimi 		case TRACEFS_SYNTH_HANDLE_CHANGE:
1966*287e80b3SSadaf Ebrahimi 			hist = create_change(hist, synth, action->handle_field);
1967*287e80b3SSadaf Ebrahimi 			break;
1968*287e80b3SSadaf Ebrahimi 		default:
1969*287e80b3SSadaf Ebrahimi 			continue;
1970*287e80b3SSadaf Ebrahimi 		}
1971*287e80b3SSadaf Ebrahimi 		switch (action->type) {
1972*287e80b3SSadaf Ebrahimi 		case ACTION_TRACE:
1973*287e80b3SSadaf Ebrahimi 			hist = create_trace(hist, synth);
1974*287e80b3SSadaf Ebrahimi 			break;
1975*287e80b3SSadaf Ebrahimi 		case ACTION_SNAPSHOT:
1976*287e80b3SSadaf Ebrahimi 			hist = append_string(hist, NULL, ".snapshot()");
1977*287e80b3SSadaf Ebrahimi 			break;
1978*287e80b3SSadaf Ebrahimi 		case ACTION_SAVE:
1979*287e80b3SSadaf Ebrahimi 			hist = append_string(hist, NULL, action->save);
1980*287e80b3SSadaf Ebrahimi 			break;
1981*287e80b3SSadaf Ebrahimi 		default:
1982*287e80b3SSadaf Ebrahimi 			continue;
1983*287e80b3SSadaf Ebrahimi 		}
1984*287e80b3SSadaf Ebrahimi 	}
1985*287e80b3SSadaf Ebrahimi 	return hist;
1986*287e80b3SSadaf Ebrahimi }
1987*287e80b3SSadaf Ebrahimi 
create_end_hist(struct tracefs_synth * synth)1988*287e80b3SSadaf Ebrahimi static char *create_end_hist(struct tracefs_synth *synth)
1989*287e80b3SSadaf Ebrahimi {
1990*287e80b3SSadaf Ebrahimi 	char *end_hist;
1991*287e80b3SSadaf Ebrahimi 
1992*287e80b3SSadaf Ebrahimi 	end_hist = create_hist(synth->end_keys, synth->end_vars);
1993*287e80b3SSadaf Ebrahimi 	return create_actions(end_hist, synth);
1994*287e80b3SSadaf Ebrahimi }
1995*287e80b3SSadaf Ebrahimi 
1996*287e80b3SSadaf Ebrahimi /*
1997*287e80b3SSadaf Ebrahimi  * tracefs_synth_raw_fmt - show the raw format of a synthetic event
1998*287e80b3SSadaf Ebrahimi  * @seq: A trace_seq to store the format string
1999*287e80b3SSadaf Ebrahimi  * @synth: The synthetic event to read format from
2000*287e80b3SSadaf Ebrahimi  *
2001*287e80b3SSadaf Ebrahimi  * This shows the raw format that describes the synthetic event, including
2002*287e80b3SSadaf Ebrahimi  * the format of the dynamic event and the start / end histograms.
2003*287e80b3SSadaf Ebrahimi  *
2004*287e80b3SSadaf Ebrahimi  * Returns 0 on succes -1 on error.
2005*287e80b3SSadaf Ebrahimi  */
tracefs_synth_raw_fmt(struct trace_seq * seq,struct tracefs_synth * synth)2006*287e80b3SSadaf Ebrahimi int tracefs_synth_raw_fmt(struct trace_seq *seq, struct tracefs_synth *synth)
2007*287e80b3SSadaf Ebrahimi {
2008*287e80b3SSadaf Ebrahimi 	if (!synth->dyn_event)
2009*287e80b3SSadaf Ebrahimi 		return -1;
2010*287e80b3SSadaf Ebrahimi 
2011*287e80b3SSadaf Ebrahimi 	trace_seq_printf(seq, "%s", synth->dyn_event->format);
2012*287e80b3SSadaf Ebrahimi 	trace_seq_printf(seq, "\n%s", synth->start_hist);
2013*287e80b3SSadaf Ebrahimi 	trace_seq_printf(seq, "\n%s", synth->end_hist);
2014*287e80b3SSadaf Ebrahimi 
2015*287e80b3SSadaf Ebrahimi 	return 0;
2016*287e80b3SSadaf Ebrahimi }
2017*287e80b3SSadaf Ebrahimi 
2018*287e80b3SSadaf Ebrahimi /*
2019*287e80b3SSadaf Ebrahimi  * tracefs_synth_show_event - show the dynamic event used by a synth event
2020*287e80b3SSadaf Ebrahimi  * @synth: The synthetic event to read format from
2021*287e80b3SSadaf Ebrahimi  *
2022*287e80b3SSadaf Ebrahimi  * This shows the raw format of the dynamic event used by the synthetic event.
2023*287e80b3SSadaf Ebrahimi  *
2024*287e80b3SSadaf Ebrahimi  * Returns format string owned by @synth on success, or NULL on error.
2025*287e80b3SSadaf Ebrahimi  */
tracefs_synth_show_event(struct tracefs_synth * synth)2026*287e80b3SSadaf Ebrahimi const char *tracefs_synth_show_event(struct tracefs_synth *synth)
2027*287e80b3SSadaf Ebrahimi {
2028*287e80b3SSadaf Ebrahimi 	return synth->dyn_event ? synth->dyn_event->format : NULL;
2029*287e80b3SSadaf Ebrahimi }
2030*287e80b3SSadaf Ebrahimi 
2031*287e80b3SSadaf Ebrahimi /*
2032*287e80b3SSadaf Ebrahimi  * tracefs_synth_show_start_hist - show the start histogram used by a synth event
2033*287e80b3SSadaf Ebrahimi  * @synth: The synthetic event to read format from
2034*287e80b3SSadaf Ebrahimi  *
2035*287e80b3SSadaf Ebrahimi  * This shows the raw format of the start histogram used by the synthetic event.
2036*287e80b3SSadaf Ebrahimi  *
2037*287e80b3SSadaf Ebrahimi  * Returns format string owned by @synth on success, or NULL on error.
2038*287e80b3SSadaf Ebrahimi  */
tracefs_synth_show_start_hist(struct tracefs_synth * synth)2039*287e80b3SSadaf Ebrahimi const char *tracefs_synth_show_start_hist(struct tracefs_synth *synth)
2040*287e80b3SSadaf Ebrahimi {
2041*287e80b3SSadaf Ebrahimi 	return synth->start_hist;
2042*287e80b3SSadaf Ebrahimi }
2043*287e80b3SSadaf Ebrahimi 
2044*287e80b3SSadaf Ebrahimi /*
2045*287e80b3SSadaf Ebrahimi  * tracefs_synth_show_end_hist - show the end histogram used by a synth event
2046*287e80b3SSadaf Ebrahimi  * @synth: The synthetic event to read format from
2047*287e80b3SSadaf Ebrahimi  *
2048*287e80b3SSadaf Ebrahimi  * This shows the raw format of the end histogram used by the synthetic event.
2049*287e80b3SSadaf Ebrahimi  *
2050*287e80b3SSadaf Ebrahimi  * Returns format string owned by @synth on success, or NULL on error.
2051*287e80b3SSadaf Ebrahimi  */
tracefs_synth_show_end_hist(struct tracefs_synth * synth)2052*287e80b3SSadaf Ebrahimi const char *tracefs_synth_show_end_hist(struct tracefs_synth *synth)
2053*287e80b3SSadaf Ebrahimi {
2054*287e80b3SSadaf Ebrahimi 	return synth->end_hist;
2055*287e80b3SSadaf Ebrahimi }
2056*287e80b3SSadaf Ebrahimi 
append_filter(char * hist,char * filter,unsigned int parens)2057*287e80b3SSadaf Ebrahimi static char *append_filter(char *hist, char *filter, unsigned int parens)
2058*287e80b3SSadaf Ebrahimi {
2059*287e80b3SSadaf Ebrahimi 	int i;
2060*287e80b3SSadaf Ebrahimi 
2061*287e80b3SSadaf Ebrahimi 	if (!filter)
2062*287e80b3SSadaf Ebrahimi 		return hist;
2063*287e80b3SSadaf Ebrahimi 
2064*287e80b3SSadaf Ebrahimi 	hist = append_string(hist, NULL, " if ");
2065*287e80b3SSadaf Ebrahimi 	hist = append_string(hist, NULL, filter);
2066*287e80b3SSadaf Ebrahimi 	for (i = 0; i < parens; i++)
2067*287e80b3SSadaf Ebrahimi 		hist = append_string(hist, NULL, ")");
2068*287e80b3SSadaf Ebrahimi 	return hist;
2069*287e80b3SSadaf Ebrahimi }
2070*287e80b3SSadaf Ebrahimi 
verify_state(struct tracefs_synth * synth)2071*287e80b3SSadaf Ebrahimi static int verify_state(struct tracefs_synth *synth)
2072*287e80b3SSadaf Ebrahimi {
2073*287e80b3SSadaf Ebrahimi 	if (trace_test_state(synth->start_state) < 0 ||
2074*287e80b3SSadaf Ebrahimi 	    trace_test_state(synth->end_state) < 0)
2075*287e80b3SSadaf Ebrahimi 		return -1;
2076*287e80b3SSadaf Ebrahimi 	return 0;
2077*287e80b3SSadaf Ebrahimi }
2078*287e80b3SSadaf Ebrahimi 
2079*287e80b3SSadaf Ebrahimi /**
2080*287e80b3SSadaf Ebrahimi  * tracefs_synth_complete - tell if the tracefs_synth is complete or not
2081*287e80b3SSadaf Ebrahimi  * @synth: The synthetic event to get the start hist from.
2082*287e80b3SSadaf Ebrahimi  *
2083*287e80b3SSadaf Ebrahimi  * Retruns true if the synthetic event @synth has both a start and
2084*287e80b3SSadaf Ebrahimi  * end event (ie. a synthetic event, or just a histogram), and
2085*287e80b3SSadaf Ebrahimi  * false otherwise.
2086*287e80b3SSadaf Ebrahimi  */
tracefs_synth_complete(struct tracefs_synth * synth)2087*287e80b3SSadaf Ebrahimi bool tracefs_synth_complete(struct tracefs_synth *synth)
2088*287e80b3SSadaf Ebrahimi {
2089*287e80b3SSadaf Ebrahimi 	return synth && synth->start_event && synth->end_event;
2090*287e80b3SSadaf Ebrahimi }
2091*287e80b3SSadaf Ebrahimi 
2092*287e80b3SSadaf Ebrahimi /**
2093*287e80b3SSadaf Ebrahimi  * tracefs_synth_get_start_hist - Return the histogram of the start event
2094*287e80b3SSadaf Ebrahimi  * @synth: The synthetic event to get the start hist from.
2095*287e80b3SSadaf Ebrahimi  *
2096*287e80b3SSadaf Ebrahimi  * On success, returns a tracefs_hist descriptor that holds the
2097*287e80b3SSadaf Ebrahimi  * histogram information of the start_event of the synthetic event
2098*287e80b3SSadaf Ebrahimi  * structure. Returns NULL on failure.
2099*287e80b3SSadaf Ebrahimi  */
2100*287e80b3SSadaf Ebrahimi struct tracefs_hist *
tracefs_synth_get_start_hist(struct tracefs_synth * synth)2101*287e80b3SSadaf Ebrahimi tracefs_synth_get_start_hist(struct tracefs_synth *synth)
2102*287e80b3SSadaf Ebrahimi {
2103*287e80b3SSadaf Ebrahimi 	struct tracefs_hist *hist = NULL;
2104*287e80b3SSadaf Ebrahimi 	struct tep_handle *tep;
2105*287e80b3SSadaf Ebrahimi 	const char *system;
2106*287e80b3SSadaf Ebrahimi 	const char *event;
2107*287e80b3SSadaf Ebrahimi 	const char *key;
2108*287e80b3SSadaf Ebrahimi 	char **keys;
2109*287e80b3SSadaf Ebrahimi 	int *types;
2110*287e80b3SSadaf Ebrahimi 	int ret;
2111*287e80b3SSadaf Ebrahimi 	int i;
2112*287e80b3SSadaf Ebrahimi 
2113*287e80b3SSadaf Ebrahimi 	if (!synth) {
2114*287e80b3SSadaf Ebrahimi 		errno = EINVAL;
2115*287e80b3SSadaf Ebrahimi 		return NULL;
2116*287e80b3SSadaf Ebrahimi 	}
2117*287e80b3SSadaf Ebrahimi 
2118*287e80b3SSadaf Ebrahimi 	system = synth->start_event->system;
2119*287e80b3SSadaf Ebrahimi 	event = synth->start_event->name;
2120*287e80b3SSadaf Ebrahimi 	types = synth->start_type;
2121*287e80b3SSadaf Ebrahimi 	keys = synth->start_keys;
2122*287e80b3SSadaf Ebrahimi 	tep = synth->tep;
2123*287e80b3SSadaf Ebrahimi 
2124*287e80b3SSadaf Ebrahimi 	if (!keys)
2125*287e80b3SSadaf Ebrahimi 		keys = synth->start_selection;
2126*287e80b3SSadaf Ebrahimi 
2127*287e80b3SSadaf Ebrahimi 	if (!keys)
2128*287e80b3SSadaf Ebrahimi 		return NULL;
2129*287e80b3SSadaf Ebrahimi 
2130*287e80b3SSadaf Ebrahimi 	for (i = 0; keys[i]; i++) {
2131*287e80b3SSadaf Ebrahimi 		int type = types ? types[i] : 0;
2132*287e80b3SSadaf Ebrahimi 
2133*287e80b3SSadaf Ebrahimi 		if (type == HIST_COUNTER_TYPE)
2134*287e80b3SSadaf Ebrahimi 			continue;
2135*287e80b3SSadaf Ebrahimi 
2136*287e80b3SSadaf Ebrahimi 		key = keys[i];
2137*287e80b3SSadaf Ebrahimi 
2138*287e80b3SSadaf Ebrahimi 		if (i) {
2139*287e80b3SSadaf Ebrahimi 			ret = tracefs_hist_add_key(hist, key, type);
2140*287e80b3SSadaf Ebrahimi 			if (ret < 0) {
2141*287e80b3SSadaf Ebrahimi 				tracefs_hist_free(hist);
2142*287e80b3SSadaf Ebrahimi 				return NULL;
2143*287e80b3SSadaf Ebrahimi 			}
2144*287e80b3SSadaf Ebrahimi 		} else {
2145*287e80b3SSadaf Ebrahimi 			hist = tracefs_hist_alloc(tep, system, event,
2146*287e80b3SSadaf Ebrahimi 						  key, type);
2147*287e80b3SSadaf Ebrahimi 			if (!hist)
2148*287e80b3SSadaf Ebrahimi 				return NULL;
2149*287e80b3SSadaf Ebrahimi 		}
2150*287e80b3SSadaf Ebrahimi 	}
2151*287e80b3SSadaf Ebrahimi 
2152*287e80b3SSadaf Ebrahimi 	if (!hist)
2153*287e80b3SSadaf Ebrahimi 		return NULL;
2154*287e80b3SSadaf Ebrahimi 
2155*287e80b3SSadaf Ebrahimi 	for (i = 0; keys[i]; i++) {
2156*287e80b3SSadaf Ebrahimi 		int type = types ? types[i] : 0;
2157*287e80b3SSadaf Ebrahimi 
2158*287e80b3SSadaf Ebrahimi 		if (type != HIST_COUNTER_TYPE)
2159*287e80b3SSadaf Ebrahimi 			continue;
2160*287e80b3SSadaf Ebrahimi 
2161*287e80b3SSadaf Ebrahimi 		key = keys[i];
2162*287e80b3SSadaf Ebrahimi 
2163*287e80b3SSadaf Ebrahimi 		ret = tracefs_hist_add_value(hist, key);
2164*287e80b3SSadaf Ebrahimi 		if (ret < 0) {
2165*287e80b3SSadaf Ebrahimi 			tracefs_hist_free(hist);
2166*287e80b3SSadaf Ebrahimi 			return NULL;
2167*287e80b3SSadaf Ebrahimi 		}
2168*287e80b3SSadaf Ebrahimi 	}
2169*287e80b3SSadaf Ebrahimi 
2170*287e80b3SSadaf Ebrahimi 	if (synth->start_filter) {
2171*287e80b3SSadaf Ebrahimi 		hist->filter = strdup(synth->start_filter);
2172*287e80b3SSadaf Ebrahimi 		if (!hist->filter) {
2173*287e80b3SSadaf Ebrahimi 			tracefs_hist_free(hist);
2174*287e80b3SSadaf Ebrahimi 			return NULL;
2175*287e80b3SSadaf Ebrahimi 		}
2176*287e80b3SSadaf Ebrahimi 	}
2177*287e80b3SSadaf Ebrahimi 
2178*287e80b3SSadaf Ebrahimi 	return hist;
2179*287e80b3SSadaf Ebrahimi }
2180*287e80b3SSadaf Ebrahimi 
2181*287e80b3SSadaf Ebrahimi /**
2182*287e80b3SSadaf Ebrahimi  * tracefs_synth_create - creates the synthetic event on the system
2183*287e80b3SSadaf Ebrahimi  * @synth: The tracefs_synth descriptor
2184*287e80b3SSadaf Ebrahimi  *
2185*287e80b3SSadaf Ebrahimi  * This creates the synthetic events.
2186*287e80b3SSadaf Ebrahimi  *
2187*287e80b3SSadaf Ebrahimi  * Returns 0 on succes and -1 on error.
2188*287e80b3SSadaf Ebrahimi  * On error, errno is set to:
2189*287e80b3SSadaf Ebrahimi  * ENOMEM - memory allocation failure.
2190*287e80b3SSadaf Ebrahimi  * ENIVAL - a parameter is passed as NULL that should not be or a problem
2191*287e80b3SSadaf Ebrahimi  *   writing into the system.
2192*287e80b3SSadaf Ebrahimi  */
tracefs_synth_create(struct tracefs_synth * synth)2193*287e80b3SSadaf Ebrahimi int tracefs_synth_create(struct tracefs_synth *synth)
2194*287e80b3SSadaf Ebrahimi {
2195*287e80b3SSadaf Ebrahimi 	int ret;
2196*287e80b3SSadaf Ebrahimi 
2197*287e80b3SSadaf Ebrahimi 	if (!synth) {
2198*287e80b3SSadaf Ebrahimi 		errno = EINVAL;
2199*287e80b3SSadaf Ebrahimi 		return -1;
2200*287e80b3SSadaf Ebrahimi 	}
2201*287e80b3SSadaf Ebrahimi 
2202*287e80b3SSadaf Ebrahimi 	if (!synth->name || !synth->end_event) {
2203*287e80b3SSadaf Ebrahimi 		errno = EUNATCH;
2204*287e80b3SSadaf Ebrahimi 		return -1;
2205*287e80b3SSadaf Ebrahimi 	}
2206*287e80b3SSadaf Ebrahimi 
2207*287e80b3SSadaf Ebrahimi 	if (verify_state(synth) < 0)
2208*287e80b3SSadaf Ebrahimi 		return -1;
2209*287e80b3SSadaf Ebrahimi 
2210*287e80b3SSadaf Ebrahimi 	if (!synth->dyn_event && alloc_synthetic_event(synth))
2211*287e80b3SSadaf Ebrahimi 		return -1;
2212*287e80b3SSadaf Ebrahimi 	if (tracefs_dynevent_create(synth->dyn_event))
2213*287e80b3SSadaf Ebrahimi 		return -1;
2214*287e80b3SSadaf Ebrahimi 
2215*287e80b3SSadaf Ebrahimi 	synth->start_hist = create_hist(synth->start_keys, synth->start_vars);
2216*287e80b3SSadaf Ebrahimi 	synth->start_hist = append_filter(synth->start_hist, synth->start_filter,
2217*287e80b3SSadaf Ebrahimi 					  synth->start_parens);
2218*287e80b3SSadaf Ebrahimi 	if (!synth->start_hist)
2219*287e80b3SSadaf Ebrahimi 		goto remove_synthetic;
2220*287e80b3SSadaf Ebrahimi 
2221*287e80b3SSadaf Ebrahimi 	synth->end_hist = create_end_hist(synth);
2222*287e80b3SSadaf Ebrahimi 	synth->end_hist = append_filter(synth->end_hist, synth->end_filter,
2223*287e80b3SSadaf Ebrahimi 					synth->end_parens);
2224*287e80b3SSadaf Ebrahimi 	if (!synth->end_hist)
2225*287e80b3SSadaf Ebrahimi 		goto remove_synthetic;
2226*287e80b3SSadaf Ebrahimi 
2227*287e80b3SSadaf Ebrahimi 	ret = tracefs_event_file_append(synth->instance, synth->start_event->system,
2228*287e80b3SSadaf Ebrahimi 					synth->start_event->name,
2229*287e80b3SSadaf Ebrahimi 					"trigger", synth->start_hist);
2230*287e80b3SSadaf Ebrahimi 	if (ret < 0)
2231*287e80b3SSadaf Ebrahimi 		goto remove_synthetic;
2232*287e80b3SSadaf Ebrahimi 
2233*287e80b3SSadaf Ebrahimi 	ret = tracefs_event_file_append(synth->instance, synth->end_event->system,
2234*287e80b3SSadaf Ebrahimi 					synth->end_event->name,
2235*287e80b3SSadaf Ebrahimi 					"trigger", synth->end_hist);
2236*287e80b3SSadaf Ebrahimi 	if (ret < 0)
2237*287e80b3SSadaf Ebrahimi 		goto remove_start_hist;
2238*287e80b3SSadaf Ebrahimi 
2239*287e80b3SSadaf Ebrahimi 	return 0;
2240*287e80b3SSadaf Ebrahimi 
2241*287e80b3SSadaf Ebrahimi  remove_start_hist:
2242*287e80b3SSadaf Ebrahimi 	remove_hist(synth->instance, synth->start_event, synth->start_hist);
2243*287e80b3SSadaf Ebrahimi  remove_synthetic:
2244*287e80b3SSadaf Ebrahimi 	tracefs_dynevent_destroy(synth->dyn_event, false);
2245*287e80b3SSadaf Ebrahimi 	return -1;
2246*287e80b3SSadaf Ebrahimi }
2247*287e80b3SSadaf Ebrahimi 
2248*287e80b3SSadaf Ebrahimi /**
2249*287e80b3SSadaf Ebrahimi  * tracefs_synth_destroy - delete the synthetic event from the system
2250*287e80b3SSadaf Ebrahimi  * @synth: The tracefs_synth descriptor
2251*287e80b3SSadaf Ebrahimi  *
2252*287e80b3SSadaf Ebrahimi  * This will destroy a synthetic event created by tracefs_synth_create()
2253*287e80b3SSadaf Ebrahimi  * with the same @synth.
2254*287e80b3SSadaf Ebrahimi  *
2255*287e80b3SSadaf Ebrahimi  * It will attempt to disable the synthetic event in its instance (top by default),
2256*287e80b3SSadaf Ebrahimi  * but if other instances have it active, it is likely to fail, which will likely
2257*287e80b3SSadaf Ebrahimi  * fail on all other parts of tearing down the synthetic event.
2258*287e80b3SSadaf Ebrahimi  *
2259*287e80b3SSadaf Ebrahimi  * Returns 0 on succes and -1 on error.
2260*287e80b3SSadaf Ebrahimi  * On error, errno is set to:
2261*287e80b3SSadaf Ebrahimi  * ENOMEM - memory allocation failure.
2262*287e80b3SSadaf Ebrahimi  * ENIVAL - a parameter is passed as NULL that should not be or a problem
2263*287e80b3SSadaf Ebrahimi  *   writing into the system.
2264*287e80b3SSadaf Ebrahimi  */
tracefs_synth_destroy(struct tracefs_synth * synth)2265*287e80b3SSadaf Ebrahimi int tracefs_synth_destroy(struct tracefs_synth *synth)
2266*287e80b3SSadaf Ebrahimi {
2267*287e80b3SSadaf Ebrahimi 	char *hist;
2268*287e80b3SSadaf Ebrahimi 	int ret;
2269*287e80b3SSadaf Ebrahimi 
2270*287e80b3SSadaf Ebrahimi 	if (!synth) {
2271*287e80b3SSadaf Ebrahimi 		errno = EINVAL;
2272*287e80b3SSadaf Ebrahimi 		return -1;
2273*287e80b3SSadaf Ebrahimi 	}
2274*287e80b3SSadaf Ebrahimi 
2275*287e80b3SSadaf Ebrahimi 	if (!synth->name || !synth->end_event) {
2276*287e80b3SSadaf Ebrahimi 		errno = EUNATCH;
2277*287e80b3SSadaf Ebrahimi 		return -1;
2278*287e80b3SSadaf Ebrahimi 	}
2279*287e80b3SSadaf Ebrahimi 
2280*287e80b3SSadaf Ebrahimi 	/* Try to disable the event if possible */
2281*287e80b3SSadaf Ebrahimi 	tracefs_event_disable(synth->instance, "synthetic", synth->name);
2282*287e80b3SSadaf Ebrahimi 
2283*287e80b3SSadaf Ebrahimi 	hist = create_end_hist(synth);
2284*287e80b3SSadaf Ebrahimi 	hist = append_filter(hist, synth->end_filter,
2285*287e80b3SSadaf Ebrahimi 			     synth->end_parens);
2286*287e80b3SSadaf Ebrahimi 	if (!hist)
2287*287e80b3SSadaf Ebrahimi 		return -1;
2288*287e80b3SSadaf Ebrahimi 	ret = remove_hist(synth->instance, synth->end_event, hist);
2289*287e80b3SSadaf Ebrahimi 	free(hist);
2290*287e80b3SSadaf Ebrahimi 
2291*287e80b3SSadaf Ebrahimi 	hist = create_hist(synth->start_keys, synth->start_vars);
2292*287e80b3SSadaf Ebrahimi 	hist = append_filter(hist, synth->start_filter,
2293*287e80b3SSadaf Ebrahimi 			     synth->start_parens);
2294*287e80b3SSadaf Ebrahimi 	if (!hist)
2295*287e80b3SSadaf Ebrahimi 		return -1;
2296*287e80b3SSadaf Ebrahimi 
2297*287e80b3SSadaf Ebrahimi 	ret = remove_hist(synth->instance, synth->start_event, hist);
2298*287e80b3SSadaf Ebrahimi 	free(hist);
2299*287e80b3SSadaf Ebrahimi 
2300*287e80b3SSadaf Ebrahimi 	ret = tracefs_dynevent_destroy(synth->dyn_event, true);
2301*287e80b3SSadaf Ebrahimi 
2302*287e80b3SSadaf Ebrahimi 	return ret ? -1 : 0;
2303*287e80b3SSadaf Ebrahimi }
2304*287e80b3SSadaf Ebrahimi 
2305*287e80b3SSadaf Ebrahimi /**
2306*287e80b3SSadaf Ebrahimi  * tracefs_synth_echo_cmd - show the command lines to create the synthetic event
2307*287e80b3SSadaf Ebrahimi  * @seq: The trace_seq to store the command lines in
2308*287e80b3SSadaf Ebrahimi  * @synth: The tracefs_synth descriptor
2309*287e80b3SSadaf Ebrahimi  *
2310*287e80b3SSadaf Ebrahimi  * This will list the "echo" commands that are equivalent to what would
2311*287e80b3SSadaf Ebrahimi  * be executed by the tracefs_synth_create() command.
2312*287e80b3SSadaf Ebrahimi  *
2313*287e80b3SSadaf Ebrahimi  * Returns 0 on succes and -1 on error.
2314*287e80b3SSadaf Ebrahimi  * On error, errno is set to:
2315*287e80b3SSadaf Ebrahimi  * ENOMEM - memory allocation failure.
2316*287e80b3SSadaf Ebrahimi  */
tracefs_synth_echo_cmd(struct trace_seq * seq,struct tracefs_synth * synth)2317*287e80b3SSadaf Ebrahimi int tracefs_synth_echo_cmd(struct trace_seq *seq,
2318*287e80b3SSadaf Ebrahimi 			   struct tracefs_synth *synth)
2319*287e80b3SSadaf Ebrahimi {
2320*287e80b3SSadaf Ebrahimi 	bool new_event = false;
2321*287e80b3SSadaf Ebrahimi 	char *hist = NULL;
2322*287e80b3SSadaf Ebrahimi 	char *path;
2323*287e80b3SSadaf Ebrahimi 	int ret = -1;
2324*287e80b3SSadaf Ebrahimi 
2325*287e80b3SSadaf Ebrahimi 	if (!synth) {
2326*287e80b3SSadaf Ebrahimi 		errno = EINVAL;
2327*287e80b3SSadaf Ebrahimi 		return -1;
2328*287e80b3SSadaf Ebrahimi 	}
2329*287e80b3SSadaf Ebrahimi 
2330*287e80b3SSadaf Ebrahimi 	if (!synth->name || !synth->end_event) {
2331*287e80b3SSadaf Ebrahimi 		errno = EUNATCH;
2332*287e80b3SSadaf Ebrahimi 		return -1;
2333*287e80b3SSadaf Ebrahimi 	}
2334*287e80b3SSadaf Ebrahimi 
2335*287e80b3SSadaf Ebrahimi 	if (!synth->dyn_event) {
2336*287e80b3SSadaf Ebrahimi 		if (alloc_synthetic_event(synth))
2337*287e80b3SSadaf Ebrahimi 			return -1;
2338*287e80b3SSadaf Ebrahimi 		new_event = true;
2339*287e80b3SSadaf Ebrahimi 	}
2340*287e80b3SSadaf Ebrahimi 
2341*287e80b3SSadaf Ebrahimi 	path = trace_find_tracing_dir(false);
2342*287e80b3SSadaf Ebrahimi 	if (!path)
2343*287e80b3SSadaf Ebrahimi 		goto out_free;
2344*287e80b3SSadaf Ebrahimi 
2345*287e80b3SSadaf Ebrahimi 	trace_seq_printf(seq, "echo '%s%s%s %s' >> %s/%s\n",
2346*287e80b3SSadaf Ebrahimi 			 synth->dyn_event->prefix,
2347*287e80b3SSadaf Ebrahimi 			 strlen(synth->dyn_event->prefix) ? ":" : "",
2348*287e80b3SSadaf Ebrahimi 			 synth->dyn_event->event,
2349*287e80b3SSadaf Ebrahimi 			 synth->dyn_event->format, path, synth->dyn_event->trace_file);
2350*287e80b3SSadaf Ebrahimi 
2351*287e80b3SSadaf Ebrahimi 	tracefs_put_tracing_file(path);
2352*287e80b3SSadaf Ebrahimi 	path = tracefs_instance_get_dir(synth->instance);
2353*287e80b3SSadaf Ebrahimi 
2354*287e80b3SSadaf Ebrahimi 	hist = create_hist(synth->start_keys, synth->start_vars);
2355*287e80b3SSadaf Ebrahimi 	hist = append_filter(hist, synth->start_filter,
2356*287e80b3SSadaf Ebrahimi 			     synth->start_parens);
2357*287e80b3SSadaf Ebrahimi 	if (!hist)
2358*287e80b3SSadaf Ebrahimi 		goto out_free;
2359*287e80b3SSadaf Ebrahimi 
2360*287e80b3SSadaf Ebrahimi 	trace_seq_printf(seq, "echo '%s' >> %s/events/%s/%s/trigger\n",
2361*287e80b3SSadaf Ebrahimi 			 hist, path, synth->start_event->system,
2362*287e80b3SSadaf Ebrahimi 			 synth->start_event->name);
2363*287e80b3SSadaf Ebrahimi 	free(hist);
2364*287e80b3SSadaf Ebrahimi 	hist = create_end_hist(synth);
2365*287e80b3SSadaf Ebrahimi 	hist = append_filter(hist, synth->end_filter,
2366*287e80b3SSadaf Ebrahimi 			     synth->end_parens);
2367*287e80b3SSadaf Ebrahimi 	if (!hist)
2368*287e80b3SSadaf Ebrahimi 		goto out_free;
2369*287e80b3SSadaf Ebrahimi 
2370*287e80b3SSadaf Ebrahimi 	trace_seq_printf(seq, "echo '%s' >> %s/events/%s/%s/trigger\n",
2371*287e80b3SSadaf Ebrahimi 			 hist, path, synth->end_event->system,
2372*287e80b3SSadaf Ebrahimi 			 synth->end_event->name);
2373*287e80b3SSadaf Ebrahimi 
2374*287e80b3SSadaf Ebrahimi 	ret = 0;
2375*287e80b3SSadaf Ebrahimi  out_free:
2376*287e80b3SSadaf Ebrahimi 	free(hist);
2377*287e80b3SSadaf Ebrahimi 	tracefs_put_tracing_file(path);
2378*287e80b3SSadaf Ebrahimi 	if (new_event) {
2379*287e80b3SSadaf Ebrahimi 		tracefs_dynevent_free(synth->dyn_event);
2380*287e80b3SSadaf Ebrahimi 		synth->dyn_event = NULL;
2381*287e80b3SSadaf Ebrahimi 	}
2382*287e80b3SSadaf Ebrahimi 	return ret;
2383*287e80b3SSadaf Ebrahimi }
2384*287e80b3SSadaf Ebrahimi 
2385*287e80b3SSadaf Ebrahimi /**
2386*287e80b3SSadaf Ebrahimi  * tracefs_synth_get_event - return tep event representing the given synthetic event
2387*287e80b3SSadaf Ebrahimi  * @tep: a handle to the trace event parser context that holds the events
2388*287e80b3SSadaf Ebrahimi  * @synth: a synthetic event context, describing given synthetic event.
2389*287e80b3SSadaf Ebrahimi  *
2390*287e80b3SSadaf Ebrahimi  * Returns a pointer to a tep event describing the given synthetic event. The pointer
2391*287e80b3SSadaf Ebrahimi  * is managed by the @tep handle and must not be freed. In case of an error, or in case
2392*287e80b3SSadaf Ebrahimi  * the requested synthetic event is missing in the @tep handler - NULL is returned.
2393*287e80b3SSadaf Ebrahimi  */
2394*287e80b3SSadaf Ebrahimi struct tep_event *
tracefs_synth_get_event(struct tep_handle * tep,struct tracefs_synth * synth)2395*287e80b3SSadaf Ebrahimi tracefs_synth_get_event(struct tep_handle *tep, struct tracefs_synth *synth)
2396*287e80b3SSadaf Ebrahimi {
2397*287e80b3SSadaf Ebrahimi 	if (!tep || !synth || !synth->name)
2398*287e80b3SSadaf Ebrahimi 		return NULL;
2399*287e80b3SSadaf Ebrahimi 
2400*287e80b3SSadaf Ebrahimi 	return get_tep_event(tep, SYNTHETIC_GROUP, synth->name);
2401*287e80b3SSadaf Ebrahimi }
2402