linux/tools/perf/util/header.c
<<
>>
Prefs
   1#include <sys/types.h>
   2#include <unistd.h>
   3#include <stdio.h>
   4#include <stdlib.h>
   5
   6#include "util.h"
   7#include "header.h"
   8
   9/*
  10 * Create new perf.data header attribute:
  11 */
  12struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr)
  13{
  14        struct perf_header_attr *self = malloc(sizeof(*self));
  15
  16        if (!self)
  17                die("nomem");
  18
  19        self->attr = *attr;
  20        self->ids = 0;
  21        self->size = 1;
  22        self->id = malloc(sizeof(u64));
  23
  24        if (!self->id)
  25                die("nomem");
  26
  27        return self;
  28}
  29
  30void perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
  31{
  32        int pos = self->ids;
  33
  34        self->ids++;
  35        if (self->ids > self->size) {
  36                self->size *= 2;
  37                self->id = realloc(self->id, self->size * sizeof(u64));
  38                if (!self->id)
  39                        die("nomem");
  40        }
  41        self->id[pos] = id;
  42}
  43
  44/*
  45 * Create new perf.data header:
  46 */
  47struct perf_header *perf_header__new(void)
  48{
  49        struct perf_header *self = malloc(sizeof(*self));
  50
  51        if (!self)
  52                die("nomem");
  53
  54        self->frozen = 0;
  55
  56        self->attrs = 0;
  57        self->size = 1;
  58        self->attr = malloc(sizeof(void *));
  59
  60        if (!self->attr)
  61                die("nomem");
  62
  63        self->data_offset = 0;
  64        self->data_size = 0;
  65
  66        return self;
  67}
  68
  69void perf_header__add_attr(struct perf_header *self,
  70                           struct perf_header_attr *attr)
  71{
  72        int pos = self->attrs;
  73
  74        if (self->frozen)
  75                die("frozen");
  76
  77        self->attrs++;
  78        if (self->attrs > self->size) {
  79                self->size *= 2;
  80                self->attr = realloc(self->attr, self->size * sizeof(void *));
  81                if (!self->attr)
  82                        die("nomem");
  83        }
  84        self->attr[pos] = attr;
  85}
  86
  87#define MAX_EVENT_NAME 64
  88
  89struct perf_trace_event_type {
  90        u64     event_id;
  91        char    name[MAX_EVENT_NAME];
  92};
  93
  94static int event_count;
  95static struct perf_trace_event_type *events;
  96
  97void perf_header__push_event(u64 id, const char *name)
  98{
  99        if (strlen(name) > MAX_EVENT_NAME)
 100                printf("Event %s will be truncated\n", name);
 101
 102        if (!events) {
 103                events = malloc(sizeof(struct perf_trace_event_type));
 104                if (!events)
 105                        die("nomem");
 106        } else {
 107                events = realloc(events, (event_count + 1) * sizeof(struct perf_trace_event_type));
 108                if (!events)
 109                        die("nomem");
 110        }
 111        memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));
 112        events[event_count].event_id = id;
 113        strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);
 114        event_count++;
 115}
 116
 117char *perf_header__find_event(u64 id)
 118{
 119        int i;
 120        for (i = 0 ; i < event_count; i++) {
 121                if (events[i].event_id == id)
 122                        return events[i].name;
 123        }
 124        return NULL;
 125}
 126
 127static const char *__perf_magic = "PERFFILE";
 128
 129#define PERF_MAGIC      (*(u64 *)__perf_magic)
 130
 131struct perf_file_section {
 132        u64 offset;
 133        u64 size;
 134};
 135
 136struct perf_file_attr {
 137        struct perf_event_attr  attr;
 138        struct perf_file_section        ids;
 139};
 140
 141struct perf_file_header {
 142        u64                             magic;
 143        u64                             size;
 144        u64                             attr_size;
 145        struct perf_file_section        attrs;
 146        struct perf_file_section        data;
 147        struct perf_file_section        event_types;
 148};
 149
 150static void do_write(int fd, void *buf, size_t size)
 151{
 152        while (size) {
 153                int ret = write(fd, buf, size);
 154
 155                if (ret < 0)
 156                        die("failed to write");
 157
 158                size -= ret;
 159                buf += ret;
 160        }
 161}
 162
 163void perf_header__write(struct perf_header *self, int fd)
 164{
 165        struct perf_file_header f_header;
 166        struct perf_file_attr   f_attr;
 167        struct perf_header_attr *attr;
 168        int i;
 169
 170        lseek(fd, sizeof(f_header), SEEK_SET);
 171
 172
 173        for (i = 0; i < self->attrs; i++) {
 174                attr = self->attr[i];
 175
 176                attr->id_offset = lseek(fd, 0, SEEK_CUR);
 177                do_write(fd, attr->id, attr->ids * sizeof(u64));
 178        }
 179
 180
 181        self->attr_offset = lseek(fd, 0, SEEK_CUR);
 182
 183        for (i = 0; i < self->attrs; i++) {
 184                attr = self->attr[i];
 185
 186                f_attr = (struct perf_file_attr){
 187                        .attr = attr->attr,
 188                        .ids  = {
 189                                .offset = attr->id_offset,
 190                                .size   = attr->ids * sizeof(u64),
 191                        }
 192                };
 193                do_write(fd, &f_attr, sizeof(f_attr));
 194        }
 195
 196        self->event_offset = lseek(fd, 0, SEEK_CUR);
 197        self->event_size = event_count * sizeof(struct perf_trace_event_type);
 198        if (events)
 199                do_write(fd, events, self->event_size);
 200
 201
 202        self->data_offset = lseek(fd, 0, SEEK_CUR);
 203
 204        f_header = (struct perf_file_header){
 205                .magic     = PERF_MAGIC,
 206                .size      = sizeof(f_header),
 207                .attr_size = sizeof(f_attr),
 208                .attrs = {
 209                        .offset = self->attr_offset,
 210                        .size   = self->attrs * sizeof(f_attr),
 211                },
 212                .data = {
 213                        .offset = self->data_offset,
 214                        .size   = self->data_size,
 215                },
 216                .event_types = {
 217                        .offset = self->event_offset,
 218                        .size   = self->event_size,
 219                },
 220        };
 221
 222        lseek(fd, 0, SEEK_SET);
 223        do_write(fd, &f_header, sizeof(f_header));
 224        lseek(fd, self->data_offset + self->data_size, SEEK_SET);
 225
 226        self->frozen = 1;
 227}
 228
 229static void do_read(int fd, void *buf, size_t size)
 230{
 231        while (size) {
 232                int ret = read(fd, buf, size);
 233
 234                if (ret < 0)
 235                        die("failed to read");
 236                if (ret == 0)
 237                        die("failed to read: missing data");
 238
 239                size -= ret;
 240                buf += ret;
 241        }
 242}
 243
 244struct perf_header *perf_header__read(int fd)
 245{
 246        struct perf_header      *self = perf_header__new();
 247        struct perf_file_header f_header;
 248        struct perf_file_attr   f_attr;
 249        u64                     f_id;
 250
 251        int nr_attrs, nr_ids, i, j;
 252
 253        lseek(fd, 0, SEEK_SET);
 254        do_read(fd, &f_header, sizeof(f_header));
 255
 256        if (f_header.magic      != PERF_MAGIC           ||
 257            f_header.size       != sizeof(f_header)     ||
 258            f_header.attr_size  != sizeof(f_attr))
 259                die("incompatible file format");
 260
 261        nr_attrs = f_header.attrs.size / sizeof(f_attr);
 262        lseek(fd, f_header.attrs.offset, SEEK_SET);
 263
 264        for (i = 0; i < nr_attrs; i++) {
 265                struct perf_header_attr *attr;
 266                off_t tmp;
 267
 268                do_read(fd, &f_attr, sizeof(f_attr));
 269                tmp = lseek(fd, 0, SEEK_CUR);
 270
 271                attr = perf_header_attr__new(&f_attr.attr);
 272
 273                nr_ids = f_attr.ids.size / sizeof(u64);
 274                lseek(fd, f_attr.ids.offset, SEEK_SET);
 275
 276                for (j = 0; j < nr_ids; j++) {
 277                        do_read(fd, &f_id, sizeof(f_id));
 278
 279                        perf_header_attr__add_id(attr, f_id);
 280                }
 281                perf_header__add_attr(self, attr);
 282                lseek(fd, tmp, SEEK_SET);
 283        }
 284
 285        if (f_header.event_types.size) {
 286                lseek(fd, f_header.event_types.offset, SEEK_SET);
 287                events = malloc(f_header.event_types.size);
 288                if (!events)
 289                        die("nomem");
 290                do_read(fd, events, f_header.event_types.size);
 291                event_count =  f_header.event_types.size / sizeof(struct perf_trace_event_type);
 292        }
 293        self->event_offset = f_header.event_types.offset;
 294        self->event_size   = f_header.event_types.size;
 295
 296        self->data_offset = f_header.data.offset;
 297        self->data_size   = f_header.data.size;
 298
 299        lseek(fd, self->data_offset, SEEK_SET);
 300
 301        self->frozen = 1;
 302
 303        return self;
 304}
 305
 306u64 perf_header__sample_type(struct perf_header *header)
 307{
 308        u64 type = 0;
 309        int i;
 310
 311        for (i = 0; i < header->attrs; i++) {
 312                struct perf_header_attr *attr = header->attr[i];
 313
 314                if (!type)
 315                        type = attr->attr.sample_type;
 316                else if (type != attr->attr.sample_type)
 317                        die("non matching sample_type");
 318        }
 319
 320        return type;
 321}
 322
 323struct perf_event_attr *
 324perf_header__find_attr(u64 id, struct perf_header *header)
 325{
 326        int i;
 327
 328        for (i = 0; i < header->attrs; i++) {
 329                struct perf_header_attr *attr = header->attr[i];
 330                int j;
 331
 332                for (j = 0; j < attr->ids; j++) {
 333                        if (attr->id[j] == id)
 334                                return &attr->attr;
 335                }
 336        }
 337
 338        return NULL;
 339}
 340