linux/tools/perf/util/trace-event-read.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#define _LARGEFILE64_SOURCE
  22
  23#include <dirent.h>
  24#include <stdio.h>
  25#include <stdlib.h>
  26#include <string.h>
  27#include <getopt.h>
  28#include <stdarg.h>
  29#include <sys/types.h>
  30#include <sys/stat.h>
  31#include <sys/wait.h>
  32#include <sys/mman.h>
  33#include <pthread.h>
  34#include <fcntl.h>
  35#include <unistd.h>
  36#include <ctype.h>
  37#include <errno.h>
  38
  39#include "../perf.h"
  40#include "util.h"
  41#include "trace-event.h"
  42
  43static int input_fd;
  44
  45static int read_page;
  46
  47int file_bigendian;
  48int host_bigendian;
  49static int long_size;
  50
  51static unsigned long    page_size;
  52
  53static int read_or_die(void *data, int size)
  54{
  55        int r;
  56
  57        r = read(input_fd, data, size);
  58        if (r != size)
  59                die("reading input file (size expected=%d received=%d)",
  60                    size, r);
  61        return r;
  62}
  63
  64static unsigned int read4(void)
  65{
  66        unsigned int data;
  67
  68        read_or_die(&data, 4);
  69        return __data2host4(data);
  70}
  71
  72static unsigned long long read8(void)
  73{
  74        unsigned long long data;
  75
  76        read_or_die(&data, 8);
  77        return __data2host8(data);
  78}
  79
  80static char *read_string(void)
  81{
  82        char buf[BUFSIZ];
  83        char *str = NULL;
  84        int size = 0;
  85        int i;
  86        int r;
  87
  88        for (;;) {
  89                r = read(input_fd, buf, BUFSIZ);
  90                if (r < 0)
  91                        die("reading input file");
  92
  93                if (!r)
  94                        die("no data");
  95
  96                for (i = 0; i < r; i++) {
  97                        if (!buf[i])
  98                                break;
  99                }
 100                if (i < r)
 101                        break;
 102
 103                if (str) {
 104                        size += BUFSIZ;
 105                        str = realloc(str, size);
 106                        if (!str)
 107                                die("malloc of size %d", size);
 108                        memcpy(str + (size - BUFSIZ), buf, BUFSIZ);
 109                } else {
 110                        size = BUFSIZ;
 111                        str = malloc_or_die(size);
 112                        memcpy(str, buf, size);
 113                }
 114        }
 115
 116        /* trailing \0: */
 117        i++;
 118
 119        /* move the file descriptor to the end of the string */
 120        r = lseek(input_fd, -(r - i), SEEK_CUR);
 121        if (r < 0)
 122                die("lseek");
 123
 124        if (str) {
 125                size += i;
 126                str = realloc(str, size);
 127                if (!str)
 128                        die("malloc of size %d", size);
 129                memcpy(str + (size - i), buf, i);
 130        } else {
 131                size = i;
 132                str = malloc_or_die(i);
 133                memcpy(str, buf, i);
 134        }
 135
 136        return str;
 137}
 138
 139static void read_proc_kallsyms(void)
 140{
 141        unsigned int size;
 142        char *buf;
 143
 144        size = read4();
 145        if (!size)
 146                return;
 147
 148        buf = malloc_or_die(size);
 149        read_or_die(buf, size);
 150
 151        parse_proc_kallsyms(buf, size);
 152
 153        free(buf);
 154}
 155
 156static void read_ftrace_printk(void)
 157{
 158        unsigned int size;
 159        char *buf;
 160
 161        size = read4();
 162        if (!size)
 163                return;
 164
 165        buf = malloc_or_die(size);
 166        read_or_die(buf, size);
 167
 168        parse_ftrace_printk(buf, size);
 169
 170        free(buf);
 171}
 172
 173static void read_header_files(void)
 174{
 175        unsigned long long size;
 176        char *header_page;
 177        char *header_event;
 178        char buf[BUFSIZ];
 179
 180        read_or_die(buf, 12);
 181
 182        if (memcmp(buf, "header_page", 12) != 0)
 183                die("did not read header page");
 184
 185        size = read8();
 186        header_page = malloc_or_die(size);
 187        read_or_die(header_page, size);
 188        parse_header_page(header_page, size);
 189        free(header_page);
 190
 191        /*
 192         * The size field in the page is of type long,
 193         * use that instead, since it represents the kernel.
 194         */
 195        long_size = header_page_size_size;
 196
 197        read_or_die(buf, 13);
 198        if (memcmp(buf, "header_event", 13) != 0)
 199                die("did not read header event");
 200
 201        size = read8();
 202        header_event = malloc_or_die(size);
 203        read_or_die(header_event, size);
 204        free(header_event);
 205}
 206
 207static void read_ftrace_file(unsigned long long size)
 208{
 209        char *buf;
 210
 211        buf = malloc_or_die(size);
 212        read_or_die(buf, size);
 213        parse_ftrace_file(buf, size);
 214        free(buf);
 215}
 216
 217static void read_event_file(char *sys, unsigned long long size)
 218{
 219        char *buf;
 220
 221        buf = malloc_or_die(size);
 222        read_or_die(buf, size);
 223        parse_event_file(buf, size, sys);
 224        free(buf);
 225}
 226
 227static void read_ftrace_files(void)
 228{
 229        unsigned long long size;
 230        int count;
 231        int i;
 232
 233        count = read4();
 234
 235        for (i = 0; i < count; i++) {
 236                size = read8();
 237                read_ftrace_file(size);
 238        }
 239}
 240
 241static void read_event_files(void)
 242{
 243        unsigned long long size;
 244        char *sys;
 245        int systems;
 246        int count;
 247        int i,x;
 248
 249        systems = read4();
 250
 251        for (i = 0; i < systems; i++) {
 252                sys = read_string();
 253
 254                count = read4();
 255                for (x=0; x < count; x++) {
 256                        size = read8();
 257                        read_event_file(sys, size);
 258                }
 259        }
 260}
 261
 262struct cpu_data {
 263        unsigned long long      offset;
 264        unsigned long long      size;
 265        unsigned long long      timestamp;
 266        struct record           *next;
 267        char                    *page;
 268        int                     cpu;
 269        int                     index;
 270        int                     page_size;
 271};
 272
 273static struct cpu_data *cpu_data;
 274
 275static void update_cpu_data_index(int cpu)
 276{
 277        cpu_data[cpu].offset += page_size;
 278        cpu_data[cpu].size -= page_size;
 279        cpu_data[cpu].index = 0;
 280}
 281
 282static void get_next_page(int cpu)
 283{
 284        off64_t save_seek;
 285        off64_t ret;
 286
 287        if (!cpu_data[cpu].page)
 288                return;
 289
 290        if (read_page) {
 291                if (cpu_data[cpu].size <= page_size) {
 292                        free(cpu_data[cpu].page);
 293                        cpu_data[cpu].page = NULL;
 294                        return;
 295                }
 296
 297                update_cpu_data_index(cpu);
 298
 299                /* other parts of the code may expect the pointer to not move */
 300                save_seek = lseek64(input_fd, 0, SEEK_CUR);
 301
 302                ret = lseek64(input_fd, cpu_data[cpu].offset, SEEK_SET);
 303                if (ret < 0)
 304                        die("failed to lseek");
 305                ret = read(input_fd, cpu_data[cpu].page, page_size);
 306                if (ret < 0)
 307                        die("failed to read page");
 308
 309                /* reset the file pointer back */
 310                lseek64(input_fd, save_seek, SEEK_SET);
 311
 312                return;
 313        }
 314
 315        munmap(cpu_data[cpu].page, page_size);
 316        cpu_data[cpu].page = NULL;
 317
 318        if (cpu_data[cpu].size <= page_size)
 319                return;
 320
 321        update_cpu_data_index(cpu);
 322
 323        cpu_data[cpu].page = mmap(NULL, page_size, PROT_READ, MAP_PRIVATE,
 324                                  input_fd, cpu_data[cpu].offset);
 325        if (cpu_data[cpu].page == MAP_FAILED)
 326                die("failed to mmap cpu %d at offset 0x%llx",
 327                    cpu, cpu_data[cpu].offset);
 328}
 329
 330static unsigned int type_len4host(unsigned int type_len_ts)
 331{
 332        if (file_bigendian)
 333                return (type_len_ts >> 27) & ((1 << 5) - 1);
 334        else
 335                return type_len_ts & ((1 << 5) - 1);
 336}
 337
 338static unsigned int ts4host(unsigned int type_len_ts)
 339{
 340        if (file_bigendian)
 341                return type_len_ts & ((1 << 27) - 1);
 342        else
 343                return type_len_ts >> 5;
 344}
 345
 346static int calc_index(void *ptr, int cpu)
 347{
 348        return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page;
 349}
 350
 351struct record *trace_peek_data(int cpu)
 352{
 353        struct record *data;
 354        void *page = cpu_data[cpu].page;
 355        int idx = cpu_data[cpu].index;
 356        void *ptr = page + idx;
 357        unsigned long long extend;
 358        unsigned int type_len_ts;
 359        unsigned int type_len;
 360        unsigned int delta;
 361        unsigned int length = 0;
 362
 363        if (cpu_data[cpu].next)
 364                return cpu_data[cpu].next;
 365
 366        if (!page)
 367                return NULL;
 368
 369        if (!idx) {
 370                /* FIXME: handle header page */
 371                if (header_page_ts_size != 8)
 372                        die("expected a long long type for timestamp");
 373                cpu_data[cpu].timestamp = data2host8(ptr);
 374                ptr += 8;
 375                switch (header_page_size_size) {
 376                case 4:
 377                        cpu_data[cpu].page_size = data2host4(ptr);
 378                        ptr += 4;
 379                        break;
 380                case 8:
 381                        cpu_data[cpu].page_size = data2host8(ptr);
 382                        ptr += 8;
 383                        break;
 384                default:
 385                        die("bad long size");
 386                }
 387                ptr = cpu_data[cpu].page + header_page_data_offset;
 388        }
 389
 390read_again:
 391        idx = calc_index(ptr, cpu);
 392
 393        if (idx >= cpu_data[cpu].page_size) {
 394                get_next_page(cpu);
 395                return trace_peek_data(cpu);
 396        }
 397
 398        type_len_ts = data2host4(ptr);
 399        ptr += 4;
 400
 401        type_len = type_len4host(type_len_ts);
 402        delta = ts4host(type_len_ts);
 403
 404        switch (type_len) {
 405        case RINGBUF_TYPE_PADDING:
 406                if (!delta)
 407                        die("error, hit unexpected end of page");
 408                length = data2host4(ptr);
 409                ptr += 4;
 410                length *= 4;
 411                ptr += length;
 412                goto read_again;
 413
 414        case RINGBUF_TYPE_TIME_EXTEND:
 415                extend = data2host4(ptr);
 416                ptr += 4;
 417                extend <<= TS_SHIFT;
 418                extend += delta;
 419                cpu_data[cpu].timestamp += extend;
 420                goto read_again;
 421
 422        case RINGBUF_TYPE_TIME_STAMP:
 423                ptr += 12;
 424                break;
 425        case 0:
 426                length = data2host4(ptr);
 427                ptr += 4;
 428                die("here! length=%d", length);
 429                break;
 430        default:
 431                length = type_len * 4;
 432                break;
 433        }
 434
 435        cpu_data[cpu].timestamp += delta;
 436
 437        data = malloc_or_die(sizeof(*data));
 438        memset(data, 0, sizeof(*data));
 439
 440        data->ts = cpu_data[cpu].timestamp;
 441        data->size = length;
 442        data->data = ptr;
 443        ptr += length;
 444
 445        cpu_data[cpu].index = calc_index(ptr, cpu);
 446        cpu_data[cpu].next = data;
 447
 448        return data;
 449}
 450
 451struct record *trace_read_data(int cpu)
 452{
 453        struct record *data;
 454
 455        data = trace_peek_data(cpu);
 456        cpu_data[cpu].next = NULL;
 457
 458        return data;
 459}
 460
 461void trace_report(void)
 462{
 463        const char *input_file = "trace.info";
 464        char buf[BUFSIZ];
 465        char test[] = { 23, 8, 68 };
 466        char *version;
 467        int show_version = 0;
 468        int show_funcs = 0;
 469        int show_printk = 0;
 470
 471        input_fd = open(input_file, O_RDONLY);
 472        if (input_fd < 0)
 473                die("opening '%s'\n", input_file);
 474
 475        read_or_die(buf, 3);
 476        if (memcmp(buf, test, 3) != 0)
 477                die("not an trace data file");
 478
 479        read_or_die(buf, 7);
 480        if (memcmp(buf, "tracing", 7) != 0)
 481                die("not a trace file (missing tracing)");
 482
 483        version = read_string();
 484        if (show_version)
 485                printf("version = %s\n", version);
 486        free(version);
 487
 488        read_or_die(buf, 1);
 489        file_bigendian = buf[0];
 490        host_bigendian = bigendian();
 491
 492        read_or_die(buf, 1);
 493        long_size = buf[0];
 494
 495        page_size = read4();
 496
 497        read_header_files();
 498
 499        read_ftrace_files();
 500        read_event_files();
 501        read_proc_kallsyms();
 502        read_ftrace_printk();
 503
 504        if (show_funcs) {
 505                print_funcs();
 506                return;
 507        }
 508        if (show_printk) {
 509                print_printk();
 510                return;
 511        }
 512
 513        return;
 514}
 515