aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/exec.c1
-rw-r--r--include/linux/perf_counter.h16
-rw-r--r--kernel/perf_counter.c93
3 files changed, 109 insertions, 1 deletions
diff --git a/fs/exec.c b/fs/exec.c
index e015c0b5a082..bf47ed0278ff 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -951,6 +951,7 @@ void set_task_comm(struct task_struct *tsk, char *buf)
951 task_lock(tsk); 951 task_lock(tsk);
952 strlcpy(tsk->comm, buf, sizeof(tsk->comm)); 952 strlcpy(tsk->comm, buf, sizeof(tsk->comm));
953 task_unlock(tsk); 953 task_unlock(tsk);
954 perf_counter_comm(tsk);
954} 955}
955 956
956int flush_old_exec(struct linux_binprm * bprm) 957int flush_old_exec(struct linux_binprm * bprm)
diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h
index 8bf764fc6220..a70a55f27598 100644
--- a/include/linux/perf_counter.h
+++ b/include/linux/perf_counter.h
@@ -142,8 +142,9 @@ struct perf_counter_hw_event {
142 exclude_idle : 1, /* don't count when idle */ 142 exclude_idle : 1, /* don't count when idle */
143 mmap : 1, /* include mmap data */ 143 mmap : 1, /* include mmap data */
144 munmap : 1, /* include munmap data */ 144 munmap : 1, /* include munmap data */
145 comm : 1, /* include comm data */
145 146
146 __reserved_1 : 53; 147 __reserved_1 : 52;
147 148
148 __u32 extra_config_len; 149 __u32 extra_config_len;
149 __u32 wakeup_events; /* wakeup every n events */ 150 __u32 wakeup_events; /* wakeup every n events */
@@ -231,6 +232,16 @@ enum perf_event_type {
231 PERF_EVENT_MUNMAP = 2, 232 PERF_EVENT_MUNMAP = 2,
232 233
233 /* 234 /*
235 * struct {
236 * struct perf_event_header header;
237 *
238 * u32 pid, tid;
239 * char comm[];
240 * };
241 */
242 PERF_EVENT_COMM = 3,
243
244 /*
234 * When header.misc & PERF_EVENT_MISC_OVERFLOW the event_type field 245 * When header.misc & PERF_EVENT_MISC_OVERFLOW the event_type field
235 * will be PERF_RECORD_* 246 * will be PERF_RECORD_*
236 * 247 *
@@ -545,6 +556,8 @@ extern void perf_counter_mmap(unsigned long addr, unsigned long len,
545extern void perf_counter_munmap(unsigned long addr, unsigned long len, 556extern void perf_counter_munmap(unsigned long addr, unsigned long len,
546 unsigned long pgoff, struct file *file); 557 unsigned long pgoff, struct file *file);
547 558
559extern void perf_counter_comm(struct task_struct *tsk);
560
548#define MAX_STACK_DEPTH 255 561#define MAX_STACK_DEPTH 255
549 562
550struct perf_callchain_entry { 563struct perf_callchain_entry {
@@ -583,6 +596,7 @@ static inline void
583perf_counter_munmap(unsigned long addr, unsigned long len, 596perf_counter_munmap(unsigned long addr, unsigned long len,
584 unsigned long pgoff, struct file *file) { } 597 unsigned long pgoff, struct file *file) { }
585 598
599static inline void perf_counter_comm(struct task_struct *tsk) { }
586#endif 600#endif
587 601
588#endif /* __KERNEL__ */ 602#endif /* __KERNEL__ */
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c
index bf12df6f3538..2d4aebb2982b 100644
--- a/kernel/perf_counter.c
+++ b/kernel/perf_counter.c
@@ -1917,6 +1917,99 @@ static void perf_counter_output(struct perf_counter *counter,
1917} 1917}
1918 1918
1919/* 1919/*
1920 * comm tracking
1921 */
1922
1923struct perf_comm_event {
1924 struct task_struct *task;
1925 char *comm;
1926 int comm_size;
1927
1928 struct {
1929 struct perf_event_header header;
1930
1931 u32 pid;
1932 u32 tid;
1933 } event;
1934};
1935
1936static void perf_counter_comm_output(struct perf_counter *counter,
1937 struct perf_comm_event *comm_event)
1938{
1939 struct perf_output_handle handle;
1940 int size = comm_event->event.header.size;
1941 int ret = perf_output_begin(&handle, counter, size, 0, 0);
1942
1943 if (ret)
1944 return;
1945
1946 perf_output_put(&handle, comm_event->event);
1947 perf_output_copy(&handle, comm_event->comm,
1948 comm_event->comm_size);
1949 perf_output_end(&handle);
1950}
1951
1952static int perf_counter_comm_match(struct perf_counter *counter,
1953 struct perf_comm_event *comm_event)
1954{
1955 if (counter->hw_event.comm &&
1956 comm_event->event.header.type == PERF_EVENT_COMM)
1957 return 1;
1958
1959 return 0;
1960}
1961
1962static void perf_counter_comm_ctx(struct perf_counter_context *ctx,
1963 struct perf_comm_event *comm_event)
1964{
1965 struct perf_counter *counter;
1966
1967 if (system_state != SYSTEM_RUNNING || list_empty(&ctx->event_list))
1968 return;
1969
1970 rcu_read_lock();
1971 list_for_each_entry_rcu(counter, &ctx->event_list, event_entry) {
1972 if (perf_counter_comm_match(counter, comm_event))
1973 perf_counter_comm_output(counter, comm_event);
1974 }
1975 rcu_read_unlock();
1976}
1977
1978static void perf_counter_comm_event(struct perf_comm_event *comm_event)
1979{
1980 struct perf_cpu_context *cpuctx;
1981 unsigned int size;
1982 char *comm = comm_event->task->comm;
1983
1984 size = ALIGN(strlen(comm), sizeof(u64));
1985
1986 comm_event->comm = comm;
1987 comm_event->comm_size = size;
1988
1989 comm_event->event.header.size = sizeof(comm_event->event) + size;
1990
1991 cpuctx = &get_cpu_var(perf_cpu_context);
1992 perf_counter_comm_ctx(&cpuctx->ctx, comm_event);
1993 put_cpu_var(perf_cpu_context);
1994
1995 perf_counter_comm_ctx(&current->perf_counter_ctx, comm_event);
1996}
1997
1998void perf_counter_comm(struct task_struct *task)
1999{
2000 struct perf_comm_event comm_event = {
2001 .task = task,
2002 .event = {
2003 .header = { .type = PERF_EVENT_COMM, },
2004 .pid = task->group_leader->pid,
2005 .tid = task->pid,
2006 },
2007 };
2008
2009 perf_counter_comm_event(&comm_event);
2010}
2011
2012/*
1920 * mmap tracking 2013 * mmap tracking
1921 */ 2014 */
1922 2015