Move Linux perf format conversion into perf tool, drop kprof2perf
authorDavide Libenzi <dlibenzi@google.com>
Sun, 13 Dec 2015 17:02:21 +0000 (09:02 -0800)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 16 Dec 2015 21:27:59 +0000 (16:27 -0500)
Move Linux perf format conversion into perf tool, drop kprof2perf.
Adding a new info field to the Akaros perf traces, and translating it to
the Linux perf format, requires access to the libpfm4 library.
At that point it is better to drop the kprof2perf tool, and have Akaros
perf directly emit the Linux perf format.

Signed-off-by: Davide Libenzi <dlibenzi@google.com>
Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
16 files changed:
Makefile
tools/profile/kprof2perf/.gitignore [deleted file]
tools/profile/kprof2perf/Makefile [deleted file]
tools/profile/kprof2perf/kprof2perf.c [deleted file]
tools/profile/kprof2perf/perf_format.h [deleted file]
tools/profile/kprof2perf/perf_patches/perf_patch.diff [deleted file]
tools/profile/perf/Makefile
tools/profile/perf/perf.c
tools/profile/perf/perf_core.c
tools/profile/perf/perf_core.h
tools/profile/perf/perf_format.h [new file with mode: 0644]
tools/profile/perf/perf_patches/perf_patch.diff [new file with mode: 0644]
tools/profile/perf/perfconv.c [new file with mode: 0644]
tools/profile/perf/perfconv.h [new file with mode: 0644]
tools/profile/perf/xlib.c
tools/profile/perf/xlib.h

index 5c18040..2bdcf79 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -669,14 +669,12 @@ realclean: userclean mrproper doxyclean objclean
 PHONY += apps-install
 apps-install: install-libs
        @$(call make_as_parent, -C tools/apps/busybox)
-       @$(call make_as_parent, -C tools/profile/kprof2perf install)
        @$(call make_as_parent, -C tools/apps/snc install)
        @$(call make_as_parent, -C tools/profile/perf install)
 
 PHONY += apps-clean
 apps-clean:
        @$(call make_as_parent, -C tools/apps/busybox clean)
-       @$(call make_as_parent, -C tools/profile/kprof2perf clean)
        @$(call make_as_parent, -C tools/apps/snc clean)
        @$(call make_as_parent, -C tools/profile/perf clean)
 
