Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/tools/perf/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 114 kB image not shown  

Quelle  builtin-script.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
#include "builtin.h"

#include "util/counts.h"
#include "util/debug.h"
#include "util/dso.h"
#include <subcmd/exec-cmd.h>
#include "util/header.h"
#include <subcmd/parse-options.h>
#include "util/perf_regs.h"
#include "util/session.h"
#include "util/tool.h"
#include "util/map.h"
#include "util/srcline.h"
#include "util/symbol.h"
#include "util/thread.h"
#include "util/trace-event.h"
#include "util/env.h"
#include "util/evlist.h"
#include "util/evsel.h"
#include "util/evsel_fprintf.h"
#include "util/evswitch.h"
#include "util/sort.h"
#include "util/data.h"
#include "util/auxtrace.h"
#include "util/cpumap.h"
#include "util/thread_map.h"
#include "util/stat.h"
#include "util/color.h"
#include "util/string2.h"
#include "util/thread-stack.h"
#include "util/time-utils.h"
#include "util/path.h"
#include "util/event.h"
#include "util/mem-info.h"
#include "ui/ui.h"
#include "print_binary.h"
#include "print_insn.h"
#include "archinsn.h"
#include <linux/bitmap.h>
#include <linux/compiler.h>
#include <linux/kernel.h>
#include <linux/stringify.h>
#include <linux/time64.h>
#include <linux/zalloc.h>
#include <sys/utsname.h>
#include "asm/bug.h"
#include "util/mem-events.h"
#include "util/dump-insn.h"
#include <dirent.h>
#include <errno.h>
#include <inttypes.h>
#include <signal.h>
#include <stdio.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <subcmd/pager.h>
#include <perf/evlist.h>
#include <linux/err.h>
#include "util/dlfilter.h"
#include "util/record.h"
#include "util/util.h"
#include "util/cgroup.h"
#include "util/annotate.h"
#include "perf.h"

#include <linux/ctype.h>
#ifdef HAVE_LIBTRACEEVENT
#include <event-parse.h>
#endif

static char const  *script_name;
static char const  *generate_script_lang;
static bool   reltime;
static bool   deltatime;
static u64   initial_time;
static u64   previous_time;
static bool   debug_mode;
static u64   last_timestamp;
static u64   nr_unordered;
static bool   no_callchain;
static bool   latency_format;
static bool   system_wide;
static bool   print_flags;
static const char  *cpu_list;
static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
static int   max_blocks;
static bool   native_arch;
static struct dlfilter  *dlfilter;
static int   dlargc;
static char   **dlargv;

enum perf_output_field {
 PERF_OUTPUT_COMM            = 1ULL << 0,
 PERF_OUTPUT_TID             = 1ULL << 1,
 PERF_OUTPUT_PID             = 1ULL << 2,
 PERF_OUTPUT_TIME            = 1ULL << 3,
 PERF_OUTPUT_CPU             = 1ULL << 4,
 PERF_OUTPUT_EVNAME          = 1ULL << 5,
 PERF_OUTPUT_TRACE           = 1ULL << 6,
 PERF_OUTPUT_IP              = 1ULL << 7,
 PERF_OUTPUT_SYM             = 1ULL << 8,
 PERF_OUTPUT_DSO             = 1ULL << 9,
 PERF_OUTPUT_ADDR            = 1ULL << 10,
 PERF_OUTPUT_SYMOFFSET       = 1ULL << 11,
 PERF_OUTPUT_SRCLINE         = 1ULL << 12,
 PERF_OUTPUT_PERIOD          = 1ULL << 13,
 PERF_OUTPUT_IREGS     = 1ULL << 14,
 PERF_OUTPUT_BRSTACK     = 1ULL << 15,
 PERF_OUTPUT_BRSTACKSYM     = 1ULL << 16,
 PERF_OUTPUT_DATA_SRC     = 1ULL << 17,
 PERF_OUTPUT_WEIGHT     = 1ULL << 18,
 PERF_OUTPUT_BPF_OUTPUT     = 1ULL << 19,
 PERF_OUTPUT_CALLINDENT     = 1ULL << 20,
 PERF_OUTPUT_INSN     = 1ULL << 21,
 PERF_OUTPUT_INSNLEN     = 1ULL << 22,
 PERF_OUTPUT_BRSTACKINSN     = 1ULL << 23,
 PERF_OUTPUT_BRSTACKOFF     = 1ULL << 24,
 PERF_OUTPUT_SYNTH           = 1ULL << 25,
 PERF_OUTPUT_PHYS_ADDR       = 1ULL << 26,
 PERF_OUTPUT_UREGS     = 1ULL << 27,
 PERF_OUTPUT_METRIC     = 1ULL << 28,
 PERF_OUTPUT_MISC            = 1ULL << 29,
 PERF_OUTPUT_SRCCODE     = 1ULL << 30,
 PERF_OUTPUT_IPC             = 1ULL << 31,
 PERF_OUTPUT_TOD             = 1ULL << 32,
 PERF_OUTPUT_DATA_PAGE_SIZE  = 1ULL << 33,
 PERF_OUTPUT_CODE_PAGE_SIZE  = 1ULL << 34,
 PERF_OUTPUT_INS_LAT         = 1ULL << 35,
 PERF_OUTPUT_BRSTACKINSNLEN  = 1ULL << 36,
 PERF_OUTPUT_MACHINE_PID     = 1ULL << 37,
 PERF_OUTPUT_VCPU            = 1ULL << 38,
 PERF_OUTPUT_CGROUP          = 1ULL << 39,
 PERF_OUTPUT_RETIRE_LAT      = 1ULL << 40,
 PERF_OUTPUT_DSOFF           = 1ULL << 41,
 PERF_OUTPUT_DISASM          = 1ULL << 42,
 PERF_OUTPUT_BRSTACKDISASM   = 1ULL << 43,
 PERF_OUTPUT_BRCNTR          = 1ULL << 44,
};

struct perf_script {
 struct perf_tool tool;
 struct perf_session *session;
 bool   show_task_events;
 bool   show_mmap_events;
 bool   show_switch_events;
 bool   show_namespace_events;
 bool   show_lost_events;
 bool   show_round_events;
 bool   show_bpf_events;
 bool   show_cgroup_events;
 bool   show_text_poke_events;
 bool   allocated;
 bool   per_event_dump;
 bool   stitch_lbr;
 struct evswitch  evswitch;
 struct perf_cpu_map *cpus;
 struct perf_thread_map *threads;
 int   name_width;
 const char              *time_str;
 struct perf_time_interval *ptime_range;
 int   range_size;
 int   range_num;
};

struct output_option {
 const char *str;
 enum perf_output_field field;
} all_output_options[] = {
 {.str = "comm",  .field = PERF_OUTPUT_COMM},
 {.str = "tid",   .field = PERF_OUTPUT_TID},
 {.str = "pid",   .field = PERF_OUTPUT_PID},
 {.str = "time",  .field = PERF_OUTPUT_TIME},
 {.str = "cpu",   .field = PERF_OUTPUT_CPU},
 {.str = "event", .field = PERF_OUTPUT_EVNAME},
 {.str = "trace", .field = PERF_OUTPUT_TRACE},
 {.str = "ip",    .field = PERF_OUTPUT_IP},
 {.str = "sym",   .field = PERF_OUTPUT_SYM},
 {.str = "dso",   .field = PERF_OUTPUT_DSO},
 {.str = "dsoff", .field = PERF_OUTPUT_DSOFF},
 {.str = "addr",  .field = PERF_OUTPUT_ADDR},
 {.str = "symoff", .field = PERF_OUTPUT_SYMOFFSET},
 {.str = "srcline", .field = PERF_OUTPUT_SRCLINE},
 {.str = "period", .field = PERF_OUTPUT_PERIOD},
 {.str = "iregs", .field = PERF_OUTPUT_IREGS},
 {.str = "uregs", .field = PERF_OUTPUT_UREGS},
 {.str = "brstack", .field = PERF_OUTPUT_BRSTACK},
 {.str = "brstacksym", .field = PERF_OUTPUT_BRSTACKSYM},
 {.str = "data_src", .field = PERF_OUTPUT_DATA_SRC},
 {.str = "weight",   .field = PERF_OUTPUT_WEIGHT},
 {.str = "bpf-output",   .field = PERF_OUTPUT_BPF_OUTPUT},
 {.str = "callindent", .field = PERF_OUTPUT_CALLINDENT},
 {.str = "insn", .field = PERF_OUTPUT_INSN},
 {.str = "disasm", .field = PERF_OUTPUT_DISASM},
 {.str = "insnlen", .field = PERF_OUTPUT_INSNLEN},
 {.str = "brstackinsn", .field = PERF_OUTPUT_BRSTACKINSN},
 {.str = "brstackoff", .field = PERF_OUTPUT_BRSTACKOFF},
 {.str = "synth", .field = PERF_OUTPUT_SYNTH},
 {.str = "phys_addr", .field = PERF_OUTPUT_PHYS_ADDR},
 {.str = "metric", .field = PERF_OUTPUT_METRIC},
 {.str = "misc", .field = PERF_OUTPUT_MISC},
 {.str = "srccode", .field = PERF_OUTPUT_SRCCODE},
 {.str = "ipc", .field = PERF_OUTPUT_IPC},
 {.str = "tod", .field = PERF_OUTPUT_TOD},
 {.str = "data_page_size", .field = PERF_OUTPUT_DATA_PAGE_SIZE},
 {.str = "code_page_size", .field = PERF_OUTPUT_CODE_PAGE_SIZE},
 {.str = "ins_lat", .field = PERF_OUTPUT_INS_LAT},
 {.str = "brstackinsnlen", .field = PERF_OUTPUT_BRSTACKINSNLEN},
 {.str = "machine_pid", .field = PERF_OUTPUT_MACHINE_PID},
 {.str = "vcpu", .field = PERF_OUTPUT_VCPU},
 {.str = "cgroup", .field = PERF_OUTPUT_CGROUP},
 {.str = "retire_lat", .field = PERF_OUTPUT_RETIRE_LAT},
 {.str = "brstackdisasm", .field = PERF_OUTPUT_BRSTACKDISASM},
 {.str = "brcntr", .field = PERF_OUTPUT_BRCNTR},
};

enum {
 OUTPUT_TYPE_SYNTH = PERF_TYPE_MAX,
 OUTPUT_TYPE_OTHER,
 OUTPUT_TYPE_MAX
};

