Commit 8b98436a authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'perf-tools-fixes-for-v5.16-2021-11-19' of...

Merge tag 'perf-tools-fixes-for-v5.16-2021-11-19' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux

Pull perf tools fixes from Arnaldo Carvalho de Melo:

 - Fix the 'local_weight', 'weight' (memory access latency),
   'local_ins_lat', 'ins_lat' (instruction latency) and 'pstage_cyc'
   (pipeline stage cycles) sort key sample aggregation.

 - Fix 'perf test' entry for watchpoints on s/390.

 - Fix branch_stack entry endianness check in the 'perf test' sample
   parsing test.

 - Fix ARM SPE handling on 'perf inject'.

 - Fix memory leaks detected with ASan.

 - Fix build on arm64 related to reallocarray() availability.

 - Sync copies of kernel headers: cpufeatures, kvm, MIPS syscalltable
   (futex_waitv).

* tag 'perf-tools-fixes-for-v5.16-2021-11-19' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux:
  perf evsel: Fix memory leaks relating to unit
  perf report: Fix memory leaks around perf_tip()
  perf hist: Fix memory leak of a perf_hpp_fmt
  tools headers UAPI: Sync MIPS syscall table file changed by new futex_waitv syscall
  tools build: Fix removal of feature-sync-compare-and-swap feature detection
  perf inject: Fix ARM SPE handling
  perf bench: Fix two memory leaks detected with ASan
  perf test sample-parsing: Fix branch_stack entry endianness check
  tools headers UAPI: Sync x86's asm/kvm.h with the kernel sources
  perf sort: Fix the 'p_stage_cyc' sort key behavior
  perf sort: Fix the 'ins_lat' sort key behavior
  perf sort: Fix the 'weight' sort key behavior
  perf tools: Set COMPAT_NEED_REALLOCARRAY for CONFIG_AUXTRACE=1
  perf tests wp: Remove unused functions on s390
  tools headers UAPI: Sync linux/kvm.h with the kernel sources
  tools headers cpufeatures: Sync with the kernel sources
