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