Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  intel-bts.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * intel-bts.c: Intel Processor Trace support
 * Copyright (c) 2013-2015, Intel Corporation.
 */


#include <endian.h>
#include <errno.h>
#include <byteswap.h>
#include <inttypes.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/bitops.h>
#include <linux/log2.h>
#include <linux/zalloc.h>

#include "color.h"
#include "evsel.h"
#include "evlist.h"
#include "machine.h"
#include "symbol.h"
#include "session.h"
#include "tool.h"
#include "thread.h"
#include "thread-stack.h"
#include "debug.h"
#include "tsc.h"
#include "auxtrace.h"
#include "intel-pt-decoder/intel-pt-insn-decoder.h"
#include "intel-bts.h"
#include "util/synthetic-events.h"

#define MAX_TIMESTAMP (~0ULL)

#define INTEL_BTS_ERR_NOINSN  5
#define INTEL_BTS_ERR_LOST    9

#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define le64_to_cpu bswap_64
#else
#define le64_to_cpu
#endif

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;
 u32    branches_filter;
 u64    branches_sample_type;
 u64    branches_id;
 size_t    branches_event_size;
 unsigned long   num_events;
};

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 intel_pt_insn intel_pt_insn;
 u32   sample_flags;
};

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, " %08zx: ", 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,
        INTEL_BTS_ERR_LOST, sample->cpu, sample->pid,
        sample->tid, 0, "Lost trace data", sample->time);

 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 inline u8 intel_bts_cpumode(struct intel_bts *bts, uint64_t ip)
{
 return machine__kernel_ip(bts->machine, ip) ?
        PERF_RECORD_MISC_KERNEL :
        PERF_RECORD_MISC_USER;
}

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;

 if (bts->synth_opts.initial_skip &&
     bts->num_events++ <= bts->synth_opts.initial_skip)
  return 0;

 perf_sample__init(&sample, /*all=*/true);
 sample.ip = le64_to_cpu(branch->from);
 sample.cpumode = intel_bts_cpumode(bts, sample.ip);
 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;
 sample.flags = btsq->sample_flags;
 sample.insn_len = btsq->intel_pt_insn.length;
 memcpy(sample.insn, btsq->intel_pt_insn.buf, INTEL_PT_INSN_BUF_SZ);

 event.sample.header.type = PERF_RECORD_SAMPLE;
 event.sample.header.misc = sample.cpumode;
 event.sample.header.size = sizeof(struct perf_event_header);

 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);
  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);

 perf_sample__exit(&sample);
 return ret;
}

static int intel_bts_get_next_insn(struct intel_bts_queue *btsq, u64 ip)
{
 struct machine *machine = btsq->bts->machine;
 struct thread *thread;
 unsigned char buf[INTEL_PT_INSN_BUF_SZ];
 ssize_t len;
 bool x86_64;
 int err = -1;

 thread = machine__find_thread(machine, -1, btsq->tid);
 if (!thread)
  return -1;

 len = thread__memcpy(thread, machine, buf, ip, INTEL_PT_INSN_BUF_SZ, &x86_64);
 if (len <= 0)
  goto out_put;

 if (intel_pt_get_insn(buf, len, x86_64, &btsq->intel_pt_insn))
  goto out_put;

 err = 0;
out_put:
 thread__put(thread);
 return err;
}