diff --git a/tools/profile/kprof2perf/.gitignore b/tools/profile/kprof2perf/.gitignore
deleted file mode 100644 (file)
index eaa7b7f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-kprof2perf-*
diff --git a/tools/profile/kprof2perf/Makefile b/tools/profile/kprof2perf/Makefile
deleted file mode 100644 (file)
index d08ab7d..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-# Do not:
-# o  use make's built-in rules and variables
-#    (this increases performance and avoids hard-to-debug behaviour);
-# o  print "Entering directory ...";
-MAKEFLAGS += -rR --no-print-directory
-
-# Overrides
-BUILDDIR ?= $(shell pwd)
-AKAROS_ROOT ?= $(BUILDDIR)/../../..
-MAKE_JOBS ?= 4
-KFS_ROOT ?= $(AKAROS_ROOT)/kern/kfs
-
-XCC = $(CROSS_COMPILE)gcc
-
-CC = gcc
-CFLAGS = -O2 -g -idirafter $(CROSS_INCLUDE)
-LDFLAGS =
-
-PHONY := all
-all: kprof2perf-ros kprof2perf-linux
-
-
-PHONY += kprof2perf-ros
-kprof2perf-ros: kprof2perf.c
-       @$(XCC) $(ROS_CFLAGS) $(ROS_LDFLAGS) -o kprof2perf-ros kprof2perf.c
-
-
-PHONY += kprof2perf-linux
-kprof2perf-linux: kprof2perf.c
-       @$(CC) $(CFLAGS) $(LDFLAGS) -o kprof2perf-linux kprof2perf.c
-
-
-PHONY += install
-install: all
-       @cp kprof2perf-ros $(KFS_ROOT)/bin/kprof2perf
-
-
-PHONY += clean
-clean:
-       @rm -f kprof2perf-ros kprof2perf-linux
-
-
-PHONY += mrproper
-mrproper: clean
-
-
-.PHONY: $(PHONY)
diff --git a/tools/profile/kprof2perf/kprof2perf.c b/tools/profile/kprof2perf/kprof2perf.c
deleted file mode 100644 (file)
index a95cb8f..0000000
+++ /dev/null
@@ -1,689 +0,0 @@
-/* Copyright (c) 2015 Google Inc
- * Davide Libenzi <dlibenzi@google.com>
- * See LICENSE for details.
- *
- * Converts kprof profiler files into Linux perf ones. The Linux Perf file
- * format has bee illustrated here:
- *
- *      https://lwn.net/Articles/644919/
- *      https://openlab-mu-internal.web.cern.ch/openlab-mu-internal/03_Documents/
- *                      3_Technical_Documents/Technical_Reports/2011/Urs_Fassler_report.pdf
- *
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <ros/profiler_records.h>
-#include "perf_format.h"
-
-#define MAX_PERF_RECORD_SIZE (32 * 1024 * 1024)
-#define PERF_RECORD_BUFFER_SIZE 1024
-#define OFFSET_NORELOC ((uint64_t) -1)
-
-#define ID_PERF_SAMPLE 0
-
-#define MBWR_SOLID (1 << 0)
-
-#define min(a, b)                                                              \
-       ({ __typeof__(a) _a = (a);                                      \
-               __typeof__(b) _b = (b);                                 \
-               _a < _b ? _a : _b; })
-#define max(a, b)                                                              \
-       ({ __typeof__(a) _a = (a);                                      \
-               __typeof__(b) _b = (b);                                 \
-               _a > _b ? _a : _b; })
-#define always_assert(c)                                                                                               \
-       do {                                                                                                                            \
-               if (!(c))                                                                                                               \
-                       fprintf(stderr, "%s: %d: Assertion failed: " #c "\n",           \
-                                       __FILE__, __LINE__);                                                            \
-       } while (0)
-
-struct perf_record {
-       uint64_t type;
-       uint64_t size;
-       char *data;
-       char buffer[PERF_RECORD_BUFFER_SIZE];
-};
-
-struct mem_file_reloc {
-       struct mem_file_reloc *next;
-       uint64_t *ptr;
-};
-
-struct mem_block {
-       struct mem_block *next;
-       char *base;
-       char *top;
-       char *wptr;
-};
-
-struct mem_file {
-       size_t size;
-       struct mem_block *head;
-       struct mem_block *tail;
-       struct mem_file_reloc *relocs;
-};
-
-struct perf_headers {
-       struct mem_block *headers[HEADER_FEAT_BITS];
-};
-
-struct static_mmap64 {
-       struct static_mmap64 *next;
-       uint64_t addr;
-       uint64_t size;
-       uint64_t offset;
-       uint32_t pid;
-       char *path;
-};
-
-static int debug_level;
-static uint64_t kernel_load_address = 0xffffffffc0000000;
-static size_t std_block_size = 64 * 1024;
-static struct static_mmap64 *static_mmaps;
-
-static inline void set_bitno(void *data, size_t bitno)
-{
-       ((char *) data)[bitno / 8] |= 1 << (bitno % 8);
-}
-
-static inline const char* vb_decode_uint64(const char *data, uint64_t *pval)
-{
-       unsigned int i;
-       uint64_t val = 0;
-
-       for (i = 0; (*data & 0x80) != 0; i += 7, data++)
-               val |= (((uint64_t) *data) & 0x7f) << i;
-       *pval = val | ((uint64_t) *data) << i;
-
-       return data + 1;
-}
-
-static inline int vb_fdecode_uint64(FILE *file, uint64_t *pval)
-{
-       unsigned int i = 0;
-       uint64_t val = 0;
-
-       for (;;) {
-               int c = fgetc(file);
-
-               if (c == EOF)
-                       return EOF;
-               val |= (((uint64_t) c) & 0x7f) << i;
-               i += 7;
-               if ((c & 0x80) == 0)
-                       break;
-       }
-       *pval = val;
-
-       return i / 7;
-}
-
-static void dbg_print(int level, FILE *file, const char *fmt, ...)
-{
-       if (debug_level >= level) {
-               va_list args;
-
-               va_start(args, fmt);
-               vfprintf(file, fmt, args);
-               va_end(args);
-       }
-}
-
-static void *xmalloc(size_t size)
-{
-       void *data = malloc(size);
-
-       if (!data) {
-               fprintf(stderr, "Unable to allocate %lu bytes: %s\n", size,
-                               strerror(errno));
-               exit(1);
-       }
-
-       return data;
-}
-
-static void *xzmalloc(size_t size)
-{
-       void *data = xmalloc(size);
-
-       memset(data, 0, size);
-
-       return data;
-}
-
-static FILE *xfopen(const char *path, const char *mode)
-{
-       FILE *file = fopen(path, mode);
-
-       if (!file) {
-               fprintf(stderr, "Unable to open file '%s' for mode '%s': %s\n",
-                               path, mode, strerror(errno));
-               exit(1);
-       }
-
-       return file;
-}
-
-static void xfwrite(const void *data, size_t size, FILE *file)
-{
-       if (fwrite(data, 1, size, file) != size) {
-               fprintf(stderr, "Unable to write %lu bytes: %s\n", size,
-                               strerror(errno));
-               exit(1);
-       }
-}
-
-static void xfseek(FILE *file, long offset, int whence)
-{
-       if (fseek(file, offset, whence)) {
-               int error = errno;
-
-               fprintf(stderr, "Unable to seek at offset %ld from %s (fpos=%ld): %s\n",
-                               offset, whence == SEEK_SET ? "beginning of file" :
-                               (whence == SEEK_END ? "end of file" : "current position"),
-                               ftell(file), strerror(error));
-               exit(1);
-       }
-}
-
-static void free_record(struct perf_record *pr)
-{
-       if (pr->data != pr->buffer)
-               free(pr->data);
-       pr->data = NULL;
-}
-
-static int read_record(FILE *file, struct perf_record *pr)
-{
-       if (vb_fdecode_uint64(file, &pr->type) == EOF ||
-               vb_fdecode_uint64(file, &pr->size) == EOF)
-               return EOF;
-       if (pr->size > MAX_PERF_RECORD_SIZE) {
-               fprintf(stderr, "Invalid record size: type=%lu size=%lu\n", pr->type,
-                               pr->size);
-               exit(1);
-       }
-       if (pr->size > sizeof(pr->buffer))
-               pr->data = xmalloc((size_t) pr->size);
-       else
-               pr->data = pr->buffer;
-       if (fread(pr->data, 1, (size_t) pr->size, file) != (size_t) pr->size) {
-               fprintf(stderr, "Unable to read record memory: size=%lu\n",
-                               pr->size);
-               return EOF;
-       }
-
-       return 0;
-}
-
-static struct mem_block *mem_block_alloc(size_t size)
-{
-       struct mem_block *mb = xmalloc(sizeof(struct mem_block) + size);
-
-       mb->next = NULL;
-       mb->base = mb->wptr = (char *) mb + sizeof(struct mem_block);
-       mb->top = mb->base + size;
-
-       return mb;
-}
-
-static char *mem_block_write(struct mem_block *mb, const void *data,
-                                                        size_t size)
-{
-       char *wrbase = mb->wptr;
-
-       always_assert(size <= mb->top - mb->wptr);
-
-       memcpy(mb->wptr, data, size);
-       mb->wptr += size;
-
-       return wrbase;
-}
-
-static void mem_file_init(struct mem_file *mf)
-{
-       memset(mf, 0, sizeof(*mf));
-}
-
-static int mem_block_can_write(struct mem_block *mb, size_t size, int flags)
-{
-       size_t space = mb->top - mb->wptr;
-
-       return (flags & MBWR_SOLID) ? (space >= size) : (space > 0);
-}
-
-static void *mem_file_write(struct mem_file *mf, const void *data, size_t size,
-                                                       int flags)
-{
-       void *wrbase = NULL;
-
-       while (size > 0) {
-               size_t space, csize;
-               struct mem_block *mb = mf->tail;
-
-               if (!mb || !mem_block_can_write(mb, size, flags)) {
-                       mb = mem_block_alloc(max(std_block_size, size));
-                       if (!mf->tail)
-                               mf->head = mb;
-                       else
-                               mf->tail->next = mb;
-                       mf->tail = mb;
-               }
-               space = mb->top - mb->wptr;
-               csize = min(size, space);
-
-               wrbase = mem_block_write(mb, data, csize);
-               mf->size += csize;
-
-               size -= csize;
-               data = (const char *) data + csize;
-       }
-
-       return wrbase;
-}
-
-static void mem_file_sync(struct mem_file *mf, FILE *file, uint64_t rel_offset)
-{
-       struct mem_block *mb;
-
-       if (rel_offset != 0) {
-               struct mem_file_reloc *rel;
-
-               always_assert(!mf->relocs || rel_offset != OFFSET_NORELOC);
-
-               for (rel = mf->relocs; rel; rel = rel->next)
-                       *rel->ptr += rel_offset;
-       }
-
-       for (mb = mf->head; mb; mb = mb->next)
-               xfwrite(mb->base, mb->wptr - mb->base, file);
-}
-
-static struct mem_file_reloc *mem_file_add_reloc(struct mem_file *mf,
-                                                                                                uint64_t *ptr)
-{
-       struct mem_file_reloc *rel = xzmalloc(sizeof(struct mem_file_reloc));
-
-       rel->ptr = ptr;
-       rel->next = mf->relocs;
-       mf->relocs = rel;
-
-       return rel;
-}
-
-static void add_static_mmap(const char *path, uint64_t addr, uint64_t offset,
-                                                       uint32_t pid)
-{
-       struct static_mmap64 *mm;
-       struct stat stb;
-
-       if (stat(path, &stb)) {
-               fprintf(stderr, "Unable to stat mmapped file '%s': %s\n",
-                               path, strerror(errno));
-               exit(1);
-       }
-
-       mm = xzmalloc(sizeof(struct static_mmap64));
-       mm->pid = pid;
-       mm->addr = addr;
-       mm->size = stb.st_size;
-       mm->offset = offset;
-       mm->path = strdup(path);
-
-       mm->next = static_mmaps;
-       static_mmaps = mm;
-}
-
-static void add_kernel_mmap(const char *path)
-{
-       add_static_mmap(path, kernel_load_address, kernel_load_address, 0);
-}
-
-static void headers_init(struct perf_headers *hdrs)
-{
-       memset(hdrs, 0, sizeof(*hdrs));
-}
-
-static void headers_add_header(struct perf_headers *hdrs, size_t nhdr,
-                                                          struct mem_block *mb)
-{
-       always_assert(nhdr < HEADER_FEAT_BITS);
-
-       hdrs->headers[nhdr] = mb;
-}
-
-static void headers_write(struct perf_headers *hdrs, struct perf_header *ph,
-                                                 struct mem_file *mf)
-{
-       size_t i;
-
-       for (i = 0; i < HEADER_FEAT_BITS; i++) {
-               struct mem_block *mb = hdrs->headers[i];
-
-               if (mb) {
-                       mem_file_write(mf, mb->base, mb->wptr - mb->base, 0);
-                       set_bitno(ph->adds_features, i);
-               }
-       }
-}
-
-static void perf_header_init(struct perf_header *ph)
-{
-       memset(ph, 0, sizeof(*ph));
-       ph->magic = PERF_MAGIC2;
-       ph->size = sizeof(*ph);
-       ph->attr_size = sizeof(struct perf_event_attr);
-}
-
-static void emit_static_mmaps(struct mem_file *mf)
-{
-       struct static_mmap64 *mm;
-
-       for (mm = static_mmaps; mm; mm = mm->next) {
-               size_t size = sizeof(struct perf_record_mmap) + strlen(mm->path) + 1;
-               struct perf_record_mmap *xrec = xzmalloc(size);
-
-               xrec->header.type = PERF_RECORD_MMAP;
-               xrec->header.misc = PERF_RECORD_MISC_USER;
-               xrec->header.size = size;
-               xrec->pid = xrec->tid = mm->pid;
-               xrec->addr = mm->addr;
-               xrec->len = mm->size;
-               xrec->pgoff = mm->offset;
-               strcpy(xrec->filename, mm->path);
-
-               mem_file_write(mf, xrec, size, 0);
-
-               free(xrec);
-       }
-}
-
-static void emit_comm(uint32_t pid, const char *comm, struct mem_file *mf)
-{
-       size_t size = sizeof(struct perf_record_comm) + strlen(comm) + 1;
-       struct perf_record_comm *xrec = xzmalloc(size);
-
-       xrec->header.type = PERF_RECORD_COMM;
-       xrec->header.misc = PERF_RECORD_MISC_USER;
-       xrec->header.size = size;
-       xrec->pid = xrec->tid = pid;
-       strcpy(xrec->comm, comm);
-
-       mem_file_write(mf, xrec, size, 0);
-
-       free(xrec);
-}
-
-static void emit_pid_mmap64(struct perf_record *pr, struct mem_file *mf)
-{
-       struct proftype_pid_mmap64 *rec = (struct proftype_pid_mmap64 *) pr->data;
-       size_t size = sizeof(struct perf_record_mmap) + strlen(rec->path) + 1;
-       struct perf_record_mmap *xrec = xzmalloc(size);
-
-       xrec->header.type = PERF_RECORD_MMAP;
-       xrec->header.misc = PERF_RECORD_MISC_USER;
-       xrec->header.size = size;
-       xrec->pid = xrec->tid = rec->pid;
-       xrec->addr = rec->addr;
-       xrec->len = rec->size;
-       xrec->pgoff = rec->offset;
-       strcpy(xrec->filename, rec->path);
-
-       mem_file_write(mf, xrec, size, 0);
-
-       free(xrec);
-}
-
-static void emit_kernel_trace64(struct perf_record *pr, struct mem_file *mf)
-{
-       struct proftype_kern_trace64 *rec = (struct proftype_kern_trace64 *)
-               pr->data;
-       size_t size = sizeof(struct perf_record_sample) +
-               (rec->num_traces - 1) * sizeof(uint64_t);
-       struct perf_record_sample *xrec = xzmalloc(size);
-
-       xrec->header.type = PERF_RECORD_SAMPLE;
-       xrec->header.misc = PERF_RECORD_MISC_USER;
-       xrec->header.size = size;
-       xrec->ip = rec->trace[0];
-       xrec->time = rec->tstamp;
-       xrec->addr = rec->trace[0];
-       xrec->id = ID_PERF_SAMPLE;
-       xrec->cpu = rec->cpu;
-       xrec->nr = rec->num_traces - 1;
-       memcpy(xrec->ips, rec->trace + 1, (rec->num_traces - 1) * sizeof(uint64_t));
-
-       mem_file_write(mf, xrec, size, 0);
-
-       free(xrec);
-}
-
-static void emit_user_trace64(struct perf_record *pr, struct mem_file *mf)
-{
-       struct proftype_user_trace64 *rec = (struct proftype_user_trace64 *)
-               pr->data;
-       size_t size = sizeof(struct perf_record_sample) +
-               (rec->num_traces - 1) * sizeof(uint64_t);
-       struct perf_record_sample *xrec = xzmalloc(size);
-
-       xrec->header.type = PERF_RECORD_SAMPLE;
-       xrec->header.misc = PERF_RECORD_MISC_USER;
-       xrec->header.size = size;
-       xrec->ip = rec->trace[0];
-       xrec->pid = xrec->tid = rec->pid;
-       xrec->time = rec->tstamp;
-       xrec->addr = rec->trace[0];
-       xrec->id = ID_PERF_SAMPLE;
-       xrec->cpu = rec->cpu;
-       xrec->nr = rec->num_traces - 1;
-       memcpy(xrec->ips, rec->trace + 1, (rec->num_traces - 1) * sizeof(uint64_t));
-
-       mem_file_write(mf, xrec, size, 0);
-
-       free(xrec);
-}
-
-static void emit_new_process(struct perf_record *pr, struct mem_file *mf)
-{
-       struct proftype_new_process *rec = (struct proftype_new_process *) pr->data;
-       const char *comm = strrchr(rec->path, '/');
-
-       if (!comm)
-               comm = rec->path;
-       else
-               comm++;
-       emit_comm(rec->pid, comm, mf);
-}
-
-static void add_attribute(struct mem_file *amf, struct mem_file *mmf,
-                                                 const struct perf_event_attr *attr,
-                                                 const uint64_t *ids, size_t nids)
-{
-       struct perf_file_section *psids;
-       struct perf_file_section sids;
-
-       mem_file_write(amf, attr, sizeof(*attr), 0);
-
-       sids.offset = mmf->size;
-       sids.size = nids * sizeof(uint64_t);
-
-       mem_file_write(mmf, ids, nids * sizeof(uint64_t), 0);
-
-       psids = mem_file_write(amf, &sids, sizeof(sids), MBWR_SOLID);
-
-       mem_file_add_reloc(amf, &psids->offset);
-}
-
-static void add_default_attribute(struct mem_file *amf, struct mem_file *mmf,
-                                                                 uint64_t event_id, uint64_t id)
-{
-       struct perf_event_attr attr;
-
-       memset(&attr, 0, sizeof(attr));
-       attr.type = PERF_TYPE_HARDWARE;
-       attr.size = sizeof(attr);
-       attr.config = event_id;
-       attr.mmap = 1;
-       attr.comm = 1;
-       attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME |
-               PERF_SAMPLE_ADDR | PERF_SAMPLE_ID | PERF_SAMPLE_CPU |
-               PERF_SAMPLE_CALLCHAIN;
-
-       add_attribute(amf, mmf, &attr, &id, 1);
-}
-
-static void add_event_type(struct mem_file *mf, uint64_t id, const char *name)
-{
-       struct perf_trace_event_type evt;
-
-       memset(&evt, 0, sizeof(evt));
-       evt.event_id = id;
-       strncpy(evt.name, name, sizeof(evt.name));
-       evt.name[sizeof(evt.name) - 1] = 0;
-
-       mem_file_write(mf, &evt, sizeof(evt), 0);
-}
-
-static void process_input(FILE *input, FILE *output)
-{
-       size_t processed_records = 0;
-       uint64_t offset, rel_offset;
-       struct perf_record pr;
-       struct perf_header ph;
-       struct perf_headers hdrs;
-       struct mem_file fhdrs, misc, attrs, data, event_types;
-
-       perf_header_init(&ph);
-       headers_init(&hdrs);
-       mem_file_init(&fhdrs);
-       mem_file_init(&misc);
-       mem_file_init(&attrs);
-       mem_file_init(&data);
-       mem_file_init(&event_types);
-
-       add_event_type(&event_types, PERF_COUNT_HW_CPU_CYCLES, "cycles");
-       add_default_attribute(&attrs, &misc, PERF_COUNT_HW_CPU_CYCLES,
-                                                 ID_PERF_SAMPLE);
-
-       emit_comm(0, "[kernel]", &data);
-       emit_static_mmaps(&data);
-
-       while (read_record(input, &pr) == 0) {
-               dbg_print(8, stderr, "Valid record: type=%lu size=%lu\n",
-                                 pr.type, pr.size);
-
-               processed_records++;
-
-               switch (pr.type) {
-               case PROFTYPE_KERN_TRACE64:
-                       emit_kernel_trace64(&pr, &data);
-                       break;
-               case PROFTYPE_USER_TRACE64:
-                       emit_user_trace64(&pr, &data);
-                       break;
-               case PROFTYPE_PID_MMAP64:
-                       emit_pid_mmap64(&pr, &data);
-                       break;
-               case PROFTYPE_NEW_PROCESS:
-                       emit_new_process(&pr, &data);
-                       break;
-               default:
-                       fprintf(stderr, "Unknown record: type=%lu size=%lu\n", pr.type,
-                                       pr.size);
-                       processed_records--;
-               }
-
-               free_record(&pr);
-       }
-
-       headers_write(&hdrs, &ph, &fhdrs);
-       offset = sizeof(ph) + fhdrs.size + misc.size;
-
-       if (event_types.size > 0) {
-               ph.event_types.offset = offset;
-               ph.event_types.size = event_types.size;
-               offset += event_types.size;
-       }
-       if (attrs.size > 0) {
-               ph.attrs.offset = offset;
-               ph.attrs.size = attrs.size;
-               offset += attrs.size;
-       }
-       if (data.size > 0) {
-               ph.data.offset = offset;
-               ph.data.size = data.size;
-               offset += data.size;
-       }
-
-       xfwrite(&ph, sizeof(ph), output);
-       mem_file_sync(&fhdrs, output, OFFSET_NORELOC);
-
-       rel_offset = (uint64_t) ftell(output);
-       mem_file_sync(&misc, output, rel_offset);
-
-       mem_file_sync(&event_types, output, rel_offset);
-       mem_file_sync(&attrs, output, rel_offset);
-       mem_file_sync(&data, output, rel_offset);
-
-       fprintf(stderr, "Conversion succeeded: %lu records converted\n",
-                       processed_records);
-}
-
-static void usage(const char *prg)
-{
-       fprintf(stderr, "Use: %s [-ioskDh]\n"
-                       "\t-i INPUT_FILE                  : Sets the input file path (STDIN).\n"
-                       "\t-o OUTPUT_FILE                 : Sets the output file path (STDOUT).\n"
-                       "\t-k KERN_ELF_FILE               : Sets the kernel file path.\n"
-                       "\t-s SIZE                                : Sets the default memory block size (%lu).\n"
-                       "\t-D DBG_LEVEL                   : Sets the debug level for messages.\n"
-                       "\t-h                                     : Displays this help screen.\n",
-                       prg, std_block_size);
-       exit(1);
-}
-
-int main(int argc, const char **argv)
-{
-       int i;
-       const char *inpath = NULL, *outpath = NULL;
-       FILE *input = stdin, *output = stdout;
-
-       for (i = 1; i < argc; i++) {
-               if (strcmp(argv[i], "-i") == 0) {
-                       if (++i < argc)
-                               inpath = argv[i];
-               } else if (strcmp(argv[i], "-o") == 0) {
-                       if (++i < argc)
-                               outpath = argv[i];
-               } else if (strcmp(argv[i], "-s") == 0) {
-                       if (++i < argc)
-                               std_block_size = atol(argv[i]);
-               } else if (strcmp(argv[i], "-k") == 0) {
-                       if (++i < argc)
-                               add_kernel_mmap(argv[i]);
-               } else if (strcmp(argv[i], "-D") == 0) {
-                       if (++i < argc)
-                               debug_level = atoi(argv[i]);
-               } else
-                       usage(argv[0]);
-       }
-       if (inpath)
-               input = xfopen(inpath, "rb");
-       if (outpath)
-               output = xfopen(outpath, "wb");
-
-       process_input(input, output);
-
-       fflush(output);
-
-       return 0;
-}
diff --git a/tools/profile/kprof2perf/perf_format.h b/tools/profile/kprof2perf/perf_format.h
deleted file mode 100644 (file)
index 474cd61..0000000
+++ /dev/null
@@ -1,528 +0,0 @@
-/* Copyright (c) 2015 Google Inc
- * Davide Libenzi <dlibenzi@google.com>
- * See LICENSE for details.
- *
- * Parts of this file come, either directly, or as baseline, from the Linux
- * kernel source file:
- *
- *      tools/perf/util/header.h
- *
- * Such file is ruled by the general Linux kernel copyright.
- */
-
-#pragma once
-
-#define BITS_PER_LONG (8 * sizeof(long))
-#define BITS_TO_LONGS(bits) (((bits) + BITS_PER_LONG - 1) / BITS_PER_LONG)
-#define DECLARE_BITMAP(name, bits)                             \
-       unsigned long name[BITS_TO_LONGS(bits)]
-
-enum {
-       HEADER_RESERVED         = 0,    /* Always cleared */
-       HEADER_FIRST_FEATURE    = 1,
-       HEADER_TRACING_DATA     = 1,
-       HEADER_BUILD_ID,
-
-       HEADER_HOSTNAME,
-       HEADER_OSRELEASE,
-       HEADER_VERSION,
-       HEADER_ARCH,
-       HEADER_NRCPUS,
-       HEADER_CPUDESC,
-       HEADER_CPUID,
-       HEADER_TOTAL_MEM,
-       HEADER_CMDLINE,
-       HEADER_EVENT_DESC,
-       HEADER_CPU_TOPOLOGY,
-       HEADER_NUMA_TOPOLOGY,
-       HEADER_BRANCH_STACK,
-       HEADER_PMU_MAPPINGS,
-       HEADER_GROUP_DESC,
-       HEADER_LAST_FEATURE,
-       HEADER_FEAT_BITS        = 256,
-};
-
-/*
- * Bits that can be set in attr.sample_type to request information
- * in the overflow packets.
- */
-enum perf_event_sample_format {
-       PERF_SAMPLE_IP                          = 1U << 0,
-       PERF_SAMPLE_TID                         = 1U << 1,
-       PERF_SAMPLE_TIME                        = 1U << 2,
-       PERF_SAMPLE_ADDR                        = 1U << 3,
-       PERF_SAMPLE_READ                        = 1U << 4,
-       PERF_SAMPLE_CALLCHAIN                   = 1U << 5,
-       PERF_SAMPLE_ID                          = 1U << 6,
-       PERF_SAMPLE_CPU                         = 1U << 7,
-       PERF_SAMPLE_PERIOD                      = 1U << 8,
-       PERF_SAMPLE_STREAM_ID                   = 1U << 9,
-       PERF_SAMPLE_RAW                         = 1U << 10,
-       PERF_SAMPLE_BRANCH_STACK                = 1U << 11,
-       PERF_SAMPLE_REGS_USER                   = 1U << 12,
-       PERF_SAMPLE_STACK_USER                  = 1U << 13,
-       PERF_SAMPLE_WEIGHT                      = 1U << 14,
-       PERF_SAMPLE_DATA_SRC                    = 1U << 15,
-       PERF_SAMPLE_IDENTIFIER                  = 1U << 16,
-       PERF_SAMPLE_TRANSACTION                 = 1U << 17,
-       PERF_SAMPLE_REGS_INTR                   = 1U << 18,
-
-       PERF_SAMPLE_MAX = 1U << 19,             /* non-ABI */
-};
-
-enum perf_event_type {
-       /*
-        * If perf_event_attr.sample_id_all is set then all event types will
-        * have the sample_type selected fields related to where/when
-        * (identity) an event took place (TID, TIME, ID, STREAM_ID, CPU,
-        * IDENTIFIER) described in PERF_RECORD_SAMPLE below, it will be stashed
-        * just after the perf_event_header and the fields already present for
-        * the existing fields, i.e. at the end of the payload. That way a newer
-        * perf.data file will be supported by older perf tools, with these new
-        * optional fields being ignored.
-        *
-        * struct sample_id {
-        *      { u32                   pid, tid; } && PERF_SAMPLE_TID
-        *      { u64                   time;     } && PERF_SAMPLE_TIME
-        *      { u64                   id;               } && PERF_SAMPLE_ID
-        *      { u64                   stream_id;} && PERF_SAMPLE_STREAM_ID
-        *      { u32                   cpu, res; } && PERF_SAMPLE_CPU
-        *      { u64                   id;       } && PERF_SAMPLE_IDENTIFIER
-        * } && perf_event_attr::sample_id_all
-        *
-        * Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID.  The
-        * advantage of PERF_SAMPLE_IDENTIFIER is that its position is fixed
-        * relative to header.size.
-        */
-
-       /*
-        * The MMAP events record the PROT_EXEC mappings so that we can
-        * correlate userspace IPs to code. They have the following structure:
-        *
-        * struct {
-        *      struct perf_event_header        header;
-        *
-        *      u32                             pid, tid;
-        *      u64                             addr;
-        *      u64                             len;
-        *      u64                             pgoff;
-        *      char                            filename[];
-        * };
-        */
-       PERF_RECORD_MMAP                        = 1,
-
-       /*
-        * struct {
-        *      struct perf_event_header        header;
-        *      u64                             id;
-        *      u64                             lost;
-        *      struct sample_id                sample_id;
-        * };
-        */
-       PERF_RECORD_LOST                        = 2,
-
-       /*
-        * struct {
-        *      struct perf_event_header        header;
-        *
-        *      u32                             pid, tid;
-        *      char                            comm[];
-        *      struct sample_id                sample_id;
-        * };
-        */
-       PERF_RECORD_COMM                        = 3,
-
-       /*
-        * struct {
-        *      struct perf_event_header        header;
-        *      u32                             pid, ppid;
-        *      u32                             tid, ptid;
-        *      u64                             time;
-        *      struct sample_id                sample_id;
-        * };
-        */
-       PERF_RECORD_EXIT                        = 4,
-
-       /*
-        * struct {
-        *      struct perf_event_header        header;
-        *      u64                             time;
-        *      u64                             id;
-        *      u64                             stream_id;
-        *      struct sample_id                sample_id;
-        * };
-        */
-       PERF_RECORD_THROTTLE                    = 5,
-       PERF_RECORD_UNTHROTTLE                  = 6,
-
-       /*
-        * struct {
-        *      struct perf_event_header        header;
-        *      u32                             pid, ppid;
-        *      u32                             tid, ptid;
-        *      u64                             time;
-        *      struct sample_id                sample_id;
-        * };
-        */
-       PERF_RECORD_FORK                        = 7,
-
-       /*
-        * struct {
-        *      struct perf_event_header        header;
-        *      u32                             pid, tid;
-        *
-        *      struct read_format              values;
-        *      struct sample_id                sample_id;
-        * };
-        */
-       PERF_RECORD_READ                        = 8,
-
-       /*
-        * struct {
-        *      struct perf_event_header        header;
-        *
-        *      #
-        *      # Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID.
-        *      # The advantage of PERF_SAMPLE_IDENTIFIER is that its position
-        *      # is fixed relative to header.
-        *      #
-        *
-        *      { u64                   id;       } && PERF_SAMPLE_IDENTIFIER
-        *      { u64                   ip;       } && PERF_SAMPLE_IP
-        *      { u32                   pid, tid; } && PERF_SAMPLE_TID
-        *      { u64                   time;     } && PERF_SAMPLE_TIME
-        *      { u64                   addr;     } && PERF_SAMPLE_ADDR
-        *      { u64                   id;       } && PERF_SAMPLE_ID
-        *      { u64                   stream_id;} && PERF_SAMPLE_STREAM_ID
-        *      { u32                   cpu, res; } && PERF_SAMPLE_CPU
-        *      { u64                   period;   } && PERF_SAMPLE_PERIOD
-        *
-        *      { struct read_format    values;   } && PERF_SAMPLE_READ
-        *
-        *      { u64                   nr,
-        *        u64                   ips[nr];  } && PERF_SAMPLE_CALLCHAIN
-        *
-        *      #
-        *      # The RAW record below is opaque data wrt the ABI
-        *      #
-        *      # That is, the ABI doesn't make any promises wrt to
-        *      # the stability of its content, it may vary depending
-        *      # on event, hardware, kernel version and phase of
-        *      # the moon.
-        *      #
-        *      # In other words, PERF_SAMPLE_RAW contents are not an ABI.
-        *      #
-        *
-        *      { u32                   size;
-        *        char                                  data[size];}&& PERF_SAMPLE_RAW
-        *
-        *      { u64                                   nr;
-        *                { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK
-        *
-        *      { u64                   abi; # enum perf_sample_regs_abi
-        *        u64                   regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER
-        *
-        *      { u64                   size;
-        *        char                  data[size];
-        *        u64                   dyn_size; } && PERF_SAMPLE_STACK_USER
-        *
-        *      { u64                   weight;   } && PERF_SAMPLE_WEIGHT
-        *      { u64                   data_src; } && PERF_SAMPLE_DATA_SRC
-        *              { u64                                   transaction; } && PERF_SAMPLE_TRANSACTION
-        *      { u64                   abi; # enum perf_sample_regs_abi
-        *        u64                   regs[weight(mask)]; } && PERF_SAMPLE_REGS_INTR
-        * };
-        */
-       PERF_RECORD_SAMPLE                      = 9,
-
-       /*
-        * The MMAP2 records are an augmented version of MMAP, they add
-        * maj, min, ino numbers to be used to uniquely identify each mapping
-        *
-        * struct {
-        *      struct perf_event_header        header;
-        *
-        *      u32                             pid, tid;
-        *      u64                             addr;
-        *      u64                             len;
-        *      u64                             pgoff;
-        *      u32                             maj;
-        *      u32                             min;
-        *      u64                             ino;
-        *      u64                             ino_generation;
-        *      char                            filename[];
-        *      struct sample_id                sample_id;
-        * };
-        */
-       PERF_RECORD_MMAP2                       = 10,
-
-       PERF_RECORD_MAX,                        /* non-ABI */
-};
-
-#define PERF_MAX_STACK_DEPTH           127
-
-enum perf_callchain_context {
-       PERF_CONTEXT_HV                         = (__uint64_t) -32,
-       PERF_CONTEXT_KERNEL                     = (__uint64_t) -128,
-       PERF_CONTEXT_USER                       = (__uint64_t) -512,
-
-       PERF_CONTEXT_GUEST                      = (__uint64_t) -2048,
-       PERF_CONTEXT_GUEST_KERNEL       = (__uint64_t) -2176,
-       PERF_CONTEXT_GUEST_USER         = (__uint64_t) -2560,
-
-       PERF_CONTEXT_MAX                        = (__uint64_t) -4095,
-};
-
-/*
- * attr.type
- */
-enum perf_type_id {
-       PERF_TYPE_HARDWARE                                              = 0,
-       PERF_TYPE_SOFTWARE                                              = 1,
-       PERF_TYPE_TRACEPOINT                                    = 2,
-       PERF_TYPE_HW_CACHE                                              = 3,
-       PERF_TYPE_RAW                                                   = 4,
-       PERF_TYPE_BREAKPOINT                                    = 5,
-       PERF_TYPE_INTEL_CQM                                             = 6,
-
-       PERF_TYPE_MAX,                                                  /* non-ABI */
-};
-
-/*
- * Generalized performance event event_id types, used by the
- * attr.event_id parameter of the sys_perf_event_open()
- * syscall:
- */
-enum perf_hw_id {
-       /*
-        * Common hardware events, generalized by the kernel:
-        */
-       PERF_COUNT_HW_CPU_CYCLES                                = 0,
-       PERF_COUNT_HW_INSTRUCTIONS                              = 1,
-       PERF_COUNT_HW_CACHE_REFERENCES                  = 2,
-       PERF_COUNT_HW_CACHE_MISSES                              = 3,
-       PERF_COUNT_HW_BRANCH_INSTRUCTIONS               = 4,
-       PERF_COUNT_HW_BRANCH_MISSES                             = 5,
-       PERF_COUNT_HW_BUS_CYCLES                                = 6,
-       PERF_COUNT_HW_STALLED_CYCLES_FRONTEND   = 7,
-       PERF_COUNT_HW_STALLED_CYCLES_BACKEND    = 8,
-       PERF_COUNT_HW_REF_CPU_CYCLES                    = 9,
-
-       PERF_COUNT_HW_MAX,                                              /* non-ABI */
-};
-
-/*
- * Hardware event_id to monitor via a performance monitoring event:
- */
-struct perf_event_attr {
-       /*
-        * Major type: hardware/software/tracepoint/etc.
-        */
-       uint32_t type;
-
-       /*
-        * Size of the attr structure, for fwd/bwd compat.
-        */
-       uint32_t size;
-
-       /*
-        * Type specific configuration information.
-        */
-       uint64_t config;
-
-       union {
-               uint64_t sample_period;
-               uint64_t sample_freq;
-       };
-
-       uint64_t sample_type;
-       uint64_t read_format;
-
-       uint64_t disabled               :  1, /* off by default            */
-               inherit            :  1, /* children inherit it   */
-               pinned             :  1, /* must always be on PMU */
-               exclusive          :  1, /* only group on PMU     */
-               exclude_user   :  1, /* don't count user          */
-               exclude_kernel :  1, /* ditto kernel              */
-               exclude_hv         :  1, /* ditto hypervisor      */
-               exclude_idle   :  1, /* don't count when idle */
-               mmap               :  1, /* include mmap data     */
-               comm               :  1, /* include comm data     */
-               freq               :  1, /* use freq, not period  */
-               inherit_stat   :  1, /* per task counts           */
-               enable_on_exec :  1, /* next exec enables         */
-               task               :  1, /* trace fork/exit               */
-               watermark          :  1, /* wakeup_watermark      */
-       /*
-        * precise_ip:
-        *
-        *      0 - SAMPLE_IP can have arbitrary skid
-        *      1 - SAMPLE_IP must have constant skid
-        *      2 - SAMPLE_IP requested to have 0 skid
-        *      3 - SAMPLE_IP must have 0 skid
-        *
-        *      See also PERF_RECORD_MISC_EXACT_IP
-        */
-               precise_ip         :  2, /* skid constraint               */
-               mmap_data          :  1, /* non-exec mmap data    */
-               sample_id_all  :  1, /* sample_type all events */
-
-               exclude_host   :  1, /* don't count in host       */
-               exclude_guest  :  1, /* don't count in guest  */
-
-               exclude_callchain_kernel : 1, /* exclude kernel callchains */
-               exclude_callchain_user   : 1, /* exclude user callchains */
-               mmap2              :  1, /* include mmap with inode data         */
-
-               __reserved_1   : 40;
-
-       union {
-               uint32_t wakeup_events;   /* wakeup every n events */
-               uint32_t wakeup_watermark; /* bytes before wakeup       */
-       };
-
-       uint32_t bp_type;
-       union {
-               uint64_t bp_addr;
-               uint64_t config1; /* extension of config */
-       };
-       union {
-               uint64_t bp_len;
-               uint64_t config2; /* extension of config1 */
-       };
-       uint64_t branch_sample_type; /* enum perf_branch_sample_type */
-
-       /*
-        * Defines set of user regs to dump on samples.
-        * See asm/perf_regs.h for details.
-        */
-       uint64_t sample_regs_user;
-
-       /*
-        * Defines size of the user stack to dump on samples.
-        */
-       uint32_t sample_stack_user;
-
-       /* Align to u64. */
-       uint32_t __reserved_2;
-
-       /*
-        * Defines set of regs to dump for each sample
-        * state captured on:
-        *      - precise = 0: PMU interrupt
-        *      - precise > 0: sampled instruction
-        *
-        * See asm/perf_regs.h for details.
-        */
-       uint64_t sample_regs_intr;
-} __attribute__((packed));
-
-#define PERF_RECORD_MISC_CPUMODE_MASK          (7 << 0)
-#define PERF_RECORD_MISC_CPUMODE_UNKNOWN       (0 << 0)
-#define PERF_RECORD_MISC_KERNEL                        (1 << 0)
-#define PERF_RECORD_MISC_USER                  (2 << 0)
-#define PERF_RECORD_MISC_HYPERVISOR            (3 << 0)
-#define PERF_RECORD_MISC_GUEST_KERNEL          (4 << 0)
-#define PERF_RECORD_MISC_GUEST_USER            (5 << 0)
-
-#define PERF_RECORD_MISC_MMAP_DATA             (1 << 13)
-/*
- * Indicates that the content of PERF_SAMPLE_IP points to
- * the actual instruction that triggered the event. See also
- * perf_event_attr::precise_ip.
- */
-#define PERF_RECORD_MISC_EXACT_IP              (1 << 14)
-/*
- * Reserve the last bit to indicate some extended misc field
- */
-#define PERF_RECORD_MISC_EXT_RESERVED          (1 << 15)
-
-struct perf_event_header {
-       uint32_t type;
-       uint16_t misc;
-       uint16_t size;
-} __attribute__((packed));
-
-struct perf_file_section {
-       uint64_t offset;        /* Offset from start of file */
-       uint64_t size;          /* Size of the section */
-} __attribute__((packed));
-
-struct perf_header_string {
-       uint32_t len;
-       char string[0];         /* Zero terminated */
-};
-
-struct perf_header_string_list {
-       uint32_t nr;
-       struct perf_header_string strings[0];   /* Variable length records */
-};
-
-#define MAX_EVENT_NAME 64
-
-struct perf_trace_event_type {
-       uint64_t event_id;
-       char name[MAX_EVENT_NAME];
-};
-
-struct perf_file_attr {
-       struct perf_event_attr attr;
-       struct perf_file_section ids;
-};
-
-/* "PERFILE2"
- */
-static const uint64_t PERF_MAGIC2 = 0x32454c4946524550ULL;
-
-struct perf_pipe_file_header {
-       uint64_t magic;                                 /* PERFILE2 */
-       uint64_t size;
-};
-
-struct perf_header {
-       uint64_t magic;                                 /* PERFILE2 */
-       uint64_t size;                                  /* Size of the header */
-       uint64_t attr_size;                             /* size of an attribute in attrs */
-       struct perf_file_section attrs;
-       struct perf_file_section data;
-       struct perf_file_section event_types;
-       DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
-} __attribute__((packed));
-
-/* For type PERF_RECORD_MMAP
- */
-struct perf_record_mmap {
-       struct perf_event_header header;
-       uint32_t pid;
-       uint32_t tid;
-       uint64_t addr;
-       uint64_t len;
-       uint64_t pgoff;
-       char filename[0];
-} __attribute__((packed));
-
-/* For type PERF_RECORD_COMM
- */
-struct perf_record_comm {
-       struct perf_event_header header;
-       uint32_t pid;
-       uint32_t tid;
-       char comm[0];
-} __attribute__((packed));
-
-/* For type PERF_RECORD_SAMPLE
- * Configured with: PERF_SAMPLE_IP | PERF_SAMPLE_TID && PERF_SAMPLE_TIME &&
- * PERF_SAMPLE_ADDR && PERF_SAMPLE_ID && PERF_SAMPLE_CPU &&
- * PERF_SAMPLE_CALLCHAIN.
- */
-struct perf_record_sample {
-       struct perf_event_header header;
-       uint64_t ip;
-       uint32_t pid, tid;
-       uint64_t time;
-       uint64_t addr;
-       uint64_t id;
-       uint32_t cpu, res;
-       uint64_t nr;
-       uint64_t ips[0];
-} __attribute__((packed));
diff --git a/tools/profile/kprof2perf/perf_patches/perf_patch.diff b/tools/profile/kprof2perf/perf_patches/perf_patch.diff
deleted file mode 100644 (file)
index 6d0d6da..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-diff --git a/tools/perf/perf.c b/tools/perf/perf.c
-index 85e1aed..ecf04c1 100644
---- a/tools/perf/perf.c
-+++ b/tools/perf/perf.c
-@@ -15,9 +15,14 @@
- #include "util/parse-events.h"
- #include <lk/debugfs.h>
- #include <pthread.h>
-+#include <fcntl.h>
-+#include <stdio.h>
-+#include <errno.h>
-+#include <string.h>
-+#include <unistd.h>
- const char perf_usage_string[] =
--      "perf [--version] [--help] COMMAND [ARGS]";
-+      "perf [--version] [--help] [--root-dir DIR] COMMAND [ARGS]";
- const char perf_more_info_string[] =
-       "See 'perf help COMMAND' for more information on a specific command.";
-@@ -25,6 +30,7 @@ const char perf_more_info_string[] =
- int use_browser = -1;
- static int use_pager = -1;
- const char *input_name;
-+static const char *perf_root_dir;
- struct cmd_struct {
-       const char *cmd;
-@@ -76,6 +82,28 @@ static int pager_command_config(const char *var, const char *value, void *data)
-       return 0;
- }
-+const char *perf_resolve_binary(const char *path, char *rpath, size_t max_size)
-+{
-+      snprintf(rpath, max_size, "%s/%s", perf_root_dir, path);
-+
-+      return access(rpath, F_OK) == 0 ? rpath: path;
-+}
-+
-+int perf_open_binary(const char *path, int flags, int mode)
-+{
-+      if (perf_root_dir) {
-+              int fd;
-+              char rpath[4096];
-+
-+              snprintf(rpath, sizeof(rpath), "%s/%s", perf_root_dir, path);
-+              fd = open(rpath, flags, mode);
-+              if (fd >= 0)
-+                      return fd;
-+      }
-+
-+      return open(path, flags, mode);
-+}
-+
- /* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
- int check_pager_config(const char *cmd)
- {
-@@ -199,6 +227,14 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
-                               *envchanged = 1;
-                       (*argv)++;
-                       (*argc)--;
-+              } else if (!strcmp(cmd, "--root-dir")) {
-+                      if (*argc < 2) {
-+                              fprintf(stderr, "No directory given for --root-dir.\n");
-+                              usage(perf_usage_string);
-+                      }
-+                      perf_root_dir = (*argv)[1];
-+                      (*argv)++;
-+                      (*argc)--;
-               } else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) {
-                       perf_debugfs_set_path(cmd + strlen(CMD_DEBUGFS_DIR));
-                       fprintf(stderr, "dir: %s\n", debugfs_mountpoint);
-diff --git a/tools/perf/perf.h b/tools/perf/perf.h
-index 32bd102..36c34f3 100644
---- a/tools/perf/perf.h
-+++ b/tools/perf/perf.h
-@@ -198,6 +198,8 @@ extern bool perf_host, perf_guest;
- extern const char perf_version_string[];
- void pthread__unblock_sigwinch(void);
-+const char *perf_resolve_binary(const char *path, char *rpath, size_t max_size);
-+int perf_open_binary(const char *path, int flags, int mode);
- #include "util/target.h"
-diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
-index d102716..65260ba 100644
---- a/tools/perf/util/annotate.c
-+++ b/tools/perf/util/annotate.c
-@@ -15,6 +15,7 @@
- #include "debug.h"
- #include "annotate.h"
- #include "evsel.h"
-+#include "perf.h"
- #include <pthread.h>
- #include <linux/bitops.h>
-@@ -831,10 +832,12 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
-       struct dso *dso = map->dso;
-       char *filename = dso__build_id_filename(dso, NULL, 0);
-       bool free_filename = true;
-+      const char *dso_name;
-       char command[PATH_MAX * 2];
-       FILE *file;
-       int err = 0;
-       char symfs_filename[PATH_MAX];
-+      char dso_namebuf[PATH_MAX];
-       if (filename) {
-               snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
-@@ -864,6 +867,11 @@ fallback:
-               free_filename = false;
-       }
-+      dso_name = perf_resolve_binary(filename, dso_namebuf, sizeof(dso_namebuf));
-+      if (dso_name == dso_namebuf)
-+              snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
-+                       symbol_conf.symfs, dso_name);
-+
-       if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) {
-               char bf[BUILD_ID_SIZE * 2 + 16] = " with build id ";
-               char *build_id_msg = NULL;
-@@ -889,7 +897,7 @@ fallback:
-       }
-       pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
--               filename, sym->name, map->unmap_ip(map, sym->start),
-+               dso_name, sym->name, map->unmap_ip(map, sym->start),
-                map->unmap_ip(map, sym->end));
-       pr_debug("annotating [%p] %30s : [%p] %30s\n",
-@@ -899,14 +907,14 @@ fallback:
-                "%s %s%s --start-address=0x%016" PRIx64
-                " --stop-address=0x%016" PRIx64
-                " -d %s %s -C %s|grep -v %s|expand",
--               objdump_path ? objdump_path : "objdump",
-+               objdump_path ? objdump_path : "x86_64-ucb-akaros-objdump",
-                disassembler_style ? "-M " : "",
-                disassembler_style ? disassembler_style : "",
-                map__rip_2objdump(map, sym->start),
-                map__rip_2objdump(map, sym->end+1),
-                symbol_conf.annotate_asm_raw ? "" : "--no-show-raw",
-                symbol_conf.annotate_src ? "-S" : "",
--               symfs_filename, filename);
-+               symfs_filename, dso_name);
-       pr_debug("Executing: %s\n", command);
-diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
-index 4b12bf8..211972b 100644
---- a/tools/perf/util/symbol-elf.c
-+++ b/tools/perf/util/symbol-elf.c
-@@ -7,6 +7,7 @@
- #include "symbol.h"
- #include "debug.h"
-+#include "perf.h"
- #ifndef NT_GNU_BUILD_ID
- #define NT_GNU_BUILD_ID 3
-@@ -550,7 +551,7 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
-       Elf *elf;
-       int fd;
--      fd = open(name, O_RDONLY);
-+      fd = perf_open_binary(name, O_RDONLY, 0);
-       if (fd < 0)
-               return -1;
-@@ -624,6 +625,11 @@ out_close:
-       return err;
- }
-+static int dso__is_kernel_mmap(struct map *map)
-+{
-+      return map->start >= 0xffffffffc0000000;
-+}
-+
- int dso__load_sym(struct dso *dso, struct map *map,
-                 struct symsrc *syms_ss, struct symsrc *runtime_ss,
-                 symbol_filter_t filter, int kmodule)
-@@ -633,6 +639,7 @@ int dso__load_sym(struct dso *dso, struct map *map,
-       struct dso *curr_dso = dso;
-       Elf_Data *symstrs, *secstrs;
-       uint32_t nr_syms;
-+      int is_kernel_map = dso__is_kernel_mmap(map);
-       int err = -1;
-       uint32_t idx;
-       GElf_Ehdr ehdr;
-@@ -793,8 +800,9 @@ int dso__load_sym(struct dso *dso, struct map *map,
-                       goto new_symbol;
-               }
--              if ((used_opd && runtime_ss->adjust_symbols)
--                              || (!used_opd && syms_ss->adjust_symbols)) {
-+              if (!is_kernel_map &&
-+                  ((used_opd && runtime_ss->adjust_symbols)
-+                   || (!used_opd && syms_ss->adjust_symbols))) {
-                       pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " "
-                                 "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__,
-                                 (u64)sym.st_value, (u64)shdr.sh_addr,
index bb737df..361227c 100644 (file)
@@ -10,7 +10,7 @@ AKAROS_ROOT ?= $(BUILDDIR)/../../..
 MAKE_JOBS ?= 4
 KFS_ROOT ?= $(AKAROS_ROOT)/kern/kfs
 
-SOURCES = perf.c xlib.c perf_core.c akaros.c
+SOURCES = perf.c perfconv.c xlib.c perf_core.c akaros.c
 
 XCC = $(CROSS_COMPILE)gcc
 
index 77e6f53..969a81c 100644 (file)
@@ -17,6 +17,7 @@
 #include <parlib/parlib.h>
 #include "xlib.h"
 #include "akaros.h"
+#include "perfconv.h"
 #include "perf_core.h"
 
 static struct perf_context_config perf_cfg = {
@@ -27,7 +28,7 @@ static struct perf_context_config perf_cfg = {
 static void usage(const char *prg)
 {
        fprintf(stderr,
-                       "Use: %s {list,cpucaps,record} [-mkecxh] -- CMD [ARGS ...]\n"
+                       "Use: %s {list,cpucaps,record} [-mkecxoKh] -- CMD [ARGS ...]\n"
                        "\tlist            Lists all the available events and their meaning.\n"
                        "\tcpucaps         Shows the system CPU capabilities in term of "
                        "performance counters.\n"
@@ -50,6 +51,8 @@ static void usage(const char *prg)
                        "\t                 Examples: all:!3.4.7  0-15:!3.5.7\n"
                        "\t-x EVENT_RX      Sets the event name regular expression for "
                        "list.\n"
+                       "\t-o PATH          Sets the perf output file path ('perf.data').\n"
+                       "\t-K PATH          Sets the kprof data file path ('#kprof/kpdata').\n"
                        "\t-h               Displays this help screen.\n", prg,
                        perf_cfg.perf_file, perf_cfg.kpctl_file);
        exit(1);
@@ -104,11 +107,14 @@ int main(int argc, const char * const *argv)
 {
        int i, icmd = -1, num_events = 0;
        const char *cmd = argv[1], *show_rx = NULL;
+       const char *kpdata_file = "#kprof/kpdata", *outfile = "perf.data";
+       struct perfconv_context *cctx;
        struct perf_context *pctx;
        struct core_set cores;
        const char *events[MAX_CPU_EVENTS];
 
        ros_get_all_cores_set(&cores);
+       cctx = perfconv_create_context();
 
        for (i = 2; i < argc; i++) {
                if (!strcmp(argv[i], "-m")) {
@@ -131,6 +137,12 @@ int main(int argc, const char * const *argv)
                } else if (!strcmp(argv[i], "-c")) {
                        if (++i < argc)
                                ros_parse_cores(argv[i], &cores);
+               } else if (!strcmp(argv[i], "-o")) {
+                       if (++i < argc)
+                               outfile = argv[i];
+               } else if (!strcmp(argv[i], "-K")) {
+                       if (++i < argc)
+                               kpdata_file = argv[i];
                } else if (!strcmp(argv[i], "--")) {
                        icmd = i + 1;
                        break;
@@ -165,10 +177,21 @@ int main(int argc, const char * const *argv)
                        run_process_and_wait(argc - icmd, argv + icmd, &cores);
 
                perf_context_show_values(pctx, stdout);
+
+               /* Flush the profiler per-CPU trace data into the main queue, so that
+                * it will be available for read.
+                */
+               perf_flush_context_traces(pctx);
+
+               /* Generate the Linux perf file format with the traces which have been
+                * created during this operation.
+                */
+               perf_convert_trace_data(cctx, kpdata_file, outfile);
        } else {
                usage(argv[0]);
        }
        perf_free_context(pctx);
