linux/tools/perf/util/session.c
<<
>>
Prefs
   1#define _FILE_OFFSET_BITS 64
   2
   3#include <linux/kernel.h>
   4
   5#include <byteswap.h>
   6#include <unistd.h>
   7#include <sys/types.h>
   8#include <sys/mman.h>
   9
  10#include "session.h"
  11#include "sort.h"
  12#include "util.h"
  13
  14static int perf_session__open(struct perf_session *self, bool force)
  15{
  16        struct stat input_stat;
  17
  18        if (!strcmp(self->filename, "-")) {
  19                self->fd_pipe = true;
  20                self->fd = STDIN_FILENO;
  21
  22                if (perf_header__read(self, self->fd) < 0)
  23                        pr_err("incompatible file format");
  24
  25                return 0;
  26        }
  27
  28        self->fd = open(self->filename, O_RDONLY);
  29        if (self->fd < 0) {
  30                pr_err("failed to open file: %s", self->filename);
  31                if (!strcmp(self->filename, "perf.data"))
  32                        pr_err("  (try 'perf record' first)");
  33                pr_err("\n");
  34                return -errno;
  35        }
  36
  37        if (fstat(self->fd, &input_stat) < 0)
  38                goto out_close;
  39
  40        if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
  41                pr_err("file %s not owned by current user or root\n",
  42                       self->filename);
  43                goto out_close;
  44        }
  45
  46        if (!input_stat.st_size) {
  47                pr_info("zero-sized file (%s), nothing to do!\n",
  48                        self->filename);
  49                goto out_close;
  50        }
  51
  52        if (perf_header__read(self, self->fd) < 0) {
  53                pr_err("incompatible file format");
  54                goto out_close;
  55        }
  56
  57        self->size = input_stat.st_size;
  58        return 0;
  59
  60out_close:
  61        close(self->fd);
  62        self->fd = -1;
  63        return -1;
  64}
  65
  66void perf_session__update_sample_type(struct perf_session *self)
  67{
  68        self->sample_type = perf_header__sample_type(&self->header);
  69}
  70
  71int perf_session__create_kernel_maps(struct perf_session *self)
  72{
  73        int ret = machine__create_kernel_maps(&self->host_machine);
  74
  75        if (ret >= 0)
  76                ret = machines__create_guest_kernel_maps(&self->machines);
  77        return ret;
  78}
  79
  80struct perf_session *perf_session__new(const char *filename, int mode, bool force, bool repipe)
  81{
  82        size_t len = filename ? strlen(filename) + 1 : 0;
  83        struct perf_session *self = zalloc(sizeof(*self) + len);
  84
  85        if (self == NULL)
  86                goto out;
  87
  88        if (perf_header__init(&self->header) < 0)
  89                goto out_free;
  90
  91        memcpy(self->filename, filename, len);
  92        self->threads = RB_ROOT;
  93        INIT_LIST_HEAD(&self->dead_threads);
  94        self->hists_tree = RB_ROOT;
  95        self->last_match = NULL;
  96        self->mmap_window = 32;
  97        self->cwd = NULL;
  98        self->cwdlen = 0;
  99        self->machines = RB_ROOT;
 100        self->repipe = repipe;
 101        INIT_LIST_HEAD(&self->ordered_samples.samples_head);
 102        machine__init(&self->host_machine, "", HOST_KERNEL_ID);
 103
 104        if (mode == O_RDONLY) {
 105                if (perf_session__open(self, force) < 0)
 106                        goto out_delete;
 107        } else if (mode == O_WRONLY) {
 108                /*
 109                 * In O_RDONLY mode this will be performed when reading the
 110                 * kernel MMAP event, in event__process_mmap().
 111                 */
 112                if (perf_session__create_kernel_maps(self) < 0)
 113                        goto out_delete;
 114        }
 115
 116        perf_session__update_sample_type(self);
 117out:
 118        return self;
 119out_free:
 120        free(self);
 121        return NULL;
 122out_delete:
 123        perf_session__delete(self);
 124        return NULL;
 125}
 126
 127void perf_session__delete(struct perf_session *self)
 128{
 129        perf_header__exit(&self->header);
 130        close(self->fd);
 131        free(self->cwd);
 132        free(self);
 133}
 134
 135void perf_session__remove_thread(struct perf_session *self, struct thread *th)
 136{
 137        rb_erase(&th->rb_node, &self->threads);
 138        /*
 139         * We may have references to this thread, for instance in some hist_entry
 140         * instances, so just move them to a separate list.
 141         */
 142        list_add_tail(&th->node, &self->dead_threads);
 143}
 144
 145static bool symbol__match_parent_regex(struct symbol *sym)
 146{
 147        if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
 148                return 1;
 149
 150        return 0;
 151}
 152
 153struct map_symbol *perf_session__resolve_callchain(struct perf_session *self,
 154                                                   struct thread *thread,
 155                                                   struct ip_callchain *chain,
 156                                                   struct symbol **parent)
 157{
 158        u8 cpumode = PERF_RECORD_MISC_USER;
 159        unsigned int i;
 160        struct map_symbol *syms = calloc(chain->nr, sizeof(*syms));
 161
 162        if (!syms)
 163                return NULL;
 164
 165        for (i = 0; i < chain->nr; i++) {
 166                u64 ip = chain->ips[i];
 167                struct addr_location al;
 168
 169                if (ip >= PERF_CONTEXT_MAX) {
 170                        switch (ip) {
 171                        case PERF_CONTEXT_HV:
 172                                cpumode = PERF_RECORD_MISC_HYPERVISOR;  break;
 173                        case PERF_CONTEXT_KERNEL:
 174                                cpumode = PERF_RECORD_MISC_KERNEL;      break;
 175                        case PERF_CONTEXT_USER:
 176                                cpumode = PERF_RECORD_MISC_USER;        break;
 177                        default:
 178                                break;
 179                        }
 180                        continue;
 181                }
 182
 183                al.filtered = false;
 184                thread__find_addr_location(thread, self, cpumode,
 185                                MAP__FUNCTION, thread->pid, ip, &al, NULL);
 186                if (al.sym != NULL) {
 187                        if (sort__has_parent && !*parent &&
 188                            symbol__match_parent_regex(al.sym))
 189                                *parent = al.sym;
 190                        if (!symbol_conf.use_callchain)
 191                                break;
 192                        syms[i].map = al.map;
 193                        syms[i].sym = al.sym;
 194                }
 195        }
 196
 197        return syms;
 198}
 199
 200static int process_event_stub(event_t *event __used,
 201                              struct perf_session *session __used)
 202{
 203        dump_printf(": unhandled!\n");
 204        return 0;
 205}
 206
 207static int process_finished_round_stub(event_t *event __used,
 208                                       struct perf_session *session __used,
 209                                       struct perf_event_ops *ops __used)
 210{
 211        dump_printf(": unhandled!\n");
 212        return 0;
 213}
 214
 215static int process_finished_round(event_t *event,
 216                                  struct perf_session *session,
 217                                  struct perf_event_ops *ops);
 218
 219static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
 220{
 221        if (handler->sample == NULL)
 222                handler->sample = process_event_stub;
 223        if (handler->mmap == NULL)
 224                handler->mmap = process_event_stub;
 225        if (handler->comm == NULL)
 226                handler->comm = process_event_stub;
 227        if (handler->fork == NULL)
 228                handler->fork = process_event_stub;
 229        if (handler->exit == NULL)
 230                handler->exit = process_event_stub;
 231        if (handler->lost == NULL)
 232                handler->lost = process_event_stub;
 233        if (handler->read == NULL)
 234                handler->read = process_event_stub;
 235        if (handler->throttle == NULL)
 236                handler->throttle = process_event_stub;
 237        if (handler->unthrottle == NULL)
 238                handler->unthrottle = process_event_stub;
 239        if (handler->attr == NULL)
 240                handler->attr = process_event_stub;
 241        if (handler->event_type == NULL)
 242                handler->event_type = process_event_stub;
 243        if (handler->tracing_data == NULL)
 244                handler->tracing_data = process_event_stub;
 245        if (handler->build_id == NULL)
 246                handler->build_id = process_event_stub;
 247        if (handler->finished_round == NULL) {
 248                if (handler->ordered_samples)
 249                        handler->finished_round = process_finished_round;
 250                else
 251                        handler->finished_round = process_finished_round_stub;
 252        }
 253}
 254
 255void mem_bswap_64(void *src, int byte_size)
 256{
 257        u64 *m = src;
 258
 259        while (byte_size > 0) {
 260                *m = bswap_64(*m);
 261                byte_size -= sizeof(u64);
 262                ++m;
 263        }
 264}
 265
 266static void event__all64_swap(event_t *self)
 267{
 268        struct perf_event_header *hdr = &self->header;
 269        mem_bswap_64(hdr + 1, self->header.size - sizeof(*hdr));
 270}
 271
 272static void event__comm_swap(event_t *self)
 273{
 274        self->comm.pid = bswap_32(self->comm.pid);
 275        self->comm.tid = bswap_32(self->comm.tid);
 276}
 277
 278static void event__mmap_swap(event_t *self)
 279{
 280        self->mmap.pid   = bswap_32(self->mmap.pid);
 281        self->mmap.tid   = bswap_32(self->mmap.tid);
 282        self->mmap.start = bswap_64(self->mmap.start);
 283        self->mmap.len   = bswap_64(self->mmap.len);
 284        self->mmap.pgoff = bswap_64(self->mmap.pgoff);
 285}
 286
 287static void event__task_swap(event_t *self)
 288{
 289        self->fork.pid  = bswap_32(self->fork.pid);
 290        self->fork.tid  = bswap_32(self->fork.tid);
 291        self->fork.ppid = bswap_32(self->fork.ppid);
 292        self->fork.ptid = bswap_32(self->fork.ptid);
 293        self->fork.time = bswap_64(self->fork.time);
 294}
 295
 296static void event__read_swap(event_t *self)
 297{
 298        self->read.pid          = bswap_32(self->read.pid);
 299        self->read.tid          = bswap_32(self->read.tid);
 300        self->read.value        = bswap_64(self->read.value);
 301        self->read.time_enabled = bswap_64(self->read.time_enabled);
 302        self->read.time_running = bswap_64(self->read.time_running);
 303        self->read.id           = bswap_64(self->read.id);
 304}
 305
 306static void event__attr_swap(event_t *self)
 307{
 308        size_t size;
 309
 310        self->attr.attr.type            = bswap_32(self->attr.attr.type);
 311        self->attr.attr.size            = bswap_32(self->attr.attr.size);
 312        self->attr.attr.config          = bswap_64(self->attr.attr.config);
 313        self->attr.attr.sample_period   = bswap_64(self->attr.attr.sample_period);
 314        self->attr.attr.sample_type     = bswap_64(self->attr.attr.sample_type);
 315        self->attr.attr.read_format     = bswap_64(self->attr.attr.read_format);
 316        self->attr.attr.wakeup_events   = bswap_32(self->attr.attr.wakeup_events);
 317        self->attr.attr.bp_type         = bswap_32(self->attr.attr.bp_type);
 318        self->attr.attr.bp_addr         = bswap_64(self->attr.attr.bp_addr);
 319        self->attr.attr.bp_len          = bswap_64(self->attr.attr.bp_len);
 320
 321        size = self->header.size;
 322        size -= (void *)&self->attr.id - (void *)self;
 323        mem_bswap_64(self->attr.id, size);
 324}
 325
 326static void event__event_type_swap(event_t *self)
 327{
 328        self->event_type.event_type.event_id =
 329                bswap_64(self->event_type.event_type.event_id);
 330}
 331
 332static void event__tracing_data_swap(event_t *self)
 333{
 334        self->tracing_data.size = bswap_32(self->tracing_data.size);
 335}
 336
 337typedef void (*event__swap_op)(event_t *self);
 338
 339static event__swap_op event__swap_ops[] = {
 340        [PERF_RECORD_MMAP]   = event__mmap_swap,
 341        [PERF_RECORD_COMM]   = event__comm_swap,
 342        [PERF_RECORD_FORK]   = event__task_swap,
 343        [PERF_RECORD_EXIT]   = event__task_swap,
 344        [PERF_RECORD_LOST]   = event__all64_swap,
 345        [PERF_RECORD_READ]   = event__read_swap,
 346        [PERF_RECORD_SAMPLE] = event__all64_swap,
 347        [PERF_RECORD_HEADER_ATTR]   = event__attr_swap,
 348        [PERF_RECORD_HEADER_EVENT_TYPE]   = event__event_type_swap,
 349        [PERF_RECORD_HEADER_TRACING_DATA]   = event__tracing_data_swap,
 350        [PERF_RECORD_HEADER_BUILD_ID]   = NULL,
 351        [PERF_RECORD_HEADER_MAX]    = NULL,
 352};
 353
 354struct sample_queue {
 355        u64                     timestamp;
 356        struct sample_event     *event;
 357        struct list_head        list;
 358};
 359
 360static void flush_sample_queue(struct perf_session *s,
 361                               struct perf_event_ops *ops)
 362{
 363        struct list_head *head = &s->ordered_samples.samples_head;
 364        u64 limit = s->ordered_samples.next_flush;
 365        struct sample_queue *tmp, *iter;
 366
 367        if (!ops->ordered_samples || !limit)
 368                return;
 369
 370        list_for_each_entry_safe(iter, tmp, head, list) {
 371                if (iter->timestamp > limit)
 372                        return;
 373
 374                if (iter == s->ordered_samples.last_inserted)
 375                        s->ordered_samples.last_inserted = NULL;
 376
 377                ops->sample((event_t *)iter->event, s);
 378
 379                s->ordered_samples.last_flush = iter->timestamp;
 380                list_del(&iter->list);
 381                free(iter->event);
 382                free(iter);
 383        }
 384}
 385
 386/*
 387 * When perf record finishes a pass on every buffers, it records this pseudo
 388 * event.
 389 * We record the max timestamp t found in the pass n.
 390 * Assuming these timestamps are monotonic across cpus, we know that if
 391 * a buffer still has events with timestamps below t, they will be all
 392 * available and then read in the pass n + 1.
 393 * Hence when we start to read the pass n + 2, we can safely flush every
 394 * events with timestamps below t.
 395 *
 396 *    ============ PASS n =================
 397 *       CPU 0         |   CPU 1
 398 *                     |
 399 *    cnt1 timestamps  |   cnt2 timestamps
 400 *          1          |         2
 401 *          2          |         3
 402 *          -          |         4  <--- max recorded
 403 *
 404 *    ============ PASS n + 1 ==============
 405 *       CPU 0         |   CPU 1
 406 *                     |
 407 *    cnt1 timestamps  |   cnt2 timestamps
 408 *          3          |         5
 409 *          4          |         6
 410 *          5          |         7 <---- max recorded
 411 *
 412 *      Flush every events below timestamp 4
 413 *
 414 *    ============ PASS n + 2 ==============
 415 *       CPU 0         |   CPU 1
 416 *                     |
 417 *    cnt1 timestamps  |   cnt2 timestamps
 418 *          6          |         8
 419 *          7          |         9
 420 *          -          |         10
 421 *
 422 *      Flush every events below timestamp 7
 423 *      etc...
 424 */
 425static int process_finished_round(event_t *event __used,
 426                                  struct perf_session *session,
 427                                  struct perf_event_ops *ops)
 428{
 429        flush_sample_queue(session, ops);
 430        session->ordered_samples.next_flush = session->ordered_samples.max_timestamp;
 431
 432        return 0;
 433}
 434
 435static void __queue_sample_end(struct sample_queue *new, struct list_head *head)
 436{
 437        struct sample_queue *iter;
 438
 439        list_for_each_entry_reverse(iter, head, list) {
 440                if (iter->timestamp < new->timestamp) {
 441                        list_add(&new->list, &iter->list);
 442                        return;
 443                }
 444        }
 445
 446        list_add(&new->list, head);
 447}
 448
 449static void __queue_sample_before(struct sample_queue *new,
 450                                  struct sample_queue *iter,
 451                                  struct list_head *head)
 452{
 453        list_for_each_entry_continue_reverse(iter, head, list) {
 454                if (iter->timestamp < new->timestamp) {
 455                        list_add(&new->list, &iter->list);
 456                        return;
 457                }
 458        }
 459
 460        list_add(&new->list, head);
 461}
 462
 463static void __queue_sample_after(struct sample_queue *new,
 464                                 struct sample_queue *iter,
 465                                 struct list_head *head)
 466{
 467        list_for_each_entry_continue(iter, head, list) {
 468                if (iter->timestamp > new->timestamp) {
 469                        list_add_tail(&new->list, &iter->list);
 470                        return;
 471                }
 472        }
 473        list_add_tail(&new->list, head);
 474}
 475
 476/* The queue is ordered by time */
 477static void __queue_sample_event(struct sample_queue *new,
 478                                 struct perf_session *s)
 479{
 480        struct sample_queue *last_inserted = s->ordered_samples.last_inserted;
 481        struct list_head *head = &s->ordered_samples.samples_head;
 482
 483
 484        if (!last_inserted) {
 485                __queue_sample_end(new, head);
 486                return;
 487        }
 488
 489        /*
 490         * Most of the time the current event has a timestamp
 491         * very close to the last event inserted, unless we just switched
 492         * to another event buffer. Having a sorting based on a list and
 493         * on the last inserted event that is close to the current one is
 494         * probably more efficient than an rbtree based sorting.
 495         */
 496        if (last_inserted->timestamp >= new->timestamp)
 497                __queue_sample_before(new, last_inserted, head);
 498        else
 499                __queue_sample_after(new, last_inserted, head);
 500}
 501
 502static int queue_sample_event(event_t *event, struct sample_data *data,
 503                              struct perf_session *s)
 504{
 505        u64 timestamp = data->time;
 506        struct sample_queue *new;
 507
 508
 509        if (timestamp < s->ordered_samples.last_flush) {
 510                printf("Warning: Timestamp below last timeslice flush\n");
 511                return -EINVAL;
 512        }
 513
 514        new = malloc(sizeof(*new));
 515        if (!new)
 516                return -ENOMEM;
 517
 518        new->timestamp = timestamp;
 519
 520        new->event = malloc(event->header.size);
 521        if (!new->event) {
 522                free(new);
 523                return -ENOMEM;
 524        }
 525
 526        memcpy(new->event, event, event->header.size);
 527
 528        __queue_sample_event(new, s);
 529        s->ordered_samples.last_inserted = new;
 530
 531        if (new->timestamp > s->ordered_samples.max_timestamp)
 532                s->ordered_samples.max_timestamp = new->timestamp;
 533
 534        return 0;
 535}
 536
 537static int perf_session__process_sample(event_t *event, struct perf_session *s,
 538                                        struct perf_event_ops *ops)
 539{
 540        struct sample_data data;
 541
 542        if (!ops->ordered_samples)
 543                return ops->sample(event, s);
 544
 545        bzero(&data, sizeof(struct sample_data));
 546        event__parse_sample(event, s->sample_type, &data);
 547
 548        queue_sample_event(event, &data, s);
 549
 550        return 0;
 551}
 552
 553static int perf_session__process_event(struct perf_session *self,
 554                                       event_t *event,
 555                                       struct perf_event_ops *ops,
 556                                       u64 offset, u64 head)
 557{
 558        trace_event(event);
 559
 560        if (event->header.type < PERF_RECORD_HEADER_MAX) {
 561                dump_printf("%#Lx [%#x]: PERF_RECORD_%s",
 562                            offset + head, event->header.size,
 563                            event__name[event->header.type]);
 564                hists__inc_nr_events(&self->hists, event->header.type);
 565        }
 566
 567        if (self->header.needs_swap && event__swap_ops[event->header.type])
 568                event__swap_ops[event->header.type](event);
 569
 570        switch (event->header.type) {
 571        case PERF_RECORD_SAMPLE:
 572                return perf_session__process_sample(event, self, ops);
 573        case PERF_RECORD_MMAP:
 574                return ops->mmap(event, self);
 575        case PERF_RECORD_COMM:
 576                return ops->comm(event, self);
 577        case PERF_RECORD_FORK:
 578                return ops->fork(event, self);
 579        case PERF_RECORD_EXIT:
 580                return ops->exit(event, self);
 581        case PERF_RECORD_LOST:
 582                return ops->lost(event, self);
 583        case PERF_RECORD_READ:
 584                return ops->read(event, self);
 585        case PERF_RECORD_THROTTLE:
 586                return ops->throttle(event, self);
 587        case PERF_RECORD_UNTHROTTLE:
 588                return ops->unthrottle(event, self);
 589        case PERF_RECORD_HEADER_ATTR:
 590                return ops->attr(event, self);
 591        case PERF_RECORD_HEADER_EVENT_TYPE:
 592                return ops->event_type(event, self);
 593        case PERF_RECORD_HEADER_TRACING_DATA:
 594                /* setup for reading amidst mmap */
 595                lseek(self->fd, offset + head, SEEK_SET);
 596                return ops->tracing_data(event, self);
 597        case PERF_RECORD_HEADER_BUILD_ID:
 598                return ops->build_id(event, self);
 599        case PERF_RECORD_FINISHED_ROUND:
 600                return ops->finished_round(event, self, ops);
 601        default:
 602                ++self->hists.stats.nr_unknown_events;
 603                return -1;
 604        }
 605}
 606
 607void perf_event_header__bswap(struct perf_event_header *self)
 608{
 609        self->type = bswap_32(self->type);
 610        self->misc = bswap_16(self->misc);
 611        self->size = bswap_16(self->size);
 612}
 613
 614static struct thread *perf_session__register_idle_thread(struct perf_session *self)
 615{
 616        struct thread *thread = perf_session__findnew(self, 0);
 617
 618        if (thread == NULL || thread__set_comm(thread, "swapper")) {
 619                pr_err("problem inserting idle task.\n");
 620                thread = NULL;
 621        }
 622
 623        return thread;
 624}
 625
 626int do_read(int fd, void *buf, size_t size)
 627{
 628        void *buf_start = buf;
 629
 630        while (size) {
 631                int ret = read(fd, buf, size);
 632
 633                if (ret <= 0)
 634                        return ret;
 635
 636                size -= ret;
 637                buf += ret;
 638        }
 639
 640        return buf - buf_start;
 641}
 642
 643#define session_done()  (*(volatile int *)(&session_done))
 644volatile int session_done;
 645
 646static int __perf_session__process_pipe_events(struct perf_session *self,
 647                                               struct perf_event_ops *ops)
 648{
 649        event_t event;
 650        uint32_t size;
 651        int skip = 0;
 652        u64 head;
 653        int err;
 654        void *p;
 655
 656        perf_event_ops__fill_defaults(ops);
 657
 658        head = 0;
 659more:
 660        err = do_read(self->fd, &event, sizeof(struct perf_event_header));
 661        if (err <= 0) {
 662                if (err == 0)
 663                        goto done;
 664
 665                pr_err("failed to read event header\n");
 666                goto out_err;
 667        }
 668
 669        if (self->header.needs_swap)
 670                perf_event_header__bswap(&event.header);
 671
 672        size = event.header.size;
 673        if (size == 0)
 674                size = 8;
 675
 676        p = &event;
 677        p += sizeof(struct perf_event_header);
 678
 679        if (size - sizeof(struct perf_event_header)) {
 680                err = do_read(self->fd, p,
 681                              size - sizeof(struct perf_event_header));
 682                if (err <= 0) {
 683                        if (err == 0) {
 684                                pr_err("unexpected end of event stream\n");
 685                                goto done;
 686                        }
 687
 688                        pr_err("failed to read event data\n");
 689                        goto out_err;
 690                }
 691        }
 692
 693        if (size == 0 ||
 694            (skip = perf_session__process_event(self, &event, ops,
 695                                                0, head)) < 0) {
 696                dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
 697                            head, event.header.size, event.header.type);
 698                /*
 699                 * assume we lost track of the stream, check alignment, and
 700                 * increment a single u64 in the hope to catch on again 'soon'.
 701                 */
 702                if (unlikely(head & 7))
 703                        head &= ~7ULL;
 704
 705                size = 8;
 706        }
 707
 708        head += size;
 709
 710        dump_printf("\n%#Lx [%#x]: event: %d\n",
 711                    head, event.header.size, event.header.type);
 712
 713        if (skip > 0)
 714                head += skip;
 715
 716        if (!session_done())
 717                goto more;
 718done:
 719        err = 0;
 720out_err:
 721        return err;
 722}
 723
 724int __perf_session__process_events(struct perf_session *self,
 725                                   u64 data_offset, u64 data_size,
 726                                   u64 file_size, struct perf_event_ops *ops)
 727{
 728        int err, mmap_prot, mmap_flags;
 729        u64 head, shift;
 730        u64 offset = 0;
 731        size_t  page_size;
 732        event_t *event;
 733        uint32_t size;
 734        char *buf;
 735        struct ui_progress *progress = ui_progress__new("Processing events...",
 736                                                        self->size);
 737        if (progress == NULL)
 738                return -1;
 739
 740        perf_event_ops__fill_defaults(ops);
 741
 742        page_size = sysconf(_SC_PAGESIZE);
 743
 744        head = data_offset;
 745        shift = page_size * (head / page_size);
 746        offset += shift;
 747        head -= shift;
 748
 749        mmap_prot  = PROT_READ;
 750        mmap_flags = MAP_SHARED;
 751
 752        if (self->header.needs_swap) {
 753                mmap_prot  |= PROT_WRITE;
 754                mmap_flags = MAP_PRIVATE;
 755        }
 756remap:
 757        buf = mmap(NULL, page_size * self->mmap_window, mmap_prot,
 758                   mmap_flags, self->fd, offset);
 759        if (buf == MAP_FAILED) {
 760                pr_err("failed to mmap file\n");
 761                err = -errno;
 762                goto out_err;
 763        }
 764
 765more:
 766        event = (event_t *)(buf + head);
 767        ui_progress__update(progress, offset);
 768
 769        if (self->header.needs_swap)
 770                perf_event_header__bswap(&event->header);
 771        size = event->header.size;
 772        if (size == 0)
 773                size = 8;
 774
 775        if (head + event->header.size >= page_size * self->mmap_window) {
 776                int munmap_ret;
 777
 778                shift = page_size * (head / page_size);
 779
 780                munmap_ret = munmap(buf, page_size * self->mmap_window);
 781                assert(munmap_ret == 0);
 782
 783                offset += shift;
 784                head -= shift;
 785                goto remap;
 786        }
 787
 788        size = event->header.size;
 789
 790        dump_printf("\n%#Lx [%#x]: event: %d\n",
 791                    offset + head, event->header.size, event->header.type);
 792
 793        if (size == 0 ||
 794            perf_session__process_event(self, event, ops, offset, head) < 0) {
 795                dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
 796                            offset + head, event->header.size,
 797                            event->header.type);
 798                /*
 799                 * assume we lost track of the stream, check alignment, and
 800                 * increment a single u64 in the hope to catch on again 'soon'.
 801                 */
 802                if (unlikely(head & 7))
 803                        head &= ~7ULL;
 804
 805                size = 8;
 806        }
 807
 808        head += size;
 809
 810        if (offset + head >= data_offset + data_size)
 811                goto done;
 812
 813        if (offset + head < file_size)
 814                goto more;
 815done:
 816        err = 0;
 817        /* do the final flush for ordered samples */
 818        self->ordered_samples.next_flush = ULLONG_MAX;
 819        flush_sample_queue(self, ops);
 820out_err:
 821        ui_progress__delete(progress);
 822        return err;
 823}
 824
 825int perf_session__process_events(struct perf_session *self,
 826                                 struct perf_event_ops *ops)
 827{
 828        int err;
 829
 830        if (perf_session__register_idle_thread(self) == NULL)
 831                return -ENOMEM;
 832
 833        if (!symbol_conf.full_paths) {
 834                char bf[PATH_MAX];
 835
 836                if (getcwd(bf, sizeof(bf)) == NULL) {
 837                        err = -errno;
 838out_getcwd_err:
 839                        pr_err("failed to get the current directory\n");
 840                        goto out_err;
 841                }
 842                self->cwd = strdup(bf);
 843                if (self->cwd == NULL) {
 844                        err = -ENOMEM;
 845                        goto out_getcwd_err;
 846                }
 847                self->cwdlen = strlen(self->cwd);
 848        }
 849
 850        if (!self->fd_pipe)
 851                err = __perf_session__process_events(self,
 852                                                     self->header.data_offset,
 853                                                     self->header.data_size,
 854                                                     self->size, ops);
 855        else
 856                err = __perf_session__process_pipe_events(self, ops);
 857out_err:
 858        return err;
 859}
 860
 861bool perf_session__has_traces(struct perf_session *self, const char *msg)
 862{
 863        if (!(self->sample_type & PERF_SAMPLE_RAW)) {
 864                pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg);
 865                return false;
 866        }
 867
 868        return true;
 869}
 870
 871int perf_session__set_kallsyms_ref_reloc_sym(struct map **maps,
 872                                             const char *symbol_name,
 873                                             u64 addr)
 874{
 875        char *bracket;
 876        enum map_type i;
 877        struct ref_reloc_sym *ref;
 878
 879        ref = zalloc(sizeof(struct ref_reloc_sym));
 880        if (ref == NULL)
 881                return -ENOMEM;
 882
 883        ref->name = strdup(symbol_name);
 884        if (ref->name == NULL) {
 885                free(ref);
 886                return -ENOMEM;
 887        }
 888
 889        bracket = strchr(ref->name, ']');
 890        if (bracket)
 891                *bracket = '\0';
 892
 893        ref->addr = addr;
 894
 895        for (i = 0; i < MAP__NR_TYPES; ++i) {
 896                struct kmap *kmap = map__kmap(maps[i]);
 897                kmap->ref_reloc_sym = ref;
 898        }
 899
 900        return 0;
 901}
 902
 903size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp)
 904{
 905        return __dsos__fprintf(&self->host_machine.kernel_dsos, fp) +
 906               __dsos__fprintf(&self->host_machine.user_dsos, fp) +
 907               machines__fprintf_dsos(&self->machines, fp);
 908}
 909
 910size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp,
 911                                          bool with_hits)
 912{
 913        size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, with_hits);
 914        return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits);
 915}
 916
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.