aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@intel.com>2015-07-17 12:33:52 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2015-08-24 16:45:08 -0400
commitbc9b6bf07c8b3f4e85509f9b3a552c86e567b4ae (patch)
treef0a184f97273fcb9bb333c8c6a6a7892d9b4a3db
parent2a21d03686881331b0af0471588674e7e896eeb2 (diff)
perf tools: Add Intel PT support for PSB periods
The PSB packet is a synchronization packet that provides a starting point for decoding or recovery from errors. This patch adds support for a new Intel PT feature that allows the frequency of PSB packets to be specified. Support for this feature is indicated by /sys/bus/event_source/devices/intel_pt/caps/psb_cyc which contains "1" if the feature is supported and "0" otherwise. The PSB period can be specified as a PMU config term e.g. perf record -e intel_pt/psb_period=2/u sleep 1 The default value is 3 or the nearest lower value that is supported. 0 is always supported. Valid values are given by: /sys/bus/event_source/devices/intel_pt/caps/psb_periods which contains a hexadecimal value, the bits of which represent valid values e.g. bit 2 set means value 2 is valid. The value is converted to the approximate number of trace bytes between PSB packets as: 2 ^ (value + 11) e.g. value 3 means 16KiB bytes between PSBs If an invalid value is entered, the error message will give a list of valid values e.g. $ perf record -e intel_pt/psb_period=15/u uname Invalid psb_period for intel_pt. Valid values are: 0-5 tools/perf/Documentation/intel-pt.txt is updated in a later patch as there are a number of new features being added. For more information about PSB periods refer to the Intel 64 and IA-32 Architectures SDM Chapter 36 Intel Processor Trace from June 2015 or later. Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Cc: Jiri Olsa <jolsa@redhat.com> Link: http://lkml.kernel.org/r/1437150840-31811-18-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--tools/perf/arch/x86/util/intel-pt.c217
1 files changed, 210 insertions, 7 deletions
diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c
index da7d2c15e611..145975b003a7 100644
--- a/tools/perf/arch/x86/util/intel-pt.c
+++ b/tools/perf/arch/x86/util/intel-pt.c
@@ -99,17 +99,121 @@ static int intel_pt_parse_terms(struct list_head *formats, const char *str,
99 return intel_pt_parse_terms_with_default(formats, str, config); 99 return intel_pt_parse_terms_with_default(formats, str, config);
100} 100}
101 101
102static size_t intel_pt_psb_period(struct perf_pmu *intel_pt_pmu __maybe_unused, 102static u64 intel_pt_masked_bits(u64 mask, u64 bits)
103 struct perf_evlist *evlist __maybe_unused)
104{ 103{
105 return 256; 104 const u64 top_bit = 1ULL << 63;
105 u64 res = 0;
106 int i;
107
108 for (i = 0; i < 64; i++) {
109 if (mask & top_bit) {
110 res <<= 1;
111 if (bits & top_bit)
112 res |= 1;
113 }
114 mask <<= 1;
115 bits <<= 1;
116 }
117
118 return res;
119}
120
121static int intel_pt_read_config(struct perf_pmu *intel_pt_pmu, const char *str,
122 struct perf_evlist *evlist, u64 *res)
123{
124 struct perf_evsel *evsel;
125 u64 mask;
126
127 *res = 0;
128
129 mask = perf_pmu__format_bits(&intel_pt_pmu->format, str);
130 if (!mask)
131 return -EINVAL;
132
133 evlist__for_each(evlist, evsel) {
134 if (evsel->attr.type == intel_pt_pmu->type) {
135 *res = intel_pt_masked_bits(mask, evsel->attr.config);
136 return 0;
137 }
138 }
139
140 return -EINVAL;
141}
142
143static size_t intel_pt_psb_period(struct perf_pmu *intel_pt_pmu,
144 struct perf_evlist *evlist)
145{
146 u64 val;
147 int err, topa_multiple_entries;
148 size_t psb_period;
149
150 if (perf_pmu__scan_file(intel_pt_pmu, "caps/topa_multiple_entries",
151 "%d", &topa_multiple_entries) != 1)
152 topa_multiple_entries = 0;
153
154 /*
155 * Use caps/topa_multiple_entries to indicate early hardware that had
156 * extra frequent PSBs.
157 */
158 if (!topa_multiple_entries) {
159 psb_period = 256;
160 goto out;
161 }
162
163 err = intel_pt_read_config(intel_pt_pmu, "psb_period", evlist, &val);
164 if (err)
165 val = 0;
166
167 psb_period = 1 << (val + 11);
168out:
169 pr_debug2("%s psb_period %zu\n", intel_pt_pmu->name, psb_period);
170 return psb_period;
171}
172
173static int intel_pt_pick_bit(int bits, int target)
174{
175 int pos, pick = -1;
176
177 for (pos = 0; bits; bits >>= 1, pos++) {
178 if (bits & 1) {
179 if (pos <= target || pick < 0)
180 pick = pos;
181 if (pos >= target)
182 break;
183 }
184 }
185
186 return pick;
106} 187}
107 188
108static u64 intel_pt_default_config(struct perf_pmu *intel_pt_pmu) 189static u64 intel_pt_default_config(struct perf_pmu *intel_pt_pmu)
109{ 190{
191 char buf[256];
192 int psb_cyc, psb_periods, psb_period;
193 int pos = 0;
110 u64 config; 194 u64 config;
111 195
112 intel_pt_parse_terms(&intel_pt_pmu->format, "tsc", &config); 196 pos += scnprintf(buf + pos, sizeof(buf) - pos, "tsc");
197
198 if (perf_pmu__scan_file(intel_pt_pmu, "caps/psb_cyc", "%d",
199 &psb_cyc) != 1)
200 psb_cyc = 1;
201
202 if (psb_cyc) {
203 if (perf_pmu__scan_file(intel_pt_pmu, "caps/psb_periods", "%x",
204 &psb_periods) != 1)
205 psb_periods = 0;
206 if (psb_periods) {
207 psb_period = intel_pt_pick_bit(psb_periods, 3);
208 pos += scnprintf(buf + pos, sizeof(buf) - pos,
209 ",psb_period=%d", psb_period);
210 }
211 }
212
213 pr_debug2("%s default config: %s\n", intel_pt_pmu->name, buf);
214
215 intel_pt_parse_terms(&intel_pt_pmu->format, buf, &config);
216
113 return config; 217 return config;
114} 218}
115 219
@@ -239,6 +343,103 @@ static int intel_pt_track_switches(struct perf_evlist *evlist)
239 return 0; 343 return 0;
240} 344}
241 345
346static void intel_pt_valid_str(char *str, size_t len, u64 valid)
347{
348 unsigned int val, last = 0, state = 1;
349 int p = 0;
350
351 str[0] = '\0';
352
353 for (val = 0; val <= 64; val++, valid >>= 1) {
354 if (valid & 1) {
355 last = val;
356 switch (state) {
357 case 0:
358 p += scnprintf(str + p, len - p, ",");
359 /* Fall through */
360 case 1:
361 p += scnprintf(str + p, len - p, "%u", val);
362 state = 2;
363 break;
364 case 2:
365 state = 3;
366 break;
367 case 3:
368 state = 4;
369 break;
370 default:
371 break;
372 }
373 } else {
374 switch (state) {
375 case 3:
376 p += scnprintf(str + p, len - p, ",%u", last);
377 state = 0;
378 break;
379 case 4:
380 p += scnprintf(str + p, len - p, "-%u", last);
381 state = 0;
382 break;
383 default:
384 break;
385 }
386 if (state != 1)
387 state = 0;
388 }
389 }
390}
391
392static int intel_pt_val_config_term(struct perf_pmu *intel_pt_pmu,
393 const char *caps, const char *name,
394 const char *supported, u64 config)
395{
396 char valid_str[256];
397 unsigned int shift;
398 unsigned long long valid;
399 u64 bits;
400 int ok;
401
402 if (perf_pmu__scan_file(intel_pt_pmu, caps, "%llx", &valid) != 1)
403 valid = 0;
404
405 if (supported &&
406 perf_pmu__scan_file(intel_pt_pmu, supported, "%d", &ok) == 1 && !ok)
407 valid = 0;
408
409 valid |= 1;
410
411 bits = perf_pmu__format_bits(&intel_pt_pmu->format, name);
412
413 config &= bits;
414
415 for (shift = 0; bits && !(bits & 1); shift++)
416 bits >>= 1;
417
418 config >>= shift;
419
420 if (config > 63)
421 goto out_err;
422
423 if (valid & (1 << config))
424 return 0;
425out_err:
426 intel_pt_valid_str(valid_str, sizeof(valid_str), valid);
427 pr_err("Invalid %s for %s. Valid values are: %s\n",
428 name, INTEL_PT_PMU_NAME, valid_str);
429 return -EINVAL;
430}
431
432static int intel_pt_validate_config(struct perf_pmu *intel_pt_pmu,
433 struct perf_evsel *evsel)
434{
435 if (!evsel)
436 return 0;
437
438 return intel_pt_val_config_term(intel_pt_pmu, "caps/psb_periods",
439 "psb_period", "caps/psb_cyc",
440 evsel->attr.config);
441}
442
242static int intel_pt_recording_options(struct auxtrace_record *itr, 443static int intel_pt_recording_options(struct auxtrace_record *itr,
243 struct perf_evlist *evlist, 444 struct perf_evlist *evlist,
244 struct record_opts *opts) 445 struct record_opts *opts)
@@ -251,6 +452,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr,
251 const struct cpu_map *cpus = evlist->cpus; 452 const struct cpu_map *cpus = evlist->cpus;
252 bool privileged = geteuid() == 0 || perf_event_paranoid() < 0; 453 bool privileged = geteuid() == 0 || perf_event_paranoid() < 0;
253 u64 tsc_bit; 454 u64 tsc_bit;
455 int err;
254 456
255 ptr->evlist = evlist; 457 ptr->evlist = evlist;
256 ptr->snapshot_mode = opts->auxtrace_snapshot_mode; 458 ptr->snapshot_mode = opts->auxtrace_snapshot_mode;
@@ -281,6 +483,10 @@ static int intel_pt_recording_options(struct auxtrace_record *itr,
281 if (!opts->full_auxtrace) 483 if (!opts->full_auxtrace)
282 return 0; 484 return 0;
283 485
486 err = intel_pt_validate_config(intel_pt_pmu, intel_pt_evsel);
487 if (err)
488 return err;
489
284 /* Set default sizes for snapshot mode */ 490 /* Set default sizes for snapshot mode */
285 if (opts->auxtrace_snapshot_mode) { 491 if (opts->auxtrace_snapshot_mode) {
286 size_t psb_period = intel_pt_psb_period(intel_pt_pmu, evlist); 492 size_t psb_period = intel_pt_psb_period(intel_pt_pmu, evlist);
@@ -366,8 +572,6 @@ static int intel_pt_recording_options(struct auxtrace_record *itr,
366 * threads. 572 * threads.
367 */ 573 */
368 if (have_timing_info && !cpu_map__empty(cpus)) { 574 if (have_timing_info && !cpu_map__empty(cpus)) {
369 int err;
370
371 err = intel_pt_track_switches(evlist); 575 err = intel_pt_track_switches(evlist);
372 if (err == -EPERM) 576 if (err == -EPERM)
373 pr_debug2("Unable to select sched:sched_switch\n"); 577 pr_debug2("Unable to select sched:sched_switch\n");
@@ -394,7 +598,6 @@ static int intel_pt_recording_options(struct auxtrace_record *itr,
394 /* Add dummy event to keep tracking */ 598 /* Add dummy event to keep tracking */
395 if (opts->full_auxtrace) { 599 if (opts->full_auxtrace) {
396 struct perf_evsel *tracking_evsel; 600 struct perf_evsel *tracking_evsel;
397 int err;
398 601
399 err = parse_events(evlist, "dummy:u", NULL); 602 err = parse_events(evlist, "dummy:u", NULL);
400 if (err) 603 if (err)