+       perfconv_free_context(cctx);
        perf_finalize();
 
        return 0;
index 06f2b25..f955263 100644 (file)
@@ -21,6 +21,7 @@
 #include <perfmon/err.h>
 #include <perfmon/pfmlib.h>
 #include "xlib.h"
+#include "perfconv.h"
 #include "akaros.h"
 #include "perf_core.h"
 
@@ -207,10 +208,10 @@ void perf_parse_event(const char *str, struct perf_eventsel *sel)
        ZERO_DATA(*sel);
        sel->eidx = -1;
        sel->ev.flags = 0;
-       sel->ev.u.v = 0;
-       sel->ev.u.b.os = 1;
-       sel->ev.u.b.usr = 1;
-       sel->ev.u.b.en = 1;
+       sel->ev.event = 0;
+       PMEV_SET_OS(sel->ev.event, 1);
+       PMEV_SET_USR(sel->ev.event, 1);
+       PMEV_SET_EN(sel->ev.event, 1);
        if (isdigit(*tok)) {
                ev = strchr(tok, ':');
                if (ev == NULL) {
@@ -219,8 +220,8 @@ void perf_parse_event(const char *str, struct perf_eventsel *sel)
                        exit(1);
                }
                *ev++ = 0;
-               sel->ev.u.b.event = (uint8_t) strtoul(tok, NULL, 0);
-               sel->ev.u.b.mask = (uint8_t) strtoul(ev, NULL, 0);
+               PMEV_SET_EVENT(sel->ev.event, (uint8_t) strtoul(tok, NULL, 0));
+               PMEV_SET_MASK(sel->ev.event, (uint8_t) strtoul(ev, NULL, 0));
        } else {
                uint32_t event, mask;
 
@@ -229,28 +230,30 @@ void perf_parse_event(const char *str, struct perf_eventsel *sel)
                        fprintf(stderr, "Unable to find event: %s\n", tok);
                        exit(1);
                }
