• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3  *
4  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation;
8  * version 2.1 of the License (not later!)
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not,  see <http://www.gnu.org/licenses>
17  *
18  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19  */
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #include "event-parse.h"
25 
write_state(struct trace_seq * s,int val)26 static void write_state(struct trace_seq *s, int val)
27 {
28 	const char states[] = "SDTtZXxW";
29 	int found = 0;
30 	int i;
31 
32 	for (i = 0; i < (sizeof(states) - 1); i++) {
33 		if (!(val & (1 << i)))
34 			continue;
35 
36 		if (found)
37 			trace_seq_putc(s, '|');
38 
39 		found = 1;
40 		trace_seq_putc(s, states[i]);
41 	}
42 
43 	if (!found)
44 		trace_seq_putc(s, 'R');
45 }
46 
write_and_save_comm(struct format_field * field,struct pevent_record * record,struct trace_seq * s,int pid)47 static void write_and_save_comm(struct format_field *field,
48 				struct pevent_record *record,
49 				struct trace_seq *s, int pid)
50 {
51 	const char *comm;
52 	int len;
53 
54 	comm = (char *)(record->data + field->offset);
55 	len = s->len;
56 	trace_seq_printf(s, "%.*s",
57 			 field->size, comm);
58 
59 	/* make sure the comm has a \0 at the end. */
60 	trace_seq_terminate(s);
61 	comm = &s->buffer[len];
62 
63 	/* Help out the comm to ids. This will handle dups */
64 	pevent_register_comm(field->event->pevent, comm, pid);
65 }
66 
sched_wakeup_handler(struct trace_seq * s,struct pevent_record * record,struct event_format * event,void * context)67 static int sched_wakeup_handler(struct trace_seq *s,
68 				struct pevent_record *record,
69 				struct event_format *event, void *context)
70 {
71 	struct format_field *field;
72 	unsigned long long val;
73 
74 	if (pevent_get_field_val(s, event, "pid", record, &val, 1))
75 		return trace_seq_putc(s, '!');
76 
77 	field = pevent_find_any_field(event, "comm");
78 	if (field) {
79 		write_and_save_comm(field, record, s, val);
80 		trace_seq_putc(s, ':');
81 	}
82 	trace_seq_printf(s, "%lld", val);
83 
84 	if (pevent_get_field_val(s, event, "prio", record, &val, 0) == 0)
85 		trace_seq_printf(s, " [%lld]", val);
86 
87 	if (pevent_get_field_val(s, event, "success", record, &val, 1) == 0)
88 		trace_seq_printf(s, " success=%lld", val);
89 
90 	if (pevent_get_field_val(s, event, "target_cpu", record, &val, 0) == 0)
91 		trace_seq_printf(s, " CPU:%03llu", val);
92 
93 	return 0;
94 }
95 
sched_switch_handler(struct trace_seq * s,struct pevent_record * record,struct event_format * event,void * context)96 static int sched_switch_handler(struct trace_seq *s,
97 				struct pevent_record *record,
98 				struct event_format *event, void *context)
99 {
100 	struct format_field *field;
101 	unsigned long long val;
102 
103 	if (pevent_get_field_val(s, event, "prev_pid", record, &val, 1))
104 		return trace_seq_putc(s, '!');
105 
106 	field = pevent_find_any_field(event, "prev_comm");
107 	if (field) {
108 		write_and_save_comm(field, record, s, val);
109 		trace_seq_putc(s, ':');
110 	}
111 	trace_seq_printf(s, "%lld ", val);
112 
113 	if (pevent_get_field_val(s, event, "prev_prio", record, &val, 0) == 0)
114 		trace_seq_printf(s, "[%lld] ", val);
115 
116 	if (pevent_get_field_val(s,  event, "prev_state", record, &val, 0) == 0)
117 		write_state(s, val);
118 
119 	trace_seq_puts(s, " ==> ");
120 
121 	if (pevent_get_field_val(s, event, "next_pid", record, &val, 1))
122 		return trace_seq_putc(s, '!');
123 
124 	field = pevent_find_any_field(event, "next_comm");
125 	if (field) {
126 		write_and_save_comm(field, record, s, val);
127 		trace_seq_putc(s, ':');
128 	}
129 	trace_seq_printf(s, "%lld", val);
130 
131 	if (pevent_get_field_val(s, event, "next_prio", record, &val, 0) == 0)
132 		trace_seq_printf(s, " [%lld]", val);
133 
134 	return 0;
135 }
136 
PEVENT_PLUGIN_LOADER(struct pevent * pevent)137 int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
138 {
139 	pevent_register_event_handler(pevent, -1, "sched", "sched_switch",
140 				      sched_switch_handler, NULL);
141 
142 	pevent_register_event_handler(pevent, -1, "sched", "sched_wakeup",
143 				      sched_wakeup_handler, NULL);
144 
145 	pevent_register_event_handler(pevent, -1, "sched", "sched_wakeup_new",
146 				      sched_wakeup_handler, NULL);
147 	return 0;
148 }
149 
PEVENT_PLUGIN_UNLOADER(struct pevent * pevent)150 void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
151 {
152 	pevent_unregister_event_handler(pevent, -1, "sched", "sched_switch",
153 					sched_switch_handler, NULL);
154 
155 	pevent_unregister_event_handler(pevent, -1, "sched", "sched_wakeup",
156 					sched_wakeup_handler, NULL);
157 
158 	pevent_unregister_event_handler(pevent, -1, "sched", "sched_wakeup_new",
159 					sched_wakeup_handler, NULL);
160 }
161