Skip to content

Commit f92f6e6

Browse files
author
Ingo Molnar
committed
Merge branch 'core' of git://git.kernel.org/pub/scm/linux/kernel/git/rric/oprofile into perf/core
2 parents 66af86e + cd254f2 commit f92f6e6

File tree

18 files changed

+510
-510
lines changed

18 files changed

+510
-510
lines changed

arch/arm/kernel/perf_event.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,12 @@ armpmu_get_max_events(void)
123123
}
124124
EXPORT_SYMBOL_GPL(armpmu_get_max_events);
125125

126+
int perf_num_counters(void)
127+
{
128+
return armpmu_get_max_events();
129+
}
130+
EXPORT_SYMBOL_GPL(perf_num_counters);
131+
126132
#define HW_OP_UNSUPPORTED 0xFFFF
127133

128134
#define C(_x) \

arch/arm/oprofile/Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,8 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
66
oprofilefs.o oprofile_stats.o \
77
timer_int.o )
88

9+
ifeq ($(CONFIG_HW_PERF_EVENTS),y)
10+
DRIVER_OBJS += $(addprefix ../../../drivers/oprofile/, oprofile_perf.o)
11+
endif
12+
913
oprofile-y := $(DRIVER_OBJS) common.o

arch/arm/oprofile/common.c

Lines changed: 6 additions & 305 deletions
Original file line numberDiff line numberDiff line change
@@ -25,139 +25,10 @@
2525
#include <asm/ptrace.h>
2626

2727
#ifdef CONFIG_HW_PERF_EVENTS
28-
/*
29-
* Per performance monitor configuration as set via oprofilefs.
30-
*/
31-
struct op_counter_config {
32-
unsigned long count;
33-
unsigned long enabled;
34-
unsigned long event;
35-
unsigned long unit_mask;
36-
unsigned long kernel;
37-
unsigned long user;
38-
struct perf_event_attr attr;
39-
};
40-
41-
static int op_arm_enabled;
42-
static DEFINE_MUTEX(op_arm_mutex);
43-
44-
static struct op_counter_config *counter_config;
45-
static struct perf_event **perf_events[nr_cpumask_bits];
46-
static int perf_num_counters;
47-
48-
/*
49-
* Overflow callback for oprofile.
50-
*/
51-
static void op_overflow_handler(struct perf_event *event, int unused,
52-
struct perf_sample_data *data, struct pt_regs *regs)
28+
char *op_name_from_perf_id(void)
5329
{
54-
int id;
55-
u32 cpu = smp_processor_id();
56-
57-
for (id = 0; id < perf_num_counters; ++id)
58-
if (perf_events[cpu][id] == event)
59-
break;
60-
61-
if (id != perf_num_counters)
62-
oprofile_add_sample(regs, id);
63-
else
64-
pr_warning("oprofile: ignoring spurious overflow "
65-
"on cpu %u\n", cpu);
66-
}
67-
68-
/*
69-
* Called by op_arm_setup to create perf attributes to mirror the oprofile
70-
* settings in counter_config. Attributes are created as `pinned' events and
71-
* so are permanently scheduled on the PMU.
72-
*/
73-
static void op_perf_setup(void)
74-
{
75-
int i;
76-
u32 size = sizeof(struct perf_event_attr);
77-
struct perf_event_attr *attr;
78-
79-
for (i = 0; i < perf_num_counters; ++i) {
80-
attr = &counter_config[i].attr;
81-
memset(attr, 0, size);
82-
attr->type = PERF_TYPE_RAW;
83-
attr->size = size;
84-
attr->config = counter_config[i].event;
85-
attr->sample_period = counter_config[i].count;
86-
attr->pinned = 1;
87-
}
88-
}
89-
90-
static int op_create_counter(int cpu, int event)
91-
{
92-
int ret = 0;
93-
struct perf_event *pevent;
94-
95-
if (!counter_config[event].enabled || (perf_events[cpu][event] != NULL))
96-
return ret;
97-
98-
pevent = perf_event_create_kernel_counter(&counter_config[event].attr,
99-
cpu, NULL,
100-
op_overflow_handler);
101-
102-
if (IS_ERR(pevent)) {
103-
ret = PTR_ERR(pevent);
104-
} else if (pevent->state != PERF_EVENT_STATE_ACTIVE) {
105-
perf_event_release_kernel(pevent);
106-
pr_warning("oprofile: failed to enable event %d "
107-
"on CPU %d\n", event, cpu);
108-
ret = -EBUSY;
109-
} else {
110-
perf_events[cpu][event] = pevent;
111-
}
112-
113-
return ret;
114-
}
30+
enum arm_perf_pmu_ids id = armpmu_get_pmu_id();
11531

