diff options
author | Paul Mackerras <paulus@samba.org> | 2009-05-22 00:17:31 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-05-22 06:18:19 -0400 |
commit | a63eaf34ae60bdb067a354cc8def2e8f4a01f5f4 (patch) | |
tree | 9e81e5e0299bd524b3d07c17a05760e33c7d58a0 /include/linux | |
parent | 34adc8062227f41b04ade0ff3fbd1dbe3002669e (diff) |
perf_counter: Dynamically allocate tasks' perf_counter_context struct
This replaces the struct perf_counter_context in the task_struct with
a pointer to a dynamically allocated perf_counter_context struct. The
main reason for doing is this is to allow us to transfer a
perf_counter_context from one task to another when we do lazy PMU
switching in a later patch.
This has a few side-benefits: the task_struct becomes a little smaller,
we save some memory because only tasks that have perf_counters attached
get a perf_counter_context allocated for them, and we can remove the
inclusion of <linux/perf_counter.h> in sched.h, meaning that we don't
end up recompiling nearly everything whenever perf_counter.h changes.
The perf_counter_context structures are reference-counted and freed
when the last reference is dropped. A context can have references
from its task and the counters on its task. Counters can outlive the
task so it is possible that a context will be freed well after its
task has exited.
Contexts are allocated on fork if the parent had a context, or
otherwise the first time that a per-task counter is created on a task.
In the latter case, we set the context pointer in the task struct
locklessly using an atomic compare-and-exchange operation in case we
raced with some other task in creating a context for the subject task.
This also removes the task pointer from the perf_counter struct. The
task pointer was not used anywhere and would make it harder to move a
context from one task to another. Anything that needed to know which
task a counter was attached to was already using counter->ctx->task.
The __perf_counter_init_context function moves up in perf_counter.c
so that it can be called from find_get_context, and now initializes
the refcount, but is otherwise unchanged.
We were potentially calling list_del_counter twice: once from
__perf_counter_exit_task when the task exits and once from
__perf_counter_remove_from_context when the counter's fd gets closed.
This adds a check in list_del_counter so it doesn't do anything if
the counter has already been removed from the lists.
Since perf_counter_task_sched_in doesn't do anything if the task doesn't
have a context, and leaves cpuctx->task_ctx = NULL, this adds code to
__perf_install_in_context to set cpuctx->task_ctx if necessary, i.e. in
the case where the current task adds the first counter to itself and
thus creates a context for itself.
This also adds similar code to __perf_counter_enable to handle a
similar situation which can arise when the counters have been disabled
using prctl; that also leaves cpuctx->task_ctx = NULL.
[ Impact: refactor counter context management to prepare for new feature ]
Signed-off-by: Paul Mackerras <paulus@samba.org>
Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
LKML-Reference: <18966.10075.781053.231153@cargo.ozlabs.ibm.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'include/linux')
-rw-r--r-- | include/linux/init_task.h | 13 | ||||
-rw-r--r-- | include/linux/perf_counter.h | 4 | ||||
-rw-r--r-- | include/linux/sched.h | 6 |
3 files changed, 5 insertions, 18 deletions
diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 503afaa0afa7..d87247d2641f 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h | |||
@@ -108,18 +108,6 @@ extern struct group_info init_groups; | |||
108 | 108 | ||
109 | extern struct cred init_cred; | 109 | extern struct cred init_cred; |
110 | 110 | ||
111 | #ifdef CONFIG_PERF_COUNTERS | ||
112 | # define INIT_PERF_COUNTERS(tsk) \ | ||
113 | .perf_counter_ctx.counter_list = \ | ||
114 | LIST_HEAD_INIT(tsk.perf_counter_ctx.counter_list), \ | ||
115 | .perf_counter_ctx.event_list = \ | ||
116 | LIST_HEAD_INIT(tsk.perf_counter_ctx.event_list), \ | ||
117 | .perf_counter_ctx.lock = \ | ||
118 | __SPIN_LOCK_UNLOCKED(tsk.perf_counter_ctx.lock), | ||
119 | #else | ||
120 | # define INIT_PERF_COUNTERS(tsk) | ||
121 | #endif | ||
122 | |||
123 | /* | 111 | /* |
124 | * INIT_TASK is used to set up the first task table, touch at | 112 | * INIT_TASK is used to set up the first task table, touch at |
125 | * your own risk!. Base=0, limit=0x1fffff (=2MB) | 113 | * your own risk!. Base=0, limit=0x1fffff (=2MB) |
@@ -183,7 +171,6 @@ extern struct cred init_cred; | |||
183 | }, \ | 171 | }, \ |
184 | .dirties = INIT_PROP_LOCAL_SINGLE(dirties), \ | 172 | .dirties = INIT_PROP_LOCAL_SINGLE(dirties), \ |
185 | INIT_IDS \ | 173 | INIT_IDS \ |
186 | INIT_PERF_COUNTERS(tsk) \ | ||
187 | INIT_TRACE_IRQFLAGS \ | 174 | INIT_TRACE_IRQFLAGS \ |
188 | INIT_LOCKDEP \ | 175 | INIT_LOCKDEP \ |
189 | INIT_FTRACE_GRAPH \ | 176 | INIT_FTRACE_GRAPH \ |
diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h index f612941ef46e..071309005468 100644 --- a/include/linux/perf_counter.h +++ b/include/linux/perf_counter.h | |||
@@ -449,7 +449,6 @@ struct perf_counter { | |||
449 | struct hw_perf_counter hw; | 449 | struct hw_perf_counter hw; |
450 | 450 | ||
451 | struct perf_counter_context *ctx; | 451 | struct perf_counter_context *ctx; |
452 | struct task_struct *task; | ||
453 | struct file *filp; | 452 | struct file *filp; |
454 | 453 | ||
455 | struct perf_counter *parent; | 454 | struct perf_counter *parent; |
@@ -498,7 +497,6 @@ struct perf_counter { | |||
498 | * Used as a container for task counters and CPU counters as well: | 497 | * Used as a container for task counters and CPU counters as well: |
499 | */ | 498 | */ |
500 | struct perf_counter_context { | 499 | struct perf_counter_context { |
501 | #ifdef CONFIG_PERF_COUNTERS | ||
502 | /* | 500 | /* |
503 | * Protect the states of the counters in the list, | 501 | * Protect the states of the counters in the list, |
504 | * nr_active, and the list: | 502 | * nr_active, and the list: |
@@ -516,6 +514,7 @@ struct perf_counter_context { | |||
516 | int nr_counters; | 514 | int nr_counters; |
517 | int nr_active; | 515 | int nr_active; |
518 | int is_active; | 516 | int is_active; |
517 | atomic_t refcount; | ||
519 | struct task_struct *task; | 518 | struct task_struct *task; |
520 | 519 | ||
521 | /* | 520 | /* |
@@ -523,7 +522,6 @@ struct perf_counter_context { | |||
523 | */ | 522 | */ |
524 | u64 time; | 523 | u64 time; |
525 | u64 timestamp; | 524 | u64 timestamp; |
526 | #endif | ||
527 | }; | 525 | }; |
528 | 526 | ||
529 | /** | 527 | /** |
diff --git a/include/linux/sched.h b/include/linux/sched.h index ff59d1231519..9714d450f417 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -71,7 +71,6 @@ struct sched_param { | |||
71 | #include <linux/path.h> | 71 | #include <linux/path.h> |
72 | #include <linux/compiler.h> | 72 | #include <linux/compiler.h> |
73 | #include <linux/completion.h> | 73 | #include <linux/completion.h> |
74 | #include <linux/perf_counter.h> | ||
75 | #include <linux/pid.h> | 74 | #include <linux/pid.h> |
76 | #include <linux/percpu.h> | 75 | #include <linux/percpu.h> |
77 | #include <linux/topology.h> | 76 | #include <linux/topology.h> |
@@ -99,6 +98,7 @@ struct robust_list_head; | |||
99 | struct bio; | 98 | struct bio; |
100 | struct bts_tracer; | 99 | struct bts_tracer; |
101 | struct fs_struct; | 100 | struct fs_struct; |
101 | struct perf_counter_context; | ||
102 | 102 | ||
103 | /* | 103 | /* |
104 | * List of flags we want to share for kernel threads, | 104 | * List of flags we want to share for kernel threads, |
@@ -1387,7 +1387,9 @@ struct task_struct { | |||
1387 | struct list_head pi_state_list; | 1387 | struct list_head pi_state_list; |
1388 | struct futex_pi_state *pi_state_cache; | 1388 | struct futex_pi_state *pi_state_cache; |
1389 | #endif | 1389 | #endif |
1390 | struct perf_counter_context perf_counter_ctx; | 1390 | #ifdef CONFIG_PERF_COUNTERS |
1391 | struct perf_counter_context *perf_counter_ctxp; | ||
1392 | #endif | ||
1391 | #ifdef CONFIG_NUMA | 1393 | #ifdef CONFIG_NUMA |
1392 | struct mempolicy *mempolicy; | 1394 | struct mempolicy *mempolicy; |
1393 | short il_next; | 1395 | short il_next; |