// We need to refactor the evsel->priv use in in 'perf script' to allow for
// using that area, that is being used only in some cases.
#define OUTPUT_TYPE_UNSET -1

/* default set to maintain compatibility with current format */
static struct {
 bool user_set;
 bool wildcard_set;
 unsigned int print_ip_opts;
 u64 fields;
 u64 invalid_fields;
 u64 user_set_fields;
 u64 user_unset_fields;
} output[OUTPUT_TYPE_MAX] = {

 [PERF_TYPE_HARDWARE] = {
  .user_set = false,

  .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
         PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
         PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
         PERF_OUTPUT_SYM | PERF_OUTPUT_SYMOFFSET |
         PERF_OUTPUT_DSO | PERF_OUTPUT_PERIOD,

  .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
 },

 [PERF_TYPE_SOFTWARE] = {
  .user_set = false,

  .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
         PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
         PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
         PERF_OUTPUT_SYM | PERF_OUTPUT_SYMOFFSET |
         PERF_OUTPUT_DSO | PERF_OUTPUT_PERIOD |
         PERF_OUTPUT_BPF_OUTPUT,

  .invalid_fields = PERF_OUTPUT_TRACE,
 },

 [PERF_TYPE_TRACEPOINT] = {
  .user_set = false,

  .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
      PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
      PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE
 },

 [PERF_TYPE_HW_CACHE] = {
  .user_set = false,

  .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
         PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
         PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
         PERF_OUTPUT_SYM | PERF_OUTPUT_SYMOFFSET |
         PERF_OUTPUT_DSO | PERF_OUTPUT_PERIOD,

  .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
 },

 [PERF_TYPE_RAW] = {
  .user_set = false,

  .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
         PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
         PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
         PERF_OUTPUT_SYM | PERF_OUTPUT_SYMOFFSET |
         PERF_OUTPUT_DSO | PERF_OUTPUT_PERIOD |
         PERF_OUTPUT_ADDR | PERF_OUTPUT_DATA_SRC |
         PERF_OUTPUT_WEIGHT | PERF_OUTPUT_PHYS_ADDR |
         PERF_OUTPUT_DATA_PAGE_SIZE | PERF_OUTPUT_CODE_PAGE_SIZE |
         PERF_OUTPUT_INS_LAT | PERF_OUTPUT_RETIRE_LAT,

  .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
 },

 [PERF_TYPE_BREAKPOINT] = {
  .user_set = false,

  .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
         PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
         PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
         PERF_OUTPUT_SYM | PERF_OUTPUT_SYMOFFSET |
         PERF_OUTPUT_DSO | PERF_OUTPUT_PERIOD,

  .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
 },

 [OUTPUT_TYPE_SYNTH] = {
  .user_set = false,

  .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
         PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
         PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
         PERF_OUTPUT_SYM | PERF_OUTPUT_SYMOFFSET |
         PERF_OUTPUT_DSO | PERF_OUTPUT_SYNTH,

  .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
 },

 [OUTPUT_TYPE_OTHER] = {
  .user_set = false,

  .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
         PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
         PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
         PERF_OUTPUT_SYM | PERF_OUTPUT_SYMOFFSET |
         PERF_OUTPUT_DSO | PERF_OUTPUT_PERIOD,

  .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
 },
};

struct evsel_script {
       char *filename;
       FILE *fp;
       u64  samples;
       /* For metric output */
       u64  val;
       int  gnum;
};

static inline struct evsel_script *evsel_script(struct evsel *evsel)
{
 return (struct evsel_script *)evsel->priv;
}

static struct evsel_script *evsel_script__new(struct evsel *evsel, struct perf_data *data)
{
 struct evsel_script *es = zalloc(sizeof(*es));

 if (es != NULL) {
  if (asprintf(&es->filename, "%s.%s.dump", data->file.path, evsel__name(evsel)) < 0)
   goto out_free;
  es->fp = fopen(es->filename, "w");
  if (es->fp == NULL)
   goto out_free_filename;
 }

 return es;
out_free_filename:
 zfree(&es->filename);
out_free:
 free(es);
 return NULL;
}

static void evsel_script__delete(struct evsel_script *es)
{
 zfree(&es->filename);
 fclose(es->fp);
 es->fp = NULL;
 free(es);
}

static int evsel_script__fprintf(struct evsel_script *es, FILE *fp)
{
 struct stat st;

 fstat(fileno(es->fp), &st);
 return fprintf(fp, "[ perf script: Wrote %.3f MB %s (%" PRIu64 " samples) ]\n",
         st.st_size / 1024.0 / 1024.0, es->filename, es->samples);
}

static inline int output_type(unsigned int type)
{
 switch (type) {
 case PERF_TYPE_SYNTH:
  return OUTPUT_TYPE_SYNTH;
 default:
  if (type < PERF_TYPE_MAX)
   return type;
 }

 return OUTPUT_TYPE_OTHER;
}

static inline int evsel__output_type(struct evsel *evsel)
{
 int type = evsel->script_output_type;

 if (type == OUTPUT_TYPE_UNSET) {
  type = output_type(evsel->core.attr.type);
  if (type == OUTPUT_TYPE_OTHER) {
   struct perf_pmu *pmu = evsel__find_pmu(evsel);

   if (pmu && pmu->is_core)
    type = PERF_TYPE_RAW;
  }
  evsel->script_output_type = type;
 }

 return type;
}

static bool output_set_by_user(void)
{
 int j;
 for (j = 0; j < OUTPUT_TYPE_MAX; ++j) {
  if (output[j].user_set)
   return true;
 }
 return false;
}

static const char *output_field2str(enum perf_output_field field)
{
 int i, imax = ARRAY_SIZE(all_output_options);
 const char *str = "";

 for (i = 0; i < imax; ++i) {
  if (all_output_options[i].field == field) {
   str = all_output_options[i].str;
   break;
  }
 }
 return str;
}

#define PRINT_FIELD(x)  (output[evsel__output_type(evsel)].fields & PERF_OUTPUT_##x)

static int evsel__do_check_stype(struct evsel *evsel, u64 sample_type, const char *sample_msg,
     enum perf_output_field field, bool allow_user_set)
{
 struct perf_event_attr *attr = &evsel->core.attr;
 int type = evsel__output_type(evsel);
 const char *evname;

 if (attr->sample_type & sample_type)
  return 0;

 if (output[type].user_set_fields & field) {
  if (allow_user_set)
   return 0;
  evname = evsel__name(evsel);
  pr_err("Samples for '%s' event do not have %s attribute set. "
         "Cannot print '%s' field.\n",
         evname, sample_msg, output_field2str(field));
  return -1;
 }

 /* user did not ask for it explicitly so remove from the default list */
 output[type].fields &= ~field;
 evname = evsel__name(evsel);
 pr_debug("Samples for '%s' event do not have %s attribute set. "
   "Skipping '%s' field.\n",
   evname, sample_msg, output_field2str(field));

 return 0;
}

static int evsel__check_stype(struct evsel *evsel, u64 sample_type, const char *sample_msg,
         enum perf_output_field field)
{
 return evsel__do_check_stype(evsel, sample_type, sample_msg, field, false);
}

static int evsel__check_attr(struct evsel *evsel, struct perf_session *session)
{
 bool allow_user_set;

 if (evsel__is_dummy_event(evsel))
  return 0;

 if (perf_header__has_feat(&session->header, HEADER_STAT))
  return 0;

 allow_user_set = perf_header__has_feat(&session->header,
            HEADER_AUXTRACE);

 if (PRINT_FIELD(TRACE) &&
     !perf_session__has_traces(session, "record -R"))
  return -EINVAL;

 if (PRINT_FIELD(IP)) {
  if (evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP", PERF_OUTPUT_IP))
   return -EINVAL;
 }

 if (PRINT_FIELD(ADDR) &&
     evsel__do_check_stype(evsel, PERF_SAMPLE_ADDR, "ADDR", PERF_OUTPUT_ADDR, allow_user_set))
  return -EINVAL;

 if (PRINT_FIELD(DATA_SRC) &&
     evsel__do_check_stype(evsel, PERF_SAMPLE_DATA_SRC, "DATA_SRC", PERF_OUTPUT_DATA_SRC, allow_user_set))
  return -EINVAL;

 if (PRINT_FIELD(WEIGHT) &&
     evsel__do_check_stype(evsel, PERF_SAMPLE_WEIGHT_TYPE, "WEIGHT", PERF_OUTPUT_WEIGHT, allow_user_set))
  return -EINVAL;

 if (PRINT_FIELD(SYM) &&
     !(evsel->core.attr.sample_type & (PERF_SAMPLE_IP|PERF_SAMPLE_ADDR))) {
  pr_err("Display of symbols requested but neither sample IP nor "
      "sample address\navailable. Hence, no addresses to convert "
         "to symbols.\n");
  return -EINVAL;
 }
 if (PRINT_FIELD(SYMOFFSET) && !PRINT_FIELD(SYM)) {
  pr_err("Display of offsets requested but symbol is not"
         "selected.\n");
  return -EINVAL;
 }
 if (PRINT_FIELD(DSO) &&
     !(evsel->core.attr.sample_type & (PERF_SAMPLE_IP|PERF_SAMPLE_ADDR))) {
  pr_err("Display of DSO requested but no address to convert.\n");
  return -EINVAL;
 }
 if ((PRINT_FIELD(SRCLINE) || PRINT_FIELD(SRCCODE)) && !PRINT_FIELD(IP)) {
  pr_err("Display of source line number requested but sample IP is not\n"
         "selected. Hence, no address to lookup the source line number.\n");
  return -EINVAL;
 }
 if ((PRINT_FIELD(BRSTACKINSN) || PRINT_FIELD(BRSTACKINSNLEN) || PRINT_FIELD(BRSTACKDISASM))
     && !allow_user_set &&
     !(evlist__combined_branch_type(session->evlist) & PERF_SAMPLE_BRANCH_ANY)) {
  pr_err("Display of branch stack assembler requested, but non all-branch filter set\n"
         "Hint: run 'perf record -b ...'\n");
  return -EINVAL;
 }
 if (PRINT_FIELD(BRCNTR) &&
     !(evlist__combined_branch_type(session->evlist) & PERF_SAMPLE_BRANCH_COUNTERS)) {
  pr_err("Display of branch counter requested but it's not enabled\n"
         "Hint: run 'perf record -j any,counter ...'\n");
  return -EINVAL;
 }
 if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) &&
     evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID", PERF_OUTPUT_TID|PERF_OUTPUT_PID))
  return -EINVAL;

 if (PRINT_FIELD(TIME) &&
     evsel__check_stype(evsel, PERF_SAMPLE_TIME, "TIME", PERF_OUTPUT_TIME))
  return -EINVAL;

 if (PRINT_FIELD(CPU) &&
     evsel__do_check_stype(evsel, PERF_SAMPLE_CPU, "CPU", PERF_OUTPUT_CPU, allow_user_set))
  return -EINVAL;

 if (PRINT_FIELD(IREGS) &&
     evsel__do_check_stype(evsel, PERF_SAMPLE_REGS_INTR, "IREGS", PERF_OUTPUT_IREGS, allow_user_set))
  return -EINVAL;

 if (PRINT_FIELD(UREGS) &&
     evsel__check_stype(evsel, PERF_SAMPLE_REGS_USER, "UREGS", PERF_OUTPUT_UREGS))
  return -EINVAL;

 if (PRINT_FIELD(PHYS_ADDR) &&
     evsel__do_check_stype(evsel, PERF_SAMPLE_PHYS_ADDR, "PHYS_ADDR", PERF_OUTPUT_PHYS_ADDR, allow_user_set))
  return -EINVAL;

 if (PRINT_FIELD(DATA_PAGE_SIZE) &&
     evsel__check_stype(evsel, PERF_SAMPLE_DATA_PAGE_SIZE, "DATA_PAGE_SIZE", PERF_OUTPUT_DATA_PAGE_SIZE))
  return -EINVAL;

 if (PRINT_FIELD(CODE_PAGE_SIZE) &&
     evsel__check_stype(evsel, PERF_SAMPLE_CODE_PAGE_SIZE, "CODE_PAGE_SIZE", PERF_OUTPUT_CODE_PAGE_SIZE))
  return -EINVAL;

 if (PRINT_FIELD(INS_LAT) &&
     evsel__check_stype(evsel, PERF_SAMPLE_WEIGHT_STRUCT, "WEIGHT_STRUCT", PERF_OUTPUT_INS_LAT))
  return -EINVAL;

 if (PRINT_FIELD(CGROUP) &&
     evsel__check_stype(evsel, PERF_SAMPLE_CGROUP, "CGROUP", PERF_OUTPUT_CGROUP)) {
  pr_err("Hint: run 'perf record --all-cgroups ...'\n");
  return -EINVAL;
 }

 if (PRINT_FIELD(RETIRE_LAT) &&
     evsel__check_stype(evsel, PERF_SAMPLE_WEIGHT_STRUCT, "WEIGHT_STRUCT", PERF_OUTPUT_RETIRE_LAT))
  return -EINVAL;

 return 0;
}

static void evsel__set_print_ip_opts(struct evsel *evsel)
{
 unsigned int type = evsel__output_type(evsel);

 output[type].print_ip_opts = 0;
 if (PRINT_FIELD(IP))
  output[type].print_ip_opts |= EVSEL__PRINT_IP;

 if (PRINT_FIELD(SYM))
  output[type].print_ip_opts |= EVSEL__PRINT_SYM;

 if (PRINT_FIELD(DSO))
  output[type].print_ip_opts |= EVSEL__PRINT_DSO;

 if (PRINT_FIELD(DSOFF))
  output[type].print_ip_opts |= EVSEL__PRINT_DSOFF;

 if (PRINT_FIELD(SYMOFFSET))
  output[type].print_ip_opts |= EVSEL__PRINT_SYMOFFSET;

 if (PRINT_FIELD(SRCLINE))
  output[type].print_ip_opts |= EVSEL__PRINT_SRCLINE;
}

static struct evsel *find_first_output_type(struct evlist *evlist,
         unsigned int type)
{
 struct evsel *evsel;

 evlist__for_each_entry(evlist, evsel) {
  if (evsel__is_dummy_event(evsel))
   continue;
  if (evsel__output_type(evsel) == (int)type)
   return evsel;
 }
 return NULL;
}

/*
 * verify all user requested events exist and the samples
 * have the expected data
 */

static int perf_session__check_output_opt(struct perf_session *session)
{
 bool tod = false;
 unsigned int j;
 struct evsel *evsel;

 for (j = 0; j < OUTPUT_TYPE_MAX; ++j) {
  evsel = find_first_output_type(session->evlist, j);

  /*
 * even if fields is set to 0 (ie., show nothing) event must
 * exist if user explicitly includes it on the command line
 */

  if (!evsel && output[j].user_set && !output[j].wildcard_set &&
      j != OUTPUT_TYPE_SYNTH) {
   pr_err("%s events do not exist. "
          "Remove corresponding -F option to proceed.\n",
          event_type(j));
   return -1;
  }

  if (evsel && output[j].fields &&
   evsel__check_attr(evsel, session))
   return -1;

  if (evsel == NULL)
   continue;

  /* 'dsoff' implys 'dso' field */
  if (output[j].fields & PERF_OUTPUT_DSOFF)
   output[j].fields |= PERF_OUTPUT_DSO;

  evsel__set_print_ip_opts(evsel);
  tod |= output[j].fields & PERF_OUTPUT_TOD;
 }

 if (!no_callchain) {
  bool use_callchain = false;
  bool not_pipe = false;

  evlist__for_each_entry(session->evlist, evsel) {
   not_pipe = true;
   if (evsel__has_callchain(evsel) || evsel__is_offcpu_event(evsel)) {
    use_callchain = true;
    break;
   }
  }
  if (not_pipe && !use_callchain)
   symbol_conf.use_callchain = false;
 }

 /*
 * set default for tracepoints to print symbols only
 * if callchains are present
 */

 if (symbol_conf.use_callchain &&
     !output[PERF_TYPE_TRACEPOINT].user_set) {
  j = PERF_TYPE_TRACEPOINT;

  evlist__for_each_entry(session->evlist, evsel) {
   if (evsel->core.attr.type != j)
    continue;

   if (evsel__has_callchain(evsel)) {
    output[j].fields |= PERF_OUTPUT_IP;
    output[j].fields |= PERF_OUTPUT_SYM;
    output[j].fields |= PERF_OUTPUT_SYMOFFSET;
    output[j].fields |= PERF_OUTPUT_DSO;
    evsel__set_print_ip_opts(evsel);
    goto out;
   }
  }
 }

 if (tod && !perf_session__env(session)->clock.enabled) {
  pr_err("Can't provide 'tod' time, missing clock data. "
         "Please record with -k/--clockid option.\n");
  return -1;
 }
out:
 return 0;
}

static int perf_sample__fprintf_regs(struct regs_dump *regs, uint64_t mask, const char *arch,
         FILE *fp)
{
 unsigned i = 0, r;
 int printed = 0;

 if (!regs || !regs->regs)
  return 0;

 printed += fprintf(fp, " ABI:%" PRIu64 " ", regs->abi);

 for_each_set_bit(r, (unsigned long *) &mask, sizeof(mask) * 8) {
  u64 val = regs->regs[i++];
  printed += fprintf(fp, "%5s:0x%"PRIx64" ", perf_reg_name(r, arch), val);
 }

 return printed;
}

#define DEFAULT_TOD_FMT "%F %H:%M:%S"

static char*
tod_scnprintf(struct perf_script *script, char *buf, int buflen,
      u64 timestamp)
{
 u64 tod_ns, clockid_ns;
 struct perf_env *env;
 unsigned long nsec;
 struct tm ltime;
 char date[64];
 time_t sec;

 buf[0] = '\0';
 if (buflen < 64 || !script)
  return buf;

 env = perf_session__env(script->session);
 if (!env->clock.enabled) {
  scnprintf(buf, buflen, "disabled");
  return buf;
 }

 clockid_ns = env->clock.clockid_ns;
 tod_ns     = env->clock.tod_ns;

 if (timestamp > clockid_ns)
  tod_ns += timestamp - clockid_ns;
 else
  tod_ns -= clockid_ns - timestamp;

 sec  = (time_t) (tod_ns / NSEC_PER_SEC);
 nsec = tod_ns - sec * NSEC_PER_SEC;

 if (localtime_r(&sec, <ime) == NULL) {
  scnprintf(buf, buflen, "failed");
 } else {
  strftime(date, sizeof(date), DEFAULT_TOD_FMT, <ime);

  if (symbol_conf.nanosecs) {
   snprintf(buf, buflen, "%s.%09lu", date, nsec);
  } else {
   snprintf(buf, buflen, "%s.%06lu",
     date, nsec / NSEC_PER_USEC);
  }
 }

 return buf;
}

static int perf_sample__fprintf_iregs(struct perf_sample *sample,
          struct perf_event_attr *attr, const char *arch, FILE *fp)
{
 if (!sample->intr_regs)
  return 0;

 return perf_sample__fprintf_regs(perf_sample__intr_regs(sample),
      attr->sample_regs_intr, arch, fp);
}

static int perf_sample__fprintf_uregs(struct perf_sample *sample,
          struct perf_event_attr *attr, const char *arch, FILE *fp)
{
 if (!sample->user_regs)
  return 0;

 return perf_sample__fprintf_regs(perf_sample__user_regs(sample),
      attr->sample_regs_user, arch, fp);
}