116-
static void op_destroy_counter(int cpu, int event)
117-
{
118-
struct perf_event *pevent = perf_events[cpu][event];
119-
120-
if (pevent) {
121-
perf_event_release_kernel(pevent);
122-
perf_events[cpu][event] = NULL;
123-
}
124-
}
125-
126-
/*
127-
* Called by op_arm_start to create active perf events based on the
128-
* perviously configured attributes.
129-
*/
130-
static int op_perf_start(void)
131-
{
132-
int cpu, event, ret = 0;
133-
134-
for_each_online_cpu(cpu) {
135-
for (event = 0; event < perf_num_counters; ++event) {
136-
ret = op_create_counter(cpu, event);
137-
if (ret)
138-
goto out;
139-
}
140-
}
141-
142-
out:
143-
return ret;
144-
}
145-
146-
/*
147-
* Called by op_arm_stop at the end of a profiling run.
148-
*/
149-
static void op_perf_stop(void)
150-
{
151-
int cpu, event;
152-
153-
for_each_online_cpu(cpu)
154-
for (event = 0; event < perf_num_counters; ++event)
155-
op_destroy_counter(cpu, event);
156-
}
157-
158-
159-
static char *op_name_from_perf_id(enum arm_perf_pmu_ids id)
160-
{
16132
switch (id) {
16233
case ARM_PERF_PMU_ID_XSCALE1:
16334
return "arm/xscale1";
@@ -176,116 +47,6 @@ static char *op_name_from_perf_id(enum arm_perf_pmu_ids id)
17647
}
17748
}
17849