-               sel->ev.u.b.event = (uint8_t) event;
-               sel->ev.u.b.mask = (uint8_t) mask;
+               PMEV_SET_EVENT(sel->ev.event, (uint8_t) event);
+               PMEV_SET_MASK(sel->ev.event, (uint8_t) mask);
        }
        while ((tok = strtok_r(NULL, ",", &sptr)) != NULL) {
                ev = strchr(tok, '=');
                if (ev)
                        *ev++ = 0;
                if (!strcmp(tok, "os")) {
-                       sel->ev.u.b.os = (ev == NULL || atoi(ev) != 0) ? 1 : 0;
+                       PMEV_SET_OS(sel->ev.event, (ev == NULL || atoi(ev) != 0) ? 1 : 0);
                } else if (!strcmp(tok, "usr")) {
-                       sel->ev.u.b.usr = (ev == NULL || atoi(ev) != 0) ? 1 : 0;
+                       PMEV_SET_USR(sel->ev.event, (ev == NULL || atoi(ev) != 0) ? 1 : 0);
                } else if (!strcmp(tok, "int")) {
-                       sel->ev.u.b.inten = (ev == NULL || atoi(ev) != 0) ? 1 : 0;
+                       PMEV_SET_INTEN(sel->ev.event,
+                                                  (ev == NULL || atoi(ev) != 0) ? 1 : 0);
                } else if (!strcmp(tok, "invcmsk")) {
-                       sel->ev.u.b.invcmsk = (ev == NULL || atoi(ev) != 0) ? 1 : 0;
+                       PMEV_SET_INVCMSK(sel->ev.event,
+                                                        (ev == NULL || atoi(ev) != 0) ? 1 : 0);
                } else if (!strcmp(tok, "cmask")) {
                        if (ev == NULL) {
                                fprintf(stderr, "Invalid event spec string: '%s'\n"
                                                "\tShould be: %s\n", str, event_spec);
                                exit(1);
                        }
-                       sel->ev.u.b.cmask = (uint32_t) strtoul(ev, NULL, 0);
+                       PMEV_SET_CMASK(sel->ev.event, (uint32_t) strtoul(ev, NULL, 0));
                } else if (!strcmp(tok, "icount")) {
                        if (ev == NULL) {
                                fprintf(stderr, "Invalid event spec string: '%s'\n"
@@ -260,7 +263,7 @@ void perf_parse_event(const char *str, struct perf_eventsel *sel)
                        sel->ev.trigger_count = (uint64_t) strtoul(ev, NULL, 0);
                }
        }
-       if (sel->ev.u.b.inten && !sel->ev.trigger_count) {
+       if (PMEV_GET_INTEN(sel->ev.event) && !sel->ev.trigger_count) {
                fprintf(stderr,
                                "Counter trigger count for interrupt is too small: %lu\n",
                                sel->ev.trigger_count);
@@ -298,7 +301,7 @@ static int perf_open_event(int perf_fd, const struct core_set *cores,
        int i, j;
 
        *wptr++ = PERFMON_CMD_COUNTER_OPEN;
-       wptr = put_le_u64(wptr, sel->ev.u.v);
+       wptr = put_le_u64(wptr, sel->ev.event);
        wptr = put_le_u64(wptr, sel->ev.flags);
        wptr = put_le_u64(wptr, sel->ev.trigger_count);
 
@@ -345,7 +348,7 @@ static uint64_t *perf_get_event_values(int perf_fd, int ped,
                exit(1);
        }
 
-       rptr = get_le_u64(rptr, &sel->ev.u.v);
+       rptr = get_le_u64(rptr, &sel->ev.event);
        rptr = get_le_u64(rptr, &sel->ev.flags);
        rptr = get_le_u64(rptr, &sel->ev.trigger_count);
        rptr = get_le_u32(rptr, &n);
@@ -389,6 +392,13 @@ static void perf_disable_sampling(int kpctl_fd)
        xwrite(kpctl_fd, disable_str, strlen(disable_str));
 }
 
+static void perf_flush_sampling(int kpctl_fd)
+{
+       static const char * const flush_str = "flush";
+
+       xwrite(kpctl_fd, flush_str, strlen(flush_str));
+}
+
 struct perf_context *perf_create_context(const struct perf_context_config *cfg)
 {
        struct perf_context *pctx = xzmalloc(sizeof(struct perf_context));
@@ -411,6 +421,11 @@ void perf_free_context(struct perf_context *pctx)
        free(pctx);
 }
 
+void perf_flush_context_traces(struct perf_context *pctx)
+{
+       perf_flush_sampling(pctx->kpctl_fd);
+}
+
 void perf_context_event_submit(struct perf_context *pctx,
                                                           const struct core_set *cores,
                                                           const struct perf_eventsel *sel)
@@ -604,15 +619,85 @@ void perf_get_event_string(const struct perf_eventsel *sel, char *sbuf,
     einfo.size = sizeof(einfo);
        if ((sel->eidx >= 0) &&
                (pfm_get_event_info(sel->eidx, PFM_OS_NONE, &einfo) == PFM_SUCCESS)) {
-               const char *mask_name = perf_get_event_mask_name(&einfo,
-                                                                                                                sel->ev.u.b.mask);
+               const char *mask_name =
+                       perf_get_event_mask_name(&einfo, PMEV_GET_MASK(sel->ev.event));
 
                if (mask_name)
                        snprintf(sbuf, size, "%s:%s", einfo.name, mask_name);
                else
                        snprintf(sbuf, size, "%s", einfo.name);
        } else {
-               snprintf(sbuf, size, "0x%02x:0x%02x", sel->ev.u.b.event,
-                                sel->ev.u.b.mask);
+               snprintf(sbuf, size, "0x%02x:0x%02x",
+                                (int) PMEV_GET_EVENT(sel->ev.event),
+                                (int) PMEV_GET_MASK(sel->ev.event));
+       }
+}
+
+void perf_make_eventsel_from_event_mask(struct perf_eventsel *sel,
+                                                                               uint32_t event, uint32_t mask)
+{
+       ZERO_DATA(*sel);
+       PMEV_SET_EVENT(sel->ev.event, (uint8_t) event);
+       PMEV_SET_MASK(sel->ev.event, (uint8_t) mask);
+       sel->eidx = perf_find_event_by_id(event, mask);
+}
+
+static bool perf_get_kernel_elf_path(char *path, size_t psize, size_t *ksize)
+{
+       bool got_path = FALSE, got_size = FALSE;
+       FILE *bfile;
+       char *ptr;
+       char lnbuf[1024];
+
+       bfile = fopen("/etc/build.info", "r");
+       if (bfile) {
+               while (fgets(lnbuf, sizeof(lnbuf) - 1, bfile)) {
+                       for (ptr = lnbuf + strlen(lnbuf); (ptr > lnbuf) &&
+                                        strchr(" \t\r\n", ptr[-1]); ptr--)
+                               ptr[-1] = '\0';
+                       if (!strncmp(lnbuf, "KernelPath:", 11)) {
+                               for (ptr = lnbuf + 11; *ptr && strchr(" \t", *ptr); ptr++)
+                                       ;
+                               if (*ptr) {
+                                       strncpy(path, ptr, psize);
+                                       path[psize - 1] = '\0';
+                                       got_path = TRUE;
+                               }
+                       } else if (!strncmp(lnbuf, "KernelSize:", 11)) {
+                               for (ptr = lnbuf + 11; *ptr && strchr(" \t", *ptr); ptr++)
+                                       ;
+                               if (*ptr && isxdigit(*ptr)) {
+                                       *ksize = (size_t) strtoul(ptr, NULL, 0);
+                                       got_size = TRUE;
+                               }
+                       }
+               }
+               fclose(bfile);
+       }
+
+       return got_path && got_size;
+}
+
+void perf_convert_trace_data(struct perfconv_context *cctx, const char *input,
+                                                        const char *output)
+{
+       FILE *infile, *outfile;
+       size_t ksize;
+       char kpath[1024];
+
+       infile = xfopen(input, "rb");
+       if (xfsize(infile) > 0) {
+               outfile = xfopen(output, "wb");
+
+               if (perf_get_kernel_elf_path(kpath, sizeof(kpath), &ksize))
+                       perfconv_add_kernel_mmap(kpath, ksize, cctx);
+               else
+                       fprintf(stderr, "Unable to fetch kernel build information!\n"
+                                       "Kernel traces will be missing symbol information.\n");
+
+               perfconv_process_input(cctx, infile, outfile);
+
+               fclose(outfile);
        }
+       fclose(infile);
 }
index 6dfbd5d..40ad881 100644 (file)
@@ -13,6 +13,7 @@
 #include <stdio.h>
 #include <limits.h>
 #include "akaros.h"
+#include "perfconv.h"
 
 #define MAX_CPU_EVENTS 256
 
@@ -54,6 +55,7 @@ void perf_finalize(void);
 void perf_parse_event(const char *str, struct perf_eventsel *sel);
 struct perf_context *perf_create_context(const struct perf_context_config *cfg);
 void perf_free_context(struct perf_context *pctx);
+void perf_flush_context_traces(struct perf_context *pctx);
 void perf_context_event_submit(struct perf_context *pctx,
                                                           const struct core_set *cores,
                                                           const struct perf_eventsel *sel);
@@ -61,6 +63,10 @@ void perf_context_show_values(struct perf_context *pctx, FILE *file);
 void perf_show_events(const char *rx, FILE *file);
 void perf_get_event_string(const struct perf_eventsel *sel, char *sbuf,
                                                   size_t size);
+void perf_make_eventsel_from_event_mask(struct perf_eventsel *sel,
+                                                                               uint32_t event, uint32_t mask);
+void perf_convert_trace_data(struct perfconv_context *cctx, const char *input,
+                                                        const char *output);
 
 static inline const struct perf_arch_info *perf_context_get_arch_info(
        const struct perf_context *pctx)
diff --git a/tools/profile/perf/perf_format.h b/tools/profile/perf/perf_format.h
new file mode 100644 (file)
index 0000000..474cd61
--- /dev/null
@@ -0,0 +1,528 @@
+/* Copyright (c) 2015 Google Inc
+ * Davide Libenzi <dlibenzi@google.com>
+ * See LICENSE for details.
+ *
+ * Parts of this file come, either directly, or as baseline, from the Linux
+ * kernel source file:
+ *
+ *      tools/perf/util/header.h
+ *
+ * Such file is ruled by the general Linux kernel copyright.
+ */
+
+#pragma once
+
+#define BITS_PER_LONG (8 * sizeof(long))
+#define BITS_TO_LONGS(bits) (((bits) + BITS_PER_LONG - 1) / BITS_PER_LONG)
+#define DECLARE_BITMAP(name, bits)                             \
+       unsigned long name[BITS_TO_LONGS(bits)]
+
+enum {
+       HEADER_RESERVED         = 0,    /* Always cleared */
+       HEADER_FIRST_FEATURE    = 1,
+       HEADER_TRACING_DATA     = 1,
+       HEADER_BUILD_ID,
+
+       HEADER_HOSTNAME,
+       HEADER_OSRELEASE,
+       HEADER_VERSION,
+       HEADER_ARCH,
+       HEADER_NRCPUS,
+       HEADER_CPUDESC,
+       HEADER_CPUID,
+       HEADER_TOTAL_MEM,
+       HEADER_CMDLINE,
+       HEADER_EVENT_DESC,
+       HEADER_CPU_TOPOLOGY,
+       HEADER_NUMA_TOPOLOGY,
+       HEADER_BRANCH_STACK,
+       HEADER_PMU_MAPPINGS,
+       HEADER_GROUP_DESC,
+       HEADER_LAST_FEATURE,
+       HEADER_FEAT_BITS        = 256,
+};
+
+/*
+ * Bits that can be set in attr.sample_type to request information
+ * in the overflow packets.
+ */
+enum perf_event_sample_format {
+       PERF_SAMPLE_IP                          = 1U << 0,
+       PERF_SAMPLE_TID                         = 1U << 1,
+       PERF_SAMPLE_TIME                        = 1U << 2,
+       PERF_SAMPLE_ADDR                        = 1U << 3,
+       PERF_SAMPLE_READ                        = 1U << 4,
+       PERF_SAMPLE_CALLCHAIN                   = 1U << 5,
+       PERF_SAMPLE_ID                          = 1U << 6,
+       PERF_SAMPLE_CPU                         = 1U << 7,
+       PERF_SAMPLE_PERIOD                      = 1U << 8,
+       PERF_SAMPLE_STREAM_ID                   = 1U << 9,
+       PERF_SAMPLE_RAW                         = 1U << 10,
+       PERF_SAMPLE_BRANCH_STACK                = 1U << 11,
+       PERF_SAMPLE_REGS_USER                   = 1U << 12,
+       PERF_SAMPLE_STACK_USER                  = 1U << 13,
+       PERF_SAMPLE_WEIGHT                      = 1U << 14,
+       PERF_SAMPLE_DATA_SRC                    = 1U << 15,
+       PERF_SAMPLE_IDENTIFIER                  = 1U << 16,
+       PERF_SAMPLE_TRANSACTION                 = 1U << 17,
+       PERF_SAMPLE_REGS_INTR                   = 1U << 18,
+
+       PERF_SAMPLE_MAX = 1U << 19,             /* non-ABI */
+};
+
+enum perf_event_type {
+       /*
+        * If perf_event_attr.sample_id_all is set then all event types will
+        * have the sample_type selected fields related to where/when
+        * (identity) an event took place (TID, TIME, ID, STREAM_ID, CPU,
+        * IDENTIFIER) described in PERF_RECORD_SAMPLE below, it will be stashed
+        * just after the perf_event_header and the fields already present for
+        * the existing fields, i.e. at the end of the payload. That way a newer
+        * perf.data file will be supported by older perf tools, with these new
+        * optional fields being ignored.
+        *
+        * struct sample_id {
+        *      { u32                   pid, tid; } && PERF_SAMPLE_TID
+        *      { u64                   time;     } && PERF_SAMPLE_TIME
+        *      { u64                   id;               } && PERF_SAMPLE_ID
+        *      { u64                   stream_id;} && PERF_SAMPLE_STREAM_ID
+        *      { u32                   cpu, res; } && PERF_SAMPLE_CPU
+        *      { u64                   id;       } && PERF_SAMPLE_IDENTIFIER
+        * } && perf_event_attr::sample_id_all
+        *
+        * Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID.  The
+        * advantage of PERF_SAMPLE_IDENTIFIER is that its position is fixed
+        * relative to header.size.
+        */
+
+       /*
+        * The MMAP events record the PROT_EXEC mappings so that we can
+        * correlate userspace IPs to code. They have the following structure:
+        *
+        * struct {
+        *      struct perf_event_header        header;
+        *
+        *      u32                             pid, tid;
+        *      u64                             addr;
+        *      u64                             len;
+        *      u64                             pgoff;
+        *      char                            filename[];
+        * };
+        */
+       PERF_RECORD_MMAP                        = 1,
+
+       /*
+        * struct {
+        *      struct perf_event_header        header;
+        *      u64                             id;
+        *      u64                             lost;
+        *      struct sample_id                sample_id;
+        * };
+        */
+       PERF_RECORD_LOST                        = 2,
+
+       /*
+        * struct {
+        *      struct perf_event_header        header;
+        *
+        *      u32                             pid, tid;
+        *      char                            comm[];
+        *      struct sample_id                sample_id;
+        * };
+        */
+       PERF_RECORD_COMM                        = 3,
+
+       /*
+        * struct {
+        *      struct perf_event_header        header;
+        *      u32                             pid, ppid;
+        *      u32                             tid, ptid;
+        *      u64                             time;
+        *      struct sample_id                sample_id;
+        * };
+        */
+       PERF_RECORD_EXIT                        = 4,
+
+       /*
+        * struct {
+        *      struct perf_event_header        header;
+        *      u64                             time;
+        *      u64                             id;
+        *      u64                             stream_id;
+        *      struct sample_id                sample_id;
+        * };
+        */
+       PERF_RECORD_THROTTLE                    = 5,
+       PERF_RECORD_UNTHROTTLE                  = 6,
+
+       /*
+        * struct {
+        *      struct perf_event_header        header;
+        *      u32                             pid, ppid;
+        *      u32                             tid, ptid;
+        *      u64                             time;
+        *      struct sample_id                sample_id;
+        * };
+        */
+       PERF_RECORD_FORK                        = 7,
+
+       /*
+        * struct {
+        *      struct perf_event_header        header;
+        *      u32                             pid, tid;
+        *
+        *      struct read_format              values;
+        *      struct sample_id                sample_id;
+        * };
+        */
+       PERF_RECORD_READ                        = 8,
+
+       /*
+        * struct {
+        *      struct perf_event_header        header;
+        *
+        *      #
+        *      # Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID.
+        *      # The advantage of PERF_SAMPLE_IDENTIFIER is that its position
+        *      # is fixed relative to header.
+        *      #
+        *
+        *      { u64                   id;       } && PERF_SAMPLE_IDENTIFIER
+        *      { u64                   ip;       } && PERF_SAMPLE_IP
+        *      { u32                   pid, tid; } && PERF_SAMPLE_TID
+        *      { u64                   time;     } && PERF_SAMPLE_TIME
+        *      { u64                   addr;     } && PERF_SAMPLE_ADDR
+        *      { u64                   id;       } && PERF_SAMPLE_ID
+        *      { u64                   stream_id;} && PERF_SAMPLE_STREAM_ID
+        *      { u32                   cpu, res; } && PERF_SAMPLE_CPU
+        *      { u64                   period;   } && PERF_SAMPLE_PERIOD
+        *
+        *      { struct read_format    values;   } && PERF_SAMPLE_READ
+        *
+        *      { u64                   nr,
+        *        u64                   ips[nr];  } && PERF_SAMPLE_CALLCHAIN
+        *
+        *      #
+        *      # The RAW record below is opaque data wrt the ABI
+        *      #
+        *      # That is, the ABI doesn't make any promises wrt to
+        *      # the stability of its content, it may vary depending
+        *      # on event, hardware, kernel version and phase of
+        *      # the moon.
+        *      #
+        *      # In other words, PERF_SAMPLE_RAW contents are not an ABI.
+        *      #
+        *
+        *      { u32                   size;
+        *        char                                  data[size];}&& PERF_SAMPLE_RAW
+        *
+        *      { u64                                   nr;
+        *                { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK
+        *
+        *      { u64                   abi; # enum perf_sample_regs_abi
+        *        u64                   regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER
+        *
+        *      { u64                   size;
+        *        char                  data[size];
+        *        u64                   dyn_size; } && PERF_SAMPLE_STACK_USER
+        *
+        *      { u64                   weight;   } && PERF_SAMPLE_WEIGHT
+        *      { u64                   data_src; } && PERF_SAMPLE_DATA_SRC
+        *              { u64                                   transaction; } && PERF_SAMPLE_TRANSACTION
+        *      { u64                   abi; # enum perf_sample_regs_abi
+        *        u64                   regs[weight(mask)]; } && PERF_SAMPLE_REGS_INTR
+        * };
+        */
+       PERF_RECORD_SAMPLE                      = 9,
+
+       /*
+        * The MMAP2 records are an augmented version of MMAP, they add
+        * maj, min, ino numbers to be used to uniquely identify each mapping
+        *
+        * struct {
+        *      struct perf_event_header        header;
+        *
+        *      u32                             pid, tid;
+        *      u64                             addr;
+        *      u64                             len;
+        *      u64                             pgoff;
+        *      u32                             maj;
+        *      u32                             min;
+        *      u64                             ino;
+        *      u64                             ino_generation;
+        *      char                            filename[];
+        *      struct sample_id                sample_id;
+        * };
+        */
+       PERF_RECORD_MMAP2                       = 10,
+
+       PERF_RECORD_MAX,                        /* non-ABI */
+};
+
+#define PERF_MAX_STACK_DEPTH           127
+
+enum perf_callchain_context {
+       PERF_CONTEXT_HV                         = (__uint64_t) -32,
+       PERF_CONTEXT_KERNEL                     = (__uint64_t) -128,
+       PERF_CONTEXT_USER                       = (__uint64_t) -512,
+
+       PERF_CONTEXT_GUEST                      = (__uint64_t) -2048,
+       PERF_CONTEXT_GUEST_KERNEL       = (__uint64_t) -2176,
+       PERF_CONTEXT_GUEST_USER         = (__uint64_t) -2560,
+
+       PERF_CONTEXT_MAX                        = (__uint64_t) -4095,
+};
+
+/*
+ * attr.type
+ */
+enum perf_type_id {
+       PERF_TYPE_HARDWARE                                              = 0,
+       PERF_TYPE_SOFTWARE                                              = 1,
+       PERF_TYPE_TRACEPOINT                                    = 2,
+       PERF_TYPE_HW_CACHE                                              = 3,
+       PERF_TYPE_RAW                                                   = 4,
+       PERF_TYPE_BREAKPOINT                                    = 5,
+       PERF_TYPE_INTEL_CQM                                             = 6,
+
+       PERF_TYPE_MAX,                                                  /* non-ABI */
+};
+
+/*
+ * Generalized performance event event_id types, used by the
+ * attr.event_id parameter of the sys_perf_event_open()
+ * syscall:
+ */
+enum perf_hw_id {
+       /*
+        * Common hardware events, generalized by the kernel:
+        */
+       PERF_COUNT_HW_CPU_CYCLES                                = 0,
+       PERF_COUNT_HW_INSTRUCTIONS                              = 1,
+       PERF_COUNT_HW_CACHE_REFERENCES                  = 2,
+       PERF_COUNT_HW_CACHE_MISSES                              = 3,
+       PERF_COUNT_HW_BRANCH_INSTRUCTIONS               = 4,
+       PERF_COUNT_HW_BRANCH_MISSES                             = 5,
+       PERF_COUNT_HW_BUS_CYCLES                                = 6,
+       PERF_COUNT_HW_STALLED_CYCLES_FRONTEND   = 7,
+       PERF_COUNT_HW_STALLED_CYCLES_BACKEND    = 8,
+       PERF_COUNT_HW_REF_CPU_CYCLES                    = 9,
+
+       PERF_COUNT_HW_MAX,                                              /* non-ABI */
+};
+
+/*
+ * Hardware event_id to monitor via a performance monitoring event:
+ */
+struct perf_event_attr {
+       /*
+        * Major type: hardware/software/tracepoint/etc.
+        */
+       uint32_t type;
+
+       /*
+        * Size of the attr structure, for fwd/bwd compat.
+        */
+       uint32_t size;
+
+       /*
+        * Type specific configuration information.
+        */
+       uint64_t config;
+
+       union {
+               uint64_t sample_period;
+               uint64_t sample_freq;
+       };
+
+       uint64_t sample_type;
+       uint64_t read_format;
+
+       uint64_t disabled               :  1, /* off by default            */
+               inherit            :  1, /* children inherit it   */
+               pinned             :  1, /* must always be on PMU */
+               exclusive          :  1, /* only group on PMU     */
+               exclude_user   :  1, /* don't count user          */
+               exclude_kernel :  1, /* ditto kernel              */
+               exclude_hv         :  1, /* ditto hypervisor      */
+               exclude_idle   :  1, /* don't count when idle */
+               mmap               :  1, /* include mmap data     */
+               comm               :  1, /* include comm data     */
+               freq               :  1, /* use freq, not period  */
+               inherit_stat   :  1, /* per task counts           */
+               enable_on_exec :  1, /* next exec enables         */
+               task               :  1, /* trace fork/exit               */
+               watermark          :  1, /* wakeup_watermark      */
+       /*
+        * precise_ip:
+        *
+        *      0 - SAMPLE_IP can have arbitrary skid
+        *      1 - SAMPLE_IP must have constant skid
+        *      2 - SAMPLE_IP requested to have 0 skid
+        *      3 - SAMPLE_IP must have 0 skid
+        *
+        *      See also PERF_RECORD_MISC_EXACT_IP
+        */
+               precise_ip         :  2, /* skid constraint               */
+               mmap_data          :  1, /* non-exec mmap data    */
+               sample_id_all  :  1, /* sample_type all events */
+
+               exclude_host   :  1, /* don't count in host       */
+               exclude_guest  :  1, /* don't count in guest  */
+
+               exclude_callchain_kernel : 1, /* exclude kernel callchains */
+               exclude_callchain_user   : 1, /* exclude user callchains */
+               mmap2              :  1, /* include mmap with inode data         */
+
+               __reserved_1   : 40;
+
+       union {
+               uint32_t wakeup_events;   /* wakeup every n events */
+               uint32_t wakeup_watermark; /* bytes before wakeup       */
+       };
+
+       uint32_t bp_type;
+       union {
+               uint64_t bp_addr;
+               uint64_t config1; /* extension of config */
+       };
+       union {
+               uint64_t bp_len;
+               uint64_t config2; /* extension of config1 */
+       };
+       uint64_t branch_sample_type; /* enum perf_branch_sample_type */
+
+       /*
+        * Defines set of user regs to dump on samples.
+        * See asm/perf_regs.h for details.
+        */
+       uint64_t sample_regs_user;
+
+       /*
+        * Defines size of the user stack to dump on samples.
+        */
+       uint32_t sample_stack_user;
+
+       /* Align to u64. */
+       uint32_t __reserved_2;
+
+       /*
+        * Defines set of regs to dump for each sample
+        * state captured on:
+        *      - precise = 0: PMU interrupt
+        *      - precise > 0: sampled instruction
+        *
+        * See asm/perf_regs.h for details.
+        */
+       uint64_t sample_regs_intr;
+} __attribute__((packed));
+
+#define PERF_RECORD_MISC_CPUMODE_MASK          (7 << 0)
+#define PERF_RECORD_MISC_CPUMODE_UNKNOWN       (0 << 0)
+#define PERF_RECORD_MISC_KERNEL                        (1 << 0)
+#define PERF_RECORD_MISC_USER                  (2 << 0)
+#define PERF_RECORD_MISC_HYPERVISOR            (3 << 0)
+#define PERF_RECORD_MISC_GUEST_KERNEL          (4 << 0)
+#define PERF_RECORD_MISC_GUEST_USER            (5 << 0)
+
+#define PERF_RECORD_MISC_MMAP_DATA             (1 << 13)
+/*
+ * Indicates that the content of PERF_SAMPLE_IP points to
+ * the actual instruction that triggered the event. See also
+ * perf_event_attr::precise_ip.
+ */
+#define PERF_RECORD_MISC_EXACT_IP              (1 << 14)
+/*
+ * Reserve the last bit to indicate some extended misc field
+ */
+#define PERF_RECORD_MISC_EXT_RESERVED          (1 << 15)
+
+struct perf_event_header {
+       uint32_t type;
+       uint16_t misc;
+       uint16_t size;
+} __attribute__((packed));
+
+struct perf_file_section {
+       uint64_t offset;        /* Offset from start of file */
+       uint64_t size;          /* Size of the section */
+} __attribute__((packed));
+
+struct perf_header_string {
+       uint32_t len;
+       char string[0];         /* Zero terminated */
+};
+
+struct perf_header_string_list {
+       uint32_t nr;
+       struct perf_header_string strings[0];   /* Variable length records */
+};
+
+#define MAX_EVENT_NAME 64
+
+struct perf_trace_event_type {
+       uint64_t event_id;
+       char name[MAX_EVENT_NAME];
+};
+
+struct perf_file_attr {
+       struct perf_event_attr attr;
+       struct perf_file_section ids;
+};
+
+/* "PERFILE2"
+ */
+static const uint64_t PERF_MAGIC2 = 0x32454c4946524550ULL;
+
+struct perf_pipe_file_header {
+       uint64_t magic;                                 /* PERFILE2 */
+       uint64_t size;
+};
+
+struct perf_header {
+       uint64_t magic;                                 /* PERFILE2 */
+       uint64_t size;                                  /* Size of the header */
+       uint64_t attr_size;                             /* size of an attribute in attrs */
+       struct perf_file_section attrs;
+       struct perf_file_section data;
+       struct perf_file_section event_types;
+       DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
+} __attribute__((packed));
+
+/* For type PERF_RECORD_MMAP
+ */
+struct perf_record_mmap {
+       struct perf_event_header header;
+       uint32_t pid;
+       uint32_t tid;
+       uint64_t addr;
+       uint64_t len;
+       uint64_t pgoff;
+       char filename[0];
+} __attribute__((packed));
+
+/* For type PERF_RECORD_COMM
+ */
+struct perf_record_comm {
+       struct perf_event_header header;
+       uint32_t pid;
+       uint32_t tid;
+       char comm[0];
+} __attribute__((packed));
+
+/* For type PERF_RECORD_SAMPLE
+ * Configured with: PERF_SAMPLE_IP | PERF_SAMPLE_TID && PERF_SAMPLE_TIME &&
+ * PERF_SAMPLE_ADDR && PERF_SAMPLE_ID && PERF_SAMPLE_CPU &&
+ * PERF_SAMPLE_CALLCHAIN.
+ */
+struct perf_record_sample {
+       struct perf_event_header header;
+       uint64_t ip;
+       uint32_t pid, tid;
+       uint64_t time;
+       uint64_t addr;
+       uint64_t id;
+       uint32_t cpu, res;
+       uint64_t nr;
+       uint64_t ips[0];
+} __attribute__((packed));
diff --git a/tools/profile/perf/perf_patches/perf_patch.diff b/tools/profile/perf/perf_patches/perf_patch.diff
new file mode 100644 (file)
index 0000000..6d0d6da
--- /dev/null
@@ -0,0 +1,201 @@
+diff --git a/tools/perf/perf.c b/tools/perf/perf.c
+index 85e1aed..ecf04c1 100644
+--- a/tools/perf/perf.c
++++ b/tools/perf/perf.c
+@@ -15,9 +15,14 @@
+ #include "util/parse-events.h"
+ #include <lk/debugfs.h>
+ #include <pthread.h>
++#include <fcntl.h>
++#include <stdio.h>
++#include <errno.h>
++#include <string.h>
++#include <unistd.h>
+ const char perf_usage_string[] =
+-      "perf [--version] [--help] COMMAND [ARGS]";
++      "perf [--version] [--help] [--root-dir DIR] COMMAND [ARGS]";
+ const char perf_more_info_string[] =
+       "See 'perf help COMMAND' for more information on a specific command.";
+@@ -25,6 +30,7 @@ const char perf_more_info_string[] =
+ int use_browser = -1;
+ static int use_pager = -1;
+ const char *input_name;
++static const char *perf_root_dir;
+ struct cmd_struct {
+       const char *cmd;
+@@ -76,6 +82,28 @@ static int pager_command_config(const char *var, const char *value, void *data)
+       return 0;
+ }
++const char *perf_resolve_binary(const char *path, char *rpath, size_t max_size)
++{
++      snprintf(rpath, max_size, "%s/%s", perf_root_dir, path);
++
++      return access(rpath, F_OK) == 0 ? rpath: path;
++}
++
++int perf_open_binary(const char *path, int flags, int mode)
++{
++      if (perf_root_dir) {
++              int fd;
++              char rpath[4096];
++
++              snprintf(rpath, sizeof(rpath), "%s/%s", perf_root_dir, path);
++              fd = open(rpath, flags, mode);
++              if (fd >= 0)
++                      return fd;
++      }
++
++      return open(path, flags, mode);
++}
++
+ /* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
+ int check_pager_config(const char *cmd)
+ {
+@@ -199,6 +227,14 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
+                               *envchanged = 1;
+                       (*argv)++;
+                       (*argc)--;
++              } else if (!strcmp(cmd, "--root-dir")) {
++                      if (*argc < 2) {
++                              fprintf(stderr, "No directory given for --root-dir.\n");
++                              usage(perf_usage_string);
++                      }
++                      perf_root_dir = (*argv)[1];
++                      (*argv)++;
++                      (*argc)--;
+               } else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) {
+                       perf_debugfs_set_path(cmd + strlen(CMD_DEBUGFS_DIR));
+                       fprintf(stderr, "dir: %s\n", debugfs_mountpoint);
+diff --git a/tools/perf/perf.h b/tools/perf/perf.h
+index 32bd102..36c34f3 100644
+--- a/tools/perf/perf.h
++++ b/tools/perf/perf.h
+@@ -198,6 +198,8 @@ extern bool perf_host, perf_guest;
+ extern const char perf_version_string[];
+ void pthread__unblock_sigwinch(void);
++const char *perf_resolve_binary(const char *path, char *rpath, size_t max_size);
++int perf_open_binary(const char *path, int flags, int mode);
+ #include "util/target.h"
+diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
+index d102716..65260ba 100644
+--- a/tools/perf/util/annotate.c
++++ b/tools/perf/util/annotate.c
+@@ -15,6 +15,7 @@
+ #include "debug.h"
+ #include "annotate.h"
+ #include "evsel.h"
++#include "perf.h"
+ #include <pthread.h>
+ #include <linux/bitops.h>
+@@ -831,10 +832,12 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
+       struct dso *dso = map->dso;
+       char *filename = dso__build_id_filename(dso, NULL, 0);
+       bool free_filename = true;
++      const char *dso_name;
+       char command[PATH_MAX * 2];
+       FILE *file;
+       int err = 0;
+       char symfs_filename[PATH_MAX];
++      char dso_namebuf[PATH_MAX];
+       if (filename) {
+               snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
+@@ -864,6 +867,11 @@ fallback:
+               free_filename = false;
+       }
++      dso_name = perf_resolve_binary(filename, dso_namebuf, sizeof(dso_namebuf));
++      if (dso_name == dso_namebuf)
++              snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
++                       symbol_conf.symfs, dso_name);
++
+       if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) {
+               char bf[BUILD_ID_SIZE * 2 + 16] = " with build id ";
+               char *build_id_msg = NULL;
+@@ -889,7 +897,7 @@ fallback:
+       }
+       pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
+-               filename, sym->name, map->unmap_ip(map, sym->start),
++               dso_name, sym->name, map->unmap_ip(map, sym->start),
+                map->unmap_ip(map, sym->end));
+       pr_debug("annotating [%p] %30s : [%p] %30s\n",
+@@ -899,14 +907,14 @@ fallback:
+                "%s %s%s --start-address=0x%016" PRIx64
+                " --stop-address=0x%016" PRIx64
+                " -d %s %s -C %s|grep -v %s|expand",
+-               objdump_path ? objdump_path : "objdump",
++               objdump_path ? objdump_path : "x86_64-ucb-akaros-objdump",
+                disassembler_style ? "-M " : "",
+                disassembler_style ? disassembler_style : "",
+                map__rip_2objdump(map, sym->start),
+                map__rip_2objdump(map, sym->end+1),
+                symbol_conf.annotate_asm_raw ? "" : "--no-show-raw",
+                symbol_conf.annotate_src ? "-S" : "",
+-               symfs_filename, filename);
++               symfs_filename, dso_name);
+       pr_debug("Executing: %s\n", command);
+diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
+index 4b12bf8..211972b 100644
+--- a/tools/perf/util/symbol-elf.c
++++ b/tools/perf/util/symbol-elf.c
+@@ -7,6 +7,7 @@
+ #include "symbol.h"
+ #include "debug.h"
++#include "perf.h"
+ #ifndef NT_GNU_BUILD_ID
+ #define NT_GNU_BUILD_ID 3
+@@ -550,7 +551,7 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
+       Elf *elf;
+       int fd;
+-      fd = open(name, O_RDONLY);
++      fd = perf_open_binary(name, O_RDONLY, 0);
+       if (fd < 0)
+               return -1;
+@@ -624,6 +625,11 @@ out_close:
+       return err;
+ }
++static int dso__is_kernel_mmap(struct map *map)
++{
++      return map->start >= 0xffffffffc0000000;
++}
++
+ int dso__load_sym(struct dso *dso, struct map *map,
+                 struct symsrc *syms_ss, struct symsrc *runtime_ss,
+                 symbol_filter_t filter, int kmodule)
+@@ -633,6 +639,7 @@ int dso__load_sym(struct dso *dso, struct map *map,
+       struct dso *curr_dso = dso;
+       Elf_Data *symstrs, *secstrs;
+       uint32_t nr_syms;
++      int is_kernel_map = dso__is_kernel_mmap(map);
+       int err = -1;
+       uint32_t idx;
+       GElf_Ehdr ehdr;
+@@ -793,8 +800,9 @@ int dso__load_sym(struct dso *dso, struct map *map,
+                       goto new_symbol;
+               }
+-              if ((used_opd && runtime_ss->adjust_symbols)
+-                              || (!used_opd && syms_ss->adjust_symbols)) {
++              if (!is_kernel_map &&
++                  ((used_opd && runtime_ss->adjust_symbols)
++                   || (!used_opd && syms_ss->adjust_symbols))) {
+                       pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " "
+                                 "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__,
+                                 (u64)sym.st_value, (u64)shdr.sh_addr,
diff --git a/tools/profile/perf/perfconv.c b/tools/profile/perf/perfconv.c
new file mode 100644 (file)
index 0000000..bcd3f69
--- /dev/null
@@ -0,0 +1,599 @@
+/* Copyright (c) 2015 Google Inc
+ * Davide Libenzi <dlibenzi@google.com>
+ * See LICENSE for details.
+ *
+ * Converts kprof profiler files into Linux perf ones. The Linux Perf file
+ * format has bee illustrated here:
+ *
+ *      https://lwn.net/Articles/644919/
+ *      https://openlab-mu-internal.web.cern.ch/openlab-mu-internal/03_Documents/
+ *                      3_Technical_Documents/Technical_Reports/2011/Urs_Fassler_report.pdf
+ *
+ */
+
+#include <ros/common.h>
+#include <ros/memops.h>
+#include <ros/profiler_records.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <stdarg.h>
+#include "perf_format.h"
+#include "xlib.h"
+#include "perf_core.h"
+#include "perfconv.h"
+
+#define MAX_PERF_RECORD_SIZE (32 * 1024 * 1024)
+#define PERF_RECORD_BUFFER_SIZE 1024
+#define OFFSET_NORELOC ((uint64_t) -1)
+#define MEMFILE_BLOCK_SIZE (64 * 1024)
+
+#define MBWR_SOLID (1 << 0)
+
+struct perf_record {
+       uint64_t type;
+       uint64_t size;
+       char *data;
+       char buffer[PERF_RECORD_BUFFER_SIZE];
+};
+
+static void dbg_print(struct perfconv_context *cctx, int level, FILE *file,
+                                         const char *fmt, ...)
+{
+       if (cctx->debug_level >= level) {
+               va_list args;
+
+               va_start(args, fmt);
+               vfprintf(file, fmt, args);
+               va_end(args);
+       }
+}
+
+void perfconv_set_dbglevel(int level, struct perfconv_context *cctx)
+{
+       cctx->debug_level = level;
+}
+
+static void free_record(struct perf_record *pr)
+{
+       if (pr->data != pr->buffer)
+               free(pr->data);
+       pr->data = NULL;
+}
+
+static int read_record(FILE *file, struct perf_record *pr)
+{
+       if (vb_fdecode_uint64(file, &pr->type) == EOF ||
+               vb_fdecode_uint64(file, &pr->size) == EOF)
+               return EOF;
+       if (pr->size > MAX_PERF_RECORD_SIZE) {
+               fprintf(stderr, "Invalid record size: type=%lu size=%lu\n", pr->type,
+                               pr->size);
+               exit(1);
+       }
+       if (pr->size > sizeof(pr->buffer))
+               pr->data = xmalloc((size_t) pr->size);
+       else
+               pr->data = pr->buffer;
+       if (fread(pr->data, 1, (size_t) pr->size, file) != (size_t) pr->size) {
+               fprintf(stderr, "Unable to read record memory: size=%lu\n",
+                               pr->size);
+               return EOF;
+       }
+
+       return 0;
+}
+
+static struct mem_block *mem_block_alloc(struct mem_file *mf, size_t size)
+{
+       struct mem_block *mb = xmem_arena_alloc(mf->ma,
+                                                                                       sizeof(struct mem_block) + size);
+
+       mb->next = NULL;
+       mb->base = mb->wptr = (char *) mb + sizeof(struct mem_block);
+       mb->top = mb->base + size;
+
+       return mb;
+}
+
+static char *mem_block_write(struct mem_block *mb, const void *data,
+                                                        size_t size)
+{
+       char *wrbase = mb->wptr;
+
+       always_assert(size <= mb->top - mb->wptr);
+
+       memcpy(mb->wptr, data, size);
+       mb->wptr += size;
+
+       return wrbase;
+}
+
+static void mem_file_init(struct mem_file *mf, struct mem_arena *ma)
+{
+       ZERO_DATA(*mf);
+       mf->ma = ma;
+}
+
+static int mem_block_can_write(struct mem_block *mb, size_t size, int flags)
+{
+       size_t space = mb->top - mb->wptr;
+
+       return (flags & MBWR_SOLID) ? (space >= size) : (space > 0);
+}
+
+static void *mem_file_write(struct mem_file *mf, const void *data, size_t size,
+                                                       int flags)
+{
+       void *wrbase = NULL;
+
+       while (size > 0) {
+               size_t space, csize;
+               struct mem_block *mb = mf->tail;
+
+               if (!mb || !mem_block_can_write(mb, size, flags)) {
+                       mb = mem_block_alloc(mf, max(MEMFILE_BLOCK_SIZE, size));
+                       if (!mf->tail)
+                               mf->head = mb;
+                       else
+                               mf->tail->next = mb;
+                       mf->tail = mb;
+               }
+               space = mb->top - mb->wptr;
+               csize = min(size, space);
+
+               wrbase = mem_block_write(mb, data, csize);
+               mf->size += csize;
+
+               size -= csize;
+               data = (const char *) data + csize;
+       }
+
+       return wrbase;
+}
+
+static void mem_file_sync(struct mem_file *mf, FILE *file, uint64_t rel_offset)
+{
+       struct mem_block *mb;
+
+       if (rel_offset != 0) {
+               struct mem_file_reloc *rel;
+
+               always_assert(!mf->relocs || rel_offset != OFFSET_NORELOC);
+
+               for (rel = mf->relocs; rel; rel = rel->next)
+                       *rel->ptr += rel_offset;
+       }
+
+       for (mb = mf->head; mb; mb = mb->next)
+               xfwrite(mb->base, mb->wptr - mb->base, file);
+}
+
+static struct mem_file_reloc *mem_file_add_reloc(struct mem_file *mf,
+                                                                                                uint64_t *ptr)
+{
+       struct mem_file_reloc *rel =
+               xmem_arena_zalloc(mf->ma, sizeof(struct mem_file_reloc));
+
+       rel->ptr = ptr;
+       rel->next = mf->relocs;
+       mf->relocs = rel;
+
+       return rel;
+}
+
+static uint64_t perfconv_make_config_id(bool is_raw, uint64_t type,
+                                                                               uint64_t event_id)
+{
+       uint64_t config = is_raw ? (uint64_t) 1 << 63 : 0;
+
+       return config | (type << 56) | (event_id & (((uint64_t) 1 << 56) - 1));
+}
+
+static uint64_t perfconv_get_config_type(uint64_t config)
+{
+       return (config >> 56) & 0x7f;
+}
+
+static void add_static_mmap(const char *path, uint64_t addr, uint64_t offset,
+                                                       uint64_t size, uint32_t pid,
+                                                       struct perfconv_context *cctx)
+{
+       struct static_mmap64 *mm;
+       struct stat stb;
+
+       if (size == 0) {
+               if (stat(path, &stb)) {
+                       fprintf(stderr, "Unable to stat mmapped file '%s': %s\n",
+                                       path, strerror(errno));
+                       exit(1);
+               }
+               size = (uint64_t) stb.st_size;
+       }
+
+       mm = xmem_arena_zalloc(&cctx->ma, sizeof(struct static_mmap64));
+       mm->pid = pid;
+       mm->addr = addr;
+       mm->size = size;
+       mm->offset = offset;
+       mm->path = xmem_arena_strdup(&cctx->ma, path);
+
+       mm->next = cctx->static_mmaps;
+       cctx->static_mmaps = mm;
+}
+
+void perfconv_add_kernel_mmap(const char *path, size_t ksize,
+                                                         struct perfconv_context *cctx)
+{
+       add_static_mmap(path, cctx->kernel_load_address, cctx->kernel_load_address,
+                                       (uint64_t) ksize, 0, cctx);
+}
+
+static void headers_init(struct perf_headers *hdrs)
+{
+       ZERO_DATA(*hdrs);
+}
+
+static void headers_add_header(struct perf_headers *hdrs, size_t nhdr,
+                                                          struct mem_block *mb)
+{
+       always_assert(nhdr < HEADER_FEAT_BITS);
+
+       hdrs->headers[nhdr] = mb;
+}
+
+static void headers_write(struct perf_headers *hdrs, struct perf_header *ph,
+                                                 struct mem_file *mf)
+{
+       size_t i;
+
+       for (i = 0; i < HEADER_FEAT_BITS; i++) {
+               struct mem_block *mb = hdrs->headers[i];
+
+               if (mb) {
+                       mem_file_write(mf, mb->base, mb->wptr - mb->base, 0);
+                       set_bitno(ph->adds_features, i);
+               }
+       }
+}
+
+static void perf_header_init(struct perf_header *ph)
+{
+       ZERO_DATA(*ph);
+       ph->magic = PERF_MAGIC2;
+       ph->size = sizeof(*ph);
+       ph->attr_size = sizeof(struct perf_event_attr);
+}
+
+static void add_attribute(struct mem_file *amf, struct mem_file *mmf,
+                                                 const struct perf_event_attr *attr,
+                                                 const uint64_t *ids, size_t nids)
+{
+       struct perf_file_section *psids;
+       struct perf_file_section sids;
+
+       mem_file_write(amf, attr, sizeof(*attr), 0);
+
+       sids.offset = mmf->size;
+       sids.size = nids * sizeof(uint64_t);
+
+       mem_file_write(mmf, ids, nids * sizeof(uint64_t), 0);
+
+       psids = mem_file_write(amf, &sids, sizeof(sids), MBWR_SOLID);
+
+       mem_file_add_reloc(amf, &psids->offset);
+}
+
+static void add_default_attribute(struct mem_file *amf, struct mem_file *mmf,
+                                                                 uint64_t config, uint64_t id)
+{
+       struct perf_event_attr attr;
+
+       ZERO_DATA(attr);
+       attr.type = (uint32_t) perfconv_get_config_type(config);
+       attr.size = sizeof(attr);
+       attr.config = config;
+       attr.mmap = 1;
+       attr.comm = 1;
+       attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME |
+               PERF_SAMPLE_ADDR | PERF_SAMPLE_ID | PERF_SAMPLE_CPU |
+               PERF_SAMPLE_CALLCHAIN;
+
+       add_attribute(amf, mmf, &attr, &id, 1);
+}
+
+static uint64_t perfconv_get_event_id(struct perfconv_context *cctx,
+                                                                         uint64_t info)
+{
+       size_t i, j, n, ipos;
+       uint64_t id, config;
+       struct perf_event_id *nevents;
+
+       for (;;) {
+               ipos = (size_t) (info % cctx->alloced_events);
+               for (i = cctx->alloced_events; (i > 0) &&
+                                (cctx->events[ipos].event != 0);
+                        i--, ipos = (ipos + 1) % cctx->alloced_events) {
+                       if (cctx->events[ipos].event == info)
+                               return cctx->events[ipos].id;
+               }
+               if (i != 0)
+                       break;
+               /* Need to resize the hash ...
+                */
+               n = 2 * cctx->alloced_events;
+               nevents = xmem_arena_zalloc(&cctx->ma, n * sizeof(*cctx->events));
+               for (i = 0; i < cctx->alloced_events; i++) {
+                       if (cctx->events[i].event == 0)
+                               continue;
+                       j = cctx->events[i].event % n;
+                       for (; nevents[j].event; j = (j + 1) % n)
+                               ;
+                       nevents[j].event = cctx->events[i].event;
+                       nevents[j].id = cctx->events[i].id;
+               }
+               cctx->alloced_events = n;
+               cctx->events = nevents;
+       }
+
+       cctx->events[ipos].event = info;
+       cctx->events[ipos].id = id = cctx->sqnr_id;
+       cctx->sqnr_id++;
+
+       switch ((int) PROF_INFO_DOM(info)) {
+       case PROF_DOM_PMU:
+               config = perfconv_make_config_id(TRUE, PERF_TYPE_RAW,
+                                                                                PROF_INFO_DATA(info));
+               break;
+       case PROF_DOM_TIMER:
+       default:
+               config = perfconv_make_config_id(FALSE, PERF_TYPE_HARDWARE,
+                                                                                PERF_COUNT_HW_CPU_CYCLES);
+       }
+
+       add_default_attribute(&cctx->attrs, &cctx->misc, config, id);
+
+       return id;
+}
+
+static void emit_static_mmaps(struct perfconv_context *cctx)
+{
+       struct static_mmap64 *mm;
+
+       for (mm = cctx->static_mmaps; mm; mm = mm->next) {
+               size_t size = sizeof(struct perf_record_mmap) + strlen(mm->path) + 1;
+               struct perf_record_mmap *xrec = xzmalloc(size);
+
+               xrec->header.type = PERF_RECORD_MMAP;
+               xrec->header.misc = PERF_RECORD_MISC_USER;
+               xrec->header.size = size;
+               xrec->pid = xrec->tid = mm->pid;
+               xrec->addr = mm->addr;
+               xrec->len = mm->size;
+               xrec->pgoff = mm->offset;
+               strcpy(xrec->filename, mm->path);
+
+               mem_file_write(&cctx->data, xrec, size, 0);
+
+               free(xrec);
+       }
+}
+
+static void emit_comm(uint32_t pid, const char *comm,
+                                         struct perfconv_context *cctx)
+{
+       size_t size = sizeof(struct perf_record_comm) + strlen(comm) + 1;
+       struct perf_record_comm *xrec = xzmalloc(size);
+
+       xrec->header.type = PERF_RECORD_COMM;
+       xrec->header.misc = PERF_RECORD_MISC_USER;
+       xrec->header.size = size;
+       xrec->pid = xrec->tid = pid;
+       strcpy(xrec->comm, comm);
+
+       mem_file_write(&cctx->data, xrec, size, 0);
+
+       free(xrec);
+}
+
+static void emit_pid_mmap64(struct perf_record *pr,
+                                                       struct perfconv_context *cctx)
+{
+       struct proftype_pid_mmap64 *rec = (struct proftype_pid_mmap64 *) pr->data;
+       size_t size = sizeof(struct perf_record_mmap) + strlen(rec->path) + 1;
+       struct perf_record_mmap *xrec = xzmalloc(size);
+
+       xrec->header.type = PERF_RECORD_MMAP;
+       xrec->header.misc = PERF_RECORD_MISC_USER;
+       xrec->header.size = size;
+       xrec->pid = xrec->tid = rec->pid;
+       xrec->addr = rec->addr;
+       xrec->len = rec->size;
+       xrec->pgoff = rec->offset;
+       strcpy(xrec->filename, rec->path);
+
+       mem_file_write(&cctx->data, xrec, size, 0);
+
+       free(xrec);
+}
+
+static void emit_kernel_trace64(struct perf_record *pr,
+                                                               struct perfconv_context *cctx)
+{
+       struct proftype_kern_trace64 *rec = (struct proftype_kern_trace64 *)
+               pr->data;
+       size_t size = sizeof(struct perf_record_sample) +
+               (rec->num_traces - 1) * sizeof(uint64_t);
+       struct perf_record_sample *xrec = xzmalloc(size);
+
+       xrec->header.type = PERF_RECORD_SAMPLE;
+       xrec->header.misc = PERF_RECORD_MISC_USER;
+       xrec->header.size = size;
+       xrec->ip = rec->trace[0];
+       xrec->time = rec->tstamp;
+       xrec->addr = rec->trace[0];
+       xrec->id = perfconv_get_event_id(cctx, rec->info);
+       xrec->cpu = rec->cpu;
+       xrec->nr = rec->num_traces - 1;
+       memcpy(xrec->ips, rec->trace + 1, (rec->num_traces - 1) * sizeof(uint64_t));
+
+       mem_file_write(&cctx->data, xrec, size, 0);
+
+       free(xrec);
+}
+
+static void emit_user_trace64(struct perf_record *pr,
+                                                         struct perfconv_context *cctx)
+{
+       struct proftype_user_trace64 *rec = (struct proftype_user_trace64 *)
+               pr->data;
+       size_t size = sizeof(struct perf_record_sample) +
+               (rec->num_traces - 1) * sizeof(uint64_t);
+       struct perf_record_sample *xrec = xzmalloc(size);
+
+       xrec->header.type = PERF_RECORD_SAMPLE;
+       xrec->header.misc = PERF_RECORD_MISC_USER;
+       xrec->header.size = size;
+       xrec->ip = rec->trace[0];
+       xrec->pid = xrec->tid = rec->pid;
+       xrec->time = rec->tstamp;
+       xrec->addr = rec->trace[0];
+       xrec->id = perfconv_get_event_id(cctx, rec->info);
+       xrec->cpu = rec->cpu;
+       xrec->nr = rec->num_traces - 1;
+       memcpy(xrec->ips, rec->trace + 1, (rec->num_traces - 1) * sizeof(uint64_t));
+
+       mem_file_write(&cctx->data, xrec, size, 0);
+
+       free(xrec);
+}
+
+static void emit_new_process(struct perf_record *pr,
+                                                        struct perfconv_context *cctx)
+{
+       struct proftype_new_process *rec = (struct proftype_new_process *) pr->data;
+       const char *comm = strrchr(rec->path, '/');
+
+       if (!comm)
+               comm = rec->path;
+       else
+               comm++;
+       emit_comm(rec->pid, comm, cctx);
+}
+
+static void add_event_type(struct mem_file *mf, uint64_t id, const char *name)
+{
+       struct perf_trace_event_type evt;
+
+       ZERO_DATA(evt);
+       evt.event_id = id;
+       strncpy(evt.name, name, sizeof(evt.name));
+       evt.name[sizeof(evt.name) - 1] = 0;
+
+       mem_file_write(mf, &evt, sizeof(evt), 0);
+}
+
+struct perfconv_context *perfconv_create_context(void)
+{
+       struct perfconv_context *cctx = xzmalloc(sizeof(struct perfconv_context));
+
+       xmem_arena_init(&cctx->ma, 0);
+       cctx->kernel_load_address = 0xffffffffc0000000;
+       cctx->alloced_events = 128;
+       cctx->events = xmem_arena_zalloc(
+               &cctx->ma, cctx->alloced_events * sizeof(*cctx->events));
+       perf_header_init(&cctx->ph);
+       headers_init(&cctx->hdrs);
+       mem_file_init(&cctx->fhdrs, &cctx->ma);
+       mem_file_init(&cctx->misc, &cctx->ma);
+       mem_file_init(&cctx->attrs, &cctx->ma);
+       mem_file_init(&cctx->data, &cctx->ma);
+       mem_file_init(&cctx->event_types, &cctx->ma);
+
+       emit_comm(0, "[kernel]", cctx);
+
+       return cctx;
+}
+
+void perfconv_free_context(struct perfconv_context *cctx)
+{
+       if (cctx) {
+               xmem_arena_destroy(&cctx->ma);
+               free(cctx);
+       }
+}
+
+void perfconv_process_input(struct perfconv_context *cctx, FILE *input,
+                                                       FILE *output)
+{
+       size_t processed_records = 0;
+       uint64_t offset, rel_offset;
+       struct perf_record pr;
+
+       emit_static_mmaps(cctx);
+
+       while (read_record(input, &pr) == 0) {
+               dbg_print(cctx, 8, stderr, "Valid record: type=%lu size=%lu\n",
+                                 pr.type, pr.size);
+
+               processed_records++;
+
+               switch (pr.type) {
+               case PROFTYPE_KERN_TRACE64:
+                       emit_kernel_trace64(&pr, cctx);
+                       break;
+               case PROFTYPE_USER_TRACE64:
+                       emit_user_trace64(&pr, cctx);
+                       break;
+               case PROFTYPE_PID_MMAP64:
+                       emit_pid_mmap64(&pr, cctx);
+                       break;
+               case PROFTYPE_NEW_PROCESS:
+                       emit_new_process(&pr, cctx);
+                       break;
+               default:
+                       fprintf(stderr, "Unknown record: type=%lu size=%lu\n", pr.type,
+                                       pr.size);
+                       processed_records--;
+               }
+
+               free_record(&pr);
+       }
+
+       headers_write(&cctx->hdrs, &cctx->ph, &cctx->fhdrs);
+       offset = sizeof(cctx->ph) + cctx->fhdrs.size + cctx->misc.size;
+
+       if (cctx->event_types.size > 0) {
+               cctx->ph.event_types.offset = offset;
+               cctx->ph.event_types.size = cctx->event_types.size;
+               offset += cctx->event_types.size;
+       }
+       if (cctx->attrs.size > 0) {
+               cctx->ph.attrs.offset = offset;
+               cctx->ph.attrs.size = cctx->attrs.size;
+               offset += cctx->attrs.size;
+       }
+       if (cctx->data.size > 0) {
+               cctx->ph.data.offset = offset;
+               cctx->ph.data.size = cctx->data.size;
+               offset += cctx->data.size;
+       }
+
+       xfwrite(&cctx->ph, sizeof(cctx->ph), output);
+       mem_file_sync(&cctx->fhdrs, output, OFFSET_NORELOC);
+
+       rel_offset = (uint64_t) ftell(output);
+       mem_file_sync(&cctx->misc, output, rel_offset);
+
+       mem_file_sync(&cctx->event_types, output, rel_offset);
+       mem_file_sync(&cctx->attrs, output, rel_offset);
+       mem_file_sync(&cctx->data, output, rel_offset);
+
+       dbg_print(cctx, 2, stderr, "Conversion succeeded: %lu records converted\n",
+                         processed_records);
+}
diff --git a/tools/profile/perf/perfconv.h b/tools/profile/perf/perfconv.h
new file mode 100644 (file)
index 0000000..946f7bd
--- /dev/null
@@ -0,0 +1,79 @@
+/* Copyright (c) 2015 Google Inc
+ * Davide Libenzi <dlibenzi@google.com>
+ * See LICENSE for details.
+ *
+ * Converts kprof profiler files into Linux perf ones. The Linux Perf file
+ * format has bee illustrated here:
+ *
+ *      https://lwn.net/Articles/644919/
+ *      https://openlab-mu-internal.web.cern.ch/openlab-mu-internal/03_Documents/
+ *                      3_Technical_Documents/Technical_Reports/2011/Urs_Fassler_report.pdf
+ *
+ */
+
+#pragma once
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdint.h>
+#include "xlib.h"
+#include "perf_format.h"
+
+struct mem_file_reloc {
+       struct mem_file_reloc *next;
+       uint64_t *ptr;
+};
+
+struct mem_block {
+       struct mem_block *next;
+       char *base;
+       char *top;
+       char *wptr;
+};
+
+struct mem_file {
+       struct mem_arena *ma;
+       size_t size;
+       struct mem_block *head;
+       struct mem_block *tail;
+       struct mem_file_reloc *relocs;
+};
+
+struct static_mmap64 {
+       struct static_mmap64 *next;
+       uint64_t addr;
+       uint64_t size;
+       uint64_t offset;
+       uint32_t pid;
+       char *path;
+};
+
+struct perf_headers {
+       struct mem_block *headers[HEADER_FEAT_BITS];
+};
+
+struct perf_event_id {
+       uint64_t event;
+       uint64_t id;
+};
+
+struct perfconv_context {
+       struct mem_arena ma;
+       int debug_level;
+       uint64_t kernel_load_address;
+       struct static_mmap64 *static_mmaps;
+       uint64_t sqnr_id;
+       struct perf_event_id *events;
+       size_t alloced_events;
+       struct perf_header ph;
+       struct perf_headers hdrs;
+       struct mem_file fhdrs, misc, attrs, data, event_types;
+};
+
+struct perfconv_context *perfconv_create_context(void);
+void perfconv_free_context(struct perfconv_context *cctx);
+void perfconv_set_dbglevel(int level, struct perfconv_context *cctx);
+void perfconv_add_kernel_mmap(const char *path, size_t size,
+                                                         struct perfconv_context *cctx);
+void perfconv_process_input(struct perfconv_context *cctx, FILE *input,
+                                                       FILE *output);
index 622f6f4..419d483 100644 (file)
 #include <errno.h>
 #include "xlib.h"
 
+void xmem_arena_init(struct mem_arena *ma, size_t block_size)
+{
+       memset(ma, 0, sizeof(*ma));
+       ma->block_size = (block_size != 0) ? block_size : (128 * 1024);
+}
+
+void xmem_arena_destroy(struct mem_arena *ma)
+{
+       struct mem_arena_block *tmp;
+
+       while ((tmp = ma->blocks) != NULL) {
+               ma->blocks = tmp->next;
+               free(tmp);
+       }
+}
+
+void *xmem_arena_alloc(struct mem_arena *ma, size_t size)
+{
+       size_t aspace = ma->top - ma->ptr;
+       void *data;
+
+       size = ROUNDUP(size, sizeof(void *));
+       if (aspace < size) {
+               size_t bsize;
+               struct mem_arena_block *blk;
+
+               /* If there is enough space left, and the requested size is big enough,
+                * hand over full block and keep the leftover space as is.
+                */
+               if (aspace >= (ma->block_size / 8)) {
+                       blk = xmalloc(size + sizeof(struct mem_arena_block));
+                       blk->next = ma->blocks;
+                       ma->blocks = blk;
+
+                       return (char *) blk + sizeof(struct mem_arena_block);
+               }
+
+               bsize = max(ma->block_size, size) + sizeof(struct mem_arena_block);
+               blk = xmalloc(bsize);
+
+               blk->next = ma->blocks;
+               ma->blocks = blk;
+               ma->ptr = (char *) blk + sizeof(struct mem_arena_block);
+               ma->top = ma->ptr + bsize;
+       }
+       data = ma->ptr;
+       ma->ptr += size;
+
+       return data;
+}
+
+void *xmem_arena_zalloc(struct mem_arena *ma, size_t size)
+{
+       void *data = xmem_arena_alloc(ma, size);
+
+       memset(data, 0, size);
+
+       return data;
+}
+
+char *xmem_arena_strdup(struct mem_arena *ma, const char *str)
+{
+       size_t size = strlen(str);
+       char *dstr = xmem_arena_alloc(ma, size + 1);
+
+       memcpy(dstr, str, size + 1);
+
+       return dstr;
+}
+
 int xopen(const char *path, int flags, mode_t mode)
 {
        int fd = open(path, flags, mode);
@@ -66,6 +136,52 @@ void xpread(int fd, void *data, size_t size, off_t off)
        }
 }
 
+FILE *xfopen(const char *path, const char *mode)
+{
+       FILE *file = fopen(path, mode);
+
+       if (!file) {
+               fprintf(stderr, "Unable to open file '%s' for mode '%s': %s\n",
+                               path, mode, strerror(errno));
+               exit(1);
+       }
+
+       return file;
+}
+
+off_t xfsize(FILE *file)
+{
+       off_t pos = ftello(file), size;
+
+       xfseek(file, 0, SEEK_END);
+       size = ftello(file);
+       xfseek(file, pos, SEEK_SET);
+
+       return size;
+}
+
+void xfwrite(const void *data, size_t size, FILE *file)
+{
+       if (fwrite(data, 1, size, file) != size) {
+               fprintf(stderr, "Unable to write %lu bytes: %s\n", size,
+                               strerror(errno));
+               exit(1);
+       }
+}
+
+void xfseek(FILE *file, off_t offset, int whence)
+{
+       if (fseeko(file, offset, whence)) {
+               int error = errno;
+
+               fprintf(stderr, "Unable to seek at offset %ld from %s (fpos=%ld): %s\n",
+                               offset, whence == SEEK_SET ? "beginning of file" :
+                               (whence == SEEK_END ? "end of file" : "current position"),
+                               ftell(file), strerror(error));
+               exit(1);
+       }
+}
+
 void *xmalloc(size_t size)
 {
        void *data = malloc(size);
@@ -98,3 +214,35 @@ char *xstrdup(const char *str)
 
        return dstr;
 }
+
+const char *vb_decode_uint64(const char *data, uint64_t *pval)
+{
+       unsigned int i;
+       uint64_t val = 0;
+
+       for (i = 0; (*data & 0x80) != 0; i += 7, data++)
+               val |= (((uint64_t) *data) & 0x7f) << i;
+       *pval = val | ((uint64_t) *data) << i;
+
+       return data + 1;
+}
+
+int vb_fdecode_uint64(FILE *file, uint64_t *pval)
+{
+       unsigned int i = 0;
+       uint64_t val = 0;
+
+       for (;;) {
+               int c = fgetc(file);
+
+               if (c == EOF)
+                       return EOF;
+               val |= (((uint64_t) c) & 0x7f) << i;
+               i += 7;
+               if ((c & 0x80) == 0)
+                       break;
+       }
+       *pval = val;
+
+       return i / 7;
+}
index 4289557..5421f67 100644 (file)
@@ -5,6 +5,7 @@
 
 #pragma once
 
+#include <ros/common.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <stdint.h>
 #include <unistd.h>
 #include <fcntl.h>
 
+#define min(a, b)                                                              \
+       ({ __typeof__(a) _a = (a);                                      \
+               __typeof__(b) _b = (b);                                 \
+               _a < _b ? _a : _b; })
+#define max(a, b)                                                              \
+       ({ __typeof__(a) _a = (a);                                      \
+               __typeof__(b) _b = (b);                                 \
+               _a > _b ? _a : _b; })
+#define always_assert(c)                                                                                               \
+       do {                                                                                                                            \
+               if (!(c))                                                                                                               \
+                       fprintf(stderr, "%s: %d: Assertion failed: " #c "\n",           \
+                                       __FILE__, __LINE__);                                                            \
+       } while (0)
+
+struct mem_arena_block {
+       struct mem_arena_block *next;
+};
+
+struct mem_arena {
+       size_t block_size;
+       struct mem_arena_block *blocks;
+       char *ptr;
+       char *top;
+};
+
+void xmem_arena_init(struct mem_arena *ma, size_t block_size);
+void xmem_arena_destroy(struct mem_arena *ma);
+void *xmem_arena_alloc(struct mem_arena *ma, size_t size);
+void *xmem_arena_zalloc(struct mem_arena *ma, size_t size);
+char *xmem_arena_strdup(struct mem_arena *ma, const char *str);
 int xopen(const char *path, int flags, mode_t mode);
 void xwrite(int fd, const void *data, size_t size);
 void xread(int fd, void *data, size_t size);
 void xpwrite(int fd, const void *data, size_t size, off_t off);
 void xpread(int fd, void *data, size_t size, off_t off);
+FILE *xfopen(const char *path, const char *mode);
+off_t xfsize(FILE *file);
+void xfwrite(const void *data, size_t size, FILE *file);
+void xfseek(FILE *file, off_t offset, int whence);
 void *xmalloc(size_t size);
 void *xzmalloc(size_t size);
 char *xstrdup(const char *str);
+const char *vb_decode_uint64(const char *data, uint64_t *pval);
+int vb_fdecode_uint64(FILE *file, uint64_t *pval);
 
 static inline void cpuid(uint32_t ieax, uint32_t iecx, uint32_t *eaxp,
                          uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp)
@@ -40,3 +78,8 @@ static inline void cpuid(uint32_t ieax, uint32_t iecx, uint32_t *eaxp,
        if (edxp)
                *edxp = edx;
 }
+
+static inline void set_bitno(void *data, size_t bitno)
+{
+       ((char *) data)[bitno / 8] |= 1 << (bitno % 8);
+}