cregit-Linux how code gets into the kernel

Release 4.10 tools/perf/builtin-c2c.c

Directory: tools/perf
/*
 * This is rewrite of original c2c tool introduced in here:
 *   http://lwn.net/Articles/588866/
 *
 * The original tool was changed to fit in current perf state.
 *
 * Original authors:
 *   Don Zickus <dzickus@redhat.com>
 *   Dick Fowles <fowles@inreach.com>
 *   Joe Mario <jmario@redhat.com>
 */
#include <linux/compiler.h>
#include <linux/kernel.h>
#include <linux/stringify.h>
#include <asm/bug.h>
#include "util.h"
#include "debug.h"
#include "builtin.h"
#include <subcmd/parse-options.h>
#include "mem-events.h"
#include "session.h"
#include "hist.h"
#include "sort.h"
#include "tool.h"
#include "data.h"
#include "sort.h"
#include "evlist.h"
#include "evsel.h"
#include <asm/bug.h>
#include "ui/browsers/hists.h"
#include "evlist.h"


struct c2c_hists {
	
struct hists		hists;
	
struct perf_hpp_list	list;
	
struct c2c_stats	stats;
};


struct compute_stats {
	
struct stats		 lcl_hitm;
	
struct stats		 rmt_hitm;
	
struct stats		 load;
};


struct c2c_hist_entry {
	
struct c2c_hists	*hists;
	
struct c2c_stats	 stats;
	
unsigned long		*cpuset;
	
struct c2c_stats	*node_stats;
	
unsigned int		 cacheline_idx;

	
struct compute_stats	 cstats;

	/*
         * must be at the end,
         * because of its callchain dynamic entry
         */
	
struct hist_entry	he;
};


static char const *coalesce_default = "pid,tid,iaddr";


struct perf_c2c {
	
struct perf_tool	tool;
	
struct c2c_hists	hists;

	
unsigned long		**nodes;
	
int			 nodes_cnt;
	
int			 cpus_cnt;
	
int			*cpu2node;
	
int			 node_info;

	
bool			 show_src;
	
bool			 show_all;
	
bool			 use_stdio;
	
bool			 stats_only;
	
bool			 symbol_full;

	/* HITM shared clines stats */
	
struct c2c_stats	hitm_stats;
	
int			shared_clines;

	
int			 display;

	
const char		*coalesce;
	
char			*cl_sort;
	
char			*cl_resort;
	
char			*cl_output;
};

enum {
	
DISPLAY_LCL,
	
DISPLAY_RMT,
	
DISPLAY_TOT,
	
DISPLAY_MAX,
};


static const char *display_str[DISPLAY_MAX] = {
	[DISPLAY_LCL] = "Local",
	[DISPLAY_RMT] = "Remote",
	[DISPLAY_TOT] = "Total",
};


static const struct option c2c_options[] = {
	OPT_INCR('v', "verbose", &verbose, "be more verbose (show counter open errors, etc)"),
	OPT_END()
};


static struct perf_c2c c2c;


static void *c2c_he_zalloc(size_t size) { struct c2c_hist_entry *c2c_he; c2c_he = zalloc(size + sizeof(*c2c_he)); if (!c2c_he) return NULL; c2c_he->cpuset = bitmap_alloc(c2c.cpus_cnt); if (!c2c_he->cpuset) return NULL; c2c_he->node_stats = zalloc(c2c.nodes_cnt * sizeof(*c2c_he->node_stats)); if (!c2c_he->node_stats) return NULL; init_stats(&c2c_he->cstats.lcl_hitm); init_stats(&c2c_he->cstats.rmt_hitm); init_stats(&c2c_he->cstats.load); return &c2c_he->he; }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa122100.00%3100.00%
Total122100.00%3100.00%


static void c2c_he_free(void *he) { struct c2c_hist_entry *c2c_he; c2c_he = container_of(he, struct c2c_hist_entry, he); if (c2c_he->hists) { hists__delete_entries(&c2c_he->hists->hists); free(c2c_he->hists); } free(c2c_he->cpuset); free(c2c_he->node_stats); free(c2c_he); }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa71100.00%2100.00%
Total71100.00%2100.00%

static struct hist_entry_ops c2c_entry_ops = { .new = c2c_he_zalloc, .free = c2c_he_free, }; static int c2c_hists__init(struct c2c_hists *hists, const char *sort, int nr_header_lines);
static struct c2c_hists* he__get_c2c_hists(struct hist_entry *he, const char *sort, int nr_header_lines) { struct c2c_hist_entry *c2c_he; struct c2c_hists *hists; int ret; c2c_he = container_of(he, struct c2c_hist_entry, he); if (c2c_he->hists) return c2c_he->hists; hists = c2c_he->hists = zalloc(sizeof(*hists)); if (!hists) return NULL; ret = c2c_hists__init(hists, sort, nr_header_lines); if (ret) { free(hists); return NULL; } return hists; }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa108100.00%3100.00%
Total108100.00%3100.00%