parents 9539ba43 b194c9cd
......@@ -277,6 +277,7 @@
#define X86_FEATURE_XSAVEC (10*32+ 1) /* XSAVEC instruction */
#define X86_FEATURE_XGETBV1 (10*32+ 2) /* XGETBV with ECX = 1 instruction */
#define X86_FEATURE_XSAVES (10*32+ 3) /* XSAVES/XRSTORS instructions */
#define X86_FEATURE_XFD (10*32+ 4) /* "" eXtended Feature Disabling */
/*
* Extended auxiliary flags: Linux defined - for features scattered in various
......@@ -298,6 +299,7 @@
/* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */
#define X86_FEATURE_AVX_VNNI (12*32+ 4) /* AVX VNNI instructions */
#define X86_FEATURE_AVX512_BF16 (12*32+ 5) /* AVX512 BFLOAT16 instructions */
#define X86_FEATURE_AMX_TILE (18*32+24) /* AMX tile Support */
/* AMD-defined CPU features, CPUID level 0x80000008 (EBX), word 13 */
#define X86_FEATURE_CLZERO (13*32+ 0) /* CLZERO instruction */
......
......@@ -504,4 +504,8 @@ struct kvm_pmu_event_filter {
#define KVM_PMU_EVENT_ALLOW 0
#define KVM_PMU_EVENT_DENY 1
/* for KVM_{GET,SET,HAS}_DEVICE_ATTR */
#define KVM_VCPU_TSC_CTRL 0 /* control group for the timestamp counter (TSC) */
#define KVM_VCPU_TSC_OFFSET 0 /* attribute for the TSC offset */
#endif /* _ASM_X86_KVM_H */
......@@ -200,7 +200,6 @@ int main(int argc, char *argv[])
main_test_timerfd();
main_test_stackprotector_all();
main_test_libdw_dwarf_unwind();
main_test_sync_compare_and_swap(argc, argv);
main_test_zlib();
main_test_pthread_attr_setaffinity_np();
main_test_pthread_barrier();
......
......@@ -269,6 +269,7 @@ struct kvm_xen_exit {
#define KVM_EXIT_AP_RESET_HOLD 32
#define KVM_EXIT_X86_BUS_LOCK 33
#define KVM_EXIT_XEN 34
#define KVM_EXIT_RISCV_SBI 35
/* For KVM_EXIT_INTERNAL_ERROR */
/* Emulate instruction failed. */
......@@ -397,13 +398,23 @@ struct kvm_run {
* "ndata" is correct, that new fields are enumerated in "flags",
* and that each flag enumerates fields that are 64-bit aligned
* and sized (so that ndata+internal.data[] is valid/accurate).
*
* Space beyond the defined fields may be used to store arbitrary
* debug information relating to the emulation failure. It is
* accounted for in "ndata" but the format is unspecified and is
* not represented in "flags". Any such information is *not* ABI!
*/
struct {
__u32 suberror;
__u32 ndata;
__u64 flags;
__u8 insn_size;
__u8 insn_bytes[15];
union {
struct {
__u8 insn_size;
__u8 insn_bytes[15];
};
};
/* Arbitrary debug data may follow. */
} emulation_failure;
/* KVM_EXIT_OSI */
struct {
......@@ -469,6 +480,13 @@ struct kvm_run {
} msr;
/* KVM_EXIT_XEN */
struct kvm_xen_exit xen;
/* KVM_EXIT_RISCV_SBI */
struct {
unsigned long extension_id;
unsigned long function_id;
unsigned long args[6];
unsigned long ret[2];
} riscv_sbi;
/* Fix the size of the union. */
char padding[256];
};
......@@ -1112,6 +1130,7 @@ struct kvm_ppc_resize_hpt {
#define KVM_CAP_BINARY_STATS_FD 203
#define KVM_CAP_EXIT_ON_EMULATION_FAILURE 204
#define KVM_CAP_ARM_MTE 205
#define KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM 206
#ifdef KVM_CAP_IRQ_ROUTING
......@@ -1223,11 +1242,16 @@ struct kvm_irqfd {
/* Do not use 1, KVM_CHECK_EXTENSION returned it before we had flags. */
#define KVM_CLOCK_TSC_STABLE 2
#define KVM_CLOCK_REALTIME (1 << 2)
#define KVM_CLOCK_HOST_TSC (1 << 3)
struct kvm_clock_data {
__u64 clock;
__u32 flags;
__u32 pad[9];
__u32 pad0;
__u64 realtime;
__u64 host_tsc;
__u32 pad[4];
};
/* For KVM_CAP_SW_TLB */
......
......@@ -1010,6 +1010,9 @@ ifndef NO_AUXTRACE
ifndef NO_AUXTRACE
$(call detected,CONFIG_AUXTRACE)
CFLAGS += -DHAVE_AUXTRACE_SUPPORT
ifeq ($(feature-reallocarray), 0)
CFLAGS += -DCOMPAT_NEED_REALLOCARRAY
endif
endif
endif
......
......@@ -363,3 +363,4 @@
446 n64 landlock_restrict_self sys_landlock_restrict_self
# 447 reserved for memfd_secret
448 n64 process_mrelease sys_process_mrelease
449 n64 futex_waitv sys_futex_waitv
......@@ -223,6 +223,8 @@ static unsigned int group(pthread_t *pth,
snd_ctx->out_fds[i] = fds[1];
if (!thread_mode)
close(fds[0]);
free(ctx);
}
/* Now we have all the fds, fork the senders */
......@@ -239,6 +241,8 @@ static unsigned int group(pthread_t *pth,
for (i = 0; i < num_fds; i++)
close(snd_ctx->out_fds[i]);
free(snd_ctx);
/* Return number of children to reap */
return num_fds * 2;
}
......
......@@ -619,14 +619,17 @@ static int report__browse_hists(struct report *rep)
int ret;
struct perf_session *session = rep->session;
struct evlist *evlist = session->evlist;
const char *help = perf_tip(system_path(TIPDIR));
char *help = NULL, *path = NULL;
if (help == NULL) {
path = system_path(TIPDIR);
if (perf_tip(&help, path) || help == NULL) {
/* fallback for people who don't install perf ;-) */
help = perf_tip(DOCDIR);
if (help == NULL)
help = "Cannot load tips.txt file, please install perf!";
free(path);
path = system_path(DOCDIR);
if (perf_tip(&help, path) || help == NULL)
help = strdup("Cannot load tips.txt file, please install perf!");
}
free(path);
switch (use_browser) {
case 1:
......@@ -651,7 +654,7 @@ static int report__browse_hists(struct report *rep)
ret = evlist__tty_browse_hists(evlist, rep, help);
break;
}
free(help);
return ret;
}
......
......@@ -88,7 +88,6 @@ static int test__event_update(struct test_suite *test __maybe_unused, int subtes
struct evsel *evsel;
struct event_name tmp;
struct evlist *evlist = evlist__new_default();
char *unit = strdup("KRAVA");
TEST_ASSERT_VAL("failed to get evlist", evlist);
......@@ -99,7 +98,8 @@ static int test__event_update(struct test_suite *test __maybe_unused, int subtes
perf_evlist__id_add(&evlist->core, &evsel->core, 0, 0, 123);
evsel->unit = unit;
free((char *)evsel->unit);
evsel->unit = strdup("KRAVA");
TEST_ASSERT_VAL("failed to synthesize attr update unit",
!perf_event__synthesize_event_update_unit(NULL, evsel, process_event_unit));
......@@ -119,7 +119,6 @@ static int test__event_update(struct test_suite *test __maybe_unused, int subtes
TEST_ASSERT_VAL("failed to synthesize attr update cpus",
!perf_event__synthesize_event_update_cpus(&tmp.tool, evsel, process_event_cpus));
free(unit);
evlist__delete(evlist);
return 0;
}
......
......@@ -36,7 +36,7 @@
* These are based on the input value (213) specified
* in branch_stack variable.
*/
#define BS_EXPECTED_BE 0xa00d000000000000
#define BS_EXPECTED_BE 0xa000d00000000000
#define BS_EXPECTED_LE 0xd5000000
#define FLAG(s) s->branch_stack->entries[i].flags
......
......@@ -21,6 +21,7 @@ do { \
volatile u64 data1;
volatile u8 data2[3];
#ifndef __s390x__
static int wp_read(int fd, long long *count, int size)
{
int ret = read(fd, count, size);
......@@ -48,7 +49,6 @@ static void get__perf_event_attr(struct perf_event_attr *attr, int wp_type,
attr->exclude_hv = 1;
}
#ifndef __s390x__
static int __event(int wp_type, void *wp_addr, unsigned long wp_len)
{
int fd;
......
......@@ -535,6 +535,18 @@ struct perf_hpp_list perf_hpp_list = {
#undef __HPP_SORT_ACC_FN
#undef __HPP_SORT_RAW_FN
static void fmt_free(struct perf_hpp_fmt *fmt)
{
/*
* At this point fmt should be completely
* unhooked, if not it's a bug.
*/
BUG_ON(!list_empty(&fmt->list));
BUG_ON(!list_empty(&fmt->sort_list));
if (fmt->free)
fmt->free(fmt);
}
void perf_hpp__init(void)
{
......@@ -598,9 +610,10 @@ void perf_hpp_list__prepend_sort_field(struct perf_hpp_list *list,
list_add(&format->sort_list, &list->sorts);
}
void perf_hpp__column_unregister(struct perf_hpp_fmt *format)
static void perf_hpp__column_unregister(struct perf_hpp_fmt *format)
{
list_del_init(&format->list);
fmt_free(format);
}
void perf_hpp__cancel_cumulate(void)
......@@ -672,19 +685,6 @@ void perf_hpp__append_sort_keys(struct perf_hpp_list *list)
}
static void fmt_free(struct perf_hpp_fmt *fmt)
{
/*
* At this point fmt should be completely
* unhooked, if not it's a bug.
*/
BUG_ON(!list_empty(&fmt->list));
BUG_ON(!list_empty(&fmt->sort_list));
if (fmt->free)
fmt->free(fmt);
}
void perf_hpp__reset_output_field(struct perf_hpp_list *list)
{
struct perf_hpp_fmt *fmt, *tmp;
......
......@@ -51,6 +51,7 @@ struct arm_spe {
u8 timeless_decoding;
u8 data_queued;
u64 sample_type;
u8 sample_flc;
u8 sample_llc;
u8 sample_tlb;
......@@ -287,6 +288,12 @@ static void arm_spe_prep_sample(struct arm_spe *spe,
event->sample.header.size = sizeof(struct perf_event_header);
}
static int arm_spe__inject_event(union perf_event *event, struct perf_sample *sample, u64 type)
{
event->header.size = perf_event__sample_event_size(sample, type, 0);
return perf_event__synthesize_sample(event, type, 0, sample);
}
static inline int
arm_spe_deliver_synth_event(struct arm_spe *spe,
struct arm_spe_queue *speq __maybe_unused,
......@@ -295,6 +302,12 @@ arm_spe_deliver_synth_event(struct arm_spe *spe,
{
int ret;
if (spe->synth_opts.inject) {
ret = arm_spe__inject_event(event, sample, spe->sample_type);
if (ret)
return ret;
}
ret = perf_session__deliver_synth_event(spe->session, event, sample);
if (ret)
pr_err("ARM SPE: failed to deliver event, error %d\n", ret);
......@@ -986,6 +999,8 @@ arm_spe_synth_events(struct arm_spe *spe, struct perf_session *session)
else
attr.sample_type |= PERF_SAMPLE_TIME;
spe->sample_type = attr.sample_type;
attr.exclude_user = evsel->core.attr.exclude_user;
attr.exclude_kernel = evsel->core.attr.exclude_kernel;
attr.exclude_hv = evsel->core.attr.exclude_hv;
......
......@@ -241,7 +241,7 @@ void evsel__init(struct evsel *evsel,
{
perf_evsel__init(&evsel->core, attr, idx);
evsel->tracking = !idx;
evsel->unit = "";
evsel->unit = strdup("");
evsel->scale = 1.0;
evsel->max_events = ULONG_MAX;
evsel->evlist = NULL;
......@@ -276,13 +276,8 @@ struct evsel *evsel__new_idx(struct perf_event_attr *attr, int idx)
}
if (evsel__is_clock(evsel)) {
/*
* The evsel->unit points to static alias->unit
* so it's ok to use static string in here.
*/
static const char *unit = "msec";
evsel->unit = unit;
free((char *)evsel->unit);
evsel->unit = strdup("msec");
evsel->scale = 1e-6;
}
......@@ -420,7 +415,11 @@ struct evsel *evsel__clone(struct evsel *orig)
evsel->max_events = orig->max_events;
evsel->tool_event = orig->tool_event;
evsel->unit = orig->unit;
free((char *)evsel->unit);
evsel->unit = strdup(orig->unit);
if (evsel->unit == NULL)
goto out_err;
evsel->scale = orig->scale;
evsel->snapshot = orig->snapshot;
evsel->per_pkg = orig->per_pkg;
......@@ -1441,6 +1440,7 @@ void evsel__exit(struct evsel *evsel)
zfree(&evsel->group_name);
zfree(&evsel->name);
zfree(&evsel->pmu_name);
zfree(&evsel->unit);
zfree(&evsel->metric_id);
evsel__zero_per_pkg(evsel);
hashmap__free(evsel->per_pkg_mask);
......
......@@ -4257,9 +4257,11 @@ int perf_event__process_event_update(struct perf_tool *tool __maybe_unused,
switch (ev->type) {
case PERF_EVENT_UPDATE__UNIT:
free((char *)evsel->unit);
evsel->unit = strdup(ev->data);
break;
case PERF_EVENT_UPDATE__NAME:
free(evsel->name);
evsel->name = strdup(ev->data);
break;
case PERF_EVENT_UPDATE__SCALE:
......@@ -4268,11 +4270,11 @@ int perf_event__process_event_update(struct perf_tool *tool __maybe_unused,
break;
case PERF_EVENT_UPDATE__CPUS:
ev_cpus = (struct perf_record_event_update_cpus *)ev->data;
map = cpu_map__new_data(&ev_cpus->cpus);
if (map)
if (map) {
perf_cpu_map__put(evsel->core.own_cpus);
evsel->core.own_cpus = map;
else
} else
pr_err("failed to get event_update cpus\n");
default:
break;
......
......@@ -289,15 +289,10 @@ static long hist_time(unsigned long htime)
return htime;
}
static void he_stat__add_period(struct he_stat *he_stat, u64 period,
u64 weight, u64 ins_lat, u64 p_stage_cyc)
static void he_stat__add_period(struct he_stat *he_stat, u64 period)
{
he_stat->period += period;
he_stat->weight += weight;
he_stat->nr_events += 1;
he_stat->ins_lat += ins_lat;
he_stat->p_stage_cyc += p_stage_cyc;
}
static void he_stat__add_stat(struct he_stat *dest, struct he_stat *src)
......@@ -308,9 +303,6 @@ static void he_stat__add_stat(struct he_stat *dest, struct he_stat *src)
dest->period_guest_sys += src->period_guest_sys;
dest->period_guest_us += src->period_guest_us;
dest->nr_events += src->nr_events;
dest->weight += src->weight;
dest->ins_lat += src->ins_lat;
dest->p_stage_cyc += src->p_stage_cyc;
}
static void he_stat__decay(struct he_stat *he_stat)
......@@ -598,9 +590,6 @@ static struct hist_entry *hists__findnew_entry(struct hists *hists,
struct hist_entry *he;
int64_t cmp;
u64 period = entry->stat.period;
u64 weight = entry->stat.weight;
u64 ins_lat = entry->stat.ins_lat;
u64 p_stage_cyc = entry->stat.p_stage_cyc;
bool leftmost = true;
p = &hists->entries_in->rb_root.rb_node;
......@@ -619,11 +608,11 @@ static struct hist_entry *hists__findnew_entry(struct hists *hists,
if (!cmp) {
if (sample_self) {
he_stat__add_period(&he->stat, period, weight, ins_lat, p_stage_cyc);
he_stat__add_period(&he->stat, period);
hist_entry__add_callchain_period(he, period);
}
if (symbol_conf.cumulate_callchain)
he_stat__add_period(he->stat_acc, period, weight, ins_lat, p_stage_cyc);
he_stat__add_period(he->stat_acc, period);
/*
* This mem info was allocated from sample__resolve_mem
......@@ -733,9 +722,6 @@ __hists__add_entry(struct hists *hists,
.stat = {
.nr_events = 1,
.period = sample->period,
.weight = sample->weight,
.ins_lat = sample->ins_lat,
.p_stage_cyc = sample->p_stage_cyc,
},
.parent = sym_parent,
.filtered = symbol__parent_filter(sym_parent) | al->filtered,
......@@ -748,6 +734,9 @@ __hists__add_entry(struct hists *hists,
.raw_size = sample->raw_size,
.ops = ops,
.time = hist_time(sample->time),
.weight = sample->weight,
.ins_lat = sample->ins_lat,
.p_stage_cyc = sample->p_stage_cyc,
}, *he = hists__findnew_entry(hists, &entry, al, sample_self);
if (!hists->has_callchains && he && he->callchain_size != 0)
......
......@@ -369,7 +369,6 @@ enum {
};
void perf_hpp__init(void);
void perf_hpp__column_unregister(struct perf_hpp_fmt *format);
void perf_hpp__cancel_cumulate(void);
void perf_hpp__setup_output_field(struct perf_hpp_list *list);
void perf_hpp__reset_output_field(struct perf_hpp_list *list);
......
......@@ -402,8 +402,10 @@ static int add_event_tool(struct list_head *list, int *idx,
if (!evsel)
return -ENOMEM;
evsel->tool_event = tool_event;
if (tool_event == PERF_TOOL_DURATION_TIME)
evsel->unit = "ns";
if (tool_event == PERF_TOOL_DURATION_TIME) {
free((char *)evsel->unit);
evsel->unit = strdup("ns");
}
return 0;
}
......@@ -1630,7 +1632,8 @@ int parse_events_add_pmu(struct parse_events_state *parse_state,
if (parse_state->fake_pmu)
return 0;
evsel->unit = info.unit;
free((char *)evsel->unit);
evsel->unit = strdup(info.unit);
evsel->scale = info.scale;
evsel->per_pkg = info.per_pkg;
evsel->snapshot = info.snapshot;
......
......@@ -1325,88 +1325,68 @@ struct sort_entry sort_mispredict = {
.se_width_idx = HISTC_MISPREDICT,
};
static u64 he_weight(struct hist_entry *he)
{
return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
}
static int64_t
sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
sort__weight_cmp(struct hist_entry *left, struct hist_entry *right)
{
return he_weight(left) - he_weight(right);
return left->weight - right->weight;
}
static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width)
{
return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
return repsep_snprintf(bf, size, "%-*llu", width, he->weight);
}
struct sort_entry sort_local_weight = {
.se_header = "Local Weight",
.se_cmp = sort__local_weight_cmp,
.se_cmp = sort__weight_cmp,
.se_snprintf = hist_entry__local_weight_snprintf,
.se_width_idx = HISTC_LOCAL_WEIGHT,
};
static int64_t
sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
{
return left->stat.weight - right->stat.weight;
}
static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width)
{
return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
return repsep_snprintf(bf, size, "%-*llu", width,
he->weight * he->stat.nr_events);
}
struct sort_entry sort_global_weight = {
.se_header = "Weight",
.se_cmp = sort__global_weight_cmp,
.se_cmp = sort__weight_cmp,
.se_snprintf = hist_entry__global_weight_snprintf,
.se_width_idx = HISTC_GLOBAL_WEIGHT,
};
static u64 he_ins_lat(struct hist_entry *he)
{
return he->stat.nr_events ? he->stat.ins_lat / he->stat.nr_events : 0;
}
static int64_t
sort__local_ins_lat_cmp(struct hist_entry *left, struct hist_entry *right)
sort__ins_lat_cmp(struct hist_entry *left, struct hist_entry *right)
{
return he_ins_lat(left) - he_ins_lat(right);
return left->ins_lat - right->ins_lat;
}
static int hist_entry__local_ins_lat_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width)
{
return repsep_snprintf(bf, size, "%-*u", width, he_ins_lat(he));
return repsep_snprintf(bf, size, "%-*u", width, he->ins_lat);
}
struct sort_entry sort_local_ins_lat = {
.se_header = "Local INSTR Latency",
.se_cmp = sort__local_ins_lat_cmp,
.se_cmp = sort__ins_lat_cmp,
.se_snprintf = hist_entry__local_ins_lat_snprintf,
.se_width_idx = HISTC_LOCAL_INS_LAT,
};
static int64_t
sort__global_ins_lat_cmp(struct hist_entry *left, struct hist_entry *right)
{
return left->stat.ins_lat - right->stat.ins_lat;
}
static int hist_entry__global_ins_lat_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width)
{
return repsep_snprintf(bf, size, "%-*u", width, he->stat.ins_lat);
return repsep_snprintf(bf, size, "%-*u", width,
he->ins_lat * he->stat.nr_events);
}
struct sort_entry sort_global_ins_lat = {
.se_header = "INSTR Latency",
.se_cmp = sort__global_ins_lat_cmp,
.se_cmp = sort__ins_lat_cmp,
.se_snprintf = hist_entry__global_ins_lat_snprintf,
.se_width_idx = HISTC_GLOBAL_INS_LAT,
};
......@@ -1414,13 +1394,13 @@ struct sort_entry sort_global_ins_lat = {
static int64_t
sort__global_p_stage_cyc_cmp(struct hist_entry *left, struct hist_entry *right)
{
return left->stat.p_stage_cyc - right->stat.p_stage_cyc;
return left->p_stage_cyc - right->p_stage_cyc;
}
static int hist_entry__p_stage_cyc_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width)
{
return repsep_snprintf(bf, size, "%-*u", width, he->stat.p_stage_cyc);
return repsep_snprintf(bf, size, "%-*u", width, he->p_stage_cyc);
}
struct sort_entry sort_p_stage_cyc = {
......
......@@ -49,9 +49,6 @@ struct he_stat {
u64 period_us;
u64 period_guest_sys;
u64 period_guest_us;
u64 weight;
u64 ins_lat;
u64 p_stage_cyc;
u32 nr_events;
};
......@@ -109,6 +106,9 @@ struct hist_entry {
s32 socket;
s32 cpu;
u64 code_page_size;
u64 weight;
u64 ins_lat;
u64 p_stage_cyc;
u8 cpumode;
u8 depth;
......
......@@ -379,32 +379,32 @@ fetch_kernel_version(unsigned int *puint, char *str,
return 0;
}
const char *perf_tip(const char *dirpath)
int perf_tip(char **strp, const char *dirpath)
{
struct strlist *tips;
struct str_node *node;
char *tip = NULL;
struct strlist_config conf = {
.dirname = dirpath,
.file_only = true,
};
int ret = 0;
*strp = NULL;
tips = strlist__new("tips.txt", &conf);
if (tips == NULL)
return errno == ENOENT ? NULL :
"Tip: check path of tips.txt or get more memory! ;-p";
return -errno;
if (strlist__nr_entries(tips) == 0)
goto out;
node = strlist__entry(tips, random() % strlist__nr_entries(tips));
if (asprintf(&tip, "Tip: %s", node->s) < 0)
tip = (char *)"Tip: get more memory! ;-)";
if (asprintf(strp, "Tip: %s", node->s) < 0)
ret = -ENOMEM;
out:
strlist__delete(tips);
return tip;
return ret;
}
char *perf_exe(char *buf, int len)
......
......@@ -39,7 +39,7 @@ int fetch_kernel_version(unsigned int *puint,
#define KVER_FMT "%d.%d.%d"
#define KVER_PARAM(x) KVER_VERSION(x), KVER_PATCHLEVEL(x), KVER_SUBLEVEL(x)
const char *perf_tip(const char *dirpath);
int perf_tip(char **strp, const char *dirpath);
#ifndef HAVE_SCHED_GETCPU_SUPPORT
int sched_getcpu(void);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment