lkml.org 
[lkml]   [2015]   [Apr]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 39/44] perf tools: Add Intel BTS support
    Date
    Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
    ---
    tools/perf/Documentation/intel-bts.txt | 67 ++
    tools/perf/arch/x86/util/auxtrace.c | 50 +-
    tools/perf/util/Build | 1 +
    tools/perf/util/auxtrace.c | 3 +
    tools/perf/util/auxtrace.h | 1 +
    tools/perf/util/intel-bts.c | 1223 ++++++++++++++++++++++++++++++++
    tools/perf/util/intel-bts.h | 31 +
    7 files changed, 1373 insertions(+), 3 deletions(-)
    create mode 100644 tools/perf/Documentation/intel-bts.txt
    create mode 100644 tools/perf/util/intel-bts.c
    create mode 100644 tools/perf/util/intel-bts.h

    diff --git a/tools/perf/Documentation/intel-bts.txt b/tools/perf/Documentation/intel-bts.txt
    new file mode 100644
    index 0000000..f349458
    --- /dev/null
    +++ b/tools/perf/Documentation/intel-bts.txt
    @@ -0,0 +1,67 @@
    +Intel Branch Trace Store
    +========================
    +
    +perf record
    +===========
    +
    +new event
    +---------
    +
    +The Intel BTS kernel driver creates a new PMU for Intel BTS. The perf record
    +option is:
    +
    + -e intel_bts//
    +
    +Currently Intel BTS is limited to per-thread tracing so the --per-thread option
    +is also needed.
    +
    +
    +snapshot option
    +---------------
    +
    +The snapshot option is the same as Intel PT (refer Intel PT documentation).
    +
    +
    +auxtrace mmap size option
    +-----------------------
    +
    +The mmap size option is the same as Intel PT (refer Intel PT documentation).
    +
    +
    +perf script
    +===========
    +
    +By default, perf script will decode trace data found in the perf.data file.
    +This can be further controlled by option -Z. The -Z option is the same as
    +Intel PT (refer Intel PT documentation) except that neither "instructions"
    +events nor "transactions" events (and consequently call chains) are supported.
    +
    +To disable trace decoding entirely, use the option --no-auxtrace.
    +
    +
    +dump option
    +-----------
    +
    +perf script has an option (-D) to "dump" the events i.e. display the binary
    +data.
    +
    +When -D is used, Intel BTS packets are displayed.
    +
    +To disable the display of Intel BTS packets, combine the -D option with
    +--no-auxtrace.
    +
    +
    +perf report
    +===========
    +
    +By default, perf report will decode trace data found in the perf.data file.
    +This can be further controlled by new option -Z exactly the same as perf script.
    +
    +
    +perf inject
    +===========
    +
    +perf inject also accepts the -Z option in which case tracing data is removed and
    +replaced with the synthesized events. e.g.
    +
    + perf inject -Z -i perf.data -o perf.data.new
    diff --git a/tools/perf/arch/x86/util/auxtrace.c b/tools/perf/arch/x86/util/auxtrace.c
    index 1236b76..aeb0812 100644
    --- a/tools/perf/arch/x86/util/auxtrace.c
    +++ b/tools/perf/arch/x86/util/auxtrace.c
    @@ -13,12 +13,56 @@
    *
    */

    +#include <stdbool.h>
    +
    #include "../../util/header.h"
    +#include "../../util/debug.h"
    +#include "../../util/pmu.h"
    #include "../../util/auxtrace.h"
    #include "../../util/intel-pt.h"
    +#include "../../util/intel-bts.h"
    +#include "../../util/evlist.h"
    +
    +static
    +struct auxtrace_record *auxtrace_record__init_intel(struct perf_evlist *evlist,
    + int *err)
    +{
    + struct perf_pmu *intel_pt_pmu;
    + struct perf_pmu *intel_bts_pmu;
    + struct perf_evsel *evsel;
    + bool found_pt = false;
    + bool found_bts = false;
    +
    + intel_pt_pmu = perf_pmu__find(INTEL_PT_PMU_NAME);
    + intel_bts_pmu = perf_pmu__find(INTEL_BTS_PMU_NAME);
    +
    + if (evlist) {
    + evlist__for_each(evlist, evsel) {
    + if (intel_pt_pmu &&
    + evsel->attr.type == intel_pt_pmu->type)
    + found_pt = true;
    + if (intel_bts_pmu &&
    + evsel->attr.type == intel_bts_pmu->type)
    + found_bts = true;
    + }
    + }
    +
    + if (found_pt && found_bts) {
    + pr_err("intel_pt and intel_bts may not be used together\n");
    + *err = -EINVAL;
    + return NULL;
    + }
    +
    + if (found_pt)
    + return intel_pt_recording_init(err);
    +
    + if (found_bts)
    + return intel_bts_recording_init(err);

    -struct auxtrace_record *auxtrace_record__init(struct perf_evlist *evlist __maybe_unused,
    - int *err)
    + return NULL;
    +}
    +
    +struct auxtrace_record *auxtrace_record__init(struct perf_evlist *evlist, int *err)
    {
    char buffer[64];
    int ret;
    @@ -32,7 +76,7 @@ struct auxtrace_record *auxtrace_record__init(struct perf_evlist *evlist __maybe
    }

    if (!strncmp(buffer, "GenuineIntel,", 13))
    - return intel_pt_recording_init(err);
    + return auxtrace_record__init_intel(evlist, err);

    return NULL;
    }
    diff --git a/tools/perf/util/Build b/tools/perf/util/Build
    index 944bff8..7ee9b78 100644
    --- a/tools/perf/util/Build
    +++ b/tools/perf/util/Build
    @@ -77,6 +77,7 @@ libperf-y += thread-stack.o
    libperf-$(CONFIG_AUXTRACE) += auxtrace.o
    libperf-$(CONFIG_AUXTRACE) += intel-pt-decoder/
    libperf-$(CONFIG_AUXTRACE) += intel-pt.o
    +libperf-$(CONFIG_AUXTRACE) += intel-bts.o

    libperf-$(CONFIG_LIBELF) += symbol-elf.o
    libperf-$(CONFIG_LIBELF) += probe-event.o
    diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
    index fc52296..c05df9c 100644
    --- a/tools/perf/util/auxtrace.c
    +++ b/tools/perf/util/auxtrace.c
    @@ -48,6 +48,7 @@
    #include "parse-options.h"

    #include "intel-pt.h"
    +#include "intel-bts.h"

    int auxtrace_mmap__mmap(struct auxtrace_mmap *mm,
    struct auxtrace_mmap_params *mp,
    @@ -889,6 +890,8 @@ int perf_event__process_auxtrace_info(struct perf_tool *tool __maybe_unused,
    switch (type) {
    case PERF_AUXTRACE_INTEL_PT:
    return intel_pt_process_auxtrace_info(event, session);
    + case PERF_AUXTRACE_INTEL_BTS:
    + return intel_bts_process_auxtrace_info(event, session);
    case PERF_AUXTRACE_UNKNOWN:
    default:
    return -EINVAL;
    diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h
    index fb639c43..318414f 100644
    --- a/tools/perf/util/auxtrace.h
    +++ b/tools/perf/util/auxtrace.h
    @@ -40,6 +40,7 @@ struct events_stats;
    enum auxtrace_type {
    PERF_AUXTRACE_UNKNOWN,
    PERF_AUXTRACE_INTEL_PT,
    + PERF_AUXTRACE_INTEL_BTS,
    };

    enum itrace_period_type {
    diff --git a/tools/perf/util/intel-bts.c b/tools/perf/util/intel-bts.c
    new file mode 100644
    index 0000000..dbd8162
    --- /dev/null
    +++ b/tools/perf/util/intel-bts.c
    @@ -0,0 +1,1223 @@
    +/*
    + * intel-bts.c: Intel Processor Trace support
    + * Copyright (c) 2013-2014, Intel Corporation.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms and conditions of the GNU General Public License,
    + * version 2, as published by the Free Software Foundation.
    + *
    + * This program is distributed in the hope it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
    + * more details.
    + *
    + */
    +
    +#include <endian.h>
    +#include <byteswap.h>
    +#include <linux/kernel.h>
    +#include <linux/types.h>
    +#include <linux/bitops.h>
    +#include <linux/log2.h>
    +
    +#include "cpumap.h"
    +#include "color.h"
    +#include "evsel.h"
    +#include "evlist.h"
    +#include "machine.h"
    +#include "session.h"
    +#include "util.h"
    +#include "pmu.h"
    +#include "debug.h"
    +#include "tsc.h"
    +#include "auxtrace.h"
    +#include "intel-bts.h"
    +
    +#define MAX_TIMESTAMP (~0ULL)
    +
    +#define KiB(x) ((x) * 1024)
    +#define MiB(x) ((x) * 1024 * 1024)
    +#define KiB_MASK(x) (KiB(x) - 1)
    +#define MiB_MASK(x) (MiB(x) - 1)
    +
    +#define INTEL_BTS_DFLT_SAMPLE_SIZE KiB(4)
    +
    +#define INTEL_BTS_MAX_SAMPLE_SIZE KiB(60)
    +
    +#if __BYTE_ORDER == __BIG_ENDIAN
    +#define le64_to_cpu bswap_64
    +#else
    +#define le64_to_cpu
    +#endif
    +
    +struct intel_bts_snapshot_ref {
    + void *ref_buf;
    + size_t ref_offset;
    + bool wrapped;
    +};
    +
    +struct intel_bts_recording {
    + struct auxtrace_record itr;
    + struct perf_pmu *intel_bts_pmu;
    + struct perf_evlist *evlist;
    + bool snapshot_mode;
    + size_t snapshot_size;
    + int snapshot_ref_cnt;
    + struct intel_bts_snapshot_ref *snapshot_refs;
    +};
    +
    +struct intel_bts {
    + struct auxtrace auxtrace;
    + struct auxtrace_queues queues;
    + struct auxtrace_heap heap;
    + u32 auxtrace_type;
    + struct perf_session *session;
    + struct machine *machine;
    + bool sampling_mode;
    + bool snapshot_mode;
    + bool data_queued;
    + u32 pmu_type;
    + struct perf_tsc_conversion tc;
    + bool cap_user_time_zero;
    + struct itrace_synth_opts synth_opts;
    + bool sample_branches;
    + u64 branches_sample_type;
    + u64 branches_id;
    + size_t branches_event_size;
    + bool synth_needs_swap;
    +};
    +
    +struct intel_bts_queue {
    + struct intel_bts *bts;
    + unsigned int queue_nr;
    + struct auxtrace_buffer *buffer;
    + bool on_heap;
    + bool done;
    + pid_t pid;
    + pid_t tid;
    + int cpu;
    + u64 time;
    +};
    +
    +struct branch {
    + u64 from;
    + u64 to;
    + u64 misc;
    +};
    +
    +static void intel_bts_dump(struct intel_bts *bts __maybe_unused,
    + unsigned char *buf, size_t len)
    +{
    + struct branch *branch;
    + size_t i, pos = 0, br_sz = sizeof(struct branch), sz;
    + const char *color = PERF_COLOR_BLUE;
    +
    + color_fprintf(stdout, color,
    + ". ... Intel BTS data: size %zu bytes\n",
    + len);
    +
    + while (len) {
    + if (len >= br_sz)
    + sz = br_sz;
    + else
    + sz = len;
    + printf(".");
    + color_fprintf(stdout, color, " %08x: ", pos);
    + for (i = 0; i < sz; i++)
    + color_fprintf(stdout, color, " %02x", buf[i]);
    + for (; i < br_sz; i++)
    + color_fprintf(stdout, color, " ");
    + if (len >= br_sz) {
    + branch = (struct branch *)buf;
    + color_fprintf(stdout, color, " %"PRIx64" -> %"PRIx64" %s\n",
    + le64_to_cpu(branch->from),
    + le64_to_cpu(branch->to),
    + le64_to_cpu(branch->misc) & 0x10 ?
    + "pred" : "miss");
    + } else {
    + color_fprintf(stdout, color, " Bad record!\n");
    + }
    + pos += sz;
    + buf += sz;
    + len -= sz;
    + }
    +}
    +
    +static void intel_bts_dump_event(struct intel_bts *bts, unsigned char *buf,
    + size_t len)
    +{
    + printf(".\n");
    + intel_bts_dump(bts, buf, len);
    +}
    +
    +static int intel_bts_lost(struct intel_bts *bts, struct perf_sample *sample)
    +{
    + union perf_event event;
    + int err;
    +
    + auxtrace_synth_error(&event.auxtrace_error, PERF_AUXTRACE_ERROR_ITRACE ,
    + ENOSPC, sample->cpu, sample->pid, sample->tid, 0,
    + "Lost trace data");
    +
    + err = perf_session__deliver_synth_event(bts->session, &event, NULL);
    + if (err)
    + pr_err("Intel BTS: failed to deliver error event, error %d\n",
    + err);
    +
    + return err;
    +}
    +
    +static struct intel_bts_queue *intel_bts_alloc_queue(struct intel_bts *bts,
    + unsigned int queue_nr)
    +{
    + struct intel_bts_queue *btsq;
    +
    + btsq = zalloc(sizeof(struct intel_bts_queue));
    + if (!btsq)
    + return NULL;
    +
    + btsq->bts = bts;
    + btsq->queue_nr = queue_nr;
    + btsq->pid = -1;
    + btsq->tid = -1;
    + btsq->cpu = -1;
    +
    + return btsq;
    +}
    +
    +static int intel_bts_setup_queue(struct intel_bts *bts,
    + struct auxtrace_queue *queue,
    + unsigned int queue_nr)
    +{
    + struct intel_bts_queue *btsq = queue->priv;
    +
    + if (list_empty(&queue->head))
    + return 0;
    +
    + if (!btsq) {
    + btsq = intel_bts_alloc_queue(bts, queue_nr);
    + if (!btsq)
    + return -ENOMEM;
    + queue->priv = btsq;
    +
    + if (queue->cpu != -1)
    + btsq->cpu = queue->cpu;
    + btsq->tid = queue->tid;
    + }
    +
    + if (bts->sampling_mode)
    + return 0;
    +
    + if (!btsq->on_heap && !btsq->buffer) {
    + int ret;
    +
    + btsq->buffer = auxtrace_buffer__next(queue, NULL);
    + if (!btsq->buffer)
    + return 0;
    +
    + ret = auxtrace_heap__add(&bts->heap, queue_nr,
    + btsq->buffer->reference);
    + if (ret)
    + return ret;
    + btsq->on_heap = true;
    + }
    +
    + return 0;
    +}
    +
    +static int intel_bts_setup_queues(struct intel_bts *bts)
    +{
    + unsigned int i;
    + int ret;
    +
    + for (i = 0; i < bts->queues.nr_queues; i++) {
    + ret = intel_bts_setup_queue(bts, &bts->queues.queue_array[i],
    + i);
    + if (ret)
    + return ret;
    + }
    + return 0;
    +}
    +
    +static inline int intel_bts_update_queues(struct intel_bts *bts)
    +{
    + if (bts->queues.new_data) {
    + bts->queues.new_data = false;
    + return intel_bts_setup_queues(bts);
    + }
    + return 0;
    +}
    +
    +static unsigned char *intel_bts_find_overlap(unsigned char *buf_a, size_t len_a,
    + unsigned char *buf_b, size_t len_b)
    +{
    + size_t offs, len;
    +
    + if (len_a > len_b)
    + offs = len_a - len_b;
    + else
    + offs = 0;
    +
    + for (; offs < len_a; offs += sizeof(struct branch)) {
    + len = len_a - offs;
    + if (!memcmp(buf_a + offs, buf_b, len))
    + return buf_b + len;
    + }
    +
    + return buf_b;
    +}
    +
    +static int intel_bts_do_fix_overlap(struct auxtrace_queue *queue,
    + struct auxtrace_buffer *b)
    +{
    + struct auxtrace_buffer *a;
    + void *start;
    +
    + if (b->list.prev == &queue->head)
    + return 0;
    + a = list_entry(b->list.prev, struct auxtrace_buffer, list);
    + start = intel_bts_find_overlap(a->data, a->size, b->data, b->size);
    + if (!start)
    + return -EINVAL;
    + b->use_size = b->data + b->size - start;
    + b->use_data = start;
    + return 0;
    +}
    +
    +static int intel_bts_synth_branch_sample(struct intel_bts_queue *btsq,
    + struct branch *branch)
    +{
    + int ret;
    + struct intel_bts *bts = btsq->bts;
    + union perf_event event;
    + struct perf_sample sample = {0};
    +
    + event.sample.header.type = PERF_RECORD_SAMPLE;
    + event.sample.header.misc = PERF_RECORD_MISC_USER;
    + event.sample.header.size = sizeof(struct perf_event_header);
    +
    + sample.ip = le64_to_cpu(branch->from);
    + sample.pid = btsq->pid;
    + sample.tid = btsq->tid;
    + sample.addr = le64_to_cpu(branch->to);
    + sample.id = btsq->bts->branches_id;
    + sample.stream_id = btsq->bts->branches_id;
    + sample.period = 1;
    + sample.cpu = btsq->cpu;
    +
    + if (bts->synth_opts.inject) {
    + event.sample.header.size = bts->branches_event_size;
    + ret = perf_event__synthesize_sample(&event,
    + bts->branches_sample_type,
    + 0, &sample,
    + bts->synth_needs_swap);
    + if (ret)
    + return ret;
    + }
    +
    + ret = perf_session__deliver_synth_event(bts->session, &event, &sample);
    + if (ret)
    + pr_err("Intel BTS: failed to deliver branch event, error %d\n",
    + ret);
    +
    + return ret;
    +}
    +
    +static int intel_bts_process_buffer(struct intel_bts_queue *btsq,
    + struct auxtrace_buffer *buffer)
    +{
    + struct branch *branch;
    + size_t sz;
    + int err = 0;
    +
    + if (buffer->use_data) {
    + sz = buffer->use_size;
    + branch = buffer->use_data;
    + } else {
    + sz = buffer->size;
    + branch = buffer->data;
    + }
    +
    + if (!btsq->bts->sample_branches)
    + return 0;
    +
    + while (sz > sizeof(struct branch)) {
    + if (!branch->from && !branch->to)
    + continue;
    + err = intel_bts_synth_branch_sample(btsq, branch);
    + if (err)
    + break;
    + branch += 1;
    + sz -= sizeof(struct branch);
    + }
    + return err;
    +}
    +
    +static int intel_bts_process_queue(struct intel_bts_queue *btsq, u64 *timestamp)
    +{
    + struct auxtrace_buffer *buffer = btsq->buffer;
    + struct auxtrace_queue *queue;
    + int err;
    +
    + if (btsq->done)
    + return 1;
    +
    + if (btsq->pid == -1) {
    + struct thread *thread;
    +
    + thread = machine__find_thread(btsq->bts->machine, -1, btsq->tid);
    + if (thread)
    + btsq->pid = thread->pid_;
    + }
    +
    + queue = &btsq->bts->queues.queue_array[btsq->queue_nr];
    +
    + if (!buffer)
    + buffer = auxtrace_buffer__next(queue, NULL);
    +
    + if (!buffer) {
    + if (!btsq->bts->sampling_mode)
    + btsq->done = 1;
    + return 1;
    + }
    +
    + /* Currently there is no support for split buffers */
    + if (buffer->consecutive)
    + return -EINVAL;
    +
    + if (!buffer->data) {
    + int fd = perf_data_file__fd(btsq->bts->session->file);
    +
    + buffer->data = auxtrace_buffer__get_data(buffer, fd);
    + if (!buffer->data)
    + return -ENOMEM;
    + }
    +
    + if (btsq->bts->snapshot_mode && !buffer->consecutive &&
    + intel_bts_do_fix_overlap(queue, buffer))
    + return -ENOMEM;
    +
    + err = intel_bts_process_buffer(btsq, buffer);
    +
    + auxtrace_buffer__drop_data(buffer);
    +
    + btsq->buffer = auxtrace_buffer__next(queue, buffer);
    + if (btsq->buffer) {
    + if (timestamp)
    + *timestamp = btsq->buffer->reference;
    + } else {
    + if (!btsq->bts->sampling_mode)
    + btsq->done = 1;
    + }
    +
    + return err;
    +}
    +
    +static int intel_bts_flush_queue(struct intel_bts_queue *btsq)
    +{
    + u64 ts = 0;
    + int ret;
    +
    + while (1) {
    + ret = intel_bts_process_queue(btsq, &ts);
    + if (ret < 0)
    + return ret;
    + if (ret)
    + break;
    + }
    + return 0;
    +}
    +
    +static int intel_bts_process_tid_exit(struct intel_bts *bts, pid_t tid)
    +{
    + struct auxtrace_queues *queues = &bts->queues;
    + unsigned int i;
    +
    + for (i = 0; i < queues->nr_queues; i++) {
    + struct auxtrace_queue *queue = &bts->queues.queue_array[i];
    + struct intel_bts_queue *btsq = queue->priv;
    +
    + if (btsq && btsq->tid == tid)
    + return intel_bts_flush_queue(btsq);
    + }
    + return 0;
    +}
    +
    +static int intel_bts_process_queues(struct intel_bts *bts, u64 timestamp)
    +{
    + while (1) {
    + unsigned int queue_nr;
    + struct auxtrace_queue *queue;
    + struct intel_bts_queue *btsq;
    + u64 ts = 0;
    + int ret;
    +
    + if (!bts->heap.heap_cnt)
    + return 0;
    +
    + if (bts->heap.heap_array[0].ordinal > timestamp)
    + return 0;
    +
    + queue_nr = bts->heap.heap_array[0].queue_nr;
    + queue = &bts->queues.queue_array[queue_nr];
    + btsq = queue->priv;
    +
    + auxtrace_heap__pop(&bts->heap);
    +
    + ret = intel_bts_process_queue(btsq, &ts);
    + if (ret < 0) {
    + auxtrace_heap__add(&bts->heap, queue_nr, ts);
    + return ret;
    + }
    +
    + if (!ret) {
    + ret = auxtrace_heap__add(&bts->heap, queue_nr, ts);
    + if (ret < 0)
    + return ret;
    + } else {
    + btsq->on_heap = false;
    + }
    + }
    +
    + return 0;
    +}
    +
    +static int intel_bts_process_event(struct perf_session *session,
    + union perf_event *event,
    + struct perf_sample *sample,
    + struct perf_tool *tool)
    +{
    + struct intel_bts *bts = container_of(session->auxtrace, struct intel_bts,
    + auxtrace);
    + u64 timestamp;
    + int err;
    +
    + if (dump_trace)
    + return 0;
    +
    + if (!tool->ordered_events) {
    + pr_err("Intel BTS requires ordered events\n");
    + return -EINVAL;
    + }
    +
    + if (sample->time)
    + timestamp = perf_time_to_tsc(sample->time, &bts->tc);
    + else
    + timestamp = 0;
    +
    + err = intel_bts_update_queues(bts);
    + if (err)
    + return err;
    +
    + err = intel_bts_process_queues(bts, timestamp);
    + if (err)
    + return err;
    + if (event->header.type == PERF_RECORD_EXIT) {
    + err = intel_bts_process_tid_exit(bts, event->comm.tid);
    + if (err)
    + return err;
    + }
    +
    + if (event->header.type == PERF_RECORD_AUX &&
    + (event->aux.flags & PERF_AUX_FLAG_TRUNCATED) &&
    + bts->synth_opts.errors)
    + err = intel_bts_lost(bts, sample);
    +
    + return err;
    +}
    +
    +static int intel_bts_process_auxtrace_event(struct perf_session *session,
    + union perf_event *event,
    + struct perf_tool *tool __maybe_unused)
    +{
    + struct intel_bts *bts = container_of(session->auxtrace, struct intel_bts,
    + auxtrace);
    +
    + if (bts->sampling_mode)
    + return 0;
    +
    + if (!bts->data_queued) {
    + struct auxtrace_buffer *buffer;
    + off_t data_offset;
    + int fd = perf_data_file__fd(session->file);
    + int err;
    +
    + if (perf_data_file__is_pipe(session->file)) {
    + data_offset = 0;
    + } else {
    + data_offset = lseek(fd, 0, SEEK_CUR);
    + if (data_offset == -1)
    + return -errno;
    + }
    +
    + err = auxtrace_queues__add_event(&bts->queues, session, event,
    + data_offset, &buffer);
    + if (err)
    + return err;
    +
    + /* Dump here now we have copied a piped trace out of the pipe */
    + if (dump_trace) {
    + if (auxtrace_buffer__get_data(buffer, fd)) {
    + intel_bts_dump_event(bts, buffer->data,
    + buffer->size);
    + auxtrace_buffer__put_data(buffer);
    + }
    + }
    + }
    +
    + return 0;
    +}
    +
    +static int intel_bts_flush(struct perf_session *session __maybe_unused,
    + struct perf_tool *tool __maybe_unused)
    +{
    + struct intel_bts *bts = container_of(session->auxtrace, struct intel_bts,
    + auxtrace);
    + int ret;
    +
    + if (dump_trace || bts->sampling_mode)
    + return 0;
    +
    + if (!tool->ordered_events)
    + return -EINVAL;
    +
    + ret = intel_bts_update_queues(bts);
    + if (ret < 0)
    + return ret;
    +
    + return intel_bts_process_queues(bts, MAX_TIMESTAMP);
    +}
    +
    +static void intel_bts_free_queue(void *priv)
    +{
    + struct intel_bts_queue *btsq = priv;
    +
    + if (!btsq)
    + return;
    + free(btsq);
    +}
    +
    +static void intel_bts_free_events(struct perf_session *session)
    +{
    + struct intel_bts *bts = container_of(session->auxtrace, struct intel_bts,
    + auxtrace);
    + struct auxtrace_queues *queues = &bts->queues;
    + unsigned int i;
    +
    + for (i = 0; i < queues->nr_queues; i++) {
    + intel_bts_free_queue(queues->queue_array[i].priv);
    + queues->queue_array[i].priv = NULL;
    + }
    + auxtrace_queues__free(queues);
    +}
    +
    +static void intel_bts_free(struct perf_session *session)
    +{
    + struct intel_bts *bts = container_of(session->auxtrace, struct intel_bts,
    + auxtrace);
    +
    + auxtrace_heap__free(&bts->heap);
    + intel_bts_free_events(session);
    + session->auxtrace = NULL;
    + free(bts);
    +}
    +
    +struct intel_bts_synth {
    + struct perf_tool dummy_tool;
    + struct perf_session *session;
    +};
    +
    +static int intel_bts_event_synth(struct perf_tool *tool,
    + union perf_event *event,
    + struct perf_sample *sample __maybe_unused,
    + struct machine *machine __maybe_unused)
    +{
    + struct intel_bts_synth *intel_bts_synth =
    + container_of(tool, struct intel_bts_synth, dummy_tool);
    +
    + return perf_session__deliver_synth_event(intel_bts_synth->session,
    + event, NULL);
    +}
    +
    +static int intel_bts_synth_event(struct perf_session *session,
    + struct perf_event_attr *attr, u64 id)
    +{
    + struct intel_bts_synth intel_bts_synth;
    +
    + memset(&intel_bts_synth, 0, sizeof(struct intel_bts_synth));
    + intel_bts_synth.session = session;
    +
    + return perf_event__synthesize_attr(&intel_bts_synth.dummy_tool, attr, 1,
    + &id, intel_bts_event_synth);
    +}
    +
    +static int intel_bts_synth_events(struct intel_bts *bts,
    + struct perf_session *session)
    +{
    + struct perf_evlist *evlist = session->evlist;
    + struct perf_evsel *evsel;
    + struct perf_event_attr attr;
    + bool found = false;
    + u64 id;
    + int err;
    +
    + evlist__for_each(evlist, evsel) {
    + if (evsel->attr.type == bts->pmu_type && evsel->ids) {
    + found = true;
    + break;
    + }
    + }
    +
    + if (!found) {
    + pr_debug("There are no selected events with Intel BTS data\n");
    + return 0;
    + }
    +
    + memset(&attr, 0, sizeof(struct perf_event_attr));
    + attr.size = sizeof(struct perf_event_attr);
    + attr.type = PERF_TYPE_HARDWARE;
    + attr.sample_type = evsel->attr.sample_type & PERF_SAMPLE_MASK;
    + attr.sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID |
    + PERF_SAMPLE_PERIOD;
    + attr.sample_type &= ~(u64)PERF_SAMPLE_TIME;
    + attr.sample_type &= ~(u64)PERF_SAMPLE_CPU;
    + attr.exclude_user = evsel->attr.exclude_user;
    + attr.exclude_kernel = evsel->attr.exclude_kernel;
    + attr.exclude_hv = evsel->attr.exclude_hv;
    + attr.exclude_host = evsel->attr.exclude_host;
    + attr.exclude_guest = evsel->attr.exclude_guest;
    + attr.sample_id_all = evsel->attr.sample_id_all;
    + attr.read_format = evsel->attr.read_format;
    +
    + id = evsel->id[0] + 1000000000;
    + if (!id)
    + id = 1;
    +
    + if (bts->synth_opts.branches) {
    + attr.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS;
    + attr.sample_period = 1;
    + attr.sample_type |= PERF_SAMPLE_ADDR;
    + pr_debug("Synthesizing 'branches' event with id %" PRIu64 " sample type %#" PRIx64 "\n",
    + id, (u64)attr.sample_type);
    + err = intel_bts_synth_event(session, &attr, id);
    + if (err) {
    + pr_err("%s: failed to synthesize 'branches' event type\n",
    + __func__);
    + return err;
    + }
    + bts->sample_branches = true;
    + bts->branches_sample_type = attr.sample_type;
    + bts->branches_id = id;
    + /*
    + * We only use sample types from PERF_SAMPLE_MASK so we can use
    + * __perf_evsel__sample_size() here.
    + */
    + bts->branches_event_size = sizeof(struct sample_event) +
    + __perf_evsel__sample_size(attr.sample_type);
    + }
    +
    + bts->synth_needs_swap = evsel->needs_swap;
    +
    + return 0;
    +}
    +
    +enum {
    + INTEL_BTS_PMU_TYPE,
    + INTEL_BTS_TIME_SHIFT,
    + INTEL_BTS_TIME_MULT,
    + INTEL_BTS_TIME_ZERO,
    + INTEL_BTS_CAP_USER_TIME_ZERO,
    + INTEL_BTS_SNAPSHOT_MODE,
    + INTEL_BTS_AUXTRACE_PRIV_SIZE,
    +};
    +
    +static const char * const intel_bts_info_fmts[] = {
    + [INTEL_BTS_PMU_TYPE] = " PMU Type %"PRId64"\n",
    + [INTEL_BTS_TIME_SHIFT] = " Time Shift %"PRIu64"\n",
    + [INTEL_BTS_TIME_MULT] = " Time Muliplier %"PRIu64"\n",
    + [INTEL_BTS_TIME_ZERO] = " Time Zero %"PRIu64"\n",
    + [INTEL_BTS_CAP_USER_TIME_ZERO] = " Cap Time Zero %"PRId64"\n",
    + [INTEL_BTS_SNAPSHOT_MODE] = " Snapshot mode %"PRId64"\n",
    +};
    +
    +static void intel_bts_print_info(u64 *arr, int start, int finish)
    +{
    + int i;
    +
    + if (!dump_trace)
    + return;
    +
    + for (i = start; i <= finish; i++)
    + fprintf(stdout, intel_bts_info_fmts[i], arr[i]);
    +}
    +
    +u64 intel_bts_auxtrace_info_priv[INTEL_BTS_AUXTRACE_PRIV_SIZE];
    +
    +int intel_bts_process_auxtrace_info(union perf_event *event,
    + struct perf_session *session)
    +{
    + struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info;
    + size_t min_sz = sizeof(u64) * INTEL_BTS_SNAPSHOT_MODE;
    + struct intel_bts *bts;
    + int err;
    +
    + if (auxtrace_info->header.size < sizeof(struct auxtrace_info_event) +
    + min_sz)
    + return -EINVAL;
    +
    + bts = zalloc(sizeof(struct intel_bts));
    + if (!bts)
    + return -ENOMEM;
    +
    + err = auxtrace_queues__init(&bts->queues);
    + if (err)
    + goto err_free;
    +
    + bts->session = session;
    + bts->machine = &session->machines.host; /* No kvm support */
    + bts->auxtrace_type = auxtrace_info->type;
    + bts->pmu_type = auxtrace_info->priv[INTEL_BTS_PMU_TYPE];
    + bts->tc.time_shift = auxtrace_info->priv[INTEL_BTS_TIME_SHIFT];
    + bts->tc.time_mult = auxtrace_info->priv[INTEL_BTS_TIME_MULT];
    + bts->tc.time_zero = auxtrace_info->priv[INTEL_BTS_TIME_ZERO];
    + bts->cap_user_time_zero =
    + auxtrace_info->priv[INTEL_BTS_CAP_USER_TIME_ZERO];
    + bts->snapshot_mode = auxtrace_info->priv[INTEL_BTS_SNAPSHOT_MODE];
    +
    + bts->sampling_mode = false;
    +
    + bts->auxtrace.process_event = intel_bts_process_event;
    + bts->auxtrace.process_auxtrace_event = intel_bts_process_auxtrace_event;
    + bts->auxtrace.flush_events = intel_bts_flush;
    + bts->auxtrace.free_events = intel_bts_free_events;
    + bts->auxtrace.free = intel_bts_free;
    + session->auxtrace = &bts->auxtrace;
    +
    + intel_bts_print_info(&auxtrace_info->priv[0], INTEL_BTS_PMU_TYPE,
    + INTEL_BTS_SNAPSHOT_MODE);
    +
    + if (dump_trace)
    + return 0;
    +
    + if (session->itrace_synth_opts && session->itrace_synth_opts->set)
    + bts->synth_opts = *session->itrace_synth_opts;
    + else
    + itrace_synth_opts__set_default(&bts->synth_opts);
    +
    + err = intel_bts_synth_events(bts, session);
    + if (err)
    + goto err_free_queues;
    +
    + err = auxtrace_queues__process_index(&bts->queues, session);
    + if (err)
    + goto err_free_queues;
    +
    + if (bts->queues.populated)
    + bts->data_queued = true;
    +
    + return 0;
    +
    +err_free_queues:
    + auxtrace_queues__free(&bts->queues);
    + session->auxtrace = NULL;
    +err_free:
    + free(bts);
    + return err;
    +}
    +
    +static size_t intel_bts_info_priv_size(struct auxtrace_record *itr __maybe_unused)
    +{
    + return sizeof(intel_bts_auxtrace_info_priv);
    +}
    +
    +static int intel_bts_info_fill(struct auxtrace_record *itr,
    + struct perf_session *session,
    + struct auxtrace_info_event *auxtrace_info,
    + size_t priv_size)
    +{
    + struct intel_bts_recording *btsr =
    + container_of(itr, struct intel_bts_recording, itr);
    + struct perf_pmu *intel_bts_pmu = btsr->intel_bts_pmu;
    + struct perf_event_mmap_page *pc;
    + struct perf_tsc_conversion tc = {0};
    + bool cap_user_time_zero = false;
    + int err;
    +
    + if (priv_size != sizeof(intel_bts_auxtrace_info_priv))
    + return -EINVAL;
    +
    + if (!session->evlist->nr_mmaps)
    + return -EINVAL;
    +
    + pc = session->evlist->mmap[0].base;
    + if (pc) {
    + err = perf_read_tsc_conversion(pc, &tc);
    + if (err) {
    + if (err != -EOPNOTSUPP)
    + return err;
    + } else {
    + cap_user_time_zero = tc.time_mult != 0;
    + }
    + if (!cap_user_time_zero)
    + ui__warning("Intel BTS: TSC not available\n");
    + }
    +
    + auxtrace_info->type = PERF_AUXTRACE_INTEL_BTS;
    + auxtrace_info->priv[INTEL_BTS_PMU_TYPE] = intel_bts_pmu->type;
    + auxtrace_info->priv[INTEL_BTS_TIME_SHIFT] = tc.time_shift;
    + auxtrace_info->priv[INTEL_BTS_TIME_MULT] = tc.time_mult;
    + auxtrace_info->priv[INTEL_BTS_TIME_ZERO] = tc.time_zero;
    + auxtrace_info->priv[INTEL_BTS_CAP_USER_TIME_ZERO] = cap_user_time_zero;
    + auxtrace_info->priv[INTEL_BTS_SNAPSHOT_MODE] = btsr->snapshot_mode;
    +
    + return 0;
    +}
    +
    +static int intel_bts_recording_options(struct auxtrace_record *itr,
    + struct perf_evlist *evlist,
    + struct record_opts *opts)
    +{
    + struct intel_bts_recording *btsr =
    + container_of(itr, struct intel_bts_recording, itr);
    + struct perf_pmu *intel_bts_pmu = btsr->intel_bts_pmu;
    + struct perf_evsel *evsel, *intel_bts_evsel = NULL;
    + const struct cpu_map *cpus = evlist->cpus;
    + bool privileged = geteuid() == 0 || perf_event_paranoid() < 0;
    +
    + btsr->evlist = evlist;
    + btsr->snapshot_mode = opts->auxtrace_snapshot_mode;
    +
    + evlist__for_each(evlist, evsel) {
    + if (evsel->attr.type == intel_bts_pmu->type) {
    + if (intel_bts_evsel) {
    + pr_err("There may be only one " INTEL_BTS_PMU_NAME " event\n");
    + return -EINVAL;
    + }
    + evsel->attr.freq = 0;
    + evsel->attr.sample_period = 1;
    + intel_bts_evsel = evsel;
    + opts->full_auxtrace = true;
    + }
    + }
    +
    + if (opts->auxtrace_snapshot_mode && !opts->full_auxtrace) {
    + pr_err("Snapshot mode (-S option) requires " INTEL_BTS_PMU_NAME " PMU event (-e " INTEL_BTS_PMU_NAME ")\n");
    + return -EINVAL;
    + }
    +
    + if (!opts->full_auxtrace)
    + return 0;
    +
    + if (opts->full_auxtrace && !cpu_map__empty(cpus)) {
    + pr_err(INTEL_BTS_PMU_NAME " does not support per-cpu recording\n");
    + return -EINVAL;
    + }
    +
    + /* Set default sizes for snapshot mode */
    + if (opts->auxtrace_snapshot_mode) {
    + if (!opts->auxtrace_snapshot_size && !opts->auxtrace_mmap_pages) {
    + if (privileged) {
    + opts->auxtrace_mmap_pages = MiB(4) / page_size;
    + } else {
    + opts->auxtrace_mmap_pages = KiB(128) / page_size;
    + if (opts->mmap_pages == UINT_MAX)
    + opts->mmap_pages = KiB(256) / page_size;
    + }
    + } else if (!opts->auxtrace_mmap_pages && !privileged &&
    + opts->mmap_pages == UINT_MAX) {
    + opts->mmap_pages = KiB(256) / page_size;
    + }
    + if (!opts->auxtrace_snapshot_size)
    + opts->auxtrace_snapshot_size =
    + opts->auxtrace_mmap_pages * (size_t)page_size;
    + if (!opts->auxtrace_mmap_pages) {
    + size_t sz = opts->auxtrace_snapshot_size;
    +
    + sz = round_up(sz, page_size) / page_size;
    + opts->auxtrace_mmap_pages = roundup_pow_of_two(sz);
    + }
    + if (opts->auxtrace_snapshot_size >
    + opts->auxtrace_mmap_pages * (size_t)page_size) {
    + pr_err("Snapshot size %zu must not be greater than AUX area tracing mmap size %zu\n",
    + opts->auxtrace_snapshot_size,
    + opts->auxtrace_mmap_pages * (size_t)page_size);
    + return -EINVAL;
    + }
    + if (!opts->auxtrace_snapshot_size || !opts->auxtrace_mmap_pages) {
    + pr_err("Failed to calculate default snapshot size and/or AUX area tracing mmap pages\n");
    + return -EINVAL;
    + }
    + pr_debug2("Intel BTS snapshot size: %zu\n",
    + opts->auxtrace_snapshot_size);
    + }
    +
    + /* Set default sizes for full trace mode */
    + if (opts->full_auxtrace && !opts->auxtrace_mmap_pages) {
    + if (privileged) {
    + opts->auxtrace_mmap_pages = MiB(4) / page_size;
    + } else {
    + opts->auxtrace_mmap_pages = KiB(128) / page_size;
    + if (opts->mmap_pages == UINT_MAX)
    + opts->mmap_pages = KiB(256) / page_size;
    + }
    + }
    +
    + /* Validate auxtrace_mmap_pages */
    + if (opts->auxtrace_mmap_pages) {
    + size_t sz = opts->auxtrace_mmap_pages * (size_t)page_size;
    + size_t min_sz;
    +
    + if (opts->auxtrace_snapshot_mode)
    + min_sz = KiB(4);
    + else
    + min_sz = KiB(8);
    +
    + if (sz < min_sz || !is_power_of_2(sz)) {
    + pr_err("Invalid mmap size for Intel BTS: must be at least %zuKiB and a power of 2\n",
    + min_sz / 1024);
    + return -EINVAL;
    + }
    + }
    +
    + if (intel_bts_evsel) {
    + /*
    + * To obtain the auxtrace buffer file descriptor, the auxtrace event
    + * must come first.
    + */
    + perf_evlist__to_front(evlist, intel_bts_evsel);
    + /*
    + * In the case of per-cpu mmaps, we need the CPU on the
    + * AUX event.
    + */
    + if (!cpu_map__empty(cpus))
    + perf_evsel__set_sample_bit(intel_bts_evsel, CPU);
    + }
    +
    + /* Add dummy event to keep tracking */
    + if (opts->full_auxtrace) {
    + struct perf_evsel *tracking_evsel;
    + int err;
    +
    + err = parse_events(evlist, "dummy:u");
    + if (err)
    + return err;
    +
    + tracking_evsel = perf_evlist__last(evlist);
    +
    + perf_evlist__set_tracking_event(evlist, tracking_evsel);
    +
    + tracking_evsel->attr.freq = 0;
    + tracking_evsel->attr.sample_period = 1;
    + }
    +
    + return 0;
    +}
    +
    +static int intel_bts_parse_snapshot_options(struct auxtrace_record *itr,
    + struct record_opts *opts,
    + const char *str)
    +{
    + struct intel_bts_recording *btsr =
    + container_of(itr, struct intel_bts_recording, itr);
    + unsigned long long snapshot_size = 0;
    + char *endptr;
    +
    + if (str) {
    + snapshot_size = strtoull(str, &endptr, 0);
    + if (*endptr || snapshot_size > SIZE_MAX)
    + return -1;
    + }
    +
    + opts->auxtrace_snapshot_mode = true;
    + opts->auxtrace_snapshot_size = snapshot_size;
    +
    + btsr->snapshot_size = snapshot_size;
    +
    + return 0;
    +}
    +
    +static u64 intel_bts_reference(struct auxtrace_record *itr __maybe_unused)
    +{
    + return rdtsc();
    +}
    +
    +static int intel_bts_alloc_snapshot_refs(struct intel_bts_recording *btsr,
    + int idx)
    +{
    + const size_t sz = sizeof(struct intel_bts_snapshot_ref);
    + int cnt = btsr->snapshot_ref_cnt, new_cnt = cnt * 2;
    + struct intel_bts_snapshot_ref *refs;
    +
    + if (!new_cnt)
    + new_cnt = 16;
    +
    + while (new_cnt <= idx)
    + new_cnt *= 2;
    +
    + refs = calloc(new_cnt, sz);
    + if (!refs)
    + return -ENOMEM;
    +
    + memcpy(refs, btsr->snapshot_refs, cnt * sz);
    +
    + btsr->snapshot_refs = refs;
    + btsr->snapshot_ref_cnt = new_cnt;
    +
    + return 0;
    +}
    +
    +static void intel_bts_free_snapshot_refs(struct intel_bts_recording *btsr)
    +{
    + int i;
    +
    + for (i = 0; i < btsr->snapshot_ref_cnt; i++)
    + free(btsr->snapshot_refs[i].ref_buf);
    + free(btsr->snapshot_refs);
    +}
    +
    +static void intel_bts_recording_free(struct auxtrace_record *itr)
    +{
    + struct intel_bts_recording *btsr =
    + container_of(itr, struct intel_bts_recording, itr);
    +
    + intel_bts_free_snapshot_refs(btsr);
    + free(btsr);
    +}
    +
    +static int intel_bts_snapshot_start(struct auxtrace_record *itr)
    +{
    + struct intel_bts_recording *btsr =
    + container_of(itr, struct intel_bts_recording, itr);
    + struct perf_evsel *evsel;
    +
    + evlist__for_each(btsr->evlist, evsel) {
    + if (evsel->attr.type == btsr->intel_bts_pmu->type)
    + return perf_evlist__disable_event(btsr->evlist, evsel);
    + }
    + return -EINVAL;
    +}
    +
    +static int intel_bts_snapshot_finish(struct auxtrace_record *itr)
    +{
    + struct intel_bts_recording *btsr =
    + container_of(itr, struct intel_bts_recording, itr);
    + struct perf_evsel *evsel;
    +
    + evlist__for_each(btsr->evlist, evsel) {
    + if (evsel->attr.type == btsr->intel_bts_pmu->type)
    + return perf_evlist__enable_event(btsr->evlist, evsel);
    + }
    + return -EINVAL;
    +}
    +
    +static bool intel_bts_first_wrap(u64 *data, size_t buf_size)
    +{
    + int i, a, b;
    +
    + b = buf_size >> 3;
    + a = b - 512;
    + if (a < 0)
    + a = 0;
    +
    + for (i = a; i < b; i++) {
    + if (data[i])
    + return true;
    + }
    +
    + return false;
    +}
    +
    +static int intel_bts_find_snapshot(struct auxtrace_record *itr, int idx,
    + struct auxtrace_mmap *mm, unsigned char *data,
    + u64 *head, u64 *old)
    +{
    + struct intel_bts_recording *btsr =
    + container_of(itr, struct intel_bts_recording, itr);
    + bool wrapped;
    + int err;
    +
    + pr_debug3("%s: mmap index %d old head %zu new head %zu\n",
    + __func__, idx, (size_t)*old, (size_t)*head);
    +
    + if (idx >= btsr->snapshot_ref_cnt) {
    + err = intel_bts_alloc_snapshot_refs(btsr, idx);
    + if (err)
    + goto out_err;
    + }
    +
    + wrapped = btsr->snapshot_refs[idx].wrapped;
    + if (!wrapped && intel_bts_first_wrap((u64 *)data, mm->len)) {
    + btsr->snapshot_refs[idx].wrapped = true;
    + wrapped = true;
    + }
    +
    + /*
    + * In full trace mode 'head' continually increases. However in snapshot
    + * mode 'head' is an offset within the buffer. Here 'old' and 'head'
    + * are adjusted to match the full trace case which expects that 'old' is
    + * always less than 'head'.
    + */
    + if (wrapped) {
    + *old = *head;
    + *head += mm->len;
    + } else {
    + if (mm->mask)
    + *old &= mm->mask;
    + else
    + *old %= mm->len;
    + if (*old > *head)
    + *head += mm->len;
    + }
    +
    + pr_debug3("%s: wrap-around %sdetected, adjusted old head %zu adjusted new head %zu\n",
    + __func__, wrapped ? "" : "not ", (size_t)*old, (size_t)*head);
    +
    + return 0;
    +
    +out_err:
    + pr_err("%s: failed, error %d\n", __func__, err);
    + return err;
    +}
    +
    +static int intel_bts_read_finish(struct auxtrace_record *itr, int idx)
    +{
    + struct intel_bts_recording *btsr =
    + container_of(itr, struct intel_bts_recording, itr);
    + struct perf_evsel *evsel;
    +
    + evlist__for_each(btsr->evlist, evsel) {
    + if (evsel->attr.type == btsr->intel_bts_pmu->type)
    + return perf_evlist__enable_event_idx(btsr->evlist,
    + evsel, idx);
    + }
    + return -EINVAL;
    +}
    +
    +struct auxtrace_record *intel_bts_recording_init(int *err)
    +{
    + struct perf_pmu *intel_bts_pmu = perf_pmu__find(INTEL_BTS_PMU_NAME);
    + struct intel_bts_recording *btsr;
    +
    + if (!intel_bts_pmu)
    + return NULL;
    +
    + btsr = zalloc(sizeof(struct intel_bts_recording));
    + if (!btsr) {
    + *err = -ENOMEM;
    + return NULL;
    + }
    +
    + btsr->intel_bts_pmu = intel_bts_pmu;
    + btsr->itr.recording_options = intel_bts_recording_options;
    + btsr->itr.info_priv_size = intel_bts_info_priv_size;
    + btsr->itr.info_fill = intel_bts_info_fill;
    + btsr->itr.free = intel_bts_recording_free;
    + btsr->itr.snapshot_start = intel_bts_snapshot_start;
    + btsr->itr.snapshot_finish = intel_bts_snapshot_finish;
    + btsr->itr.find_snapshot = intel_bts_find_snapshot;
    + btsr->itr.parse_snapshot_options = intel_bts_parse_snapshot_options;
    + btsr->itr.reference = intel_bts_reference;
    + btsr->itr.read_finish = intel_bts_read_finish;
    + btsr->itr.alignment = sizeof(struct branch);
    + return &btsr->itr;
    +}
    diff --git a/tools/perf/util/intel-bts.h b/tools/perf/util/intel-bts.h
    new file mode 100644
    index 0000000..0bbf838
    --- /dev/null
    +++ b/tools/perf/util/intel-bts.h
    @@ -0,0 +1,31 @@
    +/*
    + * intel-bts.h: Intel Processor Trace support
    + * Copyright (c) 2013-2014, Intel Corporation.
    + *
    + * This program is free software; you can redistribute it and/or modify it
    + * under the terms and conditions of the GNU General Public License,
    + * version 2, as published by the Free Software Foundation.
    + *
    + * This program is distributed in the hope it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
    + * more details.
    + *
    + */
    +
    +#ifndef INCLUDE__PERF_INTEL_BTS_H__
    +#define INCLUDE__PERF_INTEL_BTS_H__
    +
    +#define INTEL_BTS_PMU_NAME "intel_bts"
    +
    +struct auxtrace_record;
    +struct perf_tool;
    +union perf_event;
    +struct perf_session;
    +
    +struct auxtrace_record *intel_bts_recording_init(int *err);
    +
    +int intel_bts_process_auxtrace_info(union perf_event *event,
    + struct perf_session *session);
    +
    +#endif
    --
    1.9.1


    \
     
     \ /
      Last update: 2015-04-09 18:42    [W:4.245 / U:0.140 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site