static void c2c_he__set_cpu(struct c2c_hist_entry *c2c_he, struct perf_sample *sample) { if (WARN_ONCE(sample->cpu == (unsigned int) -1, "WARNING: no sample cpu value")) return; set_bit(sample->cpu, c2c_he->cpuset); }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa46100.00%1100.00%
Total46100.00%1100.00%


static void compute_stats(struct c2c_hist_entry *c2c_he, struct c2c_stats *stats, u64 weight) { struct compute_stats *cstats = &c2c_he->cstats; if (stats->rmt_hitm) update_stats(&cstats->rmt_hitm, weight); else if (stats->lcl_hitm) update_stats(&cstats->lcl_hitm, weight); else if (stats->load) update_stats(&cstats->load, weight); }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa79100.00%1100.00%
Total79100.00%1100.00%


static int process_sample_event(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel, struct machine *machine) { struct c2c_hists *c2c_hists = &c2c.hists; struct c2c_hist_entry *c2c_he; struct c2c_stats stats = { .nr_entries = 0, }; struct hist_entry *he; struct addr_location al; struct mem_info *mi, *mi_dup; int ret; if (machine__resolve(machine, &al, sample) < 0) { pr_debug("problem processing %d event, skipping it.\n", event->header.type); return -1; } ret = sample__resolve_callchain(sample, &callchain_cursor, NULL, evsel, &al, sysctl_perf_event_max_stack); if (ret) goto out; mi = sample__resolve_mem(sample, &al); if (mi == NULL) return -ENOMEM; mi_dup = memdup(mi, sizeof(*mi)); if (!mi_dup) goto free_mi; c2c_decode_stats(&stats, mi); he = hists__add_entry_ops(&c2c_hists->hists, &c2c_entry_ops, &al, NULL, NULL, mi, sample, true); if (he == NULL) goto free_mi_dup; c2c_he = container_of(he, struct c2c_hist_entry, he); c2c_add_stats(&c2c_he->stats, &stats); c2c_add_stats(&c2c_hists->stats, &stats); c2c_he__set_cpu(c2c_he, sample); hists__inc_nr_samples(&c2c_hists->hists, he->filtered); ret = hist_entry__append_callchain(he, sample); if (!ret) { /* * There's already been warning about missing * sample's cpu value. Let's account all to * node 0 in this case, without any further * warning. * * Doing node stats only for single callchain data. */ int cpu = sample->cpu == (unsigned int) -1 ? 0 : sample->cpu; int node = c2c.cpu2node[cpu]; mi = mi_dup; mi_dup = memdup(mi, sizeof(*mi)); if (!mi_dup) goto free_mi; c2c_hists = he__get_c2c_hists(he, c2c.cl_sort, 2); if (!c2c_hists) goto free_mi_dup; he = hists__add_entry_ops(&c2c_hists->hists, &c2c_entry_ops, &al, NULL, NULL, mi, sample, true); if (he == NULL) goto free_mi_dup; c2c_he = container_of(he, struct c2c_hist_entry, he); c2c_add_stats(&c2c_he->stats, &stats); c2c_add_stats(&c2c_hists->stats, &stats); c2c_add_stats(&c2c_he->node_stats[node], &stats); compute_stats(c2c_he, &stats, sample->weight); c2c_he__set_cpu(c2c_he, sample); hists__inc_nr_samples(&c2c_hists->hists, he->filtered); ret = hist_entry__append_callchain(he, sample); } out: addr_location__put(&al); return ret; free_mi_dup: free(mi_dup); free_mi: free(mi); ret = -ENOMEM; goto out; }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa521100.00%8100.00%
Total521100.00%8100.00%

static struct perf_c2c c2c = { .tool = { .sample = process_sample_event, .mmap = perf_event__process_mmap, .mmap2 = perf_event__process_mmap2, .comm = perf_event__process_comm, .exit = perf_event__process_exit, .fork = perf_event__process_fork, .lost = perf_event__process_lost, .ordered_events = true, .ordering_requires_timestamps = true, }, }; static const char * const c2c_usage[] = { "perf c2c {record|report}", NULL }; static const char * const __usage_report[] = { "perf c2c report", NULL }; static const char * const *report_c2c_usage = __usage_report; #define C2C_HEADER_MAX 2 struct c2c_header { struct { const char *text; int span; } line[C2C_HEADER_MAX]; }; struct c2c_dimension { struct c2c_header header; const char *name; int width; struct sort_entry *se; int64_t (*cmp)(struct perf_hpp_fmt *fmt, struct hist_entry *, struct hist_entry *); int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he); int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he); }; struct c2c_fmt { struct perf_hpp_fmt fmt; struct c2c_dimension *dim; }; #define SYMBOL_WIDTH 30 static struct c2c_dimension dim_symbol; static struct c2c_dimension dim_srcline;
static int symbol_width(struct hists *hists, struct sort_entry *se) { int width = hists__col_len(hists, se->se_width_idx); if (!c2c.symbol_full) width = MIN(width, SYMBOL_WIDTH); return width; }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa47100.00%1100.00%
Total47100.00%1100.00%


