Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S965487AbdCWSg5 (ORCPT ); Thu, 23 Mar 2017 14:36:57 -0400 Received: from mga11.intel.com ([192.55.52.93]:27735 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S965239AbdCWSgy (ORCPT ); Thu, 23 Mar 2017 14:36:54 -0400 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.36,210,1486454400"; d="scan'208";a="1126324380" From: kan.liang@intel.com To: peterz@infradead.org, mingo@redhat.com, acme@kernel.org, linux-kernel@vger.kernel.org Cc: tglx@linutronix.de, eranian@google.com, jolsa@kernel.org, ak@linux.intel.com, Kan Liang Subject: [PATCH 3/3] perf stat: Add support to measure SMI cost Date: Thu, 23 Mar 2017 11:25:51 -0700 Message-Id: <1490293551-5552-4-git-send-email-kan.liang@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1490293551-5552-1-git-send-email-kan.liang@intel.com> References: <1490293551-5552-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: 8166 Lines: 245 From: Kan Liang Implementing a new --smi-cost mode in perf stat to measure SMI cost. During the measurement, the /sys/device/cpu/freeze_on_smi will be set. The measurement can be done with one counter and two free running MSR counters (IA32_APERF and SMI_COUNT). The formula to caculate SMI cost is as below. The percentages of SMI cycles = (aperf - cycles) / aperf metric_only will be set by default unless the user explicitly disable it. Here is an example output. Performance counter stats for 'sudo echo ': SMI cycles% SMI# 0.1% 1 0.010858678 seconds time elapsed Signed-off-by: Kan Liang --- tools/perf/Documentation/perf-stat.txt | 9 +++++++ tools/perf/builtin-stat.c | 48 ++++++++++++++++++++++++++++++++++ tools/perf/util/stat-shadow.c | 33 +++++++++++++++++++++++ tools/perf/util/stat.c | 2 ++ tools/perf/util/stat.h | 2 ++ 5 files changed, 94 insertions(+) diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index 9785481..d8df8e9 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt @@ -236,6 +236,15 @@ To interpret the results it is usually needed to know on which CPUs the workload runs on. If needed the CPUs can be forced using taskset. +--smi-cost:: +Measure SMI cost if support and SMI is detected + +During the measurement, the /sys/device/cpu/freeze_on_smi will be +set to freeze cycles counter on SMI. The aperf event will not be +effected by freeze_on_smi. + +The percentages of SMI cycles = (aperf - cycles) / aperf + EXAMPLES -------- diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index f53f449..f10aad6 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -76,6 +76,7 @@ #define DEFAULT_SEPARATOR " " #define CNTR_NOT_SUPPORTED "" #define CNTR_NOT_COUNTED "" +#define FREEZE_ON_SMI_PATH "devices/cpu/freeze_on_smi" static void print_counters(struct timespec *ts, int argc, const char **argv); @@ -112,6 +113,14 @@ static const char * topdown_attrs[] = { NULL, }; +static const char *smi_cost_attrs = { + "{" + "msr/aperf/," + "msr/smi/," + "cycles" + "}" +}; + static struct perf_evlist *evsel_list; static struct target target = { @@ -127,6 +136,8 @@ static bool null_run = false; static int detailed_run = 0; static bool transaction_run; static bool topdown_run = false; +static bool smi_cost = false; +static bool smi_reset = false; static bool big_num = true; static int big_num_opt = -1; static const char *csv_sep = NULL; @@ -1670,6 +1681,8 @@ static const struct option stat_options[] = { "Only print computed metrics. No raw values", enable_metric_only), OPT_BOOLEAN(0, "topdown", &topdown_run, "measure topdown level 1 statistics"), + OPT_BOOLEAN(0, "smi-cost", &smi_cost, + "measure SMI cost"), OPT_END() }; @@ -2048,6 +2061,38 @@ static int add_default_attributes(void) return 0; } + if (smi_cost) { + int smi; + + if (sysfs__read_int(FREEZE_ON_SMI_PATH, &smi) < 0) { + fprintf(stderr, "freeze_on_smi is not supported.\n"); + return -1; + } + + if (!smi) { + if (sysfs__write_int(FREEZE_ON_SMI_PATH, 1) < 0) { + fprintf(stderr, "Failed to set freeze_on_smi.\n"); + return -1; + } + smi_reset = true; + } + + if (pmu_have_event("msr", "aperf") && + pmu_have_event("msr", "smi")) { + if (!force_metric_only) + metric_only = true; + err = parse_events(evsel_list, smi_cost_attrs, NULL); + } else { + fprintf(stderr, "To measure SMI cost, it needs msr/aperf/, msr/smi/ and cpu/cycles/ events support\n"); + return -1; + } + if (err) { + fprintf(stderr, "Cannot set up SMI cost events\n"); + return -1; + } + return 0; + } + if (topdown_run) { char *str = NULL; bool warn = false; @@ -2629,6 +2674,9 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) perf_stat__exit_aggr_mode(); perf_evlist__free_stats(evsel_list); out: + if (smi_cost && smi_reset) + sysfs__write_int(FREEZE_ON_SMI_PATH, 0); + perf_evlist__delete(evsel_list); return status; } diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c index 8a2bbd2..dda7877 100644 --- a/tools/perf/util/stat-shadow.c +++ b/tools/perf/util/stat-shadow.c @@ -41,6 +41,8 @@ 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 struct stats runtime_smi_num_stats[NUM_CTX][MAX_NR_CPUS]; +static struct stats runtime_aperf_stats[NUM_CTX][MAX_NR_CPUS]; static bool have_frontend_stalled; struct stats walltime_nsecs_stats; @@ -92,6 +94,9 @@ void perf_stat__reset_shadow_stats(void) 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)); + + memset(runtime_smi_num_stats, 0, sizeof(runtime_smi_num_stats)); + memset(runtime_aperf_stats, 0, sizeof(runtime_aperf_stats)); } /* @@ -143,6 +148,10 @@ void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count, update_stats(&runtime_dtlb_cache_stats[ctx][cpu], count[0]); else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_ITLB)) update_stats(&runtime_itlb_cache_stats[ctx][cpu], count[0]); + else if (perf_stat_evsel__is(counter, SMI_NUM)) + update_stats(&runtime_smi_num_stats[ctx][cpu], count[0]); + else if (perf_stat_evsel__is(counter, APERF)) + update_stats(&runtime_aperf_stats[ctx][cpu], count[0]); } /* used for get_ratio_color() */ @@ -423,6 +432,25 @@ static double td_be_bound(int ctx, int cpu) return sanitize_val(1.0 - sum); } +static void print_smi_cost(int cpu, struct perf_evsel *evsel, + struct perf_stat_output_ctx *out) +{ + double smi_num, aperf, cycles, cost = 0.0; + int ctx = evsel_context(evsel); + const char *color = NULL; + + smi_num = avg_stats(&runtime_smi_num_stats[ctx][cpu]); + aperf = avg_stats(&runtime_aperf_stats[ctx][cpu]); + cycles = avg_stats(&runtime_cycles_stats[ctx][cpu]); + + cost = (aperf - cycles) / aperf * 100.00; + + if (cost > 10) + color = PERF_COLOR_RED; + out->print_metric(out->ctx, color, "%8.1f%%", "SMI cycles%", cost); + out->print_metric(out->ctx, NULL, "%4.0f", "SMI#", smi_num); +} + void perf_stat__print_shadow_stats(struct perf_evsel *evsel, double avg, int cpu, struct perf_stat_output_ctx *out) @@ -628,6 +656,11 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel, } snprintf(unit_buf, sizeof(unit_buf), "%c/sec", unit); print_metric(ctxp, NULL, "%8.3f", unit_buf, ratio); + } else if (perf_stat_evsel__is(evsel, SMI_NUM)) { + if (avg_stats(&runtime_smi_num_stats[ctx][cpu])) + print_smi_cost(cpu, evsel, out); + else + print_metric(ctxp, NULL, NULL, " no SMI detected", 0); } else { print_metric(ctxp, NULL, NULL, NULL, 0); } diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index 0d51334..8ae3160f 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -84,6 +84,8 @@ static const char *id_str[PERF_STAT_EVSEL_ID__MAX] = { ID(TOPDOWN_SLOTS_RETIRED, topdown-slots-retired), ID(TOPDOWN_FETCH_BUBBLES, topdown-fetch-bubbles), ID(TOPDOWN_RECOVERY_BUBBLES, topdown-recovery-bubbles), + ID(SMI_NUM, msr/smi/), + ID(APERF, msr/aperf/), }; #undef ID diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index c29bb94..c3be07d 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -22,6 +22,8 @@ enum perf_stat_evsel_id { 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__SMI_NUM, + PERF_STAT_EVSEL_ID__APERF, PERF_STAT_EVSEL_ID__MAX, }; -- 2.7.4