Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752775AbbGQSpi (ORCPT ); Fri, 17 Jul 2015 14:45:38 -0400 Received: from mga09.intel.com ([134.134.136.24]:37053 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752196AbbGQSpf (ORCPT ); Fri, 17 Jul 2015 14:45:35 -0400 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.15,497,1432623600"; d="scan'208";a="749507024" From: kan.liang@intel.com To: acme@kernel.org, jolsa@kernel.org Cc: namhyung@kernel.org, ak@linux.intel.com, linux-kernel@vger.kernel.org, Kan Liang Subject: [PATCH RFC V5 3/4] perf,tool: per-event callgrap support Date: Fri, 17 Jul 2015 07:30:54 -0400 Message-Id: <1437132655-15883-4-git-send-email-kan.liang@intel.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1437132655-15883-1-git-send-email-kan.liang@intel.com> References: <1437132655-15883-1-git-send-email-kan.liang@intel.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 11200 Lines: 311 From: Kan Liang When multiple events are sampled it may not be needed to collect callgraphs for all of them. The sample sites are usually nearby, and it's enough to collect the callgraphs on a reference event (such as precise cycles or precise instructions). This patchkit adds the ability to turn off callgraphs and time stamp per event. This in term can reduce sampling overhead and the size of the perf.data. Furthermore, it makes collecting back traces and timestamps possible when PEBS threshold > 1, which significantly reducing the sampling overhead especially for frequently occurring events (https://lkml.org/lkml/2015/5/10/196). For example, A slower event with a larger period collects back traces/timestamps. Other more events run fast with multi-pebs. The time stamps from the slower events can be used to order the faster events. Their backtraces can give the user enough hint to find the right spot. Here are some examples and test results. 1. Comparing the elapsed time and perf.data size from "kernbench -M -H". The test command for FULL callgrap and time support. "perf record -e '{cpu/cpu-cycles,period=100000/,cpu/instructions,period=20000/p}' --call-graph fp --time" The test command for PARTIAL callgrap and time support. "perf record -e '{cpu/cpu-cycles,callgraph=fp,time,period=100000/, cpu/instructions,callgraph=no,time=0,period=20000/p}'" The elapsed time for FULL is 24.3 Sec, while for PARTIAL is 16.9 Sec. The perf.data size for FULL is 22.1 Gb, while for PARTIAL is 12.4 Gb. 2. Comparing the perf.data size and callgraph results. The test command for FULL callgrap and time support. "perf record -e '{cpu/cpu-cycles,period=100000/pp,cpu/instructions,period=20000/p}' --call-graph fp -- ./tchain_edit" The test command for PARTIAL callgrap and time support. "perf record -e '{cpu/cpu-cycles,callgraph=fp,time,period=100000/pp, cpu/instructions,callgraph=no,time=0,period=20000/p}' -- ./tchain_edit" The perf.data size for FULL is 43.2 MB, while for PARTIAL is 21.1 MB. The callgraph is roughly the same. The callgraph from FULL # Samples: 87K of event 'cpu/cpu-cycles,callgraph=fp,time,period=100000/pp' # Event count (approx.): 8760000000 # # Children Self Command Shared Object Symbol # ........ ........ ........... .................. .......................................... # 99.98% 0.00% tchain_edit libc-2.15.so [.] __libc_start_main | ---__libc_start_main 99.97% 0.00% tchain_edit tchain_edit [.] main | ---main __libc_start_main 99.97% 0.00% tchain_edit tchain_edit [.] f1 | ---f1 main __libc_start_main 99.85% 87.01% tchain_edit tchain_edit [.] f3 | ---f3 | |--99.74%-- f2 | f1 | main | __libc_start_main --0.26%-- [...] 99.71% 0.12% tchain_edit tchain_edit [.] f2 | ---f2 f1 main __libc_start_main The callgraph from PARTIAL # Samples: 417K of event 'cpu/instructions,callgraph=no,time=0,period=20000/p' # Event count (approx.): 8346980000 # # Children Self Command Shared Object Symbol # ........ ........ ........... ................ .......................................... # 98.82% 0.00% tchain_edit libc-2.15.so [.] __libc_start_main | ---__libc_start_main 98.82% 0.00% tchain_edit tchain_edit [.] main | ---main __libc_start_main 98.82% 0.00% tchain_edit tchain_edit [.] f1 | ---f1 main __libc_start_main 98.82% 98.28% tchain_edit tchain_edit [.] f3 | ---f3 | |--0.53%-- f2 | f1 | main | __libc_start_main | |--0.01%-- f1 | main | __libc_start_main --99.46%-- [...] 97.63% 0.03% tchain_edit tchain_edit [.] f2 | ---f2 f1 main __libc_start_main 7.13% 0.03% tchain_edit [kernel.vmlinux] [k] do_nmi | ---do_nmi end_repeat_nmi f3 f2 f1 main __libc_start_main Signed-off-by: Kan Liang --- tools/perf/Documentation/perf-record.txt | 4 ++++ tools/perf/util/evsel.c | 24 +++++++++++++++++++++++- tools/perf/util/parse-events.c | 18 ++++++++++++++++++ tools/perf/util/parse-events.h | 2 ++ tools/perf/util/parse-events.l | 2 ++ tools/perf/util/pmu.c | 3 ++- 6 files changed, 51 insertions(+), 2 deletions(-) diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index df47907..f478dc2 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -52,6 +52,10 @@ OPTIONS - 'time': Disable/enable time stamping. Acceptable values are 1 for enabling time stamping. 0 for disabling time stamping. The default is 1. + - 'callgraph': Disable/enable callgraph. Acceptable str are "fp" for + FP mode, "dwarf" for DWARF mode, "lbr" for LBR mode and + "no" for disable callgraph. + - 'stack_size': user stack size for dwarf mode Note: If user explicitly sets options which conflict with the params, the value set by the params will be overridden. diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 34f9cfd..c253ca7 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -620,6 +620,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) int track = evsel->tracking; bool per_cpu = opts->target.default_per_cpu && !opts->target.per_thread; bool sample_time = opts->sample_time; + bool callgraph = callchain_param.enabled; attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1; attr->inherit = !opts->no_inherit; @@ -636,6 +637,23 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) sample_time = false; } + if (!opts->callgraph_set) { + if (attr->sample_type & PERF_SAMPLE_CALLCHAIN) { + callgraph = true; + if (attr->sample_type & PERF_SAMPLE_STACK_USER) { + callchain_param.record_mode = CALLCHAIN_DWARF; + if (attr->sample_stack_user) + callchain_param.dump_size = attr->sample_stack_user; + else + callchain_param.dump_size = 8192; + } else if (attr->sample_type & PERF_SAMPLE_BRANCH_STACK) + callchain_param.record_mode = CALLCHAIN_LBR; + else + callchain_param.record_mode = CALLCHAIN_FP; + } else + callgraph = false; + } + /* * Event parsing doesn't check the availability * Clear the bit which event parsing may be set. @@ -648,6 +666,10 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) if (attr->sample_type & PERF_SAMPLE_TIME) perf_evsel__reset_sample_bit(evsel, TIME); + attr->sample_type &= ~(PERF_SAMPLE_CALLCHAIN | + PERF_SAMPLE_STACK_USER | + PERF_SAMPLE_BRANCH_STACK); + perf_evsel__set_sample_bit(evsel, IP); perf_evsel__set_sample_bit(evsel, TID); @@ -713,7 +735,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) if (perf_evsel__is_function_event(evsel)) evsel->attr.exclude_callchain_user = 1; - if (callchain_param.enabled && !evsel->no_aux_samples) + if (callgraph && !evsel->no_aux_samples) perf_evsel__config_callgraph(evsel, opts); if (opts->sample_intr_regs) { diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index c9981df..1a8ed26 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -19,6 +19,7 @@ #include "thread_map.h" #include "cpumap.h" #include "asm/bug.h" +#include "callchain.h" #define MAX_NAME_LEN 100 @@ -609,6 +610,23 @@ do { \ if (term->val.num == 1) attr->sample_type |= PERF_SAMPLE_TIME; break; + case PARSE_EVENTS__TERM_TYPE_CALLGRAPH: + CHECK_TYPE_VAL(STR); + if (!strcmp(term->val.str, "fp")) + attr->sample_type |= PERF_SAMPLE_CALLCHAIN; + else if (!strcmp(term->val.str, "dwarf")) + attr->sample_type |= PERF_SAMPLE_CALLCHAIN | + PERF_SAMPLE_STACK_USER; + else if (!strcmp(term->val.str, "lbr")) + attr->sample_type |= PERF_SAMPLE_CALLCHAIN | + PERF_SAMPLE_BRANCH_STACK; + else if (strcmp(term->val.str, "no")) + return -EINVAL; + break; + case PARSE_EVENTS__TERM_TYPE_STACKSIZE: + CHECK_TYPE_VAL(NUM); + attr->sample_stack_user = term->val.num; + break; case PARSE_EVENTS__TERM_TYPE_NAME: CHECK_TYPE_VAL(STR); break; diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 1083478..47136e5 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -65,6 +65,8 @@ enum { PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE, PARSE_EVENTS__TERM_TYPE_TIME, + PARSE_EVENTS__TERM_TYPE_CALLGRAPH, + PARSE_EVENTS__TERM_TYPE_STACKSIZE, }; struct parse_events_term { diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index f542750..16af73b 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -184,6 +184,8 @@ name { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); } period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); } branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); } time { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_TIME); } +callgraph { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CALLGRAPH); } +stack_size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_TIME); } , { return ','; } "/" { BEGIN(INITIAL); return '/'; } {name_minus} { return str(yyscanner, PE_NAME); } diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index b615cdf..586b9fd 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -607,7 +607,8 @@ static char *formats_error_string(struct list_head *formats) { struct perf_pmu_format *format; char *err, *str; - static const char *static_terms = "config,config1,config2,name,period,branch_type,time\n"; + static const char *static_terms = "config,config1,config2,name,period," + "branch_type,time,callgraph,stack_size\n"; unsigned i = 0; if (!asprintf(&str, "valid terms:")) -- 1.8.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/