From 90525176d71995ffde2d0c532f2758304c666a08 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 31 May 2016 12:47:46 -0300 Subject: perf evsel: Provide way to extract integer value from format_field Out of perf_evsel__intval(), that requires passing the variable name, that will then be searched in the list of tracepoint variables for the given evsel. In cases such as syscall file descriptor ("fd") tracking, this is wasteful, we need just to use perf_evsel__field() and cache the format_field. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Milian Wolff Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-r6f89jx9j5nkx037d0naviqy@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 25 +++++++++++++++---------- tools/perf/util/evsel.h | 2 ++ 2 files changed, 17 insertions(+), 10 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 8d30cbda51b6..f4f01b2e9dcc 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -2251,17 +2251,11 @@ void *perf_evsel__rawptr(struct perf_evsel *evsel, struct perf_sample *sample, return sample->raw_data + offset; } -u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample, - const char *name) +u64 format_field__intval(struct format_field *field, struct perf_sample *sample, + bool needs_swap) { - struct format_field *field = perf_evsel__field(evsel, name); - void *ptr; u64 value; - - if (!field) - return 0; - - ptr = sample->raw_data + field->offset; + void *ptr = sample->raw_data + field->offset; switch (field->size) { case 1: @@ -2279,7 +2273,7 @@ u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample, return 0; } - if (!evsel->needs_swap) + if (!needs_swap) return value; switch (field->size) { @@ -2296,6 +2290,17 @@ u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample, return 0; } +u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample, + const char *name) +{ + struct format_field *field = perf_evsel__field(evsel, name); + + if (!field) + return 0; + + return field ? format_field__intval(field, sample, evsel->needs_swap) : 0; +} + bool perf_evsel__fallback(struct perf_evsel *evsel, int err, char *msg, size_t msgsize) { diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 028412b32d5a..828ddd1c8947 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -261,6 +261,8 @@ static inline char *perf_evsel__strval(struct perf_evsel *evsel, struct format_field; +u64 format_field__intval(struct format_field *field, struct perf_sample *sample, bool needs_swap); + struct format_field *perf_evsel__field(struct perf_evsel *evsel, const char *name); #define perf_evsel__match(evsel, t, c) \ -- cgit v1.2.3 From 946ae1d41d4b0c77b9f63b4a0393d8a1283a7f9d Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Tue, 31 May 2016 13:06:15 +0000 Subject: perf evlist: Fix alloc_mmap() failure path If zalloc fail, setting evlist->mmap[i].fd is unsafe and perf_evlist__alloc_mmap() should bail out right after that. Signed-off-by: Wang Nan Acked-by: Masami Hiramatsu Cc: He Kuang Cc: Jiri Olsa Cc: Namhyung Kim Cc: Zefan Li Cc: pi3orama@163.com Fixes: d4c6fb36ac2c ("perf evsel: Record fd into perf_mmap") Link: http://lkml.kernel.org/r/1464699975-230440-1-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index e0f30946ed1a..1b918aa075d6 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -946,9 +946,12 @@ static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) if (cpu_map__empty(evlist->cpus)) evlist->nr_mmaps = thread_map__nr(evlist->threads); evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); + if (!evlist->mmap) + return -ENOMEM; + for (i = 0; i < evlist->nr_mmaps; i++) evlist->mmap[i].fd = -1; - return evlist->mmap != NULL ? 0 : -ENOMEM; + return 0; } struct mmap_params { -- cgit v1.2.3 From 44b1e60ab576c343aa592a2a6c679297cc69740d Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 30 May 2016 12:49:42 -0300 Subject: perf stat: Basic support for TopDown in perf stat Add basic plumbing for TopDown in perf stat TopDown is intended to replace the frontend cycles idle/ backend cycles idle metrics in standard perf stat output. These metrics are not reliable in many workloads, due to out of order effects. This implements a new --topdown mode in perf stat (similar to --transaction) that measures the pipe line bottlenecks using standardized formulas. The measurement can be all done with 5 counters (one fixed counter) The result are four metrics: FrontendBound, BackendBound, BadSpeculation, Retiring that describe the CPU pipeline behavior on a high level. The full top down methology has many hierarchical metrics. This implementation only supports level 1 which can be collected without multiplexing. A full implementation of top down on top of perf is available in pmu-tools toplev. (http://github.com/andikleen/pmu-tools) The current version works on Intel Core CPUs starting with Sandy Bridge, and Atom CPUs starting with Silvermont. In principle the generic metrics should be also implementable on other out of order CPUs. TopDown level 1 uses a set of abstracted metrics which are generic to out of order CPU cores (although some CPUs may not implement all of them): topdown-total-slots Available slots in the pipeline topdown-slots-issued Slots issued into the pipeline topdown-slots-retired Slots successfully retired topdown-fetch-bubbles Pipeline gaps in the frontend topdown-recovery-bubbles Pipeline gaps during recovery from misspeculation These metrics then allow to compute four useful metrics: FrontendBound, BackendBound, Retiring, BadSpeculation. Add a new --topdown options to enable events. When --topdown is specified set up events for all topdown events supported by the kernel. Add topdown-* as a special case to the event parser, as is needed for all events containing -. The actual code to compute the metrics is in follow-on patches. v2: Use standard sysctl read function. v3: Move x86 specific code to arch/ v4: Enable --metric-only implicitly for topdown. v5: Add --single-thread option to not force per core mode v6: Fix output order of topdown metrics v7: Allow combining with -d v8: Remove --single-thread again v9: Rename functions, adding arch_ and topdown_. v10: Expand man page and describe TopDown better Paste intro into commit description. Print error when malloc fails. Signed-off-by: Andi Kleen Acked-by: Jiri Olsa Link: http://lkml.kernel.org/r/1464119559-17203-1-git-send-email-andi@firstfloor.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/group.h | 7 +++++++ tools/perf/util/parse-events.l | 1 + 2 files changed, 8 insertions(+) create mode 100644 tools/perf/util/group.h (limited to 'tools/perf/util') diff --git a/tools/perf/util/group.h b/tools/perf/util/group.h new file mode 100644 index 000000000000..116debe7a995 --- /dev/null +++ b/tools/perf/util/group.h @@ -0,0 +1,7 @@ +#ifndef GROUP_H +#define GROUP_H 1 + +bool arch_topdown_check_group(bool *warn); +void arch_topdown_group_warn(void); + +#endif diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 01af1ee90a27..3c15b33b2e84 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -260,6 +260,7 @@ cycles-ct { return str(yyscanner, PE_KERNEL_PMU_EVENT); } cycles-t { return str(yyscanner, PE_KERNEL_PMU_EVENT); } mem-loads { return str(yyscanner, PE_KERNEL_PMU_EVENT); } mem-stores { return str(yyscanner, PE_KERNEL_PMU_EVENT); } +topdown-[a-z-]+ { return str(yyscanner, PE_KERNEL_PMU_EVENT); } L1-dcache|l1-d|l1d|L1-data | L1-icache|l1-i|l1i|L1-instruction | -- cgit v1.2.3 From 239bd47f8355eb5defc865cf408824b6cfeca5dc Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 24 May 2016 12:52:37 -0700 Subject: perf stat: Add computation of TopDown formulas Implement the TopDown formulas in 'perf stat'. The topdown basic metrics reported by the kernel are collected, and the formulas are computed and output as normal metrics. See the kernel commit exporting the events for details on the used metrics. Committer note: Output example: # perf stat --topdown -a usleep 1 Performance counter stats for 'system wide': retiring bad speculation frontend bound backend bound S0-C0 2 23.8% 11.6% 28.3% 36.3% S0-C1 2 16.2% 15.7% 36.5% 31.6% 0.000579956 seconds time elapsed # v2: Always print all metrics, only use thresholds for coloring. v3: Mark retiring over threshold green, not red. v4: Only print one decimal digit Fix color printing of one metric v5: Avoid printing -0.0 v6: Remove extra frontend event lookup Signed-off-by: Andi Kleen Acked-by: Jiri Olsa Link: http://lkml.kernel.org/r/1464119559-17203-2-git-send-email-andi@firstfloor.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/stat-shadow.c | 162 ++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/stat.c | 5 ++ tools/perf/util/stat.h | 5 ++ 3 files changed, 172 insertions(+) (limited to 'tools/perf/util') diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c index aa9efe08762b..8a2bbd2a4d82 100644 --- a/tools/perf/util/stat-shadow.c +++ b/tools/perf/util/stat-shadow.c @@ -36,6 +36,11 @@ static struct stats runtime_dtlb_cache_stats[NUM_CTX][MAX_NR_CPUS]; static struct stats runtime_cycles_in_tx_stats[NUM_CTX][MAX_NR_CPUS]; static struct stats runtime_transaction_stats[NUM_CTX][MAX_NR_CPUS]; static struct stats runtime_elision_stats[NUM_CTX][MAX_NR_CPUS]; +static struct stats runtime_topdown_total_slots[NUM_CTX][MAX_NR_CPUS]; +static struct stats runtime_topdown_slots_issued[NUM_CTX][MAX_NR_CPUS]; +static struct stats runtime_topdown_slots_retired[NUM_CTX][MAX_NR_CPUS]; +static struct stats runtime_topdown_fetch_bubbles[NUM_CTX][MAX_NR_CPUS]; +static struct stats runtime_topdown_recovery_bubbles[NUM_CTX][MAX_NR_CPUS]; static bool have_frontend_stalled; struct stats walltime_nsecs_stats; @@ -82,6 +87,11 @@ void perf_stat__reset_shadow_stats(void) sizeof(runtime_transaction_stats)); memset(runtime_elision_stats, 0, sizeof(runtime_elision_stats)); memset(&walltime_nsecs_stats, 0, sizeof(walltime_nsecs_stats)); + memset(runtime_topdown_total_slots, 0, sizeof(runtime_topdown_total_slots)); + memset(runtime_topdown_slots_retired, 0, sizeof(runtime_topdown_slots_retired)); + memset(runtime_topdown_slots_issued, 0, sizeof(runtime_topdown_slots_issued)); + memset(runtime_topdown_fetch_bubbles, 0, sizeof(runtime_topdown_fetch_bubbles)); + memset(runtime_topdown_recovery_bubbles, 0, sizeof(runtime_topdown_recovery_bubbles)); } /* @@ -105,6 +115,16 @@ void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count, update_stats(&runtime_transaction_stats[ctx][cpu], count[0]); else if (perf_stat_evsel__is(counter, ELISION_START)) update_stats(&runtime_elision_stats[ctx][cpu], count[0]); + else if (perf_stat_evsel__is(counter, TOPDOWN_TOTAL_SLOTS)) + update_stats(&runtime_topdown_total_slots[ctx][cpu], count[0]); + else if (perf_stat_evsel__is(counter, TOPDOWN_SLOTS_ISSUED)) + update_stats(&runtime_topdown_slots_issued[ctx][cpu], count[0]); + else if (perf_stat_evsel__is(counter, TOPDOWN_SLOTS_RETIRED)) + update_stats(&runtime_topdown_slots_retired[ctx][cpu], count[0]); + else if (perf_stat_evsel__is(counter, TOPDOWN_FETCH_BUBBLES)) + update_stats(&runtime_topdown_fetch_bubbles[ctx][cpu],count[0]); + else if (perf_stat_evsel__is(counter, TOPDOWN_RECOVERY_BUBBLES)) + update_stats(&runtime_topdown_recovery_bubbles[ctx][cpu], count[0]); else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) update_stats(&runtime_stalled_cycles_front_stats[ctx][cpu], count[0]); else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_BACKEND)) @@ -302,6 +322,107 @@ static void print_ll_cache_misses(int cpu, out->print_metric(out->ctx, color, "%7.2f%%", "of all LL-cache hits", ratio); } +/* + * High level "TopDown" CPU core pipe line bottleneck break down. + * + * Basic concept following + * Yasin, A Top Down Method for Performance analysis and Counter architecture + * ISPASS14 + * + * The CPU pipeline is divided into 4 areas that can be bottlenecks: + * + * Frontend -> Backend -> Retiring + * BadSpeculation in addition means out of order execution that is thrown away + * (for example branch mispredictions) + * Frontend is instruction decoding. + * Backend is execution, like computation and accessing data in memory + * Retiring is good execution that is not directly bottlenecked + * + * The formulas are computed in slots. + * A slot is an entry in the pipeline each for the pipeline width + * (for example a 4-wide pipeline has 4 slots for each cycle) + * + * Formulas: + * BadSpeculation = ((SlotsIssued - SlotsRetired) + RecoveryBubbles) / + * TotalSlots + * Retiring = SlotsRetired / TotalSlots + * FrontendBound = FetchBubbles / TotalSlots + * BackendBound = 1.0 - BadSpeculation - Retiring - FrontendBound + * + * The kernel provides the mapping to the low level CPU events and any scaling + * needed for the CPU pipeline width, for example: + * + * TotalSlots = Cycles * 4 + * + * The scaling factor is communicated in the sysfs unit. + * + * In some cases the CPU may not be able to measure all the formulas due to + * missing events. In this case multiple formulas are combined, as possible. + * + * Full TopDown supports more levels to sub-divide each area: for example + * BackendBound into computing bound and memory bound. For now we only + * support Level 1 TopDown. + */ + +static double sanitize_val(double x) +{ + if (x < 0 && x >= -0.02) + return 0.0; + return x; +} + +static double td_total_slots(int ctx, int cpu) +{ + return avg_stats(&runtime_topdown_total_slots[ctx][cpu]); +} + +static double td_bad_spec(int ctx, int cpu) +{ + double bad_spec = 0; + double total_slots; + double total; + + total = avg_stats(&runtime_topdown_slots_issued[ctx][cpu]) - + avg_stats(&runtime_topdown_slots_retired[ctx][cpu]) + + avg_stats(&runtime_topdown_recovery_bubbles[ctx][cpu]); + total_slots = td_total_slots(ctx, cpu); + if (total_slots) + bad_spec = total / total_slots; + return sanitize_val(bad_spec); +} + +static double td_retiring(int ctx, int cpu) +{ + double retiring = 0; + double total_slots = td_total_slots(ctx, cpu); + double ret_slots = avg_stats(&runtime_topdown_slots_retired[ctx][cpu]); + + if (total_slots) + retiring = ret_slots / total_slots; + return retiring; +} + +static double td_fe_bound(int ctx, int cpu) +{ + double fe_bound = 0; + double total_slots = td_total_slots(ctx, cpu); + double fetch_bub = avg_stats(&runtime_topdown_fetch_bubbles[ctx][cpu]); + + if (total_slots) + fe_bound = fetch_bub / total_slots; + return fe_bound; +} + +static double td_be_bound(int ctx, int cpu) +{ + double sum = (td_fe_bound(ctx, cpu) + + td_bad_spec(ctx, cpu) + + td_retiring(ctx, cpu)); + if (sum == 0) + return 0; + return sanitize_val(1.0 - sum); +} + void perf_stat__print_shadow_stats(struct perf_evsel *evsel, double avg, int cpu, struct perf_stat_output_ctx *out) @@ -309,6 +430,7 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel, void *ctxp = out->ctx; print_metric_t print_metric = out->print_metric; double total, ratio = 0.0, total2; + const char *color = NULL; int ctx = evsel_context(evsel); if (perf_evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) { @@ -452,6 +574,46 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel, avg / ratio); else print_metric(ctxp, NULL, NULL, "CPUs utilized", 0); + } else if (perf_stat_evsel__is(evsel, TOPDOWN_FETCH_BUBBLES)) { + double fe_bound = td_fe_bound(ctx, cpu); + + if (fe_bound > 0.2) + color = PERF_COLOR_RED; + print_metric(ctxp, color, "%8.1f%%", "frontend bound", + fe_bound * 100.); + } else if (perf_stat_evsel__is(evsel, TOPDOWN_SLOTS_RETIRED)) { + double retiring = td_retiring(ctx, cpu); + + if (retiring > 0.7) + color = PERF_COLOR_GREEN; + print_metric(ctxp, color, "%8.1f%%", "retiring", + retiring * 100.); + } else if (perf_stat_evsel__is(evsel, TOPDOWN_RECOVERY_BUBBLES)) { + double bad_spec = td_bad_spec(ctx, cpu); + + if (bad_spec > 0.1) + color = PERF_COLOR_RED; + print_metric(ctxp, color, "%8.1f%%", "bad speculation", + bad_spec * 100.); + } else if (perf_stat_evsel__is(evsel, TOPDOWN_SLOTS_ISSUED)) { + double be_bound = td_be_bound(ctx, cpu); + const char *name = "backend bound"; + static int have_recovery_bubbles = -1; + + /* In case the CPU does not support topdown-recovery-bubbles */ + if (have_recovery_bubbles < 0) + have_recovery_bubbles = pmu_have_event("cpu", + "topdown-recovery-bubbles"); + if (!have_recovery_bubbles) + name = "backend bound/bad spec"; + + if (be_bound > 0.2) + color = PERF_COLOR_RED; + if (td_total_slots(ctx, cpu) > 0) + print_metric(ctxp, color, "%8.1f%%", name, + be_bound * 100.); + else + print_metric(ctxp, NULL, NULL, name, 0); } else if (runtime_nsecs_stats[cpu].n != 0) { char unit = 'M'; char unit_buf[10]; diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index ffa1d0653861..c1ba255f2abe 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -79,6 +79,11 @@ static const char *id_str[PERF_STAT_EVSEL_ID__MAX] = { ID(TRANSACTION_START, cpu/tx-start/), ID(ELISION_START, cpu/el-start/), ID(CYCLES_IN_TX_CP, cpu/cycles-ct/), + ID(TOPDOWN_TOTAL_SLOTS, topdown-total-slots), + ID(TOPDOWN_SLOTS_ISSUED, topdown-slots-issued), + ID(TOPDOWN_SLOTS_RETIRED, topdown-slots-retired), + ID(TOPDOWN_FETCH_BUBBLES, topdown-fetch-bubbles), + ID(TOPDOWN_RECOVERY_BUBBLES, topdown-recovery-bubbles), }; #undef ID diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index 0150e786ccc7..c29bb94c48a4 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -17,6 +17,11 @@ enum perf_stat_evsel_id { PERF_STAT_EVSEL_ID__TRANSACTION_START, PERF_STAT_EVSEL_ID__ELISION_START, PERF_STAT_EVSEL_ID__CYCLES_IN_TX_CP, + PERF_STAT_EVSEL_ID__TOPDOWN_TOTAL_SLOTS, + PERF_STAT_EVSEL_ID__TOPDOWN_SLOTS_ISSUED, + PERF_STAT_EVSEL_ID__TOPDOWN_SLOTS_RETIRED, + PERF_STAT_EVSEL_ID__TOPDOWN_FETCH_BUBBLES, + PERF_STAT_EVSEL_ID__TOPDOWN_RECOVERY_BUBBLES, PERF_STAT_EVSEL_ID__MAX, }; -- cgit v1.2.3 From 78f71c996fb92d129ec75d572e2f5367a4f4c757 Mon Sep 17 00:00:00 2001 From: Taeung Song Date: Mon, 6 Jun 2016 19:52:52 +0900 Subject: perf config: Fix abnormal termination at perf_parse_file() If a config file has wrong key-value pairs, the perf process will be forcibly terminated by die() at perf_parse_file() called by perf_config() so terminal settings can be crushed because of unusual termination. For example: If user config file has a wrong value 'red;default' instead of a normal value like 'red, default' for a key 'colors.top', # cat ~/.perfconfig [colors] medium = red;default # wrong value and if running sub-command 'top', # perf top perf process is dead by force and terminal setting is broken with a messge like below. Fatal: bad config file line 2 in /root/.perfconfig So fix it. If perf_config() can return on failure without calling die() at perf_parse_file(), this problem can be solved. And if a config file has wrong values, show the error message and then use default config values instead of wrong config values. Signed-off-by: Taeung Song Tested-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1465210380-26749-2-git-send-email-treeze.taeung@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/config.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index dad7d8272168..b50073741b80 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -275,7 +275,8 @@ static int perf_parse_file(config_fn_t fn, void *data) break; } } - die("bad config file line %d in %s", config_linenr, config_file_name); + pr_err("bad config file line %d in %s\n", config_linenr, config_file_name); + return -1; } static int parse_unit_factor(const char *end, unsigned long *val) @@ -479,16 +480,15 @@ static int perf_config_global(void) int perf_config(config_fn_t fn, void *data) { - int ret = 0, found = 0; + int ret = -1; const char *home = NULL; /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */ if (config_exclusive_filename) return perf_config_from_file(fn, config_exclusive_filename, data); if (perf_config_system() && !access(perf_etc_perfconfig(), R_OK)) { - ret += perf_config_from_file(fn, perf_etc_perfconfig(), - data); - found += 1; + if (perf_config_from_file(fn, perf_etc_perfconfig(), data) < 0) + goto out; } home = getenv("HOME"); @@ -514,14 +514,12 @@ int perf_config(config_fn_t fn, void *data) if (!st.st_size) goto out_free; - ret += perf_config_from_file(fn, user_config, data); - found += 1; + ret = perf_config_from_file(fn, user_config, data); + out_free: free(user_config); } out: - if (found == 0) - return -1; return ret; } -- cgit v1.2.3 From 7db91f251056f90fec4121f028680ab3153a0f3c Mon Sep 17 00:00:00 2001 From: Taeung Song Date: Mon, 6 Jun 2016 19:52:54 +0900 Subject: perf config: Handle the error when config set is NULL at collect_config() collect_config() collect all config key-value pairs from config files and put each config info in config set. But if config set (i.e. 'set' variable at collect_config()) is NULL, this is wrong so handle it. Signed-off-by: Taeung Song Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1465210380-26749-4-git-send-email-treeze.taeung@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/config.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index b50073741b80..c73f1c4d1ca9 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -607,8 +607,12 @@ static int collect_config(const char *var, const char *value, struct perf_config_section *section = NULL; struct perf_config_item *item = NULL; struct perf_config_set *set = perf_config_set; - struct list_head *sections = &set->sections; + struct list_head *sections; + if (set == NULL) + return -1; + + sections = &set->sections; key = ptr = strdup(var); if (!key) { pr_debug("%s: strdup failed\n", __func__); -- cgit v1.2.3