static int c2c_width(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp __maybe_unused, struct hists *hists) { struct c2c_fmt *c2c_fmt; struct c2c_dimension *dim; c2c_fmt = container_of(fmt, struct c2c_fmt, fmt); dim = c2c_fmt->dim; if (dim == &dim_symbol || dim == &dim_srcline) return symbol_width(hists, dim->se); return dim->se ? hists__col_len(hists, dim->se->se_width_idx) : c2c_fmt->dim->width; }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa94100.00%3100.00%
Total94100.00%3100.00%


static int c2c_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hists *hists, int line, int *span) { struct perf_hpp_list *hpp_list = hists->hpp_list; struct c2c_fmt *c2c_fmt; struct c2c_dimension *dim; const char *text = NULL; int width = c2c_width(fmt, hpp, hists); c2c_fmt = container_of(fmt, struct c2c_fmt, fmt); dim = c2c_fmt->dim; if (dim->se) { text = dim->header.line[line].text; /* Use the last line from sort_entry if not defined. */ if (!text && (line == hpp_list->nr_header_lines - 1)) text = dim->se->se_header; } else { text = dim->header.line[line].text; if (*span) { (*span)--; return 0; } else { *span = dim->header.line[line].span; } } if (text == NULL) text = ""; return scnprintf(hpp->buf, hpp->size, "%*s", width, text); }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa206100.00%2100.00%
Total206100.00%2100.00%

#define HEX_STR(__s, __v) \ ({ \ scnprintf(__s, sizeof(__s), "0x%" PRIx64, __v); \ __s; \ })
static int64_t dcacheline_cmp(struct perf_hpp_fmt *fmt __maybe_unused, struct hist_entry *left, struct hist_entry *right) { return sort__dcacheline_cmp(left, right); }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa30100.00%1100.00%
Total30100.00%1100.00%


static int dcacheline_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he) { uint64_t addr = 0; int width = c2c_width(fmt, hpp, he->hists); char buf[20]; if (he->mem_info) addr = cl_address(he->mem_info->daddr.addr); return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr)); }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa88100.00%1100.00%
Total88100.00%1100.00%


static int offset_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he) { uint64_t addr = 0; int width = c2c_width(fmt, hpp, he->hists); char buf[20]; if (he->mem_info) addr = cl_offset(he->mem_info->daddr.al_addr); return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr)); }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa88100.00%1100.00%
Total88100.00%1100.00%


static int64_t offset_cmp(struct perf_hpp_fmt *fmt __maybe_unused, struct hist_entry *left, struct hist_entry *right) { uint64_t l = 0, r = 0; if (left->mem_info) l = cl_offset(left->mem_info->daddr.addr); if (right->mem_info) r = cl_offset(right->mem_info->daddr.addr); return (int64_t)(r - l); }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa79100.00%1100.00%
Total79100.00%1100.00%


static int iaddr_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he) { uint64_t addr = 0; int width = c2c_width(fmt, hpp, he->hists); char buf[20]; if (he->mem_info) addr = he->mem_info->iaddr.addr; return scnprintf(hpp->buf, hpp->size, "%*s", width, HEX_STR(buf, addr)); }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa85100.00%1100.00%
Total85100.00%1100.00%


static int64_t iaddr_cmp(struct perf_hpp_fmt *fmt __maybe_unused, struct hist_entry *left, struct hist_entry *right) { return sort__iaddr_cmp(left, right); }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa30100.00%1100.00%
Total30100.00%1100.00%


static int tot_hitm_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he) { struct c2c_hist_entry *c2c_he; int width = c2c_width(fmt, hpp, he->hists); unsigned int tot_hitm; c2c_he = container_of(he, struct c2c_hist_entry, he); tot_hitm = c2c_he->stats.lcl_hitm + c2c_he->stats.rmt_hitm; return scnprintf(hpp->buf, hpp->size, "%*u", width, tot_hitm); }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa88100.00%1100.00%
Total88100.00%1100.00%


