Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf stat: Add support to measure SMI cost

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 (unhalted core cycles), and
two free running MSR counters (IA32_APERF and SMI_COUNT).

In practice, the percentages of SMI core cycles should be more useful
than absolute value. So the output will be the percentage of SMI core
cycles and SMI#. metric_only will be set by default.

SMI cycles% = (aperf - unhalted core cycles) / aperf

Here is an example output.

Performance counter stats for 'sudo echo ':

SMI cycles% SMI#
0.1% 1

0.010858678 seconds time elapsed

Users who wants to get the actual value can apply additional
--no-metric-only.

Signed-off-by: Kan Liang <Kan.liang@intel.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Kan Liang <kan.liang@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Robert Elliott <elliott@hpe.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/1495825538-5230-3-git-send-email-kan.liang@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Kan Liang and committed by
Arnaldo Carvalho de Melo
daefd0bc 3b00ea93

+100
+14
tools/perf/Documentation/perf-stat.txt
··· 239 239 --no-merge:: 240 240 Do not merge results from same PMUs. 241 241 242 + --smi-cost:: 243 + Measure SMI cost if msr/aperf/ and msr/smi/ events are supported. 244 + 245 + During the measurement, the /sys/device/cpu/freeze_on_smi will be set to 246 + freeze core counters on SMI. 247 + The aperf counter will not be effected by the setting. 248 + The cost of SMI can be measured by (aperf - unhalted core cycles). 249 + 250 + In practice, the percentages of SMI cycles is very useful for performance 251 + oriented analysis. --metric_only will be applied by default. 252 + The output is SMI cycles%, equals to (aperf - unhalted core cycles) / aperf 253 + 254 + Users who wants to get the actual value can apply --no-metric-only. 255 + 242 256 EXAMPLES 243 257 -------- 244 258
+49
tools/perf/builtin-stat.c
··· 86 86 #define DEFAULT_SEPARATOR " " 87 87 #define CNTR_NOT_SUPPORTED "<not supported>" 88 88 #define CNTR_NOT_COUNTED "<not counted>" 89 + #define FREEZE_ON_SMI_PATH "devices/cpu/freeze_on_smi" 89 90 90 91 static void print_counters(struct timespec *ts, int argc, const char **argv); 91 92 ··· 123 122 NULL, 124 123 }; 125 124 125 + static const char *smi_cost_attrs = { 126 + "{" 127 + "msr/aperf/," 128 + "msr/smi/," 129 + "cycles" 130 + "}" 131 + }; 132 + 126 133 static struct perf_evlist *evsel_list; 127 134 128 135 static struct target target = { ··· 146 137 static int detailed_run = 0; 147 138 static bool transaction_run; 148 139 static bool topdown_run = false; 140 + static bool smi_cost = false; 141 + static bool smi_reset = false; 149 142 static bool big_num = true; 150 143 static int big_num_opt = -1; 151 144 static const char *csv_sep = NULL; ··· 1793 1782 "Only print computed metrics. No raw values", enable_metric_only), 1794 1783 OPT_BOOLEAN(0, "topdown", &topdown_run, 1795 1784 "measure topdown level 1 statistics"), 1785 + OPT_BOOLEAN(0, "smi-cost", &smi_cost, 1786 + "measure SMI cost"), 1796 1787 OPT_END() 1797 1788 }; 1798 1789 ··· 2168 2155 err = parse_events(evsel_list, transaction_limited_attrs, NULL); 2169 2156 if (err) { 2170 2157 fprintf(stderr, "Cannot set up transaction events\n"); 2158 + return -1; 2159 + } 2160 + return 0; 2161 + } 2162 + 2163 + if (smi_cost) { 2164 + int smi; 2165 + 2166 + if (sysfs__read_int(FREEZE_ON_SMI_PATH, &smi) < 0) { 2167 + fprintf(stderr, "freeze_on_smi is not supported.\n"); 2168 + return -1; 2169 + } 2170 + 2171 + if (!smi) { 2172 + if (sysfs__write_int(FREEZE_ON_SMI_PATH, 1) < 0) { 2173 + fprintf(stderr, "Failed to set freeze_on_smi.\n"); 2174 + return -1; 2175 + } 2176 + smi_reset = true; 2177 + } 2178 + 2179 + if (pmu_have_event("msr", "aperf") && 2180 + pmu_have_event("msr", "smi")) { 2181 + if (!force_metric_only) 2182 + metric_only = true; 2183 + err = parse_events(evsel_list, smi_cost_attrs, NULL); 2184 + } else { 2185 + fprintf(stderr, "To measure SMI cost, it needs " 2186 + "msr/aperf/, msr/smi/ and cpu/cycles/ support\n"); 2187 + return -1; 2188 + } 2189 + if (err) { 2190 + fprintf(stderr, "Cannot set up SMI cost events\n"); 2171 2191 return -1; 2172 2192 } 2173 2193 return 0; ··· 2788 2742 perf_stat__exit_aggr_mode(); 2789 2743 perf_evlist__free_stats(evsel_list); 2790 2744 out: 2745 + if (smi_cost && smi_reset) 2746 + sysfs__write_int(FREEZE_ON_SMI_PATH, 0); 2747 + 2791 2748 perf_evlist__delete(evsel_list); 2792 2749 return status; 2793 2750 }
+33
tools/perf/util/stat-shadow.c
··· 44 44 static struct stats runtime_topdown_slots_retired[NUM_CTX][MAX_NR_CPUS]; 45 45 static struct stats runtime_topdown_fetch_bubbles[NUM_CTX][MAX_NR_CPUS]; 46 46 static struct stats runtime_topdown_recovery_bubbles[NUM_CTX][MAX_NR_CPUS]; 47 + static struct stats runtime_smi_num_stats[NUM_CTX][MAX_NR_CPUS]; 48 + static struct stats runtime_aperf_stats[NUM_CTX][MAX_NR_CPUS]; 47 49 static struct rblist runtime_saved_values; 48 50 static bool have_frontend_stalled; 49 51 ··· 159 157 memset(runtime_topdown_slots_issued, 0, sizeof(runtime_topdown_slots_issued)); 160 158 memset(runtime_topdown_fetch_bubbles, 0, sizeof(runtime_topdown_fetch_bubbles)); 161 159 memset(runtime_topdown_recovery_bubbles, 0, sizeof(runtime_topdown_recovery_bubbles)); 160 + memset(runtime_smi_num_stats, 0, sizeof(runtime_smi_num_stats)); 161 + memset(runtime_aperf_stats, 0, sizeof(runtime_aperf_stats)); 162 162 163 163 next = rb_first(&runtime_saved_values.entries); 164 164 while (next) { ··· 221 217 update_stats(&runtime_dtlb_cache_stats[ctx][cpu], count[0]); 222 218 else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_ITLB)) 223 219 update_stats(&runtime_itlb_cache_stats[ctx][cpu], count[0]); 220 + else if (perf_stat_evsel__is(counter, SMI_NUM)) 221 + update_stats(&runtime_smi_num_stats[ctx][cpu], count[0]); 222 + else if (perf_stat_evsel__is(counter, APERF)) 223 + update_stats(&runtime_aperf_stats[ctx][cpu], count[0]); 224 224 225 225 if (counter->collect_stat) { 226 226 struct saved_value *v = saved_value_lookup(counter, cpu, ctx, ··· 600 592 return sanitize_val(1.0 - sum); 601 593 } 602 594 595 + static void print_smi_cost(int cpu, struct perf_evsel *evsel, 596 + struct perf_stat_output_ctx *out) 597 + { 598 + double smi_num, aperf, cycles, cost = 0.0; 599 + int ctx = evsel_context(evsel); 600 + const char *color = NULL; 601 + 602 + smi_num = avg_stats(&runtime_smi_num_stats[ctx][cpu]); 603 + aperf = avg_stats(&runtime_aperf_stats[ctx][cpu]); 604 + cycles = avg_stats(&runtime_cycles_stats[ctx][cpu]); 605 + 606 + if ((cycles == 0) || (aperf == 0)) 607 + return; 608 + 609 + if (smi_num) 610 + cost = (aperf - cycles) / aperf * 100.00; 611 + 612 + if (cost > 10) 613 + color = PERF_COLOR_RED; 614 + out->print_metric(out->ctx, color, "%8.1f%%", "SMI cycles%", cost); 615 + out->print_metric(out->ctx, NULL, "%4.0f", "SMI#", smi_num); 616 + } 617 + 603 618 void perf_stat__print_shadow_stats(struct perf_evsel *evsel, 604 619 double avg, int cpu, 605 620 struct perf_stat_output_ctx *out) ··· 856 825 } 857 826 snprintf(unit_buf, sizeof(unit_buf), "%c/sec", unit); 858 827 print_metric(ctxp, NULL, "%8.3f", unit_buf, ratio); 828 + } else if (perf_stat_evsel__is(evsel, SMI_NUM)) { 829 + print_smi_cost(cpu, evsel, out); 859 830 } else { 860 831 print_metric(ctxp, NULL, NULL, NULL, 0); 861 832 }
+2
tools/perf/util/stat.c
··· 86 86 ID(TOPDOWN_SLOTS_RETIRED, topdown-slots-retired), 87 87 ID(TOPDOWN_FETCH_BUBBLES, topdown-fetch-bubbles), 88 88 ID(TOPDOWN_RECOVERY_BUBBLES, topdown-recovery-bubbles), 89 + ID(SMI_NUM, msr/smi/), 90 + ID(APERF, msr/aperf/), 89 91 }; 90 92 #undef ID 91 93
+2
tools/perf/util/stat.h
··· 22 22 PERF_STAT_EVSEL_ID__TOPDOWN_SLOTS_RETIRED, 23 23 PERF_STAT_EVSEL_ID__TOPDOWN_FETCH_BUBBLES, 24 24 PERF_STAT_EVSEL_ID__TOPDOWN_RECOVERY_BUBBLES, 25 + PERF_STAT_EVSEL_ID__SMI_NUM, 26 + PERF_STAT_EVSEL_ID__APERF, 25 27 PERF_STAT_EVSEL_ID__MAX, 26 28 }; 27 29