xref: /aosp_15_r20/external/libtraceevent/plugins/plugin_sched_switch.c (revision 436bf2bcd5202612ffffe471bbcc1f277cc8d28e)
1*436bf2bcSAndroid Build Coastguard Worker // SPDX-License-Identifier: LGPL-2.1
2*436bf2bcSAndroid Build Coastguard Worker /*
3*436bf2bcSAndroid Build Coastguard Worker  * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <[email protected]>
4*436bf2bcSAndroid Build Coastguard Worker  */
5*436bf2bcSAndroid Build Coastguard Worker #include <stdio.h>
6*436bf2bcSAndroid Build Coastguard Worker #include <stdlib.h>
7*436bf2bcSAndroid Build Coastguard Worker #include <string.h>
8*436bf2bcSAndroid Build Coastguard Worker 
9*436bf2bcSAndroid Build Coastguard Worker #include "event-parse.h"
10*436bf2bcSAndroid Build Coastguard Worker #include "trace-seq.h"
11*436bf2bcSAndroid Build Coastguard Worker 
12*436bf2bcSAndroid Build Coastguard Worker /*
13*436bf2bcSAndroid Build Coastguard Worker  * prev_state is of size long, which is 32 bits on 32 bit architectures.
14*436bf2bcSAndroid Build Coastguard Worker  * As it needs to have the same bits for both 32 bit and 64 bit architectures
15*436bf2bcSAndroid Build Coastguard Worker  * we can just assume that the flags we care about will all be within
16*436bf2bcSAndroid Build Coastguard Worker  * the 32 bits.
17*436bf2bcSAndroid Build Coastguard Worker  */
18*436bf2bcSAndroid Build Coastguard Worker #define MAX_STATE_BITS	32
19*436bf2bcSAndroid Build Coastguard Worker 
convert_sym(struct tep_print_flag_sym * sym)20*436bf2bcSAndroid Build Coastguard Worker static const char *convert_sym(struct tep_print_flag_sym *sym)
21*436bf2bcSAndroid Build Coastguard Worker {
22*436bf2bcSAndroid Build Coastguard Worker 	static char save_states[MAX_STATE_BITS + 1];
23*436bf2bcSAndroid Build Coastguard Worker 
24*436bf2bcSAndroid Build Coastguard Worker 	memset(save_states, 0, sizeof(save_states));
25*436bf2bcSAndroid Build Coastguard Worker 
26*436bf2bcSAndroid Build Coastguard Worker 	/* This is the flags for the prev_state_field, now make them into a string */
27*436bf2bcSAndroid Build Coastguard Worker 	for (; sym; sym = sym->next) {
28*436bf2bcSAndroid Build Coastguard Worker 		long bitmask = strtoul(sym->value, NULL, 0);
29*436bf2bcSAndroid Build Coastguard Worker 		int i;
30*436bf2bcSAndroid Build Coastguard Worker 
31*436bf2bcSAndroid Build Coastguard Worker 		for (i = 0; !(bitmask & 1); i++)
32*436bf2bcSAndroid Build Coastguard Worker 			bitmask >>= 1;
33*436bf2bcSAndroid Build Coastguard Worker 
34*436bf2bcSAndroid Build Coastguard Worker 		if (i >= MAX_STATE_BITS)
35*436bf2bcSAndroid Build Coastguard Worker 			continue;
36*436bf2bcSAndroid Build Coastguard Worker 
37*436bf2bcSAndroid Build Coastguard Worker 		save_states[i] = sym->str[0];
38*436bf2bcSAndroid Build Coastguard Worker 	}
39*436bf2bcSAndroid Build Coastguard Worker 
40*436bf2bcSAndroid Build Coastguard Worker 	return save_states;
41*436bf2bcSAndroid Build Coastguard Worker }
42*436bf2bcSAndroid Build Coastguard Worker 
43*436bf2bcSAndroid Build Coastguard Worker static struct tep_print_arg_field *
find_arg_field(struct tep_format_field * prev_state_field,struct tep_print_arg * arg)44*436bf2bcSAndroid Build Coastguard Worker find_arg_field(struct tep_format_field *prev_state_field, struct tep_print_arg *arg)
45*436bf2bcSAndroid Build Coastguard Worker {
46*436bf2bcSAndroid Build Coastguard Worker 	struct tep_print_arg_field *field;
47*436bf2bcSAndroid Build Coastguard Worker 
48*436bf2bcSAndroid Build Coastguard Worker 	if (!arg)
49*436bf2bcSAndroid Build Coastguard Worker 		return NULL;
50*436bf2bcSAndroid Build Coastguard Worker 
51*436bf2bcSAndroid Build Coastguard Worker 	if (arg->type == TEP_PRINT_FIELD)
52*436bf2bcSAndroid Build Coastguard Worker 		return &arg->field;
53*436bf2bcSAndroid Build Coastguard Worker 
54*436bf2bcSAndroid Build Coastguard Worker 	if (arg->type == TEP_PRINT_OP) {
55*436bf2bcSAndroid Build Coastguard Worker 		field = find_arg_field(prev_state_field, arg->op.left);
56*436bf2bcSAndroid Build Coastguard Worker 		if (field && field->field == prev_state_field)
57*436bf2bcSAndroid Build Coastguard Worker 			return field;
58*436bf2bcSAndroid Build Coastguard Worker 		field = find_arg_field(prev_state_field, arg->op.right);
59*436bf2bcSAndroid Build Coastguard Worker 		if (field && field->field == prev_state_field)
60*436bf2bcSAndroid Build Coastguard Worker 			return field;
61*436bf2bcSAndroid Build Coastguard Worker 	}
62*436bf2bcSAndroid Build Coastguard Worker 	return NULL;
63*436bf2bcSAndroid Build Coastguard Worker }
64*436bf2bcSAndroid Build Coastguard Worker 
65*436bf2bcSAndroid Build Coastguard Worker static struct tep_print_flag_sym *
test_flags(struct tep_format_field * prev_state_field,struct tep_print_arg * arg)66*436bf2bcSAndroid Build Coastguard Worker test_flags(struct tep_format_field *prev_state_field, struct tep_print_arg *arg)
67*436bf2bcSAndroid Build Coastguard Worker {
68*436bf2bcSAndroid Build Coastguard Worker 	struct tep_print_arg_field *field;
69*436bf2bcSAndroid Build Coastguard Worker 
70*436bf2bcSAndroid Build Coastguard Worker 	field = find_arg_field(prev_state_field, arg->flags.field);
71*436bf2bcSAndroid Build Coastguard Worker 	if (!field)
72*436bf2bcSAndroid Build Coastguard Worker 		return NULL;
73*436bf2bcSAndroid Build Coastguard Worker 
74*436bf2bcSAndroid Build Coastguard Worker 	return arg->flags.flags;
75*436bf2bcSAndroid Build Coastguard Worker }
76*436bf2bcSAndroid Build Coastguard Worker 
77*436bf2bcSAndroid Build Coastguard Worker static struct tep_print_flag_sym *
search_op(struct tep_format_field * prev_state_field,struct tep_print_arg * arg)78*436bf2bcSAndroid Build Coastguard Worker search_op(struct tep_format_field *prev_state_field, struct tep_print_arg *arg)
79*436bf2bcSAndroid Build Coastguard Worker {
80*436bf2bcSAndroid Build Coastguard Worker 	struct tep_print_flag_sym *sym = NULL;
81*436bf2bcSAndroid Build Coastguard Worker 
82*436bf2bcSAndroid Build Coastguard Worker 	if (!arg)
83*436bf2bcSAndroid Build Coastguard Worker 		return NULL;
84*436bf2bcSAndroid Build Coastguard Worker 
85*436bf2bcSAndroid Build Coastguard Worker 	if (arg->type == TEP_PRINT_OP) {
86*436bf2bcSAndroid Build Coastguard Worker 		sym = search_op(prev_state_field, arg->op.left);
87*436bf2bcSAndroid Build Coastguard Worker 		if (sym)
88*436bf2bcSAndroid Build Coastguard Worker 			return sym;
89*436bf2bcSAndroid Build Coastguard Worker 
90*436bf2bcSAndroid Build Coastguard Worker 		sym = search_op(prev_state_field, arg->op.right);
91*436bf2bcSAndroid Build Coastguard Worker 		if (sym)
92*436bf2bcSAndroid Build Coastguard Worker 			return sym;
93*436bf2bcSAndroid Build Coastguard Worker 	} else if (arg->type == TEP_PRINT_FLAGS) {
94*436bf2bcSAndroid Build Coastguard Worker 		sym = test_flags(prev_state_field, arg);
95*436bf2bcSAndroid Build Coastguard Worker 	}
96*436bf2bcSAndroid Build Coastguard Worker 
97*436bf2bcSAndroid Build Coastguard Worker 	return sym;
98*436bf2bcSAndroid Build Coastguard Worker }
99*436bf2bcSAndroid Build Coastguard Worker 
get_states(struct tep_format_field * prev_state_field)100*436bf2bcSAndroid Build Coastguard Worker static const char *get_states(struct tep_format_field *prev_state_field)
101*436bf2bcSAndroid Build Coastguard Worker {
102*436bf2bcSAndroid Build Coastguard Worker 	struct tep_print_flag_sym *sym;
103*436bf2bcSAndroid Build Coastguard Worker 	struct tep_print_arg *arg;
104*436bf2bcSAndroid Build Coastguard Worker 	struct tep_event *event;
105*436bf2bcSAndroid Build Coastguard Worker 
106*436bf2bcSAndroid Build Coastguard Worker 	event = prev_state_field->event;
107*436bf2bcSAndroid Build Coastguard Worker 
108*436bf2bcSAndroid Build Coastguard Worker 	/*
109*436bf2bcSAndroid Build Coastguard Worker 	 * Look at the event format fields, and search for where
110*436bf2bcSAndroid Build Coastguard Worker 	 * the prev_state is parsed via the format flags.
111*436bf2bcSAndroid Build Coastguard Worker 	 */
112*436bf2bcSAndroid Build Coastguard Worker 	for (arg = event->print_fmt.args; arg; arg = arg->next) {
113*436bf2bcSAndroid Build Coastguard Worker 		/*
114*436bf2bcSAndroid Build Coastguard Worker 		 * Currently, the __print_flags() for the prev_state
115*436bf2bcSAndroid Build Coastguard Worker 		 * is embedded in operations, so they too must be
116*436bf2bcSAndroid Build Coastguard Worker 		 * searched.
117*436bf2bcSAndroid Build Coastguard Worker 		 */
118*436bf2bcSAndroid Build Coastguard Worker 		sym = search_op(prev_state_field, arg);
119*436bf2bcSAndroid Build Coastguard Worker 		if (sym)
120*436bf2bcSAndroid Build Coastguard Worker 			return convert_sym(sym);
121*436bf2bcSAndroid Build Coastguard Worker 	}
122*436bf2bcSAndroid Build Coastguard Worker 	return NULL;
123*436bf2bcSAndroid Build Coastguard Worker }
124*436bf2bcSAndroid Build Coastguard Worker 
write_state(struct trace_seq * s,struct tep_format_field * field,struct tep_record * record)125*436bf2bcSAndroid Build Coastguard Worker static void write_state(struct trace_seq *s, struct tep_format_field *field,
126*436bf2bcSAndroid Build Coastguard Worker 			struct tep_record *record)
127*436bf2bcSAndroid Build Coastguard Worker {
128*436bf2bcSAndroid Build Coastguard Worker 	static struct tep_format_field *prev_state_field;
129*436bf2bcSAndroid Build Coastguard Worker 	static const char *states;
130*436bf2bcSAndroid Build Coastguard Worker 	unsigned long long val;
131*436bf2bcSAndroid Build Coastguard Worker 	int found = 0;
132*436bf2bcSAndroid Build Coastguard Worker 	int len;
133*436bf2bcSAndroid Build Coastguard Worker 	int i;
134*436bf2bcSAndroid Build Coastguard Worker 
135*436bf2bcSAndroid Build Coastguard Worker 	if (!field)
136*436bf2bcSAndroid Build Coastguard Worker 		return;
137*436bf2bcSAndroid Build Coastguard Worker 
138*436bf2bcSAndroid Build Coastguard Worker 	if (!states || field != prev_state_field) {
139*436bf2bcSAndroid Build Coastguard Worker 		states = get_states(field);
140*436bf2bcSAndroid Build Coastguard Worker 		if (!states)
141*436bf2bcSAndroid Build Coastguard Worker 			states = "SDTtXZPI";
142*436bf2bcSAndroid Build Coastguard Worker 		prev_state_field = field;
143*436bf2bcSAndroid Build Coastguard Worker 	}
144*436bf2bcSAndroid Build Coastguard Worker 
145*436bf2bcSAndroid Build Coastguard Worker 	tep_read_number_field(field, record->data, &val);
146*436bf2bcSAndroid Build Coastguard Worker 
147*436bf2bcSAndroid Build Coastguard Worker 	len = strlen(states);
148*436bf2bcSAndroid Build Coastguard Worker 	for (i = 0; i < len; i++) {
149*436bf2bcSAndroid Build Coastguard Worker 		if (!(val & (1 << i)))
150*436bf2bcSAndroid Build Coastguard Worker 			continue;
151*436bf2bcSAndroid Build Coastguard Worker 
152*436bf2bcSAndroid Build Coastguard Worker 		if (found)
153*436bf2bcSAndroid Build Coastguard Worker 			trace_seq_putc(s, '|');
154*436bf2bcSAndroid Build Coastguard Worker 
155*436bf2bcSAndroid Build Coastguard Worker 		found = 1;
156*436bf2bcSAndroid Build Coastguard Worker 		trace_seq_putc(s, states[i]);
157*436bf2bcSAndroid Build Coastguard Worker 	}
158*436bf2bcSAndroid Build Coastguard Worker 
159*436bf2bcSAndroid Build Coastguard Worker 	if (!found)
160*436bf2bcSAndroid Build Coastguard Worker 		trace_seq_putc(s, 'R');
161*436bf2bcSAndroid Build Coastguard Worker }
162*436bf2bcSAndroid Build Coastguard Worker 
write_and_save_comm(struct tep_format_field * field,struct tep_record * record,struct trace_seq * s,int pid)163*436bf2bcSAndroid Build Coastguard Worker static void write_and_save_comm(struct tep_format_field *field,
164*436bf2bcSAndroid Build Coastguard Worker 				struct tep_record *record,
165*436bf2bcSAndroid Build Coastguard Worker 				struct trace_seq *s, int pid)
166*436bf2bcSAndroid Build Coastguard Worker {
167*436bf2bcSAndroid Build Coastguard Worker 	const char *comm;
168*436bf2bcSAndroid Build Coastguard Worker 	int len;
169*436bf2bcSAndroid Build Coastguard Worker 
170*436bf2bcSAndroid Build Coastguard Worker 	comm = (char *)(record->data + field->offset);
171*436bf2bcSAndroid Build Coastguard Worker 	len = s->len;
172*436bf2bcSAndroid Build Coastguard Worker 	trace_seq_printf(s, "%.*s",
173*436bf2bcSAndroid Build Coastguard Worker 			 field->size, comm);
174*436bf2bcSAndroid Build Coastguard Worker 
175*436bf2bcSAndroid Build Coastguard Worker 	/* make sure the comm has a \0 at the end. */
176*436bf2bcSAndroid Build Coastguard Worker 	trace_seq_terminate(s);
177*436bf2bcSAndroid Build Coastguard Worker 	comm = &s->buffer[len];
178*436bf2bcSAndroid Build Coastguard Worker 
179*436bf2bcSAndroid Build Coastguard Worker 	/* Help out the comm to ids. This will handle dups */
180*436bf2bcSAndroid Build Coastguard Worker 	tep_register_comm(field->event->tep, comm, pid);
181*436bf2bcSAndroid Build Coastguard Worker }
182*436bf2bcSAndroid Build Coastguard Worker 
sched_wakeup_handler(struct trace_seq * s,struct tep_record * record,struct tep_event * event,void * context)183*436bf2bcSAndroid Build Coastguard Worker static int sched_wakeup_handler(struct trace_seq *s,
184*436bf2bcSAndroid Build Coastguard Worker 				struct tep_record *record,
185*436bf2bcSAndroid Build Coastguard Worker 				struct tep_event *event, void *context)
186*436bf2bcSAndroid Build Coastguard Worker {
187*436bf2bcSAndroid Build Coastguard Worker 	struct tep_format_field *field;
188*436bf2bcSAndroid Build Coastguard Worker 	unsigned long long val;
189*436bf2bcSAndroid Build Coastguard Worker 
190*436bf2bcSAndroid Build Coastguard Worker 	if (tep_get_field_val(s, event, "pid", record, &val, 1))
191*436bf2bcSAndroid Build Coastguard Worker 		return trace_seq_putc(s, '!');
192*436bf2bcSAndroid Build Coastguard Worker 
193*436bf2bcSAndroid Build Coastguard Worker 	field = tep_find_any_field(event, "comm");
194*436bf2bcSAndroid Build Coastguard Worker 	if (field) {
195*436bf2bcSAndroid Build Coastguard Worker 		write_and_save_comm(field, record, s, val);
196*436bf2bcSAndroid Build Coastguard Worker 		trace_seq_putc(s, ':');
197*436bf2bcSAndroid Build Coastguard Worker 	}
198*436bf2bcSAndroid Build Coastguard Worker 	trace_seq_printf(s, "%lld", val);
199*436bf2bcSAndroid Build Coastguard Worker 
200*436bf2bcSAndroid Build Coastguard Worker 	if (tep_get_field_val(s, event, "prio", record, &val, 1) == 0)
201*436bf2bcSAndroid Build Coastguard Worker 		trace_seq_printf(s, " [%lld]", val);
202*436bf2bcSAndroid Build Coastguard Worker 
203*436bf2bcSAndroid Build Coastguard Worker 	if (tep_get_field_val(s, event, "success", record, &val, 0) == 0)
204*436bf2bcSAndroid Build Coastguard Worker 		trace_seq_printf(s, " success=%lld", val);
205*436bf2bcSAndroid Build Coastguard Worker 
206*436bf2bcSAndroid Build Coastguard Worker 	if (tep_get_field_val(s, event, "target_cpu", record, &val, 0) == 0)
207*436bf2bcSAndroid Build Coastguard Worker 		trace_seq_printf(s, " CPU:%03llu", val);
208*436bf2bcSAndroid Build Coastguard Worker 
209*436bf2bcSAndroid Build Coastguard Worker 	return 0;
210*436bf2bcSAndroid Build Coastguard Worker }
211*436bf2bcSAndroid Build Coastguard Worker 
sched_switch_handler(struct trace_seq * s,struct tep_record * record,struct tep_event * event,void * context)212*436bf2bcSAndroid Build Coastguard Worker static int sched_switch_handler(struct trace_seq *s,
213*436bf2bcSAndroid Build Coastguard Worker 				struct tep_record *record,
214*436bf2bcSAndroid Build Coastguard Worker 				struct tep_event *event, void *context)
215*436bf2bcSAndroid Build Coastguard Worker {
216*436bf2bcSAndroid Build Coastguard Worker 	struct tep_format_field *field;
217*436bf2bcSAndroid Build Coastguard Worker 	unsigned long long val;
218*436bf2bcSAndroid Build Coastguard Worker 
219*436bf2bcSAndroid Build Coastguard Worker 	if (tep_get_field_val(s, event, "prev_pid", record, &val, 1))
220*436bf2bcSAndroid Build Coastguard Worker 		return trace_seq_putc(s, '!');
221*436bf2bcSAndroid Build Coastguard Worker 
222*436bf2bcSAndroid Build Coastguard Worker 	field = tep_find_any_field(event, "prev_comm");
223*436bf2bcSAndroid Build Coastguard Worker 	if (field) {
224*436bf2bcSAndroid Build Coastguard Worker 		write_and_save_comm(field, record, s, val);
225*436bf2bcSAndroid Build Coastguard Worker 		trace_seq_putc(s, ':');
226*436bf2bcSAndroid Build Coastguard Worker 	}
227*436bf2bcSAndroid Build Coastguard Worker 	trace_seq_printf(s, "%lld ", val);
228*436bf2bcSAndroid Build Coastguard Worker 
229*436bf2bcSAndroid Build Coastguard Worker 	if (tep_get_field_val(s, event, "prev_prio", record, &val, 1) == 0)
230*436bf2bcSAndroid Build Coastguard Worker 		trace_seq_printf(s, "[%d] ", (int) val);
231*436bf2bcSAndroid Build Coastguard Worker 
232*436bf2bcSAndroid Build Coastguard Worker 	field = tep_find_any_field(event, "prev_state");
233*436bf2bcSAndroid Build Coastguard Worker 	write_state(s, field, record);
234*436bf2bcSAndroid Build Coastguard Worker 
235*436bf2bcSAndroid Build Coastguard Worker 	trace_seq_puts(s, " ==> ");
236*436bf2bcSAndroid Build Coastguard Worker 
237*436bf2bcSAndroid Build Coastguard Worker 	if (tep_get_field_val(s, event, "next_pid", record, &val, 1))
238*436bf2bcSAndroid Build Coastguard Worker 		return trace_seq_putc(s, '!');
239*436bf2bcSAndroid Build Coastguard Worker 
240*436bf2bcSAndroid Build Coastguard Worker 	field = tep_find_any_field(event, "next_comm");
241*436bf2bcSAndroid Build Coastguard Worker 	if (field) {
242*436bf2bcSAndroid Build Coastguard Worker 		write_and_save_comm(field, record, s, val);
243*436bf2bcSAndroid Build Coastguard Worker 		trace_seq_putc(s, ':');
244*436bf2bcSAndroid Build Coastguard Worker 	}
245*436bf2bcSAndroid Build Coastguard Worker 	trace_seq_printf(s, "%lld", val);
246*436bf2bcSAndroid Build Coastguard Worker 
247*436bf2bcSAndroid Build Coastguard Worker 	if (tep_get_field_val(s, event, "next_prio", record, &val, 1) == 0)
248*436bf2bcSAndroid Build Coastguard Worker 		trace_seq_printf(s, " [%d]", (int) val);
249*436bf2bcSAndroid Build Coastguard Worker 
250*436bf2bcSAndroid Build Coastguard Worker 	return 0;
251*436bf2bcSAndroid Build Coastguard Worker }
252*436bf2bcSAndroid Build Coastguard Worker 
TEP_PLUGIN_LOADER(struct tep_handle * tep)253*436bf2bcSAndroid Build Coastguard Worker int TEP_PLUGIN_LOADER(struct tep_handle *tep)
254*436bf2bcSAndroid Build Coastguard Worker {
255*436bf2bcSAndroid Build Coastguard Worker 	tep_register_event_handler(tep, -1, "sched", "sched_switch",
256*436bf2bcSAndroid Build Coastguard Worker 				   sched_switch_handler, NULL);
257*436bf2bcSAndroid Build Coastguard Worker 
258*436bf2bcSAndroid Build Coastguard Worker 	tep_register_event_handler(tep, -1, "sched", "sched_wakeup",
259*436bf2bcSAndroid Build Coastguard Worker 				   sched_wakeup_handler, NULL);
260*436bf2bcSAndroid Build Coastguard Worker 
261*436bf2bcSAndroid Build Coastguard Worker 	tep_register_event_handler(tep, -1, "sched", "sched_wakeup_new",
262*436bf2bcSAndroid Build Coastguard Worker 				   sched_wakeup_handler, NULL);
263*436bf2bcSAndroid Build Coastguard Worker 	return 0;
264*436bf2bcSAndroid Build Coastguard Worker }
265*436bf2bcSAndroid Build Coastguard Worker 
TEP_PLUGIN_UNLOADER(struct tep_handle * tep)266*436bf2bcSAndroid Build Coastguard Worker void TEP_PLUGIN_UNLOADER(struct tep_handle *tep)
267*436bf2bcSAndroid Build Coastguard Worker {
268*436bf2bcSAndroid Build Coastguard Worker 	tep_unregister_event_handler(tep, -1, "sched", "sched_switch",
269*436bf2bcSAndroid Build Coastguard Worker 				     sched_switch_handler, NULL);
270*436bf2bcSAndroid Build Coastguard Worker 
271*436bf2bcSAndroid Build Coastguard Worker 	tep_unregister_event_handler(tep, -1, "sched", "sched_wakeup",
272*436bf2bcSAndroid Build Coastguard Worker 				     sched_wakeup_handler, NULL);
273*436bf2bcSAndroid Build Coastguard Worker 
274*436bf2bcSAndroid Build Coastguard Worker 	tep_unregister_event_handler(tep, -1, "sched", "sched_wakeup_new",
275*436bf2bcSAndroid Build Coastguard Worker 				     sched_wakeup_handler, NULL);
276*436bf2bcSAndroid Build Coastguard Worker }
277