aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2009-05-22 00:17:31 -0400
committerIngo Molnar <mingo@elte.hu>2009-05-22 06:18:19 -0400
commita63eaf34ae60bdb067a354cc8def2e8f4a01f5f4 (patch)
tree9e81e5e0299bd524b3d07c17a05760e33c7d58a0 /include/linux
parent34adc8062227f41b04ade0ff3fbd1dbe3002669e (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.h13
-rw-r--r--include/linux/perf_counter.h4
-rw-r--r--include/linux/sched.h6
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
109extern struct cred init_cred; 109extern 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 */
500struct perf_counter_context { 499struct 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;
99struct bio; 98struct bio;
100struct bts_tracer; 99struct bts_tracer;
101struct fs_struct; 100struct fs_struct;
101struct 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;