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 26static 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 47static 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 67static 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 96static 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 137int 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 150void 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