diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-12-11 06:46:46 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-12-11 09:45:51 -0500 |
commit | 621a01eac89b5e2f81a4cf576568b31f40a02724 (patch) | |
tree | 79a7f2a8d49017077f40cfac4e78ee255cf2f43e /kernel | |
parent | ccff286d85098ba5438e22aa2ea807fc1e18cf2f (diff) |
perf counters: hw driver API
Impact: restructure code, introduce hw_ops driver abstraction
Introduce this abstraction to handle counter details:
struct hw_perf_counter_ops {
void (*hw_perf_counter_enable) (struct perf_counter *counter);
void (*hw_perf_counter_disable) (struct perf_counter *counter);
void (*hw_perf_counter_read) (struct perf_counter *counter);
};
This will be useful to support assymetric hw details, and it will also
be useful to implement "software counters". (Counters that count kernel
managed sw events such as pagefaults, context-switches, wall-clock time
or task-local time.)
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/perf_counter.c | 45 |
1 files changed, 24 insertions, 21 deletions
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index 278209c547a8..e6e41ca95463 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c | |||
@@ -37,18 +37,15 @@ static DEFINE_MUTEX(perf_resource_mutex); | |||
37 | /* | 37 | /* |
38 | * Architecture provided APIs - weak aliases: | 38 | * Architecture provided APIs - weak aliases: |
39 | */ | 39 | */ |
40 | 40 | extern __weak struct hw_perf_counter_ops * | |
41 | int __weak hw_perf_counter_init(struct perf_counter *counter) | 41 | hw_perf_counter_init(struct perf_counter *counter) |
42 | { | 42 | { |
43 | return -EINVAL; | 43 | return ERR_PTR(-EINVAL); |
44 | } | 44 | } |
45 | 45 | ||
46 | void __weak hw_perf_counter_enable(struct perf_counter *counter) { } | 46 | void __weak hw_perf_disable_all(void) { } |
47 | void __weak hw_perf_counter_disable(struct perf_counter *counter) { } | 47 | void __weak hw_perf_enable_all(void) { } |
48 | void __weak hw_perf_counter_read(struct perf_counter *counter) { } | 48 | void __weak hw_perf_counter_setup(void) { } |
49 | void __weak hw_perf_disable_all(void) { } | ||
50 | void __weak hw_perf_enable_all(void) { } | ||
51 | void __weak hw_perf_counter_setup(void) { } | ||
52 | 49 | ||
53 | #if BITS_PER_LONG == 64 | 50 | #if BITS_PER_LONG == 64 |
54 | 51 | ||
@@ -146,7 +143,7 @@ static void __perf_counter_remove_from_context(void *info) | |||
146 | spin_lock(&ctx->lock); | 143 | spin_lock(&ctx->lock); |
147 | 144 | ||
148 | if (counter->active) { | 145 | if (counter->active) { |
149 | hw_perf_counter_disable(counter); | 146 | counter->hw_ops->hw_perf_counter_disable(counter); |
150 | counter->active = 0; | 147 | counter->active = 0; |
151 | ctx->nr_active--; | 148 | ctx->nr_active--; |
152 | cpuctx->active_oncpu--; | 149 | cpuctx->active_oncpu--; |
@@ -257,7 +254,7 @@ static void __perf_install_in_context(void *info) | |||
257 | ctx->nr_counters++; | 254 | ctx->nr_counters++; |
258 | 255 | ||
259 | if (cpuctx->active_oncpu < perf_max_counters) { | 256 | if (cpuctx->active_oncpu < perf_max_counters) { |
260 | hw_perf_counter_enable(counter); | 257 | counter->hw_ops->hw_perf_counter_enable(counter); |
261 | counter->active = 1; | 258 | counter->active = 1; |
262 | counter->oncpu = cpu; | 259 | counter->oncpu = cpu; |
263 | ctx->nr_active++; | 260 | ctx->nr_active++; |
@@ -333,7 +330,7 @@ counter_sched_out(struct perf_counter *counter, | |||
333 | if (!counter->active) | 330 | if (!counter->active) |
334 | return; | 331 | return; |
335 | 332 | ||
336 | hw_perf_counter_disable(counter); | 333 | counter->hw_ops->hw_perf_counter_disable(counter); |
337 | counter->active = 0; | 334 | counter->active = 0; |
338 | counter->oncpu = -1; | 335 | counter->oncpu = -1; |
339 | 336 | ||
@@ -392,7 +389,7 @@ counter_sched_in(struct perf_counter *counter, | |||
392 | struct perf_counter_context *ctx, | 389 | struct perf_counter_context *ctx, |
393 | int cpu) | 390 | int cpu) |
394 | { | 391 | { |
395 | hw_perf_counter_enable(counter); | 392 | counter->hw_ops->hw_perf_counter_enable(counter); |
396 | counter->active = 1; | 393 | counter->active = 1; |
397 | counter->oncpu = cpu; /* TODO: put 'cpu' into cpuctx->cpu */ | 394 | counter->oncpu = cpu; /* TODO: put 'cpu' into cpuctx->cpu */ |
398 | 395 | ||
@@ -509,7 +506,9 @@ void perf_counter_init_task(struct task_struct *task) | |||
509 | */ | 506 | */ |
510 | static void __hw_perf_counter_read(void *info) | 507 | static void __hw_perf_counter_read(void *info) |
511 | { | 508 | { |
512 | hw_perf_counter_read(info); | 509 | struct perf_counter *counter = info; |
510 | |||
511 | counter->hw_ops->hw_perf_counter_read(counter); | ||
513 | } | 512 | } |
514 | 513 | ||
515 | static u64 perf_counter_read(struct perf_counter *counter) | 514 | static u64 perf_counter_read(struct perf_counter *counter) |
@@ -816,8 +815,10 @@ perf_counter_alloc(struct perf_counter_hw_event *hw_event, | |||
816 | int cpu, | 815 | int cpu, |
817 | struct perf_counter *group_leader) | 816 | struct perf_counter *group_leader) |
818 | { | 817 | { |
819 | struct perf_counter *counter = kzalloc(sizeof(*counter), GFP_KERNEL); | 818 | struct hw_perf_counter_ops *hw_ops; |
819 | struct perf_counter *counter; | ||
820 | 820 | ||
821 | counter = kzalloc(sizeof(*counter), GFP_KERNEL); | ||
821 | if (!counter) | 822 | if (!counter) |
822 | return NULL; | 823 | return NULL; |
823 | 824 | ||
@@ -839,6 +840,14 @@ perf_counter_alloc(struct perf_counter_hw_event *hw_event, | |||
839 | counter->hw_event = *hw_event; | 840 | counter->hw_event = *hw_event; |
840 | counter->wakeup_pending = 0; | 841 | counter->wakeup_pending = 0; |
841 | counter->group_leader = group_leader; | 842 | counter->group_leader = group_leader; |
843 | counter->hw_ops = NULL; | ||
844 | |||
845 | hw_ops = hw_perf_counter_init(counter); | ||
846 | if (!hw_ops) { | ||
847 | kfree(counter); | ||
848 | return NULL; | ||
849 | } | ||
850 | counter->hw_ops = hw_ops; | ||
842 | 851 | ||
843 | return counter; | 852 | return counter; |
844 | } | 853 | } |
@@ -908,10 +917,6 @@ asmlinkage int sys_perf_counter_open( | |||
908 | if (!counter) | 917 | if (!counter) |
909 | goto err_put_context; | 918 | goto err_put_context; |
910 | 919 | ||
911 | ret = hw_perf_counter_init(counter); | ||
912 | if (ret) | ||
913 | goto err_free_put_context; | ||
914 | |||
915 | perf_install_in_context(ctx, counter, cpu); | 920 | perf_install_in_context(ctx, counter, cpu); |
916 | 921 | ||
917 | ret = anon_inode_getfd("[perf_counter]", &perf_fops, counter, 0); | 922 | ret = anon_inode_getfd("[perf_counter]", &perf_fops, counter, 0); |
@@ -927,8 +932,6 @@ err_remove_free_put_context: | |||
927 | mutex_lock(&counter->mutex); | 932 | mutex_lock(&counter->mutex); |
928 | perf_counter_remove_from_context(counter); | 933 | perf_counter_remove_from_context(counter); |
929 | mutex_unlock(&counter->mutex); | 934 | mutex_unlock(&counter->mutex); |
930 | |||
931 | err_free_put_context: | ||
932 | kfree(counter); | 935 | kfree(counter); |
933 | 936 | ||
934 | err_put_context: | 937 | err_put_context: |