static int64_t tot_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused, struct hist_entry *left, struct hist_entry *right) { struct c2c_hist_entry *c2c_left; struct c2c_hist_entry *c2c_right; unsigned int tot_hitm_left; unsigned int tot_hitm_right; c2c_left = container_of(left, struct c2c_hist_entry, he); c2c_right = container_of(right, struct c2c_hist_entry, he); tot_hitm_left = c2c_left->stats.lcl_hitm + c2c_left->stats.rmt_hitm; tot_hitm_right = c2c_right->stats.lcl_hitm + c2c_right->stats.rmt_hitm; return tot_hitm_left - tot_hitm_right; }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa97100.00%1100.00%
Total97100.00%1100.00%

#define STAT_FN_ENTRY(__f) \ static int \ __f ## _entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, \ struct hist_entry *he) \ { \ struct c2c_hist_entry *c2c_he; \ int width = c2c_width(fmt, hpp, he->hists); \ \ c2c_he = container_of(he, struct c2c_hist_entry, he); \ return scnprintf(hpp->buf, hpp->size, "%*u", width, \ c2c_he->stats.__f); \ } #define STAT_FN_CMP(__f) \ static int64_t \ __f ## _cmp(struct perf_hpp_fmt *fmt __maybe_unused, \ struct hist_entry *left, struct hist_entry *right) \ { \ struct c2c_hist_entry *c2c_left, *c2c_right; \ \ c2c_left = container_of(left, struct c2c_hist_entry, he); \ c2c_right = container_of(right, struct c2c_hist_entry, he); \ return c2c_left->stats.__f - c2c_right->stats.__f; \ } #define STAT_FN(__f) \ STAT_FN_ENTRY(__f) \ STAT_FN_CMP(__f) STAT_FN(rmt_hitm) STAT_FN(lcl_hitm) STAT_FN(store) STAT_FN(st_l1hit) STAT_FN(st_l1miss) STAT_FN(ld_fbhit) STAT_FN(ld_l1hit) STAT_FN(ld_l2hit) STAT_FN(ld_llchit) STAT_FN(rmt_hit)
static uint64_t llc_miss(struct c2c_stats *stats) { uint64_t llcmiss; llcmiss = stats->lcl_dram + stats->rmt_dram + stats->rmt_hitm + stats->rmt_hit; return llcmiss; }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa35100.00%1100.00%
Total35100.00%1100.00%


static int ld_llcmiss_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he) { struct c2c_hist_entry *c2c_he; int width = c2c_width(fmt, hpp, he->hists); c2c_he = container_of(he, struct c2c_hist_entry, he); return scnprintf(hpp->buf, hpp->size, "%*lu", width, llc_miss(&c2c_he->stats)); }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa76100.00%1100.00%
Total76100.00%1100.00%


static int64_t ld_llcmiss_cmp(struct perf_hpp_fmt *fmt __maybe_unused, struct hist_entry *left, struct hist_entry *right) { struct c2c_hist_entry *c2c_left; struct c2c_hist_entry *c2c_right; c2c_left = container_of(left, struct c2c_hist_entry, he); c2c_right = container_of(right, struct c2c_hist_entry, he); return llc_miss(&c2c_left->stats) - llc_miss(&c2c_right->stats); }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa73100.00%1100.00%
Total73100.00%1100.00%


static uint64_t total_records(struct c2c_stats *stats) { uint64_t lclmiss, ldcnt, total; lclmiss = stats->lcl_dram + stats->rmt_dram + stats->rmt_hitm + stats->rmt_hit; ldcnt = lclmiss + stats->ld_fbhit + stats->ld_l1hit + stats->ld_l2hit + stats->ld_llchit + stats->lcl_hitm; total = ldcnt + stats->st_l1hit + stats->st_l1miss; return total; }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa75100.00%1100.00%
Total75100.00%1100.00%


static int tot_recs_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he) { struct c2c_hist_entry *c2c_he; int width = c2c_width(fmt, hpp, he->hists); uint64_t tot_recs; c2c_he = container_of(he, struct c2c_hist_entry, he); tot_recs = total_records(&c2c_he->stats); return scnprintf(hpp->buf, hpp->size, "%*" PRIu64, width, tot_recs); }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa84100.00%1100.00%
Total84100.00%1100.00%


static int64_t tot_recs_cmp(struct perf_hpp_fmt *fmt __maybe_unused, struct hist_entry *left, struct hist_entry *right) { struct c2c_hist_entry *c2c_left; struct c2c_hist_entry *c2c_right; uint64_t tot_recs_left; uint64_t tot_recs_right; c2c_left = container_of(left, struct c2c_hist_entry, he); c2c_right = container_of(right, struct c2c_hist_entry, he); tot_recs_left = total_records(&c2c_left->stats); tot_recs_right = total_records(&c2c_right->stats); return tot_recs_left - tot_recs_right; }

Contributors

PersonTokensPropCommitsCommitProp
jiri olsajiri olsa87100.00%1100.00%
Total87100.00%1100.00%


static uint64_t total_loads(struct c2c_stats *stats) { uint64_t lclmiss, ldcnt