static int perf_sample__fprintf_start(struct perf_script *script,
          struct perf_sample *sample,
          struct thread *thread,
          struct evsel *evsel,
          u32 type, FILE *fp)
{
 unsigned long secs;
 unsigned long long nsecs;
 int printed = 0;
 char tstr[128];

 /*
 * Print the branch counter's abbreviation list,
 * if the branch counter is available.
 */

 if (PRINT_FIELD(BRCNTR) && !verbose) {
  char *buf;

  if (!annotation_br_cntr_abbr_list(&buf, evsel, true)) {
   printed += fprintf(stdout, "%s", buf);
   free(buf);
  }
 }

 if (PRINT_FIELD(MACHINE_PID) && sample->machine_pid)
  printed += fprintf(fp, "VM:%5d ", sample->machine_pid);

 /* Print VCPU only for guest events i.e. with machine_pid */
 if (PRINT_FIELD(VCPU) && sample->machine_pid)
  printed += fprintf(fp, "VCPU:%03d ", sample->vcpu);

 if (PRINT_FIELD(COMM)) {
  const char *comm = thread ? thread__comm_str(thread) : ":-1";

  if (latency_format)
   printed += fprintf(fp, "%8.8s ", comm);
  else if (PRINT_FIELD(IP) && evsel__has_callchain(evsel) && symbol_conf.use_callchain)
   printed += fprintf(fp, "%s ", comm);
  else
   printed += fprintf(fp, "%16s ", comm);
 }

 if (PRINT_FIELD(PID) && PRINT_FIELD(TID))
  printed += fprintf(fp, "%7d/%-7d ", sample->pid, sample->tid);
 else if (PRINT_FIELD(PID))
  printed += fprintf(fp, "%7d ", sample->pid);
 else if (PRINT_FIELD(TID))
  printed += fprintf(fp, "%7d ", sample->tid);

 if (PRINT_FIELD(CPU)) {
  if (latency_format)
   printed += fprintf(fp, "%3d ", sample->cpu);
  else
   printed += fprintf(fp, "[%03d] ", sample->cpu);
 }

 if (PRINT_FIELD(MISC)) {
  int ret = 0;

  #define has(m) \
   (sample->misc & PERF_RECORD_MISC_##m) == PERF_RECORD_MISC_##m

  if (has(KERNEL))
   ret += fprintf(fp, "K");
  if (has(USER))
   ret += fprintf(fp, "U");
  if (has(HYPERVISOR))
   ret += fprintf(fp, "H");
  if (has(GUEST_KERNEL))
   ret += fprintf(fp, "G");
  if (has(GUEST_USER))
   ret += fprintf(fp, "g");

  switch (type) {
  case PERF_RECORD_MMAP:
  case PERF_RECORD_MMAP2:
   if (has(MMAP_DATA))
    ret += fprintf(fp, "M");
   break;
  case PERF_RECORD_COMM:
   if (has(COMM_EXEC))
    ret += fprintf(fp, "E");
   break;
  case PERF_RECORD_SWITCH:
  case PERF_RECORD_SWITCH_CPU_WIDE:
   if (has(SWITCH_OUT)) {
    ret += fprintf(fp, "S");
    if (sample->misc & PERF_RECORD_MISC_SWITCH_OUT_PREEMPT)
     ret += fprintf(fp, "p");
   }
  default:
   break;
  }

  #undef has

  ret += fprintf(fp, "%*s", 6 - ret, " ");
  printed += ret;
 }

 if (PRINT_FIELD(TOD)) {
  tod_scnprintf(script, tstr, sizeof(tstr), sample->time);
  printed += fprintf(fp, "%s ", tstr);
 }

 if (PRINT_FIELD(TIME)) {
  u64 t = sample->time;
  if (reltime) {
   if (!initial_time)
    initial_time = sample->time;
   t = sample->time - initial_time;
  } else if (deltatime) {
   if (previous_time)
    t = sample->time - previous_time;
   else {
    t = 0;
   }
   previous_time = sample->time;
  }
  nsecs = t;
  secs = nsecs / NSEC_PER_SEC;
  nsecs -= secs * NSEC_PER_SEC;

  if (symbol_conf.nanosecs)
   printed += fprintf(fp, "%5lu.%09llu: ", secs, nsecs);
  else {
   char sample_time[32];
   timestamp__scnprintf_usec(t, sample_time, sizeof(sample_time));
   printed += fprintf(fp, "%12s: ", sample_time);
  }
 }

 return printed;
}

static inline size_t
bstack_event_str(struct branch_entry *br, char *buf, size_t sz)
{
 if (!(br->flags.mispred || br->flags.predicted || br->flags.not_taken))
  return snprintf(buf, sz, "-");

 return snprintf(buf, sz, "%s%s",
   br->flags.predicted ? "P" : "M",
   br->flags.not_taken ? "N" : "");
}

static int print_bstack_flags(FILE *fp, struct branch_entry *br)
{
 char events[16] = { 0 };
 size_t pos;

 pos = bstack_event_str(br, events, sizeof(events));
 return fprintf(fp, "/%s/%c/%c/%d/%s/%s ",
         pos < 0 ? "-" : events,
         br->flags.in_tx ? 'X' : '-',
         br->flags.abort ? 'A' : '-',
         br->flags.cycles,
         get_branch_type(br),
         br->flags.spec ? branch_spec_desc(br->flags.spec) : "-");
}

static int perf_sample__fprintf_brstack(struct perf_sample *sample,
     struct thread *thread,
     struct evsel *evsel, FILE *fp)
{
 struct branch_stack *br = sample->branch_stack;
 struct branch_entry *entries = perf_sample__branch_entries(sample);
 u64 i, from, to;
 int printed = 0;

 if (!(br && br->nr))
  return 0;

 for (i = 0; i < br->nr; i++) {
  from = entries[i].from;
  to   = entries[i].to;

  printed += fprintf(fp, " 0x%"PRIx64, from);
  if (PRINT_FIELD(DSO)) {
   struct addr_location alf, alt;

   addr_location__init(&alf);
   addr_location__init(&alt);
   thread__find_map_fb(thread, sample->cpumode, from, &alf);
   thread__find_map_fb(thread, sample->cpumode, to, &alt);

   printed += map__fprintf_dsoname_dsoff(alf.map, PRINT_FIELD(DSOFF), alf.addr, fp);
   printed += fprintf(fp, "/0x%"PRIx64, to);
   printed += map__fprintf_dsoname_dsoff(alt.map, PRINT_FIELD(DSOFF), alt.addr, fp);
   addr_location__exit(&alt);
   addr_location__exit(&alf);
  } else
   printed += fprintf(fp, "/0x%"PRIx64, to);

  printed += print_bstack_flags(fp, entries + i);
 }

 return printed;
}

static int perf_sample__fprintf_brstacksym(struct perf_sample *sample,
        struct thread *thread,
        struct evsel *evsel, FILE *fp)
{
 struct branch_stack *br = sample->branch_stack;
 struct branch_entry *entries = perf_sample__branch_entries(sample);
 u64 i, from, to;
 int printed = 0;

 if (!(br && br->nr))
  return 0;

 for (i = 0; i < br->nr; i++) {
  struct addr_location alf, alt;

  addr_location__init(&alf);
  addr_location__init(&alt);
  from = entries[i].from;
  to   = entries[i].to;

  thread__find_symbol_fb(thread, sample->cpumode, from, &alf);
  thread__find_symbol_fb(thread, sample->cpumode, to, &alt);

  printed += symbol__fprintf_symname_offs(alf.sym, &alf, fp);
  if (PRINT_FIELD(DSO))
   printed += map__fprintf_dsoname_dsoff(alf.map, PRINT_FIELD(DSOFF), alf.addr, fp);
  printed += fprintf(fp, "%c"'/');
  printed += symbol__fprintf_symname_offs(alt.sym, &alt, fp);
  if (PRINT_FIELD(DSO))
   printed += map__fprintf_dsoname_dsoff(alt.map, PRINT_FIELD(DSOFF), alt.addr, fp);
  printed += print_bstack_flags(fp, entries + i);
  addr_location__exit(&alt);
  addr_location__exit(&alf);
 }

 return printed;
}

static int perf_sample__fprintf_brstackoff(struct perf_sample *sample,
        struct thread *thread,
        struct evsel *evsel, FILE *fp)
{
 struct branch_stack *br = sample->branch_stack;
 struct branch_entry *entries = perf_sample__branch_entries(sample);
 u64 i, from, to;
 int printed = 0;

 if (!(br && br->nr))
  return 0;

 for (i = 0; i < br->nr; i++) {
  struct addr_location alf, alt;

  addr_location__init(&alf);
  addr_location__init(&alt);
  from = entries[i].from;
  to   = entries[i].to;

  if (thread__find_map_fb(thread, sample->cpumode, from, &alf) &&
      !dso__adjust_symbols(map__dso(alf.map)))
   from = map__dso_map_ip(alf.map, from);

  if (thread__find_map_fb(thread, sample->cpumode, to, &alt) &&
      !dso__adjust_symbols(map__dso(alt.map)))
   to = map__dso_map_ip(alt.map, to);

  printed += fprintf(fp, " 0x%"PRIx64, from);
  if (PRINT_FIELD(DSO))
   printed += map__fprintf_dsoname_dsoff(alf.map, PRINT_FIELD(DSOFF), alf.addr, fp);
  printed += fprintf(fp, "/0x%"PRIx64, to);
  if (PRINT_FIELD(DSO))
   printed += map__fprintf_dsoname_dsoff(alt.map, PRINT_FIELD(DSOFF), alt.addr, fp);
  printed += print_bstack_flags(fp, entries + i);
  addr_location__exit(&alt);
  addr_location__exit(&alf);
 }

 return printed;
}
#define MAXBB 16384UL

static int grab_bb(u8 *buffer, u64 start, u64 end,
      struct machine *machine, struct thread *thread,
      bool *is64bit, u8 *cpumode, bool last)
{
 long offset, len;
 struct addr_location al;
 bool kernel;
 struct dso *dso;
 int ret = 0;

 if (!start || !end)
  return 0;

 kernel = machine__kernel_ip(machine, start);
 if (kernel)
  *cpumode = PERF_RECORD_MISC_KERNEL;
 else
  *cpumode = PERF_RECORD_MISC_USER;

 /*
 * Block overlaps between kernel and user.
 * This can happen due to ring filtering
 * On Intel CPUs the entry into the kernel is filtered,
 * but the exit is not. Let the caller patch it up.
 */

 if (kernel != machine__kernel_ip(machine, end)) {
  pr_debug("\tblock %" PRIx64 "-%" PRIx64 " transfers between kernel and user\n", start, end);
  return -ENXIO;
 }

 if (end - start > MAXBB - MAXINSN) {
  if (last)
   pr_debug("\tbrstack does not reach to final jump (%" PRIx64 "-%" PRIx64 ")\n", start, end);
  else
   pr_debug("\tblock %" PRIx64 "-%" PRIx64 " (%" PRIu64 ") too long to dump\n", start, end, end - start);
  return 0;
 }

 addr_location__init(&al);
 if (!thread__find_map(thread, *cpumode, start, &al) || (dso = map__dso(al.map)) == NULL) {
  pr_debug("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end);
  goto out;
 }
 if (dso__data(dso)->status == DSO_DATA_STATUS_ERROR) {
  pr_debug("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end);
  goto out;
 }

 /* Load maps to ensure dso->is_64_bit has been updated */
 map__load(al.map);

 offset = map__map_ip(al.map, start);
 len = dso__data_read_offset(dso, machine, offset, (u8 *)buffer,
        end - start + MAXINSN);

 *is64bit = dso__is_64_bit(dso);
 if (len <= 0)
  pr_debug("\tcannot fetch code for block at %" PRIx64 "-%" PRIx64 "\n",
   start, end);
 ret = len;
out:
 addr_location__exit(&al);
 return ret;
}

static int map__fprintf_srccode(struct map *map, u64 addr, FILE *fp, struct srccode_state *state)
{
 char *srcfile;
 int ret = 0;
 unsigned line;
 int len;
 char *srccode;
 struct dso *dso;

 if (!map || (dso = map__dso(map)) == NULL)
  return 0;
 srcfile = get_srcline_split(dso,
        map__rip_2objdump(map, addr),
        &line);
 if (!srcfile)
  return 0;

 /* Avoid redundant printing */
 if (state &&
     state->srcfile &&
     !strcmp(state->srcfile, srcfile) &&
     state->line == line) {
  free(srcfile);
  return 0;
 }

 srccode = find_sourceline(srcfile, line, &len);
 if (!srccode)
  goto out_free_line;

 ret = fprintf(fp, "|%-8d %.*s", line, len, srccode);

 if (state) {
  state->srcfile = srcfile;
  state->line = line;
 }
 return ret;

out_free_line:
 free(srcfile);
 return ret;
}

static int print_srccode(struct thread *thread, u8 cpumode, uint64_t addr)
{
 struct addr_location al;
 int ret = 0;

 addr_location__init(&al);
 thread__find_map(thread, cpumode, addr, &al);
 if (!al.map)
  goto out;
 ret = map__fprintf_srccode(al.map, al.addr, stdout,
       thread__srccode_state(thread));
 if (ret)
  ret += printf("\n");
out:
 addr_location__exit(&al);
 return ret;
}

static int any_dump_insn(struct evsel *evsel __maybe_unused,
    struct perf_insn *x, uint64_t ip,
    u8 *inbuf, int inlen, int *lenp,
    FILE *fp)
{
#ifdef HAVE_LIBCAPSTONE_SUPPORT
 if (PRINT_FIELD(BRSTACKDISASM)) {
  int printed = fprintf_insn_asm(x->machine, x->thread, x->cpumode, x->is64bit,
            (uint8_t *)inbuf, inlen, ip, lenp,
            PRINT_INSN_IMM_HEX, fp);

  if (printed > 0)
   return printed;
 }
#endif
 return fprintf(fp, "%s", dump_insn(x, ip, inbuf, inlen, lenp));
}

static int add_padding(FILE *fp, int printed, int padding)
{
 if (printed >= 0 && printed < padding)
  printed += fprintf(fp, "%*s", padding - printed, "");
 return printed;
}

static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en,
       struct perf_insn *x, u8 *inbuf, int len,
       int insn, FILE *fp, int *total_cycles,
       struct evsel *evsel,
       struct thread *thread,
       u64 br_cntr)
{
 int ilen = 0;
 int printed = fprintf(fp, "\t%016" PRIx64 "\t", ip);

 printed += add_padding(fp, any_dump_insn(evsel, x, ip, inbuf, len, &ilen, fp), 30);
 printed += fprintf(fp, "\t");

 if (PRINT_FIELD(BRSTACKINSNLEN))
  printed += fprintf(fp, "ilen: %d\t", ilen);

 if (PRINT_FIELD(SRCLINE)) {
  struct addr_location al;

  addr_location__init(&al);
  thread__find_map(thread, x->cpumode, ip, &al);
  printed += map__fprintf_srcline(al.map, al.addr, " srcline: ", fp);
  printed += fprintf(fp, "\t");
  addr_location__exit(&al);
 }

 if (PRINT_FIELD(BRCNTR)) {
  struct evsel *pos = evsel__leader(evsel);
  unsigned int i = 0, j, num, mask, width;

  perf_env__find_br_cntr_info(evsel__env(evsel), NULL, &width);
  mask = (1L << width) - 1;
  printed += fprintf(fp, "br_cntr: ");
  evlist__for_each_entry_from(evsel->evlist, pos) {
   if (!(pos->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_COUNTERS))
    continue;
   if (evsel__leader(pos) != evsel__leader(evsel))
    break;

   num = (br_cntr >> (i++ * width)) & mask;
   if (!verbose) {
    for (j = 0; j < num; j++)
     printed += fprintf(fp, "%s", pos->abbr_name);
   } else
    printed += fprintf(fp, "%s %d ", pos->name, num);
  }
  printed += fprintf(fp, "\t");
 }

 printed += fprintf(fp, "#%s%s%s%s",
         en->flags.predicted ? " PRED" : "",
         en->flags.mispred ? " MISPRED" : "",
         en->flags.in_tx ? " INTX" : "",
         en->flags.abort ? " ABORT" : "");
 if (en->flags.cycles) {
  *total_cycles += en->flags.cycles;
  printed += fprintf(fp, " %d cycles [%d]", en->flags.cycles, *total_cycles);
  if (insn)
   printed += fprintf(fp, " %.2f IPC", (float)insn / en->flags.cycles);
 }

 return printed + fprintf(fp, "\n");
}

static int ip__fprintf_sym(uint64_t addr, struct thread *thread,
      u8 cpumode, int cpu, struct symbol **lastsym,
      struct evsel *evsel, FILE *fp)
{
 struct addr_location al;
 int off, printed = 0, ret = 0;

 addr_location__init(&al);
 thread__find_map(thread, cpumode, addr, &al);

 if ((*lastsym) && al.addr >= (*lastsym)->start && al.addr < (*lastsym)->end)
  goto out;

 al.cpu = cpu;
 al.sym = NULL;
 if (al.map)
  al.sym = map__find_symbol(al.map, al.addr);

 if (!al.sym)
  goto out;

 if (al.addr < al.sym->end)
  off = al.addr - al.sym->start;
 else
  off = al.addr - map__start(al.map) - al.sym->start;
 printed += fprintf(fp, "\t%s", al.sym->name);
 if (off)
  printed += fprintf(fp, "%+d", off);
 printed += fprintf(fp, ":");
 if (PRINT_FIELD(SRCLINE))
  printed += map__fprintf_srcline(al.map, al.addr, "\t", fp);
 printed += fprintf(fp, "\n");
 *lastsym = al.sym;

 ret = printed;
out:
 addr_location__exit(&al);
 return ret;
}

static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
         struct evsel *evsel,
         struct thread *thread,
         struct perf_event_attr *attr,
         struct machine *machine, FILE *fp)
{
 struct branch_stack *br = sample->branch_stack;
 struct branch_entry *entries = perf_sample__branch_entries(sample);
 u64 start, end;
 int i, insn, len, nr, ilen, printed = 0;
 struct perf_insn x;
 u8 buffer[MAXBB];
 unsigned off;
 struct symbol *lastsym = NULL;
 int total_cycles = 0;
 u64 br_cntr = 0;

 if (!(br && br->nr))
  return 0;
 nr = br->nr;
 if (max_blocks && nr > max_blocks + 1)
  nr = max_blocks + 1;

 x.thread = thread;
 x.machine = machine;
 x.cpu = sample->cpu;

 if (PRINT_FIELD(BRCNTR) && sample->branch_stack_cntr)
  br_cntr = sample->branch_stack_cntr[nr - 1];

 printed += fprintf(fp, "%c"'\n');

 /* Handle first from jump, of which we don't know the entry. */
 len = grab_bb(buffer, entries[nr-1].from,
   entries[nr-1].from,
   machine, thread, &x.is64bit, &x.cpumode, false);
 if (len > 0) {
  printed += ip__fprintf_sym(entries[nr - 1].from, thread,
        x.cpumode, x.cpu, &lastsym, evsel, fp);
  printed += ip__fprintf_jump(entries[nr - 1].from, &entries[nr - 1],
         &x, buffer, len, 0, fp, &total_cycles,
         evsel, thread, br_cntr);
  if (PRINT_FIELD(SRCCODE))
   printed += print_srccode(thread, x.cpumode, entries[nr - 1].from);
 }

 /* Print all blocks */
 for (i = nr - 2; i >= 0; i--) {
  if (entries[i].from || entries[i].to)
   pr_debug("%d: %" PRIx64 "-%" PRIx64 "\n", i,
     entries[i].from,
     entries[i].to);
  start = entries[i + 1].to;
  end   = entries[i].from;

  len = grab_bb(buffer, start, end, machine, thread, &x.is64bit, &x.cpumode, false);
  /* Patch up missing kernel transfers due to ring filters */
  if (len == -ENXIO && i > 0) {
   end = entries[--i].from;
   pr_debug("\tpatching up to %" PRIx64 "-%" PRIx64 "\n", start, end);
   len = grab_bb(buffer, start, end, machine, thread, &x.is64bit, &x.cpumode, false);
  }
  if (len <= 0)
   continue;

  insn = 0;
  for (off = 0; off < (unsigned)len; off += ilen) {
   uint64_t ip = start + off;

   printed += ip__fprintf_sym(ip, thread, x.cpumode, x.cpu, &lastsym, evsel, fp);
   if (ip == end) {
    if (PRINT_FIELD(BRCNTR) && sample->branch_stack_cntr)
     br_cntr = sample->branch_stack_cntr[i];
    printed += ip__fprintf_jump(ip, &entries[i], &x, buffer + off, len - off, ++insn, fp,
           &total_cycles, evsel, thread, br_cntr);
    if (PRINT_FIELD(SRCCODE))
     printed += print_srccode(thread, x.cpumode, ip);
    break;
   } else {
    ilen = 0;
    printed += fprintf(fp, "\t%016" PRIx64 "\t", ip);
    printed += any_dump_insn(evsel, &x, ip, buffer + off, len - off, &ilen, fp);
    if (PRINT_FIELD(BRSTACKINSNLEN))
     printed += fprintf(fp, "\tilen: %d", ilen);
    printed += fprintf(fp, "\n");
    if (ilen == 0)
     break;
    if (PRINT_FIELD(SRCCODE))
     print_srccode(thread, x.cpumode, ip);
    insn++;
   }
  }
  if (off != end - start)
   printed += fprintf(fp, "\tmismatch of LBR data and executable\n");
 }

 /*
 * Hit the branch? In this case we are already done, and the target
 * has not been executed yet.
 */

 if (entries[0].from == sample->ip)
  goto out;
 if (entries[0].flags.abort)
  goto out;

 /*
 * Print final block up to sample
 *
 * Due to pipeline delays the LBRs might be missing a branch
 * or two, which can result in very large or negative blocks
 * between final branch and sample. When this happens just
 * continue walking after the last TO.
 */

 start = entries[0].to;
 end = sample->ip;
 if (end < start) {
  /* Missing jump. Scan 128 bytes for the next branch */
  end = start + 128;
 }
 len = grab_bb(buffer, start, end, machine, thread, &x.is64bit, &x.cpumode, true);
 printed += ip__fprintf_sym(start, thread, x.cpumode, x.cpu, &lastsym, evsel, fp);
 if (len <= 0) {
  /* Print at least last IP if basic block did not work */
  len = grab_bb(buffer, sample->ip, sample->ip,
         machine, thread, &x.is64bit, &x.cpumode, false);
  if (len <= 0)
   goto out;
  ilen = 0;
  printed += fprintf(fp, "\t%016" PRIx64 "\t", sample->ip);
  printed += any_dump_insn(evsel, &x, sample->ip, buffer, len, &ilen, fp);
  if (PRINT_FIELD(BRSTACKINSNLEN))
   printed += fprintf(fp, "\tilen: %d", ilen);
  printed += fprintf(fp, "\n");
  if (PRINT_FIELD(SRCCODE))
   print_srccode(thread, x.cpumode, sample->ip);
  goto out;
 }
 for (off = 0; off <= end - start; off += ilen) {
  ilen = 0;
  printed += fprintf(fp, "\t%016" PRIx64 "\t", start + off);
  printed += any_dump_insn(evsel, &x, start + off, buffer + off, len - off, &ilen, fp);
  if (PRINT_FIELD(BRSTACKINSNLEN))
   printed += fprintf(fp, "\tilen: %d", ilen);
  printed += fprintf(fp, "\n");
  if (ilen == 0)
   break;
  if ((attr->branch_sample_type == 0 || attr->branch_sample_type & PERF_SAMPLE_BRANCH_ANY)
    && arch_is_uncond_branch(buffer + off, len - off, x.is64bit)
    && start + off != sample->ip) {
   /*
 * Hit a missing branch. Just stop.
 */

   printed += fprintf(fp, "\t... not reaching sample ...\n");
   break;
  }
  if (PRINT_FIELD(SRCCODE))
   print_srccode(thread, x.cpumode, start + off);
 }
out:
 return printed;
}

static int perf_sample__fprintf_addr(struct perf_sample *sample,
         struct thread *thread,
         struct evsel *evsel, FILE *fp)
{
 struct addr_location al;
 int printed = fprintf(fp, "%16" PRIx64, sample->addr);

 addr_location__init(&al);
 if (!sample_addr_correlates_sym(&evsel->core.attr))
  goto out;

 thread__resolve(thread, &al, sample);

 if (PRINT_FIELD(SYM)) {
  printed += fprintf(fp, " ");
  if (PRINT_FIELD(SYMOFFSET))
   printed += symbol__fprintf_symname_offs(al.sym, &al, fp);
  else
   printed += symbol__fprintf_symname(al.sym, fp);
 }

 if (PRINT_FIELD(DSO))
  printed += map__fprintf_dsoname_dsoff(al.map, PRINT_FIELD(DSOFF), al.addr, fp);
out:
 addr_location__exit(&al);
 return printed;
}

static const char *resolve_branch_sym(struct perf_sample *sample,
          struct evsel *evsel,
          struct thread *thread,
          struct addr_location *al,
          struct addr_location *addr_al,
          u64 *ip)
{
 const char *name = NULL;

 if (sample->flags & (PERF_IP_FLAG_CALL | PERF_IP_FLAG_TRACE_BEGIN)) {
  if (sample_addr_correlates_sym(&evsel->core.attr)) {
   if (!addr_al->thread)
    thread__resolve(thread, addr_al, sample);
   if (addr_al->sym)
    name = addr_al->sym->name;
   else
    *ip = sample->addr;
  } else {
   *ip = sample->addr;
  }
 } else if (sample->flags & (PERF_IP_FLAG_RETURN | PERF_IP_FLAG_TRACE_END)) {
  if (al->sym)
   name = al->sym->name;
  else
   *ip = sample->ip;
 }
 return name;
}

static int perf_sample__fprintf_callindent(struct perf_sample *sample,
        struct evsel *evsel,
        struct thread *thread,
        struct addr_location *al,
        struct addr_location *addr_al,
        FILE *fp)
{
 size_t depth = thread_stack__depth(thread, sample->cpu);
 const char *name = NULL;
 static int spacing;
 int len = 0;
 int dlen = 0;
 u64 ip = 0;

 /*
 * The 'return' has already been popped off the stack so the depth has
 * to be adjusted to match the 'call'.
 */

 if (thread__ts(thread) && sample->flags & PERF_IP_FLAG_RETURN)
  depth += 1;

 name = resolve_branch_sym(sample, evsel, thread, al, addr_al, &ip);

 if (PRINT_FIELD(DSO) && !(PRINT_FIELD(IP) || PRINT_FIELD(ADDR))) {
  dlen += fprintf(fp, "(");
  dlen += map__fprintf_dsoname(al->map, fp);
  dlen += fprintf(fp, ")\t");
 }

 if (name)
  len = fprintf(fp, "%*s%s", (int)depth * 4, "", name);
 else if (ip)
  len = fprintf(fp, "%*s%16" PRIx64, (int)depth * 4, "", ip);

 if (len < 0)
  return len;

 /*
 * Try to keep the output length from changing frequently so that the
 * output lines up more nicely.
 */

 if (len > spacing || (len && len < spacing - 52))
  spacing = round_up(len + 4, 32);

 if (len < spacing)
  len += fprintf(fp, "%*s", spacing - len, "");

 return len + dlen;
}

static int perf_sample__fprintf_insn(struct perf_sample *sample,
         struct evsel *evsel,
         struct perf_event_attr *attr,
         struct thread *thread,
         struct machine *machine, FILE *fp,
         struct addr_location *al)
{
 int printed = 0;

 script_fetch_insn(sample, thread, machine, native_arch);

 if (PRINT_FIELD(INSNLEN))
  printed += fprintf(fp, " ilen: %d", sample->insn_len);
 if (PRINT_FIELD(INSN) && sample->insn_len) {
  printed += fprintf(fp, " insn: ");
  printed += sample__fprintf_insn_raw(sample, fp);
 }
 if (PRINT_FIELD(DISASM) && sample->insn_len) {
  printed += fprintf(fp, "\t\t");
  printed += sample__fprintf_insn_asm(sample, thread, machine, fp, al);
 }
 if (PRINT_FIELD(BRSTACKINSN) || PRINT_FIELD(BRSTACKINSNLEN) || PRINT_FIELD(BRSTACKDISASM))
  printed += perf_sample__fprintf_brstackinsn(sample, evsel, thread, attr, machine, fp);

 return printed;
}

static int perf_sample__fprintf_ipc(struct perf_sample *sample,
        struct evsel *evsel, FILE *fp)
{
 unsigned int ipc;

 if (!PRINT_FIELD(IPC) || !sample->cyc_cnt || !sample->insn_cnt)
  return 0;

 ipc = (sample->insn_cnt * 100) / sample->cyc_cnt;

 return fprintf(fp, " \t IPC: %u.%02u (%" PRIu64 "/%" PRIu64 ") ",
         ipc / 100, ipc % 100, sample->insn_cnt, sample->cyc_cnt);
}

static int perf_sample__fprintf_bts(struct perf_sample *sample,
        struct evsel *evsel,
        struct thread *thread,
        struct addr_location *al,
        struct addr_location *addr_al,
        struct machine *machine, FILE *fp)
{
 struct perf_event_attr *attr = &evsel->core.attr;
 unsigned int type = evsel__output_type(evsel);
 bool print_srcline_last = false;
 int printed = 0;

 if (PRINT_FIELD(CALLINDENT))
  printed += perf_sample__fprintf_callindent(sample, evsel, thread, al, addr_al, fp);

 /* print branch_from information */
 if (PRINT_FIELD(IP)) {
  unsigned int print_opts = output[type].print_ip_opts;
  struct callchain_cursor *cursor = NULL;

  if (symbol_conf.use_callchain && sample->callchain) {
   cursor = get_tls_callchain_cursor();
   if (thread__resolve_callchain(al->thread, cursor, evsel,
            sample, NULL, NULL,
            scripting_max_stack))
    cursor = NULL;
  }
  if (cursor == NULL) {
   printed += fprintf(fp, " ");
   if (print_opts & EVSEL__PRINT_SRCLINE) {
    print_srcline_last = true;
    print_opts &= ~EVSEL__PRINT_SRCLINE;
   }
  } else
   printed += fprintf(fp, "\n");

  printed += sample__fprintf_sym(sample, al, 0, print_opts, cursor,
            symbol_conf.bt_stop_list, fp);
 }

 /* print branch_to information */
 if (PRINT_FIELD(ADDR) ||
     ((evsel->core.attr.sample_type & PERF_SAMPLE_ADDR) &&
      !output[type].user_set)) {
  printed += fprintf(fp, " => ");
  printed += perf_sample__fprintf_addr(sample, thread, evsel, fp);
 }

 printed += perf_sample__fprintf_ipc(sample, evsel, fp);

 if (print_srcline_last)
  printed += map__fprintf_srcline(al->map, al->addr, "\n ", fp);

 printed += perf_sample__fprintf_insn(sample, evsel, attr, thread, machine, fp, al);
 printed += fprintf(fp, "\n");
 if (PRINT_FIELD(SRCCODE)) {
  int ret = map__fprintf_srccode(al->map, al->addr, stdout,
            thread__srccode_state(thread));
  if (ret) {
   printed += ret;
   printed += printf("\n");
  }
 }
 return printed;
}

static int perf_sample__fprintf_flags(u32 flags, FILE *fp)
{
 char str[SAMPLE_FLAGS_BUF_SIZE];
 int ret;

 ret = perf_sample__sprintf_flags(flags, str, sizeof(str));
 if (ret < 0)
  return fprintf(fp, " raw flags:0x%-*x ",
          SAMPLE_FLAGS_STR_ALIGNED_SIZE - 12, flags);

 return fprintf(fp, " %-*s ", SAMPLE_FLAGS_STR_ALIGNED_SIZE, str);
}

struct printer_data {
 int line_no;
 bool hit_nul;
 bool is_printable;
};

static int sample__fprintf_bpf_output(enum binary_printer_ops op,
          unsigned int val,
          void *extra, FILE *fp)
{
 unsigned char ch = (unsigned char)val;
 struct printer_data *printer_data = extra;
 int printed = 0;

 switch (op) {
 case BINARY_PRINT_DATA_BEGIN:
  printed += fprintf(fp, "\n");
  break;
 case BINARY_PRINT_LINE_BEGIN:
  printed += fprintf(fp, "%17s", !printer_data->line_no ? "BPF output:" :
              " ");
  break;
 case BINARY_PRINT_ADDR:
  printed += fprintf(fp, " %04x:", val);
  break;
 case BINARY_PRINT_NUM_DATA:
  printed += fprintf(fp, " %02x", val);
  break;
 case BINARY_PRINT_NUM_PAD:
  printed += fprintf(fp, " ");
  break;
 case BINARY_PRINT_SEP:
  printed += fprintf(fp, " ");
  break;
 case BINARY_PRINT_CHAR_DATA:
  if (printer_data->hit_nul && ch)
   printer_data->is_printable = false;

  if (!isprint(ch)) {
   printed += fprintf(fp, "%c"'.');

   if (!printer_data->is_printable)
    break;

   if (ch == '\0')
    printer_data->hit_nul = true;
   else
    printer_data->is_printable = false;
  } else {
   printed += fprintf(fp, "%c", ch);
  }
  break;
 case BINARY_PRINT_CHAR_PAD:
  printed += fprintf(fp, " ");
  break;
 case BINARY_PRINT_LINE_END:
  printed += fprintf(fp, "\n");
  printer_data->line_no++;
  break;
 case BINARY_PRINT_DATA_END:
 default:
  break;
 }

 return printed;
}

static int perf_sample__fprintf_bpf_output(struct perf_sample *sample, FILE *fp)
{
 unsigned int nr_bytes = sample->raw_size;
 struct printer_data printer_data = {0, falsetrue};
 int printed = binary__fprintf(sample->raw_data, nr_bytes, 8,
          sample__fprintf_bpf_output, &printer_data, fp);

 if (printer_data.is_printable && printer_data.hit_nul)
  printed += fprintf(fp, "%17s \"%s\"\n""BPF string:", (char *)(sample->raw_data));

 return printed;
}

static int perf_sample__fprintf_spacing(int len, int spacing, FILE *fp)
{
 if (len > 0 && len < spacing)
  return fprintf(fp, "%*s", spacing - len, "");

 return 0;
}

static int perf_sample__fprintf_pt_spacing(int len, FILE *fp)
{
 return perf_sample__fprintf_spacing(len, 34, fp);
}

/* If a value contains only printable ASCII characters padded with NULLs */
static bool ptw_is_prt(u64 val)
{
 char c;
 u32 i;

 for (i = 0; i < sizeof(val); i++) {
  c = ((char *)&val)[i];
  if (!c)
   break;
  if (!isprint(c) || !isascii(c))
   return false;
 }
 for (; i < sizeof(val); i++) {
  c = ((char *)&val)[i];
  if (c)
   return false;
 }
 return true;
}

static int perf_sample__fprintf_synth_ptwrite(struct perf_sample *sample, FILE *fp)
{
 struct perf_synth_intel_ptwrite *data = perf_sample__synth_ptr(sample);
 char str[sizeof(u64) + 1] = "";
 int len;
 u64 val;

 if (perf_sample__bad_synth_size(sample, *data))
  return 0;

 val = le64_to_cpu(data->payload);
 if (ptw_is_prt(val)) {
  memcpy(str, &val, sizeof(val));
  str[sizeof(val)] = 0;
 }
 len = fprintf(fp, " IP: %u payload: %#" PRIx64 " %s ",
        data->ip, val, str);
 return len + perf_sample__fprintf_pt_spacing(len, fp);
}

static int perf_sample__fprintf_synth_mwait(struct perf_sample *sample, FILE *fp)
{
 struct perf_synth_intel_mwait *data = perf_sample__synth_ptr(sample);
 int len;

 if (perf_sample__bad_synth_size(sample, *data))
  return 0;

 len = fprintf(fp, " hints: %#x extensions: %#x ",
        data->hints, data->extensions);
 return len + perf_sample__fprintf_pt_spacing(len, fp);
}

static int perf_sample__fprintf_synth_pwre(struct perf_sample *sample, FILE *fp)
{
 struct perf_synth_intel_pwre *data = perf_sample__synth_ptr(sample);
 int len;

 if (perf_sample__bad_synth_size(sample, *data))
  return 0;

 len = fprintf(fp, " hw: %u cstate: %u sub-cstate: %u ",
        data->hw, data->cstate, data->subcstate);
 return len + perf_sample__fprintf_pt_spacing(len, fp);
}

static int perf_sample__fprintf_synth_exstop(struct perf_sample *sample, FILE *fp)
{
 struct perf_synth_intel_exstop *data = perf_sample__synth_ptr(sample);
 int len;

 if (perf_sample__bad_synth_size(sample, *data))
  return 0;

 len = fprintf(fp, " IP: %u ", data->ip);
 return len + perf_sample__fprintf_pt_spacing(len, fp);
}

static int perf_sample__fprintf_synth_pwrx(struct perf_sample *sample, FILE *fp)
{
 struct perf_synth_intel_pwrx *data = perf_sample__synth_ptr(sample);
 int len;

 if (perf_sample__bad_synth_size(sample, *data))
  return 0;

 len = fprintf(fp, " deepest cstate: %u last cstate: %u wake reason: %#x ",
       data->deepest_cstate, data->last_cstate,
       data->wake_reason);
 return len + perf_sample__fprintf_pt_spacing(len, fp);
}

static int perf_sample__fprintf_synth_cbr(struct perf_sample *sample, FILE *fp)
{
 struct perf_synth_intel_cbr *data = perf_sample__synth_ptr(sample);
 unsigned int percent, freq;
 int len;

 if (perf_sample__bad_synth_size(sample, *data))
  return 0;

 freq = (le32_to_cpu(data->freq) + 500) / 1000;
 len = fprintf(fp, " cbr: %2u freq: %4u MHz ", data->cbr, freq);
 if (data->max_nonturbo) {
  percent = (5 + (1000 * data->cbr) / data->max_nonturbo) / 10;
  len += fprintf(fp, "(%3u%%) ", percent);
 }
 return len + perf_sample__fprintf_pt_spacing(len, fp);
}

static int perf_sample__fprintf_synth_psb(struct perf_sample *sample, FILE *fp)
{
 struct perf_synth_intel_psb *data = perf_sample__synth_ptr(sample);
 int len;

 if (perf_sample__bad_synth_size(sample, *data))
  return 0;

 len = fprintf(fp, " psb offs: %#" PRIx64, data->offset);
 return len + perf_sample__fprintf_pt_spacing(len, fp);
}

/* Intel PT Event Trace */
static int perf_sample__fprintf_synth_evt(struct perf_sample *sample, FILE *fp)
{
 struct perf_synth_intel_evt *data = perf_sample__synth_ptr(sample);
 const char *cfe[32] = {NULL, "INTR""IRET""SMI""RSM""SIPI",
          "INIT""VMENTRY""VMEXIT""VMEXIT_INTR",
          "SHUTDOWN", NULL, "UINTR""UIRET"};
 const char *evd[64] = {"PFA""VMXQ""VMXR"};
 const char *s;
 int len, i;

 if (perf_sample__bad_synth_size(sample, *data))
  return 0;

 s = cfe[data->type];
 if (s) {
  len = fprintf(fp, " cfe: %s IP: %d vector: %u",
         s, data->ip, data->vector);
 } else {
  len = fprintf(fp, " cfe: %u IP: %d vector: %u",
         data->type, data->ip, data->vector);
 }
 for (i = 0; i < data->evd_cnt; i++) {
  unsigned int et = data->evd[i].evd_type & 0x3f;

  s = evd[et];
  if (s) {
   len += fprintf(fp, " %s: %#" PRIx64,
           s, data->evd[i].payload);
  } else {
   len += fprintf(fp, " EVD_%u: %#" PRIx64,
           et, data->evd[i].payload);
  }
 }
 return len + perf_sample__fprintf_pt_spacing(len, fp);
}

static int perf_sample__fprintf_synth_iflag_chg(struct perf_sample *sample, FILE *fp)
{
 struct perf_synth_intel_iflag_chg *data = perf_sample__synth_ptr(sample);
 int len;

 if (perf_sample__bad_synth_size(sample, *data))
  return 0;

 len = fprintf(fp, " IFLAG: %d->%d %s branch", !data->iflag, data->iflag,
        data->via_branch ? "via" : "non");
 return len + perf_sample__fprintf_pt_spacing(len, fp);
}

static int perf_sample__fprintf_synth(struct perf_sample *sample,
          struct evsel *evsel, FILE *fp)
{
 switch (evsel->core.attr.config) {
 case PERF_SYNTH_INTEL_PTWRITE:
  return perf_sample__fprintf_synth_ptwrite(sample, fp);
 case PERF_SYNTH_INTEL_MWAIT:
  return perf_sample__fprintf_synth_mwait(sample, fp);
 case PERF_SYNTH_INTEL_PWRE:
  return perf_sample__fprintf_synth_pwre(sample, fp);
 case PERF_SYNTH_INTEL_EXSTOP:
  return perf_sample__fprintf_synth_exstop(sample, fp);
 case PERF_SYNTH_INTEL_PWRX:
  return perf_sample__fprintf_synth_pwrx(sample, fp);
 case PERF_SYNTH_INTEL_CBR:
  return perf_sample__fprintf_synth_cbr(sample, fp);
 case PERF_SYNTH_INTEL_PSB:
  return perf_sample__fprintf_synth_psb(sample, fp);
 case PERF_SYNTH_INTEL_EVT:
  return perf_sample__fprintf_synth_evt(sample, fp);
 case PERF_SYNTH_INTEL_IFLAG_CHG:
  return perf_sample__fprintf_synth_iflag_chg(sample, fp);
 default:
  break;
 }

 return 0;
}

static int evlist__max_name_len(struct evlist *evlist)
{
 struct evsel *evsel;
 int max = 0;

 evlist__for_each_entry(evlist, evsel) {
  int len = strlen(evsel__name(evsel));

  max = MAX(len, max);
 }

 return max;
}

static int data_src__fprintf(u64 data_src, FILE *fp)
{
 struct mem_info *mi = mem_info__new();
 char decode[100];
 char out[100];
 static int maxlen;
 int len;

 if (!mi)
  return -ENOMEM;

 mem_info__data_src(mi)->val = data_src;
 perf_script__meminfo_scnprintf(decode, 100, mi);
 mem_info__put(mi);

 len = scnprintf(out, 100, "%16" PRIx64 " %s", data_src, decode);
 if (maxlen < len)
  maxlen = len;

 return fprintf(fp, "%-*s", maxlen, out);
}

struct metric_ctx {
 struct perf_sample *sample;
 struct thread  *thread;
 struct evsel *evsel;
 FILE    *fp;
};

static void script_print_metric(struct perf_stat_config *config __maybe_unused,
    void *ctx, enum metric_threshold_classify thresh,
    const char *fmt, const char *unit, double val)
{
 struct metric_ctx *mctx = ctx;
 const char *color = metric_threshold_classify__color(thresh);

 if (!fmt)
  return;
 perf_sample__fprintf_start(NULL, mctx->sample, mctx->thread, mctx->evsel,
       PERF_RECORD_SAMPLE, mctx->fp);
 fputs("\tmetric: ", mctx->fp);
 if (color)
  color_fprintf(mctx->fp, color, fmt, val);
 else
  printf(fmt, val);
 fprintf(mctx->fp, " %s\n", unit);
}

static void script_new_line(struct perf_stat_config *config __maybe_unused,
       void *ctx)
{
 struct metric_ctx *mctx = ctx;

 perf_sample__fprintf_start(NULL, mctx->sample, mctx->thread, mctx->evsel,
       PERF_RECORD_SAMPLE, mctx->fp);
 fputs("\tmetric: ", mctx->fp);
}

static void perf_sample__fprint_metric(struct perf_script *script,
           struct thread *thread,
           struct evsel *evsel,
           struct perf_sample *sample,
           FILE *fp)
{
 struct evsel *leader = evsel__leader(evsel);
 struct perf_stat_output_ctx ctx = {
  .print_metric = script_print_metric,
  .new_line = script_new_line,
  .ctx = &(struct metric_ctx) {
    .sample = sample,
    .thread = thread,
    .evsel  = evsel,
    .fp     = fp,
    },
  .force_header = false,
 };
 struct evsel *ev2;
 u64 val;

 if (!evsel->stats)
  evlist__alloc_stats(&stat_config, script->session->evlist, /*alloc_raw=*/false);
 if (evsel_script(leader)->gnum++ == 0)
  perf_stat__reset_shadow_stats();
 val = sample->period * evsel->scale;
 evsel_script(evsel)->val = val;
 if (evsel_script(leader)->gnum == leader->core.nr_members) {
  for_each_group_member (ev2, leader) {
   perf_stat__print_shadow_stats(&stat_config, ev2,
            evsel_script(ev2)->val,
            sample->cpu,
            &ctx);
  }
  evsel_script(leader)->gnum = 0;
 }
}

static bool show_event(struct perf_sample *sample,
         struct evsel *evsel,
         struct thread *thread,
         struct addr_location *al,
         struct addr_location *addr_al)
{
 int depth = thread_stack__depth(thread, sample->cpu);

 if (!symbol_conf.graph_function)
  return true;

 if (thread__filter(thread)) {
  if (depth <= thread__filter_entry_depth(thread)) {
   thread__set_filter(thread, false);
   return false;
  }
  return true;
 } else {
  const char *s = symbol_conf.graph_function;
  u64 ip;
  const char *name = resolve_branch_sym(sample, evsel, thread, al, addr_al,
    &ip);
  unsigned nlen;

  if (!name)
   return false;
  nlen = strlen(name);
  while (*s) {
   unsigned len = strcspn(s, ",");
   if (nlen == len && !strncmp(name, s, len)) {
    thread__set_filter(thread, true);
    thread__set_filter_entry_depth(thread, depth);
    return true;
   }
   s += len;
   if (*s == ',')
    s++;
  }
  return false;
 }
}

static void process_event(struct perf_script *script,
     struct perf_sample *sample, struct evsel *evsel,
     struct addr_location *al,
     struct addr_location *addr_al,
     struct machine *machine)
{
 struct thread *thread = al->thread;
 struct perf_event_attr *attr = &evsel->core.attr;
 unsigned int type = evsel__output_type(evsel);
 struct evsel_script *es = evsel->priv;
 FILE *fp = es->fp;
 char str[PAGE_SIZE_NAME_LEN];
 const char *arch = perf_env__arch(machine->env);

 if (output[type].fields == 0)
  return;

 ++es->samples;

 perf_sample__fprintf_start(script, sample, thread, evsel,
       PERF_RECORD_SAMPLE, fp);

 if (PRINT_FIELD(PERIOD))
  fprintf(fp, "%10" PRIu64 " ", sample->period);

 if (PRINT_FIELD(EVNAME)) {
  const char *evname = evsel__name(evsel);

  if (!script->name_width)
   script->name_width = evlist__max_name_len(script->session->evlist);

  fprintf(fp, "%*s: ", script->name_width, evname ?: "[unknown]");
 }

 if (print_flags)
  perf_sample__fprintf_flags(sample->flags, fp);

 if (is_bts_event(attr)) {
  perf_sample__fprintf_bts(sample, evsel, thread, al, addr_al, machine, fp);
  return;
 }
#ifdef HAVE_LIBTRACEEVENT
 if (PRINT_FIELD(TRACE) && sample->raw_data) {
  const struct tep_event *tp_format = evsel__tp_format(evsel);

  if (tp_format) {
   event_format__fprintf(tp_format, sample->cpu,
           sample->raw_data, sample->raw_size,
           fp);
  }
 }
#endif
 if (attr->type == PERF_TYPE_SYNTH && PRINT_FIELD(SYNTH))
  perf_sample__fprintf_synth(sample, evsel, fp);

 if (PRINT_FIELD(ADDR))
  perf_sample__fprintf_addr(sample, thread, evsel, fp);

 if (PRINT_FIELD(DATA_SRC))
  data_src__fprintf(sample->data_src, fp);

 if (PRINT_FIELD(WEIGHT))
  fprintf(fp, "%16" PRIu64, sample->weight);

 if (PRINT_FIELD(INS_LAT))
  fprintf(fp, "%16" PRIu16, sample->ins_lat);

 if (PRINT_FIELD(RETIRE_LAT))
  fprintf(fp, "%16" PRIu16, sample->weight3);

 if (PRINT_FIELD(CGROUP)) {
  const char *cgrp_name;
  struct cgroup *cgrp = cgroup__find(machine->env,
         sample->cgroup);
  if (cgrp != NULL)
   cgrp_name = cgrp->name;
  else
   cgrp_name = "unknown";
  fprintf(fp, " %s", cgrp_name);
 }

 if (PRINT_FIELD(IP)) {
  struct callchain_cursor *cursor = NULL;

  if (script->stitch_lbr)
   thread__set_lbr_stitch_enable(al->thread, true);

  if (symbol_conf.use_callchain && sample->callchain) {
   cursor = get_tls_callchain_cursor();
   if (thread__resolve_callchain(al->thread, cursor, evsel,
            sample, NULL, NULL,
            scripting_max_stack))
    cursor = NULL;
  }
  fputc(cursor ? '\n' : ' ', fp);
  sample__fprintf_sym(sample, al, 0, output[type].print_ip_opts, cursor,
        symbol_conf.bt_stop_list, fp);
 }

 if (PRINT_FIELD(IREGS))
  perf_sample__fprintf_iregs(sample, attr, arch, fp);

 if (PRINT_FIELD(UREGS))
  perf_sample__fprintf_uregs(sample, attr, arch, fp);

 if (PRINT_FIELD(BRSTACK))
  perf_sample__fprintf_brstack(sample, thread, evsel, fp);
 else if (PRINT_FIELD(BRSTACKSYM))
  perf_sample__fprintf_brstacksym(sample, thread, evsel, fp);
 else if (PRINT_FIELD(BRSTACKOFF))
  perf_sample__fprintf_brstackoff(sample, thread, evsel, fp);

 if (evsel__is_bpf_output(evsel) && !evsel__is_offcpu_event(evsel) && PRINT_FIELD(BPF_OUTPUT))
  perf_sample__fprintf_bpf_output(sample, fp);
 perf_sample__fprintf_insn(sample, evsel, attr, thread, machine, fp, al);

 if (PRINT_FIELD(PHYS_ADDR))
  fprintf(fp, "%16" PRIx64, sample->phys_addr);

 if (PRINT_FIELD(DATA_PAGE_SIZE))
  fprintf(fp, " %s", get_page_size_name(sample->data_page_size, str));

 if (PRINT_FIELD(CODE_PAGE_SIZE))
  fprintf(fp, " %s", get_page_size_name(sample->code_page_size, str));

 perf_sample__fprintf_ipc(sample, evsel, fp);

 fprintf(fp, "\n");

 if (PRINT_FIELD(SRCCODE)) {
  if (map__fprintf_srccode(al->map, al->addr, stdout,
      thread__srccode_state(thread)))
   printf("\n");
 }

 if (PRINT_FIELD(METRIC))
  perf_sample__fprint_metric(script, thread, evsel, sample, fp);

 if (verbose > 0)
  fflush(fp);
}

static struct scripting_ops *scripting_ops;

static void __process_stat(struct evsel *counter, u64 tstamp)
{
 int nthreads = perf_thread_map__nr(counter->core.threads);
 int idx, thread;
 struct perf_cpu cpu;
 static int header_printed;

 if (!header_printed) {
  printf("%3s %8s %15s %15s %15s %15s %s\n",
         "CPU""THREAD""VAL""ENA""RUN""TIME""EVENT");
  header_printed = 1;
 }

 for (thread = 0; thread < nthreads; thread++) {
  perf_cpu_map__for_each_cpu(cpu, idx, evsel__cpus(counter)) {
   struct perf_counts_values *counts;

   counts = perf_counts(counter->counts, idx, thread);

   printf("%3d %8d %15" PRIu64 " %15" PRIu64 " %15" PRIu64 " %15" PRIu64 " %s\n",
    cpu.cpu,
    perf_thread_map__pid(counter->core.threads, thread),
    counts->val,
    counts->ena,
    counts->run,
    tstamp,
    evsel__name(counter));
  }
 }
}

static void process_stat(struct evsel *counter, u64 tstamp)
{
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=96 H=97 G=96

¤ Dauer der Verarbeitung: 0.22 Sekunden  ¤

*© 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.