This patch adds a new software event for munmaps. It will allows users to profile changes to address space. munmaps will be tracked with mmaps. Signed-off-by: Eric B Munson <ebmunson@xxxxxxxxxx> Signed-off-by: Anton Blanchard <anton@xxxxxxxxx> --- include/linux/perf_event.h | 6 ++++- kernel/perf_event.c | 49 +++++++++++++++++++++++++++++++++++++++--- mm/mmap.c | 2 + tools/perf/builtin-record.c | 1 + 4 files changed, 53 insertions(+), 5 deletions(-) diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 716f99b..937dd93 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -215,8 +215,9 @@ struct perf_event_attr { */ precise_ip : 2, /* skid constraint */ mmap_data : 1, /* non-exec mmap data */ + munmap : 1, /* include munmap events */ - __reserved_1 : 46; + __reserved_1 : 45; union { __u32 wakeup_events; /* wakeup every n events */ @@ -341,6 +342,7 @@ enum perf_event_type { * }; */ PERF_RECORD_MMAP = 1, + PERF_RECORD_MUNMAP = 10, /* * struct { @@ -969,6 +971,8 @@ perf_sw_event(u32 event_id, u64 nr, int nmi, struct pt_regs *regs, u64 addr) } extern void perf_event_mmap(struct vm_area_struct *vma); +extern void perf_event_munmap(struct vm_area_struct *vma, unsigned long start, + size_t len); extern struct perf_guest_info_callbacks *perf_guest_cbs; extern int perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *callbacks); extern int perf_unregister_guest_info_callbacks(struct perf_guest_info_callbacks *callbacks); diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 403d180..2d24e4e 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -46,6 +46,7 @@ static int perf_overcommit __read_mostly = 1; static atomic_t nr_events __read_mostly; static atomic_t nr_mmap_events __read_mostly; +static atomic_t nr_munmap_events __read_mostly; static atomic_t nr_comm_events __read_mostly; static atomic_t nr_task_events __read_mostly; @@ -1891,6 +1892,8 @@ static void free_event(struct perf_event *event) atomic_dec(&nr_events); if (event->attr.mmap || event->attr.mmap_data) atomic_dec(&nr_mmap_events); + if (event->attr.munmap) + atomic_dec(&nr_munmap_events); if (event->attr.comm) atomic_dec(&nr_comm_events); if (event->attr.task) @@ -3491,7 +3494,8 @@ perf_event_read_event(struct perf_event *event, /* * task tracking -- fork/exit * - * enabled by: attr.comm | attr.mmap | attr.mmap_data | attr.task + * enabled by: attr.comm | attr.mmap | attr.mmap_data | attr.munmap | + * attr.task */ struct perf_task_event { @@ -3542,7 +3546,7 @@ static int perf_event_task_match(struct perf_event *event) return 0; if (event->attr.comm || event->attr.mmap || - event->attr.mmap_data || event->attr.task) + event->attr.mmap_data || event->attr.munmap || event->attr.task) return 1; return 0; @@ -3583,6 +3587,7 @@ static void perf_event_task(struct task_struct *task, if (!atomic_read(&nr_comm_events) && !atomic_read(&nr_mmap_events) && + !atomic_read(&nr_munmap_events) && !atomic_read(&nr_task_events)) return; @@ -3776,9 +3781,14 @@ static int perf_event_mmap_match(struct perf_event *event, if (event->cpu != -1 && event->cpu != smp_processor_id()) return 0; - if ((!executable && event->attr.mmap_data) || - (executable && event->attr.mmap)) + if (mmap_event->event_id.header.type == PERF_RECORD_MMAP) { + if ((!executable && event->attr.mmap_data) || + (executable && event->attr.mmap)) + return 1; + } else if ((mmap_event->event_id.header.type == PERF_RECORD_MUNMAP) && + event->attr.munmap) { return 1; + } return 0; } @@ -3896,6 +3906,35 @@ void perf_event_mmap(struct vm_area_struct *vma) perf_event_mmap_event(&mmap_event); } +void perf_event_munmap(struct vm_area_struct *vma, unsigned long start, + size_t len) +{ + struct perf_mmap_event mmap_event; + + if (!atomic_read(&nr_munmap_events)) + return; + + mmap_event = (struct perf_mmap_event){ + .vma = vma, + /* .file_name */ + /* .file_size */ + .event_id = { + .header = { + .type = PERF_RECORD_MUNMAP, + .misc = 0, + /* .size */ + }, + /* .pid */ + /* .tid */ + .start = start, + .len = len, + .pgoff = 0, + }, + }; + + perf_event_mmap_event(&mmap_event); +} + /* * IRQ throttle logging */ @@ -4925,6 +4964,8 @@ done: atomic_inc(&nr_events); if (event->attr.mmap || event->attr.mmap_data) atomic_inc(&nr_mmap_events); + if (event->attr.munmap) + atomic_inc(&nr_munmap_events); if (event->attr.comm) atomic_inc(&nr_comm_events); if (event->attr.task) diff --git a/mm/mmap.c b/mm/mmap.c index e38e910..cb03746 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -2082,6 +2082,8 @@ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len) } } + perf_event_munmap(vma, start, end - start); + /* * Remove the vma's, and unmap the actual pages */ diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index b938796..b2018be 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -287,6 +287,7 @@ static void create_counter(int counter, int cpu) } attr->mmap = track; + attr->munmap = track; attr->comm = track; attr->inherit = !no_inherit; if (target_pid == -1 && target_tid == -1 && !system_wide) { -- 1.7.0.4 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@xxxxxxxxxx For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@xxxxxxxxx"> email@xxxxxxxxx </a>