linux/tools/perf/util/trace-event-parse.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com>
   3 *
   4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; version 2 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 General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write to the Free Software
  17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18 *
  19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  20 */
  21#include <stdio.h>
  22#include <stdlib.h>
  23#include <string.h>
  24#include <ctype.h>
  25#include <errno.h>
  26
  27#include "../perf.h"
  28#include "util.h"
  29#include "trace-event.h"
  30
  31int header_page_size_size;
  32int header_page_ts_size;
  33int header_page_data_offset;
  34
  35struct pevent *perf_pevent;
  36static struct pevent *pevent;
  37
  38bool latency_format;
  39
  40int read_trace_init(int file_bigendian, int host_bigendian)
  41{
  42        if (pevent)
  43                return 0;
  44
  45        perf_pevent = pevent_alloc();
  46        pevent = perf_pevent;
  47
  48        pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT);
  49        pevent_set_file_bigendian(pevent, file_bigendian);
  50        pevent_set_host_bigendian(pevent, host_bigendian);
  51
  52        return 0;
  53}
  54
  55static int get_common_field(struct scripting_context *context,
  56                            int *offset, int *size, const char *type)
  57{
  58        struct event_format *event;
  59        struct format_field *field;
  60
  61        if (!*size) {
  62                if (!pevent->events)
  63                        return 0;
  64
  65                event = pevent->events[0];
  66                field = pevent_find_common_field(event, type);
  67                if (!field)
  68                        return 0;
  69                *offset = field->offset;
  70                *size = field->size;
  71        }
  72
  73        return pevent_read_number(pevent, context->event_data + *offset, *size);
  74}
  75
  76int common_lock_depth(struct scripting_context *context)
  77{
  78        static int offset;
  79        static int size;
  80        int ret;
  81
  82        ret = get_common_field(context, &size, &offset,
  83                               "common_lock_depth");
  84        if (ret < 0)
  85                return -1;
  86
  87        return ret;
  88}
  89
  90int common_flags(struct scripting_context *context)
  91{
  92        static int offset;
  93        static int size;
  94        int ret;
  95
  96        ret = get_common_field(context, &size, &offset,
  97                               "common_flags");
  98        if (ret < 0)
  99                return -1;
 100
 101        return ret;
 102}
 103
 104int common_pc(struct scripting_context *context)
 105{
 106        static int offset;
 107        static int size;
 108        int ret;
 109
 110        ret = get_common_field(context, &size, &offset,
 111                               "common_preempt_count");
 112        if (ret < 0)
 113                return -1;
 114
 115        return ret;
 116}
 117
 118unsigned long long
 119raw_field_value(struct event_format *event, const char *name, void *data)
 120{
 121        struct format_field *field;
 122        unsigned long long val;
 123
 124        field = pevent_find_any_field(event, name);
 125        if (!field)
 126                return 0ULL;
 127
 128        pevent_read_number_field(field, data, &val);
 129
 130        return val;
 131}
 132
 133void *raw_field_ptr(struct event_format *event, const char *name, void *data)
 134{
 135        struct format_field *field;
 136
 137        field = pevent_find_any_field(event, name);
 138        if (!field)
 139                return NULL;
 140
 141        if (field->flags & FIELD_IS_DYNAMIC) {
 142                int offset;
 143
 144                offset = *(int *)(data + field->offset);
 145                offset &= 0xffff;
 146
 147                return data + offset;
 148        }
 149
 150        return data + field->offset;
 151}
 152
 153int trace_parse_common_type(void *data)
 154{
 155        struct pevent_record record;
 156
 157        record.data = data;
 158        return pevent_data_type(pevent, &record);
 159}
 160
 161int trace_parse_common_pid(void *data)
 162{
 163        struct pevent_record record;
 164
 165        record.data = data;
 166        return pevent_data_pid(pevent, &record);
 167}
 168
 169unsigned long long read_size(void *ptr, int size)
 170{
 171        return pevent_read_number(pevent, ptr, size);
 172}
 173
 174struct event_format *trace_find_event(int type)
 175{
 176        return pevent_find_event(pevent, type);
 177}
 178
 179
 180void print_trace_event(int cpu, void *data, int size)
 181{
 182        struct event_format *event;
 183        struct pevent_record record;
 184        struct trace_seq s;
 185        int type;
 186
 187        type = trace_parse_common_type(data);
 188
 189        event = trace_find_event(type);
 190        if (!event) {
 191                warning("ug! no event found for type %d", type);
 192                return;
 193        }
 194
 195        memset(&record, 0, sizeof(record));
 196        record.cpu = cpu;
 197        record.size = size;
 198        record.data = data;
 199
 200        trace_seq_init(&s);
 201        pevent_event_info(&s, event, &record);
 202        trace_seq_do_printf(&s);
 203}
 204
 205void print_event(int cpu, void *data, int size, unsigned long long nsecs,
 206                  char *comm)
 207{
 208        struct pevent_record record;
 209        struct trace_seq s;
 210        int pid;
 211
 212        pevent->latency_format = latency_format;
 213
 214        record.ts = nsecs;
 215        record.cpu = cpu;
 216        record.size = size;
 217        record.data = data;
 218        pid = pevent_data_pid(pevent, &record);
 219
 220        if (!pevent_pid_is_registered(pevent, pid))
 221                pevent_register_comm(pevent, comm, pid);
 222
 223        trace_seq_init(&s);
 224        pevent_print_event(pevent, &s, &record);
 225        trace_seq_do_printf(&s);
 226        printf("\n");
 227}
 228
 229void parse_proc_kallsyms(char *file, unsigned int size __unused)
 230{
 231        unsigned long long addr;
 232        char *func;
 233        char *line;
 234        char *next = NULL;
 235        char *addr_str;
 236        char *mod;
 237        char ch;
 238
 239        line = strtok_r(file, "\n", &next);
 240        while (line) {
 241                mod = NULL;
 242                sscanf(line, "%as %c %as\t[%as",
 243                       (float *)(void *)&addr_str, /* workaround gcc warning */
 244                       &ch, (float *)(void *)&func, (float *)(void *)&mod);
 245                addr = strtoull(addr_str, NULL, 16);
 246                free(addr_str);
 247
 248                /* truncate the extra ']' */
 249                if (mod)
 250                        mod[strlen(mod) - 1] = 0;
 251
 252                pevent_register_function(pevent, func, addr, mod);
 253                free(func);
 254                free(mod);
 255
 256                line = strtok_r(NULL, "\n", &next);
 257        }
 258}
 259
 260void parse_ftrace_printk(char *file, unsigned int size __unused)
 261{
 262        unsigned long long addr;
 263        char *printk;
 264        char *line;
 265        char *next = NULL;
 266        char *addr_str;
 267        char *fmt;
 268
 269        line = strtok_r(file, "\n", &next);
 270        while (line) {
 271                addr_str = strtok_r(line, ":", &fmt);
 272                if (!addr_str) {
 273                        warning("printk format with empty entry");
 274                        break;
 275                }
 276                addr = strtoull(addr_str, NULL, 16);
 277                /* fmt still has a space, skip it */
 278                printk = strdup(fmt+1);
 279                line = strtok_r(NULL, "\n", &next);
 280                pevent_register_print_string(pevent, printk, addr);
 281        }
 282}
 283
 284int parse_ftrace_file(char *buf, unsigned long size)
 285{
 286        return pevent_parse_event(pevent, buf, size, "ftrace");
 287}
 288
 289int parse_event_file(char *buf, unsigned long size, char *sys)
 290{
 291        return pevent_parse_event(pevent, buf, size, sys);
 292}
 293
 294struct event_format *trace_find_next_event(struct event_format *event)
 295{
 296        static int idx;
 297
 298        if (!pevent->events)
 299                return NULL;
 300
 301        if (!event) {
 302                idx = 0;
 303                return pevent->events[0];
 304        }
 305
 306        if (idx < pevent->nr_events && event == pevent->events[idx]) {
 307                idx++;
 308                if (idx == pevent->nr_events)
 309                        return NULL;
 310                return pevent->events[idx];
 311        }
 312
 313        for (idx = 1; idx < pevent->nr_events; idx++) {
 314                if (event == pevent->events[idx - 1])
 315                        return pevent->events[idx];
 316        }
 317        return NULL;
 318}
 319
 320struct flag {
 321        const char *name;
 322        unsigned long long value;
 323};
 324
 325static const struct flag flags[] = {
 326        { "HI_SOFTIRQ", 0 },
 327        { "TIMER_SOFTIRQ", 1 },
 328        { "NET_TX_SOFTIRQ", 2 },
 329        { "NET_RX_SOFTIRQ", 3 },
 330        { "BLOCK_SOFTIRQ", 4 },
 331        { "BLOCK_IOPOLL_SOFTIRQ", 5 },
 332        { "TASKLET_SOFTIRQ", 6 },
 333        { "SCHED_SOFTIRQ", 7 },
 334        { "HRTIMER_SOFTIRQ", 8 },
 335        { "RCU_SOFTIRQ", 9 },
 336
 337        { "HRTIMER_NORESTART", 0 },
 338        { "HRTIMER_RESTART", 1 },
 339};
 340
 341unsigned long long eval_flag(const char *flag)
 342{
 343        int i;
 344
 345        /*
 346         * Some flags in the format files do not get converted.
 347         * If the flag is not numeric, see if it is something that
 348         * we already know about.
 349         */
 350        if (isdigit(flag[0]))
 351                return strtoull(flag, NULL, 0);
 352
 353        for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); i++)
 354                if (strcmp(flags[i].name, flag) == 0)
 355                        return flags[i].value;
 356
 357        return 0;
 358}
 359