25
25
#include <asm/ptrace.h>
26
26
27
27
#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 )
53
29
{
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 ();
115
31
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
- {
161
32
switch (id ) {
162
33
case ARM_PERF_PMU_ID_XSCALE1 :
163
34
return "arm/xscale1" ;
@@ -176,116 +47,6 @@ static char *op_name_from_perf_id(enum arm_perf_pmu_ids id)
176
47
}
177
48
}
178
49
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
-
289
50
static int report_trace (struct stackframe * frame , void * d )
290
51
{
291
52
unsigned int * depth = d ;
@@ -350,80 +111,20 @@ static void arm_backtrace(struct pt_regs * const regs, unsigned int depth)
350
111
351
112
int __init oprofile_arch_init (struct oprofile_operations * ops )
352
113
{
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
-
385
114
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 );
397
115
398
- return ret ;
116
+ return oprofile_perf_init ( ops ) ;
399
117
}
400
118
401
- void oprofile_arch_exit (void )
119
+ void __exit oprofile_arch_exit (void )
402
120
{
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 ();
421
122
}
422
123
#else
423
124
int __init oprofile_arch_init (struct oprofile_operations * ops )
424
125
{
425
126
pr_info ("oprofile: hardware counters not available\n" );
426
127
return - ENODEV ;
427
128
}
428
- void oprofile_arch_exit (void ) {}
129
+ void __exit oprofile_arch_exit (void ) {}
429
130
#endif /* CONFIG_HW_PERF_EVENTS */
0 commit comments