static int intel_bts_synth_error(struct intel_bts *bts, int cpu, pid_t pid,
     pid_t tid, u64 ip)
{
 union perf_event event;
 int err;

 auxtrace_synth_error(&event.auxtrace_error, PERF_AUXTRACE_ERROR_ITRACE,
        INTEL_BTS_ERR_NOINSN, cpu, pid, tid, ip,
        "Failed to get instruction", 0);

 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 int intel_bts_get_branch_type(struct intel_bts_queue *btsq,
         struct branch *branch)
{
 int err;

 if (!branch->from) {
  if (branch->to)
   btsq->sample_flags = PERF_IP_FLAG_BRANCH |
          PERF_IP_FLAG_TRACE_BEGIN;
  else
   btsq->sample_flags = 0;
  btsq->intel_pt_insn.length = 0;
 } else if (!branch->to) {
  btsq->sample_flags = PERF_IP_FLAG_BRANCH |
         PERF_IP_FLAG_TRACE_END;
  btsq->intel_pt_insn.length = 0;
 } else {
  err = intel_bts_get_next_insn(btsq, branch->from);
  if (err) {
   btsq->sample_flags = 0;
   btsq->intel_pt_insn.length = 0;
   if (!btsq->bts->synth_opts.errors)
    return 0;
   err = intel_bts_synth_error(btsq->bts, btsq->cpu,
          btsq->pid, btsq->tid,
          branch->from);
   return err;
  }
  btsq->sample_flags = intel_pt_insn_type(btsq->intel_pt_insn.op);
  /* Check for an async branch into the kernel */
  if (!machine__kernel_ip(btsq->bts->machine, branch->from) &&
      machine__kernel_ip(btsq->bts->machine, branch->to) &&
      btsq->sample_flags != (PERF_IP_FLAG_BRANCH |
        PERF_IP_FLAG_CALL |
        PERF_IP_FLAG_SYSCALLRET))
   btsq->sample_flags = PERF_IP_FLAG_BRANCH |
          PERF_IP_FLAG_CALL |
          PERF_IP_FLAG_ASYNC |
          PERF_IP_FLAG_INTERRUPT;
 }

 return 0;
}

static int intel_bts_process_buffer(struct intel_bts_queue *btsq,
        struct auxtrace_buffer *buffer,
        struct thread *thread)
{
 struct branch *branch;
 size_t sz, bsz = sizeof(struct branch);
 u32 filter = btsq->bts->branches_filter;
 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;

 for (; sz > bsz; branch += 1, sz -= bsz) {
  if (!branch->from && !branch->to)
   continue;
  intel_bts_get_branch_type(btsq, branch);
  if (btsq->bts->synth_opts.thread_stack)
   thread_stack__event(thread, btsq->cpu, btsq->sample_flags,
         le64_to_cpu(branch->from),
         le64_to_cpu(branch->to),
         btsq->intel_pt_insn.length,
         buffer->buffer_nr + 1, true, 0, 0);
  if (filter && !(filter & btsq->sample_flags))
   continue;
  err = intel_bts_synth_branch_sample(btsq, branch);
  if (err)
   break;
 }
 return err;
}

static int intel_bts_process_queue(struct intel_bts_queue *btsq, u64 *timestamp)
{
 struct auxtrace_buffer *buffer = btsq->buffer, *old_buffer = buffer;
 struct auxtrace_queue *queue;
 struct thread *thread;
 int err;

 if (btsq->done)
  return 1;

 if (btsq->pid == -1) {
  thread = machine__find_thread(btsq->bts->machine, -1,
           btsq->tid);
  if (thread)
   btsq->pid = thread__pid(thread);
 } else {
  thread = machine__findnew_thread(btsq->bts->machine, btsq->pid,
       btsq->tid);
 }

 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;
  err = 1;
  goto out_put;
 }

 /* Currently there is no support for split buffers */
 if (buffer->consecutive) {
  err = -EINVAL;
  goto out_put;
 }

 if (!buffer->data) {
  int fd = perf_data__fd(btsq->bts->session->data);

  buffer->data = auxtrace_buffer__get_data(buffer, fd);
  if (!buffer->data) {
   err = -ENOMEM;
   goto out_put;
  }
 }

 if (btsq->bts->snapshot_mode && !buffer->consecutive &&
     intel_bts_do_fix_overlap(queue, buffer)) {
  err = -ENOMEM;
  goto out_put;
 }

 if (!btsq->bts->synth_opts.callchain &&
     !btsq->bts->synth_opts.thread_stack && thread &&
     (!old_buffer || btsq->bts->sampling_mode ||
      (btsq->bts->snapshot_mode && !buffer->consecutive)))
  thread_stack__set_trace_nr(thread, btsq->cpu, buffer->buffer_nr + 1);

 err = intel_bts_process_buffer(btsq, buffer, thread);

 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;
 }
out_put:
 thread__put(thread);
 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,
       const 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 && sample->time != (u64)-1)
  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->fork.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,
         const 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__fd(session->data);
  int err;

  if (perf_data__is_pipe(session->data)) {
   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,
      const 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);
}

static bool intel_bts_evsel_is_auxtrace(struct perf_session *session,
     struct evsel *evsel)
{
 struct intel_bts *bts = container_of(session->auxtrace, struct intel_bts,
          auxtrace);

 return evsel->core.attr.type == bts->pmu_type;
}

static int intel_bts_synth_events(struct intel_bts *bts,
      struct perf_session *session)
{
 struct evlist *evlist = session->evlist;
 struct evsel *evsel;
 struct perf_event_attr attr;
 bool found = false;
 u64 id;
 int err;

 evlist__for_each_entry(evlist, evsel) {
  if (evsel->core.attr.type == bts->pmu_type && evsel->core.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->core.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->core.attr.exclude_user;
 attr.exclude_kernel = evsel->core.attr.exclude_kernel;
 attr.exclude_hv = evsel->core.attr.exclude_hv;
 attr.exclude_host = evsel->core.attr.exclude_host;
 attr.exclude_guest = evsel->core.attr.exclude_guest;
 attr.sample_id_all = evsel->core.attr.sample_id_all;
 attr.read_format = evsel->core.attr.read_format;

 id = evsel->core.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 = perf_session__deliver_synth_attr_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
 * __evsel__sample_size() here.
 */

  bts->branches_event_size = sizeof(struct perf_record_sample) +
        __evsel__sample_size(attr.sample_type);
 }

 return 0;
}

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 Multiplier %"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]);
}

int intel_bts_process_auxtrace_info(union perf_event *event,
        struct perf_session *session)
{
 struct perf_record_auxtrace_info *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 perf_record_auxtrace_info) +
     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;
 bts->auxtrace.evsel_is_auxtrace = intel_bts_evsel_is_auxtrace;
 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->set) {
  bts->synth_opts = *session->itrace_synth_opts;
 } else {
  itrace_synth_opts__set_default(&bts->synth_opts,
    session->itrace_synth_opts->default_no_sample);
  bts->synth_opts.thread_stack =
    session->itrace_synth_opts->thread_stack;
 }

 if (bts->synth_opts.calls)
  bts->branches_filter |= PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC |
     PERF_IP_FLAG_TRACE_END;
 if (bts->synth_opts.returns)
  bts->branches_filter |= PERF_IP_FLAG_RETURN |
     PERF_IP_FLAG_TRACE_BEGIN;

 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;
}

Messung V0.5
C=100 H=92 G=95

¤ Dauer der Verarbeitung: 0.4 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge