aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/perf_counter.h13
-rw-r--r--init/Kconfig11
-rw-r--r--kernel/fork.c4
-rw-r--r--kernel/perf_counter.c101
-rw-r--r--tools/perf/Makefile2
-rw-r--r--tools/perf/builtin-report.c24
-rw-r--r--tools/perf/builtin-top.c1
-rw-r--r--tools/perf/util/quote.c2
-rw-r--r--tools/perf/util/symbol.c2
9 files changed, 117 insertions, 43 deletions
diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h
index bd15d7a5f5ce..e604e6ef72dd 100644
--- a/include/linux/perf_counter.h
+++ b/include/linux/perf_counter.h
@@ -181,8 +181,9 @@ struct perf_counter_attr {
181 freq : 1, /* use freq, not period */ 181 freq : 1, /* use freq, not period */
182 inherit_stat : 1, /* per task counts */ 182 inherit_stat : 1, /* per task counts */
183 enable_on_exec : 1, /* next exec enables */ 183 enable_on_exec : 1, /* next exec enables */
184 task : 1, /* trace fork/exit */
184 185
185 __reserved_1 : 51; 186 __reserved_1 : 50;
186 187
187 __u32 wakeup_events; /* wakeup every n events */ 188 __u32 wakeup_events; /* wakeup every n events */
188 __u32 __reserved_2; 189 __u32 __reserved_2;
@@ -311,6 +312,15 @@ enum perf_event_type {
311 /* 312 /*
312 * struct { 313 * struct {
313 * struct perf_event_header header; 314 * struct perf_event_header header;
315 * u32 pid, ppid;
316 * u32 tid, ptid;
317 * };
318 */
319 PERF_EVENT_EXIT = 4,
320
321 /*
322 * struct {
323 * struct perf_event_header header;
314 * u64 time; 324 * u64 time;
315 * u64 id; 325 * u64 id;
316 * u64 stream_id; 326 * u64 stream_id;
@@ -323,6 +333,7 @@ enum perf_event_type {
323 * struct { 333 * struct {
324 * struct perf_event_header header; 334 * struct perf_event_header header;
325 * u32 pid, ppid; 335 * u32 pid, ppid;
336 * u32 tid, ptid;
326 * }; 337 * };
327 */ 338 */
328 PERF_EVENT_FORK = 7, 339 PERF_EVENT_FORK = 7,
diff --git a/init/Kconfig b/init/Kconfig
index cb2c09270226..3f7e60995c80 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -940,6 +940,7 @@ menu "Performance Counters"
940 940
941config PERF_COUNTERS 941config PERF_COUNTERS
942 bool "Kernel Performance Counters" 942 bool "Kernel Performance Counters"
943 default y if PROFILING
943 depends on HAVE_PERF_COUNTERS 944 depends on HAVE_PERF_COUNTERS
944 select ANON_INODES 945 select ANON_INODES
945 help 946 help
@@ -961,9 +962,17 @@ config PERF_COUNTERS
961 Say Y if unsure. 962 Say Y if unsure.
962 963
963config EVENT_PROFILE 964config EVENT_PROFILE
964 bool "Tracepoint profile sources" 965 bool "Tracepoint profiling sources"
965 depends on PERF_COUNTERS && EVENT_TRACING 966 depends on PERF_COUNTERS && EVENT_TRACING
966 default y 967 default y
968 help
969 Allow the use of tracepoints as software performance counters.
970
971 When this is enabled, you can create perf counters based on
972 tracepoints using PERF_TYPE_TRACEPOINT and the tracepoint ID
973 found in debugfs://tracing/events/*/*/id. (The -e/--events
974 option to the perf tool can parse and interpret symbolic
975 tracepoints, in the subsystem:tracepoint_name format.)
967 976
968endmenu 977endmenu
969 978
diff --git a/kernel/fork.c b/kernel/fork.c
index 29b532e718f7..466531eb92cc 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1269,6 +1269,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
1269 write_unlock_irq(&tasklist_lock); 1269 write_unlock_irq(&tasklist_lock);
1270 proc_fork_connector(p); 1270 proc_fork_connector(p);
1271 cgroup_post_fork(p); 1271 cgroup_post_fork(p);
1272 perf_counter_fork(p);
1272 return p; 1273 return p;
1273 1274
1274bad_fork_free_pid: 1275bad_fork_free_pid:
@@ -1410,9 +1411,6 @@ long do_fork(unsigned long clone_flags,
1410 init_completion(&vfork); 1411 init_completion(&vfork);
1411 } 1412 }
1412 1413
1413 if (!(clone_flags & CLONE_THREAD))
1414 perf_counter_fork(p);
1415
1416 audit_finish_fork(p); 1414 audit_finish_fork(p);
1417 tracehook_report_clone(regs, clone_flags, nr, p); 1415 tracehook_report_clone(regs, clone_flags, nr, p);
1418 1416
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c
index 950931041954..199ed4771315 100644
--- a/kernel/perf_counter.c
+++ b/kernel/perf_counter.c
@@ -42,6 +42,7 @@ static int perf_overcommit __read_mostly = 1;
42static atomic_t nr_counters __read_mostly; 42static atomic_t nr_counters __read_mostly;
43static atomic_t nr_mmap_counters __read_mostly; 43static atomic_t nr_mmap_counters __read_mostly;
44static atomic_t nr_comm_counters __read_mostly; 44static atomic_t nr_comm_counters __read_mostly;
45static atomic_t nr_task_counters __read_mostly;
45 46
46/* 47/*
47 * perf counter paranoia level: 48 * perf counter paranoia level:
@@ -1654,6 +1655,8 @@ static void free_counter(struct perf_counter *counter)
1654 atomic_dec(&nr_mmap_counters); 1655 atomic_dec(&nr_mmap_counters);
1655 if (counter->attr.comm) 1656 if (counter->attr.comm)
1656 atomic_dec(&nr_comm_counters); 1657 atomic_dec(&nr_comm_counters);
1658 if (counter->attr.task)
1659 atomic_dec(&nr_task_counters);
1657 } 1660 }
1658 1661
1659 if (counter->destroy) 1662 if (counter->destroy)
@@ -1688,6 +1691,18 @@ static int perf_release(struct inode *inode, struct file *file)
1688 return 0; 1691 return 0;
1689} 1692}
1690 1693
1694static u64 perf_counter_read_tree(struct perf_counter *counter)
1695{
1696 struct perf_counter *child;
1697 u64 total = 0;
1698
1699 total += perf_counter_read(counter);
1700 list_for_each_entry(child, &counter->child_list, child_list)
1701 total += perf_counter_read(child);
1702
1703 return total;
1704}
1705
1691/* 1706/*
1692 * Read the performance counter - simple non blocking version for now 1707 * Read the performance counter - simple non blocking version for now
1693 */ 1708 */
@@ -1707,7 +1722,7 @@ perf_read_hw(struct perf_counter *counter, char __user *buf, size_t count)
1707 1722
1708 WARN_ON_ONCE(counter->ctx->parent_ctx); 1723 WARN_ON_ONCE(counter->ctx->parent_ctx);
1709 mutex_lock(&counter->child_mutex); 1724 mutex_lock(&counter->child_mutex);
1710 values[0] = perf_counter_read(counter); 1725 values[0] = perf_counter_read_tree(counter);
1711 n = 1; 1726 n = 1;
1712 if (counter->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) 1727 if (counter->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
1713 values[n++] = counter->total_time_enabled + 1728 values[n++] = counter->total_time_enabled +
@@ -2819,10 +2834,12 @@ perf_counter_read_event(struct perf_counter *counter,
2819} 2834}
2820 2835
2821/* 2836/*
2822 * fork tracking 2837 * task tracking -- fork/exit
2838 *
2839 * enabled by: attr.comm | attr.mmap | attr.task
2823 */ 2840 */
2824 2841
2825struct perf_fork_event { 2842struct perf_task_event {
2826 struct task_struct *task; 2843 struct task_struct *task;
2827 2844
2828 struct { 2845 struct {
@@ -2830,37 +2847,42 @@ struct perf_fork_event {
2830 2847
2831 u32 pid; 2848 u32 pid;
2832 u32 ppid; 2849 u32 ppid;
2850 u32 tid;
2851 u32 ptid;
2833 } event; 2852 } event;
2834}; 2853};
2835 2854
2836static void perf_counter_fork_output(struct perf_counter *counter, 2855static void perf_counter_task_output(struct perf_counter *counter,
2837 struct perf_fork_event *fork_event) 2856 struct perf_task_event *task_event)
2838{ 2857{
2839 struct perf_output_handle handle; 2858 struct perf_output_handle handle;
2840 int size = fork_event->event.header.size; 2859 int size = task_event->event.header.size;
2841 struct task_struct *task = fork_event->task; 2860 struct task_struct *task = task_event->task;
2842 int ret = perf_output_begin(&handle, counter, size, 0, 0); 2861 int ret = perf_output_begin(&handle, counter, size, 0, 0);
2843 2862
2844 if (ret) 2863 if (ret)
2845 return; 2864 return;
2846 2865
2847 fork_event->event.pid = perf_counter_pid(counter, task); 2866 task_event->event.pid = perf_counter_pid(counter, task);
2848 fork_event->event.ppid = perf_counter_pid(counter, task->real_parent); 2867 task_event->event.ppid = perf_counter_pid(counter, task->real_parent);
2849 2868
2850 perf_output_put(&handle, fork_event->event); 2869 task_event->event.tid = perf_counter_tid(counter, task);
2870 task_event->event.ptid = perf_counter_tid(counter, task->real_parent);
2871
2872 perf_output_put(&handle, task_event->event);
2851 perf_output_end(&handle); 2873 perf_output_end(&handle);
2852} 2874}
2853 2875
2854static int perf_counter_fork_match(struct perf_counter *counter) 2876static int perf_counter_task_match(struct perf_counter *counter)
2855{ 2877{
2856 if (counter->attr.comm || counter->attr.mmap) 2878 if (counter->attr.comm || counter->attr.mmap || counter->attr.task)
2857 return 1; 2879 return 1;
2858 2880
2859 return 0; 2881 return 0;
2860} 2882}
2861 2883
2862static void perf_counter_fork_ctx(struct perf_counter_context *ctx, 2884static void perf_counter_task_ctx(struct perf_counter_context *ctx,
2863 struct perf_fork_event *fork_event) 2885 struct perf_task_event *task_event)
2864{ 2886{
2865 struct perf_counter *counter; 2887 struct perf_counter *counter;
2866 2888
@@ -2869,19 +2891,19 @@ static void perf_counter_fork_ctx(struct perf_counter_context *ctx,
2869 2891
2870 rcu_read_lock(); 2892 rcu_read_lock();
2871 list_for_each_entry_rcu(counter, &ctx->event_list, event_entry) { 2893 list_for_each_entry_rcu(counter, &ctx->event_list, event_entry) {
2872 if (perf_counter_fork_match(counter)) 2894 if (perf_counter_task_match(counter))
2873 perf_counter_fork_output(counter, fork_event); 2895 perf_counter_task_output(counter, task_event);
2874 } 2896 }
2875 rcu_read_unlock(); 2897 rcu_read_unlock();
2876} 2898}
2877 2899
2878static void perf_counter_fork_event(struct perf_fork_event *fork_event) 2900static void perf_counter_task_event(struct perf_task_event *task_event)
2879{ 2901{
2880 struct perf_cpu_context *cpuctx; 2902 struct perf_cpu_context *cpuctx;
2881 struct perf_counter_context *ctx; 2903 struct perf_counter_context *ctx;
2882 2904
2883 cpuctx = &get_cpu_var(perf_cpu_context); 2905 cpuctx = &get_cpu_var(perf_cpu_context);
2884 perf_counter_fork_ctx(&cpuctx->ctx, fork_event); 2906 perf_counter_task_ctx(&cpuctx->ctx, task_event);
2885 put_cpu_var(perf_cpu_context); 2907 put_cpu_var(perf_cpu_context);
2886 2908
2887 rcu_read_lock(); 2909 rcu_read_lock();
@@ -2891,32 +2913,40 @@ static void perf_counter_fork_event(struct perf_fork_event *fork_event)
2891 */ 2913 */
2892 ctx = rcu_dereference(current->perf_counter_ctxp); 2914 ctx = rcu_dereference(current->perf_counter_ctxp);
2893 if (ctx) 2915 if (ctx)
2894 perf_counter_fork_ctx(ctx, fork_event); 2916 perf_counter_task_ctx(ctx, task_event);
2895 rcu_read_unlock(); 2917 rcu_read_unlock();
2896} 2918}
2897 2919
2898void perf_counter_fork(struct task_struct *task) 2920static void perf_counter_task(struct task_struct *task, int new)
2899{ 2921{
2900 struct perf_fork_event fork_event; 2922 struct perf_task_event task_event;
2901 2923
2902 if (!atomic_read(&nr_comm_counters) && 2924 if (!atomic_read(&nr_comm_counters) &&
2903 !atomic_read(&nr_mmap_counters)) 2925 !atomic_read(&nr_mmap_counters) &&
2926 !atomic_read(&nr_task_counters))
2904 return; 2927 return;
2905 2928
2906 fork_event = (struct perf_fork_event){ 2929 task_event = (struct perf_task_event){
2907 .task = task, 2930 .task = task,
2908 .event = { 2931 .event = {
2909 .header = { 2932 .header = {
2910 .type = PERF_EVENT_FORK, 2933 .type = new ? PERF_EVENT_FORK : PERF_EVENT_EXIT,
2911 .misc = 0, 2934 .misc = 0,
2912 .size = sizeof(fork_event.event), 2935 .size = sizeof(task_event.event),
2913 }, 2936 },
2914 /* .pid */ 2937 /* .pid */
2915 /* .ppid */ 2938 /* .ppid */
2939 /* .tid */
2940 /* .ptid */
2916 }, 2941 },
2917 }; 2942 };
2918 2943
2919 perf_counter_fork_event(&fork_event); 2944 perf_counter_task_event(&task_event);
2945}
2946
2947void perf_counter_fork(struct task_struct *task)
2948{
2949 perf_counter_task(task, 1);
2920} 2950}
2921 2951
2922/* 2952/*
@@ -3875,6 +3905,8 @@ done:
3875 atomic_inc(&nr_mmap_counters); 3905 atomic_inc(&nr_mmap_counters);
3876 if (counter->attr.comm) 3906 if (counter->attr.comm)
3877 atomic_inc(&nr_comm_counters); 3907 atomic_inc(&nr_comm_counters);
3908 if (counter->attr.task)
3909 atomic_inc(&nr_task_counters);
3878 } 3910 }
3879 3911
3880 return counter; 3912 return counter;
@@ -4236,8 +4268,10 @@ void perf_counter_exit_task(struct task_struct *child)
4236 struct perf_counter_context *child_ctx; 4268 struct perf_counter_context *child_ctx;
4237 unsigned long flags; 4269 unsigned long flags;
4238 4270
4239 if (likely(!child->perf_counter_ctxp)) 4271 if (likely(!child->perf_counter_ctxp)) {
4272 perf_counter_task(child, 0);
4240 return; 4273 return;
4274 }
4241 4275
4242 local_irq_save(flags); 4276 local_irq_save(flags);
4243 /* 4277 /*
@@ -4255,15 +4289,22 @@ void perf_counter_exit_task(struct task_struct *child)
4255 * incremented the context's refcount before we do put_ctx below. 4289 * incremented the context's refcount before we do put_ctx below.
4256 */ 4290 */
4257 spin_lock(&child_ctx->lock); 4291 spin_lock(&child_ctx->lock);
4258 child->perf_counter_ctxp = NULL;
4259 /* 4292 /*
4260 * If this context is a clone; unclone it so it can't get 4293 * If this context is a clone; unclone it so it can't get
4261 * swapped to another process while we're removing all 4294 * swapped to another process while we're removing all
4262 * the counters from it. 4295 * the counters from it.
4263 */ 4296 */
4264 unclone_ctx(child_ctx); 4297 unclone_ctx(child_ctx);
4265 spin_unlock(&child_ctx->lock); 4298 spin_unlock_irqrestore(&child_ctx->lock, flags);
4266 local_irq_restore(flags); 4299
4300 /*
4301 * Report the task dead after unscheduling the counters so that we
4302 * won't get any samples after PERF_EVENT_EXIT. We can however still
4303 * get a few PERF_EVENT_READ events.
4304 */
4305 perf_counter_task(child, 0);
4306
4307 child->perf_counter_ctxp = NULL;
4267 4308
4268 /* 4309 /*
4269 * We can recurse on the same lock type through: 4310 * We can recurse on the same lock type through:
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index a5e9b876ca09..4b20fa47c3ab 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -345,7 +345,7 @@ BUILTIN_OBJS += builtin-stat.o
345BUILTIN_OBJS += builtin-top.o 345BUILTIN_OBJS += builtin-top.o
346 346
347PERFLIBS = $(LIB_FILE) 347PERFLIBS = $(LIB_FILE)
348EXTLIBS = -lbfd 348EXTLIBS = -lbfd -liberty
349 349
350# 350#
351# Platform specific tweaks 351# Platform specific tweaks
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index b20a4b6e31b7..ce4f28645e64 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -99,6 +99,7 @@ struct comm_event {
99struct fork_event { 99struct fork_event {
100 struct perf_event_header header; 100 struct perf_event_header header;
101 u32 pid, ppid; 101 u32 pid, ppid;
102 u32 tid, ptid;
102}; 103};
103 104
104struct lost_event { 105struct lost_event {
@@ -252,7 +253,7 @@ static int strcommon(const char *pathname)
252{ 253{
253 int n = 0; 254 int n = 0;
254 255
255 while (pathname[n] == cwd[n] && n < cwdlen) 256 while (n < cwdlen && pathname[n] == cwd[n])
256 ++n; 257 ++n;
257 258
258 return n; 259 return n;
@@ -1608,15 +1609,27 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head)
1608} 1609}
1609 1610
1610static int 1611static int
1611process_fork_event(event_t *event, unsigned long offset, unsigned long head) 1612process_task_event(event_t *event, unsigned long offset, unsigned long head)
1612{ 1613{
1613 struct thread *thread = threads__findnew(event->fork.pid); 1614 struct thread *thread = threads__findnew(event->fork.pid);
1614 struct thread *parent = threads__findnew(event->fork.ppid); 1615 struct thread *parent = threads__findnew(event->fork.ppid);
1615 1616
1616 dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n", 1617 dprintf("%p [%p]: PERF_EVENT_%s: (%d:%d):(%d:%d)\n",
1617 (void *)(offset + head), 1618 (void *)(offset + head),
1618 (void *)(long)(event->header.size), 1619 (void *)(long)(event->header.size),
1619 event->fork.pid, event->fork.ppid); 1620 event->header.type == PERF_EVENT_FORK ? "FORK" : "EXIT",
1621 event->fork.pid, event->fork.tid,
1622 event->fork.ppid, event->fork.ptid);
1623
1624 /*
1625 * A thread clone will have the same PID for both
1626 * parent and child.
1627 */
1628 if (thread == parent)
1629 return 0;
1630
1631 if (event->header.type == PERF_EVENT_EXIT)
1632 return 0;
1620 1633
1621 if (!thread || !parent || thread__fork(thread, parent)) { 1634 if (!thread || !parent || thread__fork(thread, parent)) {
1622 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n"); 1635 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n");
@@ -1706,7 +1719,8 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1706 return process_comm_event(event, offset, head); 1719 return process_comm_event(event, offset, head);
1707 1720
1708 case PERF_EVENT_FORK: 1721 case PERF_EVENT_FORK:
1709 return process_fork_event(event, offset, head); 1722 case PERF_EVENT_EXIT:
1723 return process_task_event(event, offset, head);
1710 1724
1711 case PERF_EVENT_LOST: 1725 case PERF_EVENT_LOST:
1712 return process_lost_event(event, offset, head); 1726 return process_lost_event(event, offset, head);
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index c0a423004e15..f139f1ab9333 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -285,6 +285,7 @@ static const char *skip_symbols[] = {
285 "enter_idle", 285 "enter_idle",
286 "exit_idle", 286 "exit_idle",
287 "mwait_idle", 287 "mwait_idle",
288 "mwait_idle_with_hints",
288 "ppc64_runlatch_off", 289 "ppc64_runlatch_off",
289 "pseries_dedicated_idle_sleep", 290 "pseries_dedicated_idle_sleep",
290 NULL 291 NULL
diff --git a/tools/perf/util/quote.c b/tools/perf/util/quote.c
index c6e5dc0dc82f..2726fe40eb5d 100644
--- a/tools/perf/util/quote.c
+++ b/tools/perf/util/quote.c
@@ -318,7 +318,7 @@ char *quote_path_relative(const char *in, int len,
318 strbuf_addch(out, '"'); 318 strbuf_addch(out, '"');
319 if (prefix) { 319 if (prefix) {
320 int off = 0; 320 int off = 0;
321 while (prefix[off] && off < len && prefix[off] == in[off]) 321 while (off < len && prefix[off] && prefix[off] == in[off])
322 if (prefix[off] == '/') { 322 if (prefix[off] == '/') {
323 prefix += off + 1; 323 prefix += off + 1;
324 in += off + 1; 324 in += off + 1;
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 28106059bf12..b4fe0579bd6b 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -565,7 +565,7 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
565 goto out_elf_end; 565 goto out_elf_end;
566 566
567 secstrs = elf_getdata(sec_strndx, NULL); 567 secstrs = elf_getdata(sec_strndx, NULL);
568 if (symstrs == NULL) 568 if (secstrs == NULL)
569 goto out_elf_end; 569 goto out_elf_end;
570 570
571 nr_syms = shdr.sh_size / shdr.sh_entsize; 571 nr_syms = shdr.sh_size / shdr.sh_entsize;