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