aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephane Eranian <eranian@google.com>2013-08-21 06:10:24 -0400
committerIngo Molnar <mingo@kernel.org>2013-09-02 02:42:48 -0400
commit13d7a2410fa637f450a29ecb515ac318ee40c741 (patch)
tree04479b0a2b3a96ebeda6a414dfb8a32dc0d5467d
parent1fa64180fbf7a33b7a30636a2f174a5cad68d48f (diff)
perf: Add attr->mmap2 attribute to an event
Adds a new PERF_RECORD_MMAP2 record type which is essence an expanded version of PERF_RECORD_MMAP. Used to request mmap records with more information about the mapping, including device major, minor and the inode number and generation for mappings associated with files or shared memory segments. Works for code and data (with attr->mmap_data set). Existing PERF_RECORD_MMAP record is unmodified by this patch. Signed-off-by: Stephane Eranian <eranian@google.com> Signed-off-by: Peter Zijlstra <peterz@infradead.org> Cc: Al Viro <viro@zeniv.linux.org.uk> Link: http://lkml.kernel.org/r/1377079825-19057-2-git-send-email-eranian@google.com [ Added Al to the Cc:. Are the ino, maj/min exports of vma->vm_file OK? ] Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--include/uapi/linux/perf_event.h24
-rw-r--r--kernel/events/core.c46
2 files changed, 65 insertions, 5 deletions
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index 42cb7b62ca59..a77f43af72b8 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -276,8 +276,9 @@ struct perf_event_attr {
276 276
277 exclude_callchain_kernel : 1, /* exclude kernel callchains */ 277 exclude_callchain_kernel : 1, /* exclude kernel callchains */
278 exclude_callchain_user : 1, /* exclude user callchains */ 278 exclude_callchain_user : 1, /* exclude user callchains */
279 mmap2 : 1, /* include mmap with inode data */
279 280
280 __reserved_1 : 41; 281 __reserved_1 : 40;
281 282
282 union { 283 union {
283 __u32 wakeup_events; /* wakeup every n events */ 284 __u32 wakeup_events; /* wakeup every n events */
@@ -651,6 +652,27 @@ enum perf_event_type {
651 */ 652 */
652 PERF_RECORD_SAMPLE = 9, 653 PERF_RECORD_SAMPLE = 9,
653 654
655 /*
656 * The MMAP2 records are an augmented version of MMAP, they add
657 * maj, min, ino numbers to be used to uniquely identify each mapping
658 *
659 * struct {
660 * struct perf_event_header header;
661 *
662 * u32 pid, tid;
663 * u64 addr;
664 * u64 len;
665 * u64 pgoff;
666 * u32 maj;
667 * u32 min;
668 * u64 ino;
669 * u64 ino_generation;
670 * char filename[];
671 * struct sample_id sample_id;
672 * };
673 */
674 PERF_RECORD_MMAP2 = 10,
675
654 PERF_RECORD_MAX, /* non-ABI */ 676 PERF_RECORD_MAX, /* non-ABI */
655}; 677};
656 678
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 15d0f2418e54..c7ee497c39a7 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -4776,7 +4776,7 @@ next:
4776/* 4776/*
4777 * task tracking -- fork/exit 4777 * task tracking -- fork/exit
4778 * 4778 *
4779 * enabled by: attr.comm | attr.mmap | attr.mmap_data | attr.task 4779 * enabled by: attr.comm | attr.mmap | attr.mmap2 | attr.mmap_data | attr.task
4780 */ 4780 */
4781 4781
4782struct perf_task_event { 4782struct perf_task_event {
@@ -4796,8 +4796,9 @@ struct perf_task_event {
4796 4796
4797static int perf_event_task_match(struct perf_event *event) 4797static int perf_event_task_match(struct perf_event *event)
4798{ 4798{
4799 return event->attr.comm || event->attr.mmap || 4799 return event->attr.comm || event->attr.mmap ||
4800 event->attr.mmap_data || event->attr.task; 4800 event->attr.mmap2 || event->attr.mmap_data ||
4801 event->attr.task;
4801} 4802}
4802 4803
4803static void perf_event_task_output(struct perf_event *event, 4804static void perf_event_task_output(struct perf_event *event,
@@ -4992,6 +4993,9 @@ struct perf_mmap_event {
4992 4993
4993 const char *file_name; 4994 const char *file_name;
4994 int file_size; 4995 int file_size;
4996 int maj, min;
4997 u64 ino;
4998 u64 ino_generation;
4995 4999
4996 struct { 5000 struct {
4997 struct perf_event_header header; 5001 struct perf_event_header header;
@@ -5012,7 +5016,7 @@ static int perf_event_mmap_match(struct perf_event *event,
5012 int executable = vma->vm_flags & VM_EXEC; 5016 int executable = vma->vm_flags & VM_EXEC;
5013 5017
5014 return (!executable && event->attr.mmap_data) || 5018 return (!executable && event->attr.mmap_data) ||
5015 (executable && event->attr.mmap); 5019 (executable && (event->attr.mmap || event->attr.mmap2));
5016} 5020}
5017 5021
5018static void perf_event_mmap_output(struct perf_event *event, 5022static void perf_event_mmap_output(struct perf_event *event,
@@ -5027,6 +5031,13 @@ static void perf_event_mmap_output(struct perf_event *event,
5027 if (!perf_event_mmap_match(event, data)) 5031 if (!perf_event_mmap_match(event, data))
5028 return; 5032 return;
5029 5033
5034 if (event->attr.mmap2) {
5035 mmap_event->event_id.header.type = PERF_RECORD_MMAP2;
5036 mmap_event->event_id.header.size += sizeof(mmap_event->maj);
5037 mmap_event->event_id.header.size += sizeof(mmap_event->min);
5038 mmap_event->event_id.header.size += sizeof(mmap_event->ino);
5039 }
5040
5030 perf_event_header__init_id(&mmap_event->event_id.header, &sample, event); 5041 perf_event_header__init_id(&mmap_event->event_id.header, &sample, event);
5031 ret = perf_output_begin(&handle, event, 5042 ret = perf_output_begin(&handle, event,
5032 mmap_event->event_id.header.size); 5043 mmap_event->event_id.header.size);
@@ -5037,6 +5048,14 @@ static void perf_event_mmap_output(struct perf_event *event,
5037 mmap_event->event_id.tid = perf_event_tid(event, current); 5048 mmap_event->event_id.tid = perf_event_tid(event, current);
5038 5049
5039 perf_output_put(&handle, mmap_event->event_id); 5050 perf_output_put(&handle, mmap_event->event_id);
5051
5052 if (event->attr.mmap2) {
5053 perf_output_put(&handle, mmap_event->maj);
5054 perf_output_put(&handle, mmap_event->min);
5055 perf_output_put(&handle, mmap_event->ino);
5056 perf_output_put(&handle, mmap_event->ino_generation);
5057 }
5058
5040 __output_copy(&handle, mmap_event->file_name, 5059 __output_copy(&handle, mmap_event->file_name,
5041 mmap_event->file_size); 5060 mmap_event->file_size);
5042 5061
@@ -5051,6 +5070,8 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
5051{ 5070{
5052 struct vm_area_struct *vma = mmap_event->vma; 5071 struct vm_area_struct *vma = mmap_event->vma;
5053 struct file *file = vma->vm_file; 5072 struct file *file = vma->vm_file;
5073 int maj = 0, min = 0;
5074 u64 ino = 0, gen = 0;
5054 unsigned int size; 5075 unsigned int size;
5055 char tmp[16]; 5076 char tmp[16];
5056 char *buf = NULL; 5077 char *buf = NULL;
@@ -5059,6 +5080,8 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
5059 memset(tmp, 0, sizeof(tmp)); 5080 memset(tmp, 0, sizeof(tmp));
5060 5081
5061 if (file) { 5082 if (file) {
5083 struct inode *inode;
5084 dev_t dev;
5062 /* 5085 /*
5063 * d_path works from the end of the rb backwards, so we 5086 * d_path works from the end of the rb backwards, so we
5064 * need to add enough zero bytes after the string to handle 5087 * need to add enough zero bytes after the string to handle
@@ -5074,6 +5097,13 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
5074 name = strncpy(tmp, "//toolong", sizeof(tmp)); 5097 name = strncpy(tmp, "//toolong", sizeof(tmp));
5075 goto got_name; 5098 goto got_name;
5076 } 5099 }
5100 inode = file_inode(vma->vm_file);
5101 dev = inode->i_sb->s_dev;
5102 ino = inode->i_ino;
5103 gen = inode->i_generation;
5104 maj = MAJOR(dev);
5105 min = MINOR(dev);
5106
5077 } else { 5107 } else {
5078 if (arch_vma_name(mmap_event->vma)) { 5108 if (arch_vma_name(mmap_event->vma)) {
5079 name = strncpy(tmp, arch_vma_name(mmap_event->vma), 5109 name = strncpy(tmp, arch_vma_name(mmap_event->vma),
@@ -5104,6 +5134,10 @@ got_name:
5104 5134
5105 mmap_event->file_name = name; 5135 mmap_event->file_name = name;
5106 mmap_event->file_size = size; 5136 mmap_event->file_size = size;
5137 mmap_event->maj = maj;
5138 mmap_event->min = min;
5139 mmap_event->ino = ino;
5140 mmap_event->ino_generation = gen;
5107 5141
5108 if (!(vma->vm_flags & VM_EXEC)) 5142 if (!(vma->vm_flags & VM_EXEC))
5109 mmap_event->event_id.header.misc |= PERF_RECORD_MISC_MMAP_DATA; 5143 mmap_event->event_id.header.misc |= PERF_RECORD_MISC_MMAP_DATA;
@@ -5140,6 +5174,10 @@ void perf_event_mmap(struct vm_area_struct *vma)
5140 .len = vma->vm_end - vma->vm_start, 5174 .len = vma->vm_end - vma->vm_start,
5141 .pgoff = (u64)vma->vm_pgoff << PAGE_SHIFT, 5175 .pgoff = (u64)vma->vm_pgoff << PAGE_SHIFT,
5142 }, 5176 },
5177 /* .maj (attr_mmap2 only) */
5178 /* .min (attr_mmap2 only) */
5179 /* .ino (attr_mmap2 only) */
5180 /* .ino_generation (attr_mmap2 only) */
5143 }; 5181 };
5144 5182
5145 perf_event_mmap_event(&mmap_event); 5183 perf_event_mmap_event(&mmap_event);