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

perf: Sysfs enumeration

Simple sysfs emumeration of the PMUs.

Use a "event_source" bus, and add PMU devices using their name.

Each PMU device has a type attribute which contrains the value needed
for perf_event_attr::type to identify this PMU.

This is the minimal stub needed to start using this interface,
we'll consider extending the sysfs usage later.

Cc: Kay Sievers <kay.sievers@vrfy.org>
Cc: Greg KH <gregkh@suse.de>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <20101117222056.316982569@chello.nl>
Signed-off-by: Ingo Molnar <mingo@elte.hu>

authored by

Peter Zijlstra and committed by
Ingo Molnar
abe43400 2e80a82a

+95 -1
+1
include/linux/perf_event.h
··· 588 588 struct pmu { 589 589 struct list_head entry; 590 590 591 + struct device *dev; 591 592 char *name; 592 593 int type; 593 594
+94 -1
kernel/perf_event.c
··· 24 24 #include <linux/ptrace.h> 25 25 #include <linux/reboot.h> 26 26 #include <linux/vmstat.h> 27 + #include <linux/device.h> 27 28 #include <linux/vmalloc.h> 28 29 #include <linux/hardirq.h> 29 30 #include <linux/rculist.h> ··· 5309 5308 } 5310 5309 static struct idr pmu_idr; 5311 5310 5311 + static ssize_t 5312 + type_show(struct device *dev, struct device_attribute *attr, char *page) 5313 + { 5314 + struct pmu *pmu = dev_get_drvdata(dev); 5315 + 5316 + return snprintf(page, PAGE_SIZE-1, "%d\n", pmu->type); 5317 + } 5318 + 5319 + static struct device_attribute pmu_dev_attrs[] = { 5320 + __ATTR_RO(type), 5321 + __ATTR_NULL, 5322 + }; 5323 + 5324 + static int pmu_bus_running; 5325 + static struct bus_type pmu_bus = { 5326 + .name = "event_source", 5327 + .dev_attrs = pmu_dev_attrs, 5328 + }; 5329 + 5330 + static void pmu_dev_release(struct device *dev) 5331 + { 5332 + kfree(dev); 5333 + } 5334 + 5335 + static int pmu_dev_alloc(struct pmu *pmu) 5336 + { 5337 + int ret = -ENOMEM; 5338 + 5339 + pmu->dev = kzalloc(sizeof(struct device), GFP_KERNEL); 5340 + if (!pmu->dev) 5341 + goto out; 5342 + 5343 + device_initialize(pmu->dev); 5344 + ret = dev_set_name(pmu->dev, "%s", pmu->name); 5345 + if (ret) 5346 + goto free_dev; 5347 + 5348 + dev_set_drvdata(pmu->dev, pmu); 5349 + pmu->dev->bus = &pmu_bus; 5350 + pmu->dev->release = pmu_dev_release; 5351 + ret = device_add(pmu->dev); 5352 + if (ret) 5353 + goto free_dev; 5354 + 5355 + out: 5356 + return ret; 5357 + 5358 + free_dev: 5359 + put_device(pmu->dev); 5360 + goto out; 5361 + } 5362 + 5312 5363 int perf_pmu_register(struct pmu *pmu, char *name, int type) 5313 5364 { 5314 5365 int cpu, ret; ··· 5389 5336 } 5390 5337 pmu->type = type; 5391 5338 5339 + if (pmu_bus_running) { 5340 + ret = pmu_dev_alloc(pmu); 5341 + if (ret) 5342 + goto free_idr; 5343 + } 5344 + 5392 5345 skip_type: 5393 5346 pmu->pmu_cpu_context = find_pmu_context(pmu->task_ctx_nr); 5394 5347 if (pmu->pmu_cpu_context) ··· 5402 5343 5403 5344 pmu->pmu_cpu_context = alloc_percpu(struct perf_cpu_context); 5404 5345 if (!pmu->pmu_cpu_context) 5405 - goto free_ird; 5346 + goto free_dev; 5406 5347 5407 5348 for_each_possible_cpu(cpu) { 5408 5349 struct perf_cpu_context *cpuctx; ··· 5446 5387 5447 5388 return ret; 5448 5389 5390 + free_dev: 5391 + device_del(pmu->dev); 5392 + put_device(pmu->dev); 5393 + 5449 5394 free_idr: 5450 5395 if (pmu->type >= PERF_TYPE_MAX) 5451 5396 idr_remove(&pmu_idr, pmu->type); ··· 5475 5412 free_percpu(pmu->pmu_disable_count); 5476 5413 if (pmu->type >= PERF_TYPE_MAX) 5477 5414 idr_remove(&pmu_idr, pmu->type); 5415 + device_del(pmu->dev); 5416 + put_device(pmu->dev); 5478 5417 free_pmu_context(pmu); 5479 5418 } 5480 5419 ··· 6668 6603 ret = init_hw_breakpoint(); 6669 6604 WARN(ret, "hw_breakpoint initialization failed with: %d", ret); 6670 6605 } 6606 + 6607 + static int __init perf_event_sysfs_init(void) 6608 + { 6609 + struct pmu *pmu; 6610 + int ret; 6611 + 6612 + mutex_lock(&pmus_lock); 6613 + 6614 + ret = bus_register(&pmu_bus); 6615 + if (ret) 6616 + goto unlock; 6617 + 6618 + list_for_each_entry(pmu, &pmus, entry) { 6619 + if (!pmu->name || pmu->type < 0) 6620 + continue; 6621 + 6622 + ret = pmu_dev_alloc(pmu); 6623 + WARN(ret, "Failed to register pmu: %s, reason %d\n", pmu->name, ret); 6624 + } 6625 + pmu_bus_running = 1; 6626 + ret = 0; 6627 + 6628 + unlock: 6629 + mutex_unlock(&pmus_lock); 6630 + 6631 + return ret; 6632 + } 6633 + device_initcall(perf_event_sysfs_init);