aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>2016-02-16 22:21:25 -0500
committerMichael Ellerman <mpe@ellerman.id.au>2016-03-10 06:57:23 -0500
commit8f69dc701aac170421117adf7e04d8ec7031a05f (patch)
tree21d5864dce4a282f2c547b43e1e9e4e4e6b8855f
parentd34171e88aeed4a99c00c7f2af3d5c553e7a4972 (diff)
powerpc/perf/24x7: Eliminate domain suffix in event names
The Physical Core events of the 24x7 PMU can be monitored across various domains (physical core, vcpu home core, vcpu home node etc). For each of these core events, we currently create multiple events in sysfs, one for each domain the event can be monitored in. These events are distinguished by their suffixes like __PHYS_CORE, __VCPU_HOME_CORE etc. Rather than creating multiple such entries, we could let the user specify make 'domain' index a required parameter and let the user specify a value for it (like they currently specify the core index). $ cat /sys/bus/event_source/devices/hv_24x7/events/HPM_CCYC domain=?,offset=0x98,core=?,lpar=0x0 $ perf stat -C 0 -e hv_24x7/HPM_CCYC,domain=2,core=1/ true (the 'domain=?' and 'core=?' in sysfs tell perf tool to enforce them as required parameters). This simplifies the interface and allows users to identify events by the name specified in the catalog (User can determine the domain index by referring to '/sys/bus/event_source/devices/hv_24x7/interface/domains'). Eliminating the event suffix eliminates several functions and simplifies code. Note that Physical Chip events can only be monitored in the chip domain so those events have the domain set to 1 (rather than =?) and users don't need to specify the domain index for the Chip events. $ cat /sys/bus/event_source/devices/hv_24x7/events/PM_XLINK_CYCLES domain=1,offset=0x230,chip=?,lpar=0x0 $ perf stat -C 0 -e hv_24x7/PM_XLINK_CYCLES,chip=1/ true Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r--arch/powerpc/perf/hv-24x7.c149
1 files changed, 66 insertions, 83 deletions
diff --git a/arch/powerpc/perf/hv-24x7.c b/arch/powerpc/perf/hv-24x7.c
index 36b29fd9295d..59012e750abe 100644
--- a/arch/powerpc/perf/hv-24x7.c
+++ b/arch/powerpc/perf/hv-24x7.c
@@ -27,20 +27,6 @@
27#include "hv-24x7-catalog.h" 27#include "hv-24x7-catalog.h"
28#include "hv-common.h" 28#include "hv-common.h"
29 29
30static const char *event_domain_suffix(unsigned domain)
31{
32 switch (domain) {
33#define DOMAIN(n, v, x, c) \
34 case HV_PERF_DOMAIN_##n: \
35 return "__" #n;
36#include "hv-24x7-domains.h"
37#undef DOMAIN
38 default:
39 WARN(1, "unknown domain %d\n", domain);
40 return "__UNKNOWN_DOMAIN_SUFFIX";
41 }
42}
43
44static bool domain_is_valid(unsigned domain) 30static bool domain_is_valid(unsigned domain)
45{ 31{
46 switch (domain) { 32 switch (domain) {
@@ -294,38 +280,70 @@ static unsigned long h_get_24x7_catalog_page(char page[],
294 version, index); 280 version, index);
295} 281}
296 282
297static unsigned core_domains[] = { 283/*
298 HV_PERF_DOMAIN_PHYS_CORE, 284 * Each event we find in the catalog, will have a sysfs entry. Format the
299 HV_PERF_DOMAIN_VCPU_HOME_CORE, 285 * data for this sysfs entry based on the event's domain.
300 HV_PERF_DOMAIN_VCPU_HOME_CHIP, 286 *
301 HV_PERF_DOMAIN_VCPU_HOME_NODE, 287 * Events belonging to the Chip domain can only be monitored in that domain.
302 HV_PERF_DOMAIN_VCPU_REMOTE_NODE, 288 * i.e the domain for these events is a fixed/knwon value.
303}; 289 *
304/* chip event data always yeilds a single event, core yeilds multiple */ 290 * Events belonging to the Core domain can be monitored either in the physical
305#define MAX_EVENTS_PER_EVENT_DATA ARRAY_SIZE(core_domains) 291 * core or in one of the virtual CPU domains. So the domain value for these
306 292 * events must be specified by the user (i.e is a required parameter). Format
293 * the Core events with 'domain=?' so the perf-tool can error check required
294 * parameters.
295 *
296 * NOTE: For the Core domain events, rather than making domain a required
297 * parameter we could default it to PHYS_CORE and allowe users to
298 * override the domain to one of the VCPU domains.
299 *
300 * However, this can make the interface a little inconsistent.
301 *
302 * If we set domain=2 (PHYS_CHIP) and allow user to override this field
303 * the user may be tempted to also modify the "offset=x" field in which
304 * can lead to confusing usage. Consider the HPM_PCYC (offset=0x18) and
305 * HPM_INST (offset=0x20) events. With:
306 *
307 * perf stat -e hv_24x7/HPM_PCYC,offset=0x20/
308 *
309 * we end up monitoring HPM_INST, while the command line has HPM_PCYC.
310 *
311 * By not assigning a default value to the domain for the Core events,
312 * we can have simple guidelines:
313 *
314 * - Specifying values for parameters with "=?" is required.
315 *
316 * - Specifying (i.e overriding) values for other parameters
317 * is undefined.
318 */
307static char *event_fmt(struct hv_24x7_event_data *event, unsigned domain) 319static char *event_fmt(struct hv_24x7_event_data *event, unsigned domain)
308{ 320{
309 const char *sindex; 321 const char *sindex;
310 const char *lpar; 322 const char *lpar;
323 const char *domain_str;
324 char buf[8];
311 325
312 switch (domain) { 326 switch (domain) {
313 case HV_PERF_DOMAIN_PHYS_CHIP: 327 case HV_PERF_DOMAIN_PHYS_CHIP:
328 snprintf(buf, sizeof(buf), "%d", domain);
329 domain_str = buf;
314 lpar = "0x0"; 330 lpar = "0x0";
315 sindex = "chip"; 331 sindex = "chip";
316 break; 332 break;
317 case HV_PERF_DOMAIN_PHYS_CORE: 333 case HV_PERF_DOMAIN_PHYS_CORE:
334 domain_str = "?";
318 lpar = "0x0"; 335 lpar = "0x0";
319 sindex = "core"; 336 sindex = "core";
320 break; 337 break;
321 default: 338 default:
339 domain_str = "?";
322 lpar = "?"; 340 lpar = "?";
323 sindex = "vcpu"; 341 sindex = "vcpu";
324 } 342 }
325 343
326 return kasprintf(GFP_KERNEL, 344 return kasprintf(GFP_KERNEL,
327 "domain=0x%x,offset=0x%x,%s=?,lpar=%s", 345 "domain=%s,offset=0x%x,%s=?,lpar=%s",
328 domain, 346 domain_str,
329 be16_to_cpu(event->event_counter_offs) + 347 be16_to_cpu(event->event_counter_offs) +
330 be16_to_cpu(event->event_group_record_offs), 348 be16_to_cpu(event->event_group_record_offs),
331 sindex, 349 sindex,
@@ -365,6 +383,15 @@ static struct attribute *device_str_attr_create_(char *name, char *str)
365 return &attr->attr.attr; 383 return &attr->attr.attr;
366} 384}
367 385
386/*
387 * Allocate and initialize strings representing event attributes.
388 *
389 * NOTE: The strings allocated here are never destroyed and continue to
390 * exist till shutdown. This is to allow us to create as many events
391 * from the catalog as possible, even if we encounter errors with some.
392 * In case of changes to error paths in future, these may need to be
393 * freed by the caller.
394 */
368static struct attribute *device_str_attr_create(char *name, int name_max, 395static struct attribute *device_str_attr_create(char *name, int name_max,
369 int name_nonce, 396 int name_nonce,
370 char *str, size_t str_max) 397 char *str, size_t str_max)
@@ -396,16 +423,6 @@ out_s:
396 return NULL; 423 return NULL;
397} 424}
398 425
399static void device_str_attr_destroy(struct attribute *attr)
400{
401 struct dev_ext_attribute *d;
402
403 d = container_of(attr, struct dev_ext_attribute, attr.attr);
404 kfree(d->var);
405 kfree(d->attr.attr.name);
406 kfree(d);
407}
408
409static struct attribute *event_to_attr(unsigned ix, 426static struct attribute *event_to_attr(unsigned ix,
410 struct hv_24x7_event_data *event, 427 struct hv_24x7_event_data *event,
411 unsigned domain, 428 unsigned domain,
@@ -413,7 +430,6 @@ static struct attribute *event_to_attr(unsigned ix,
413{ 430{
414 int event_name_len; 431 int event_name_len;
415 char *ev_name, *a_ev_name, *val; 432 char *ev_name, *a_ev_name, *val;
416 const char *ev_suffix;
417 struct attribute *attr; 433 struct attribute *attr;
418 434
419 if (!domain_is_valid(domain)) { 435 if (!domain_is_valid(domain)) {
@@ -426,14 +442,13 @@ static struct attribute *event_to_attr(unsigned ix,
426 if (!val) 442 if (!val)
427 return NULL; 443 return NULL;
428 444
429 ev_suffix = event_domain_suffix(domain);
430 ev_name = event_name(event, &event_name_len); 445 ev_name = event_name(event, &event_name_len);
431 if (!nonce) 446 if (!nonce)
432 a_ev_name = kasprintf(GFP_KERNEL, "%.*s%s", 447 a_ev_name = kasprintf(GFP_KERNEL, "%.*s",
433 (int)event_name_len, ev_name, ev_suffix); 448 (int)event_name_len, ev_name);
434 else 449 else
435 a_ev_name = kasprintf(GFP_KERNEL, "%.*s%s__%d", 450 a_ev_name = kasprintf(GFP_KERNEL, "%.*s__%d",
436 (int)event_name_len, ev_name, ev_suffix, nonce); 451 (int)event_name_len, ev_name, nonce);
437 452
438 if (!a_ev_name) 453 if (!a_ev_name)
439 goto out_val; 454 goto out_val;
@@ -478,45 +493,14 @@ event_to_long_desc_attr(struct hv_24x7_event_data *event, int nonce)
478 return device_str_attr_create(name, nl, nonce, desc, dl); 493 return device_str_attr_create(name, nl, nonce, desc, dl);
479} 494}
480 495
481static ssize_t event_data_to_attrs(unsigned ix, struct attribute **attrs, 496static int event_data_to_attrs(unsigned ix, struct attribute **attrs,
482 struct hv_24x7_event_data *event, int nonce) 497 struct hv_24x7_event_data *event, int nonce)
483{ 498{
484 unsigned i; 499 *attrs = event_to_attr(ix, event, event->domain, nonce);
485 500 if (!*attrs)
486 switch (event->domain) {
487 case HV_PERF_DOMAIN_PHYS_CHIP:
488 *attrs = event_to_attr(ix, event, event->domain, nonce);
489 return 1;
490 case HV_PERF_DOMAIN_PHYS_CORE:
491 for (i = 0; i < ARRAY_SIZE(core_domains); i++) {
492 attrs[i] = event_to_attr(ix, event, core_domains[i],
493 nonce);
494 if (!attrs[i]) {
495 pr_warn("catalog event %u: individual attr %u "
496 "creation failure\n", ix, i);
497 for (; i; i--)
498 device_str_attr_destroy(attrs[i - 1]);
499 return -1;
500 }
501 }
502 return i;
503 default:
504 pr_warn("catalog event %u: domain %u is not allowed in the "
505 "catalog\n", ix, event->domain);
506 return -1; 501 return -1;
507 }
508}
509 502
510static size_t event_to_attr_ct(struct hv_24x7_event_data *event) 503 return 0;
511{
512 switch (event->domain) {
513 case HV_PERF_DOMAIN_PHYS_CHIP:
514 return 1;
515 case HV_PERF_DOMAIN_PHYS_CORE:
516 return ARRAY_SIZE(core_domains);
517 default:
518 return 0;
519 }
520} 504}
521 505
522static unsigned long vmalloc_to_phys(void *v) 506static unsigned long vmalloc_to_phys(void *v)
@@ -752,9 +736,8 @@ static int create_events_from_catalog(struct attribute ***events_,
752 goto e_free; 736 goto e_free;
753 } 737 }
754 738
755 if (SIZE_MAX / MAX_EVENTS_PER_EVENT_DATA - 1 < event_entry_count) { 739 if (SIZE_MAX - 1 < event_entry_count) {
756 pr_err("event_entry_count %zu is invalid\n", 740 pr_err("event_entry_count %zu is invalid\n", event_entry_count);
757 event_entry_count);
758 ret = -EIO; 741 ret = -EIO;
759 goto e_free; 742 goto e_free;
760 } 743 }
@@ -827,7 +810,7 @@ static int create_events_from_catalog(struct attribute ***events_,
827 continue; 810 continue;
828 } 811 }
829 812
830 attr_max += event_to_attr_ct(event); 813 attr_max++;
831 } 814 }
832 815
833 event_idx_last = event_idx; 816 event_idx_last = event_idx;
@@ -877,12 +860,12 @@ static int create_events_from_catalog(struct attribute ***events_,
877 nonce = event_uniq_add(&ev_uniq, name, nl, event->domain); 860 nonce = event_uniq_add(&ev_uniq, name, nl, event->domain);
878 ct = event_data_to_attrs(event_idx, events + event_attr_ct, 861 ct = event_data_to_attrs(event_idx, events + event_attr_ct,
879 event, nonce); 862 event, nonce);
880 if (ct <= 0) { 863 if (ct < 0) {
881 pr_warn("event %zu (%.*s) creation failure, skipping\n", 864 pr_warn("event %zu (%.*s) creation failure, skipping\n",
882 event_idx, nl, name); 865 event_idx, nl, name);
883 junk_events++; 866 junk_events++;
884 } else { 867 } else {
885 event_attr_ct += ct; 868 event_attr_ct++;
886 event_descs[desc_ct] = event_to_desc_attr(event, nonce); 869 event_descs[desc_ct] = event_to_desc_attr(event, nonce);
887 if (event_descs[desc_ct]) 870 if (event_descs[desc_ct])
888 desc_ct++; 871 desc_ct++;