aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Zijlstra <a.p.zijlstra@chello.nl>2009-09-21 10:08:49 -0400
committerIngo Molnar <mingo@elte.hu>2009-10-06 08:21:50 -0400
commit906010b2134e14a2e377decbadd357b3d0ab9c6a (patch)
tree598b30d08f5ca8df1e00abc295b120fa1bd2c2e2
parente13dbd7d75d1ecc315c6e3071b3c4e8fba4f6bec (diff)
perf_event: Provide vmalloc() based mmap() backing
Some architectures such as Sparc, ARM and MIPS (basically everything with flush_dcache_page()) need to deal with dcache aliases by carefully placing pages in both kernel and user maps. These architectures typically have to use vmalloc_user() for this. However, on other architectures, vmalloc() is not needed and has the downsides of being more restricted and slower than regular allocations. Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Acked-by: David Miller <davem@davemloft.net> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Jens Axboe <jens.axboe@oracle.com> Cc: Paul Mackerras <paulus@samba.org> LKML-Reference: <1254830228.21044.272.camel@laptop> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--arch/sparc/Kconfig2
-rw-r--r--include/linux/perf_event.h5
-rw-r--r--init/Kconfig18
-rw-r--r--kernel/perf_event.c248
-rw-r--r--tools/perf/design.txt3
5 files changed, 214 insertions, 62 deletions
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 97fca4695e0b..9b70a2f28dc7 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -26,6 +26,7 @@ config SPARC
26 select RTC_CLASS 26 select RTC_CLASS
27 select RTC_DRV_M48T59 27 select RTC_DRV_M48T59
28 select HAVE_PERF_EVENTS 28 select HAVE_PERF_EVENTS
29 select PERF_USE_VMALLOC
29 select HAVE_DMA_ATTRS 30 select HAVE_DMA_ATTRS
30 select HAVE_DMA_API_DEBUG 31 select HAVE_DMA_API_DEBUG
31 32
@@ -48,6 +49,7 @@ config SPARC64
48 select RTC_DRV_SUN4V 49 select RTC_DRV_SUN4V
49 select RTC_DRV_STARFIRE 50 select RTC_DRV_STARFIRE
50 select HAVE_PERF_EVENTS 51 select HAVE_PERF_EVENTS
52 select PERF_USE_VMALLOC
51 53
52config ARCH_DEFCONFIG 54config ARCH_DEFCONFIG
53 string 55 string
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 3a9d36d1e92a..2e6d95f97419 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -442,6 +442,7 @@ enum perf_callchain_context {
442#include <linux/hrtimer.h> 442#include <linux/hrtimer.h>
443#include <linux/fs.h> 443#include <linux/fs.h>
444#include <linux/pid_namespace.h> 444#include <linux/pid_namespace.h>
445#include <linux/workqueue.h>
445#include <asm/atomic.h> 446#include <asm/atomic.h>
446 447
447#define PERF_MAX_STACK_DEPTH 255 448#define PERF_MAX_STACK_DEPTH 255
@@ -513,6 +514,10 @@ struct file;
513 514
514struct perf_mmap_data { 515struct perf_mmap_data {
515 struct rcu_head rcu_head; 516 struct rcu_head rcu_head;
517#ifdef CONFIG_PERF_USE_VMALLOC
518 struct work_struct work;
519#endif
520 int data_order;
516 int nr_pages; /* nr of data pages */ 521 int nr_pages; /* nr of data pages */
517 int writable; /* are we writable */ 522 int writable; /* are we writable */
518 int nr_locked; /* nr pages mlocked */ 523 int nr_locked; /* nr pages mlocked */
diff --git a/init/Kconfig b/init/Kconfig
index c7bac39d6c61..09c5c6431f42 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -921,6 +921,11 @@ config HAVE_PERF_EVENTS
921 help 921 help
922 See tools/perf/design.txt for details. 922 See tools/perf/design.txt for details.
923 923
924config PERF_USE_VMALLOC
925 bool
926 help
927 See tools/perf/design.txt for details
928
924menu "Kernel Performance Events And Counters" 929menu "Kernel Performance Events And Counters"
925 930
926config PERF_EVENTS 931config PERF_EVENTS
@@ -976,6 +981,19 @@ config PERF_COUNTERS
976 981
977 Say N if unsure. 982 Say N if unsure.
978 983
984config DEBUG_PERF_USE_VMALLOC
985 default n
986 bool "Debug: use vmalloc to back perf mmap() buffers"
987 depends on PERF_EVENTS && DEBUG_KERNEL
988 select PERF_USE_VMALLOC
989 help
990 Use vmalloc memory to back perf mmap() buffers.
991
992 Mostly useful for debugging the vmalloc code on platforms
993 that don't require it.
994
995 Say N if unsure.
996
979endmenu 997endmenu
980 998
981config VM_EVENT_COUNTERS 999config VM_EVENT_COUNTERS
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index e491fb087939..9d0b5c665883 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -20,6 +20,7 @@
20#include <linux/percpu.h> 20#include <linux/percpu.h>
21#include <linux/ptrace.h> 21#include <linux/ptrace.h>
22#include <linux/vmstat.h> 22#include <linux/vmstat.h>
23#include <linux/vmalloc.h>
23#include <linux/hardirq.h> 24#include <linux/hardirq.h>
24#include <linux/rculist.h> 25#include <linux/rculist.h>
25#include <linux/uaccess.h> 26#include <linux/uaccess.h>
@@ -2091,49 +2092,31 @@ unlock:
2091 rcu_read_unlock(); 2092 rcu_read_unlock();
2092} 2093}
2093 2094
2094static int perf_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) 2095static unsigned long perf_data_size(struct perf_mmap_data *data)
2095{ 2096{
2096 struct perf_event *event = vma->vm_file->private_data; 2097 return data->nr_pages << (PAGE_SHIFT + data->data_order);
2097 struct perf_mmap_data *data; 2098}
2098 int ret = VM_FAULT_SIGBUS;
2099
2100 if (vmf->flags & FAULT_FLAG_MKWRITE) {
2101 if (vmf->pgoff == 0)
2102 ret = 0;
2103 return ret;
2104 }
2105
2106 rcu_read_lock();
2107 data = rcu_dereference(event->data);
2108 if (!data)
2109 goto unlock;
2110
2111 if (vmf->pgoff == 0) {
2112 vmf->page = virt_to_page(data->user_page);
2113 } else {
2114 int nr = vmf->pgoff - 1;
2115
2116 if ((unsigned)nr > data->nr_pages)
2117 goto unlock;
2118 2099
2119 if (vmf->flags & FAULT_FLAG_WRITE) 2100#ifndef CONFIG_PERF_USE_VMALLOC
2120 goto unlock;
2121 2101
2122 vmf->page = virt_to_page(data->data_pages[nr]); 2102/*
2123 } 2103 * Back perf_mmap() with regular GFP_KERNEL-0 pages.
2104 */
2124 2105
2125 get_page(vmf->page); 2106static struct page *
2126 vmf->page->mapping = vma->vm_file->f_mapping; 2107perf_mmap_to_page(struct perf_mmap_data *data, unsigned long pgoff)
2127 vmf->page->index = vmf->pgoff; 2108{
2109 if (pgoff > data->nr_pages)
2110 return NULL;
2128 2111
2129 ret = 0; 2112 if (pgoff == 0)
2130unlock: 2113 return virt_to_page(data->user_page);
2131 rcu_read_unlock();
2132 2114
2133 return ret; 2115 return virt_to_page(data->data_pages[pgoff - 1]);
2134} 2116}
2135 2117
2136static int perf_mmap_data_alloc(struct perf_event *event, int nr_pages) 2118static struct perf_mmap_data *
2119perf_mmap_data_alloc(struct perf_event *event, int nr_pages)
2137{ 2120{
2138 struct perf_mmap_data *data; 2121 struct perf_mmap_data *data;
2139 unsigned long size; 2122 unsigned long size;
@@ -2158,19 +2141,10 @@ static int perf_mmap_data_alloc(struct perf_event *event, int nr_pages)
2158 goto fail_data_pages; 2141 goto fail_data_pages;
2159 } 2142 }
2160 2143
2144 data->data_order = 0;
2161 data->nr_pages = nr_pages; 2145 data->nr_pages = nr_pages;
2162 atomic_set(&data->lock, -1);
2163
2164 if (event->attr.watermark) {
2165 data->watermark = min_t(long, PAGE_SIZE * nr_pages,
2166 event->attr.wakeup_watermark);
2167 }
2168 if (!data->watermark)
2169 data->watermark = max(PAGE_SIZE, PAGE_SIZE * nr_pages / 4);
2170 2146
2171 rcu_assign_pointer(event->data, data); 2147 return data;
2172
2173 return 0;
2174 2148
2175fail_data_pages: 2149fail_data_pages:
2176 for (i--; i >= 0; i--) 2150 for (i--; i >= 0; i--)
@@ -2182,7 +2156,7 @@ fail_user_page:
2182 kfree(data); 2156 kfree(data);