179-
static int op_arm_create_files(struct super_block *sb, struct dentry *root)
180-
{
181-
unsigned int i;
182-
183-
for (i = 0; i < perf_num_counters; i++) {
184-
struct dentry *dir;
185-
char buf[4];
186-
187-
snprintf(buf, sizeof buf, "%d", i);
188-
dir = oprofilefs_mkdir(sb, root, buf);
189-
oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled);
190-
oprofilefs_create_ulong(sb, dir, "event", &counter_config[i].event);
191-
oprofilefs_create_ulong(sb, dir, "count", &counter_config[i].count);
192-
oprofilefs_create_ulong(sb, dir, "unit_mask", &counter_config[i].unit_mask);
193-
oprofilefs_create_ulong(sb, dir, "kernel", &counter_config[i].kernel);
194-
oprofilefs_create_ulong(sb, dir, "user", &counter_config[i].user);
195-
}
196-
197-
return 0;
198-
}
199-
200-
static int op_arm_setup(void)
201-
{
202-
spin_lock(&oprofilefs_lock);
203-
op_perf_setup();
204-
spin_unlock(&oprofilefs_lock);
205-
return 0;
206-
}
207-
208-
static int op_arm_start(void)
209-
{
210-
int ret = -EBUSY;
211-
212-
mutex_lock(&op_arm_mutex);
213-
if (!op_arm_enabled) {
214-
ret = 0;
215-
op_perf_start();
216-
op_arm_enabled = 1;
217-
}
218-
mutex_unlock(&op_arm_mutex);
219-
return ret;
220-
}
221-
222-
static void op_arm_stop(void)
223-
{
224-
mutex_lock(&op_arm_mutex);
225-
if (op_arm_enabled)
226-
op_perf_stop();
227-
op_arm_enabled = 0;
228-
mutex_unlock(&op_arm_mutex);
229-
}
230-
231-
#ifdef CONFIG_PM
232-
static int op_arm_suspend(struct platform_device *dev, pm_message_t state)
233-
{
234-
mutex_lock(&op_arm_mutex);
235-
if (op_arm_enabled)
236-
op_perf_stop();
237-
mutex_unlock(&op_arm_mutex);
238-
return 0;
239-
}
240-
241-
static int op_arm_resume(struct platform_device *dev)
242-
{
243-
mutex_lock(&op_arm_mutex);
244-
if (op_arm_enabled && op_perf_start())
245-
op_arm_enabled = 0;
246-
mutex_unlock(&op_arm_mutex);
247-
return 0;
248-
}
249-
250-
static struct platform_driver oprofile_driver = {
251-
.driver = {
252-
.name = "arm-oprofile",
253-
},
254-
.resume = op_arm_resume,
255-
.suspend = op_arm_suspend,
256-
};
257-
258-
static struct platform_device *oprofile_pdev;
259-
260-
static int __init init_driverfs(void)
261-
{
262-
int ret;
263-
264-
ret = platform_driver_register(&oprofile_driver);
265-
if (ret)
266-
goto out;
267-
268-
oprofile_pdev = platform_device_register_simple(
269-
oprofile_driver.driver.name, 0, NULL, 0);
270-
if (IS_ERR(oprofile_pdev)) {
271-
ret = PTR_ERR(oprofile_pdev);
272-
platform_driver_unregister(&oprofile_driver);
273-
}
274-
275-
out:
276-
return ret;
277-
}
278-
279-
static void exit_driverfs(void)
280-
{
281-
platform_device_unregister(oprofile_pdev);
282-
platform_driver_unregister(&oprofile_driver);
283-
}
284-
#else
285-
static int __init init_driverfs(void) { return 0; }
286-
#define exit_driverfs() do { } while (0)
287-
#endif /* CONFIG_PM */
288-
28950
static int report_trace(struct stackframe *frame, void *d)
29051
{
29152
unsigned int *depth = d;
@@ -350,80 +111,20 @@ static void arm_backtrace(struct pt_regs * const regs, unsigned int depth)
350111

351112
int __init oprofile_arch_init(struct oprofile_operations *ops)
352113
{
353-
int cpu, ret = 0;
354-
355-
perf_num_counters = armpmu_get_max_events();
356-
357-
counter_config = kcalloc(perf_num_counters,
358-
sizeof(struct op_counter_config), GFP_KERNEL);
359-
360-
if (!counter_config) {
361-
pr_info("oprofile: failed to allocate %d "
362-
"counters\n", perf_num_counters);
363-
return -ENOMEM;
364-
}
365-
366-
ret = init_driverfs();
367-
if (ret) {
368-
kfree(counter_config);
369-
counter_config = NULL;
370-
return ret;
371-
}
372-
373-
for_each_possible_cpu(cpu) {
374-
perf_events[cpu] = kcalloc(perf_num_counters,
375-
sizeof(struct perf_event *), GFP_KERNEL);
376-
if (!perf_events[cpu]) {
377-
pr_info("oprofile: failed to allocate %d perf events "
378-
"for cpu %d\n", perf_num_counters, cpu);
379-
while (--cpu >= 0)
380-
kfree(perf_events[cpu]);
381-
return -ENOMEM;
382-
}
383-
}
384-
385114
ops->backtrace = arm_backtrace;
386-
ops->create_files = op_arm_create_files;
387-
ops->setup = op_arm_setup;
388-
ops->start = op_arm_start;
389-
ops->stop = op_arm_stop;
390-
ops->shutdown = op_arm_stop;
391-
ops->cpu_type = op_name_from_perf_id(armpmu_get_pmu_id());
392-
393-
if (!ops->cpu_type)
394-
ret = -ENODEV;
395-
else
396-
pr_info("oprofile: using %s\n", ops->cpu_type);
397115

398-
return ret;
116+
return oprofile_perf_init(ops);
399117
}
400118

401-
void oprofile_arch_exit(void)
119+
void __exit oprofile_arch_exit(void)
402120
{
403-
int cpu, id;
404-
struct perf_event *event;
405-
406-
if (*perf_events) {
407-
for_each_possible_cpu(cpu) {
408-
for (id = 0; id < perf_num_counters; ++id) {
409-
event = perf_events[cpu][id];
410-
if (event != NULL)
411-
perf_event_release_kernel(event);
412-
}
413-
kfree(perf_events[cpu]);
414-
}
415-
}
416-
417-
if (counter_config) {
418-
kfree(counter_config);
419-
exit_driverfs();
420-
}
121+
oprofile_perf_exit();
421122
}
422123
#else
423124
int __init oprofile_arch_init(struct oprofile_operations *ops)
424125
{
425126
pr_info("oprofile: hardware counters not available\n");
426127
return -ENODEV;
427128
}
428-
void oprofile_arch_exit(void) {}
129+
void __exit oprofile_arch_exit(void) {}
429130
#endif /* CONFIG_HW_PERF_EVENTS */

arch/sh/Kconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,11 @@ config ARCH_SHMOBILE
249249
select PM
250250
select PM_RUNTIME
251251

252+
config CPU_HAS_PMU
253+
depends on CPU_SH4 || CPU_SH4A
254+
default y
255+
bool
256+
252257
if SUPERH32
253258

254259
choice
@@ -738,6 +743,14 @@ config GUSA_RB
738743
LLSC, this should be more efficient than the other alternative of
739744
disabling interrupts around the atomic sequence.
740745

746+
config HW_PERF_EVENTS
747+
bool "Enable hardware performance counter support for perf events"
748+
depends on PERF_EVENTS && CPU_HAS_PMU
749+
default y
750+
help
751+
Enable hardware performance counter support for perf events. If
752+
disabled, perf events will use software events only.
753+
741754
source "drivers/sh/Kconfig"
742755

743756
endmenu

0 commit comments

Comments
 (0)