Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 147305
b: refs/heads/master
c: 0a4a939
h: refs/heads/master
i:
  147303: c4566f7
v: v3
  • Loading branch information
Peter Zijlstra authored and Ingo Molnar committed Apr 6, 2009
1 parent cbb62f0 commit b8c3774
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 3 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 195564390210977954fe4ef45b39cdee34f41b59
refs/heads/master: 0a4a93919bdc5cee48fe4367591e8e0449c1086c
24 changes: 22 additions & 2 deletions trunk/include/linux/perf_counter.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,11 @@ struct perf_counter_hw_event {
exclude_kernel : 1, /* ditto kernel */
exclude_hv : 1, /* ditto hypervisor */
exclude_idle : 1, /* don't count when idle */
include_tid : 1, /* include the tid */
include_tid : 1, /* include the tid */
mmap : 1, /* include mmap data */
munmap : 1, /* include munmap data */

__reserved_1 : 54;
__reserved_1 : 52;

__u32 extra_config_len;
__u32 __reserved_4;
Expand Down Expand Up @@ -211,6 +213,9 @@ enum perf_event_type {
PERF_EVENT_IP = 0,
PERF_EVENT_GROUP = 1,

PERF_EVENT_MMAP = 2,
PERF_EVENT_MUNMAP = 3,

__PERF_EVENT_TID = 0x100,
};

Expand Down Expand Up @@ -491,6 +496,12 @@ static inline int is_software_counter(struct perf_counter *counter)

extern void perf_swcounter_event(u32, u64, int, struct pt_regs *);

extern void perf_counter_mmap(unsigned long addr, unsigned long len,
unsigned long pgoff, struct file *file);

extern void perf_counter_munmap(unsigned long addr, unsigned long len,
unsigned long pgoff, struct file *file);

#else
static inline void
perf_counter_task_sched_in(struct task_struct *task, int cpu) { }
Expand All @@ -511,6 +522,15 @@ static inline int perf_counter_task_enable(void) { return -EINVAL; }
static inline void
perf_swcounter_event(u32 event, u64 nr, int nmi, struct pt_regs *regs) { }


static inline void
perf_counter_mmap(unsigned long addr, unsigned long len,
unsigned long pgoff, struct file *file) { }

static inline void
perf_counter_munmap(unsigned long addr, unsigned long len,
unsigned long pgoff, struct file *file) { }

#endif

#endif /* __KERNEL__ */
Expand Down
145 changes: 145 additions & 0 deletions trunk/kernel/perf_counter.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <linux/anon_inodes.h>
#include <linux/kernel_stat.h>
#include <linux/perf_counter.h>
#include <linux/dcache.h>

#include <asm/irq_regs.h>

Expand Down Expand Up @@ -1843,6 +1844,150 @@ void perf_counter_output(struct perf_counter *counter,
}
}

/*
* mmap tracking
*/

struct perf_mmap_event {
struct file *file;
char *file_name;
int file_size;

struct {
struct perf_event_header header;

u32 pid;
u32 tid;
u64 start;
u64 len;
u64 pgoff;
} event;
};

static void perf_counter_mmap_output(struct perf_counter *counter,
struct perf_mmap_event *mmap_event)
{
struct perf_output_handle handle;
int size = mmap_event->event.header.size;
int ret = perf_output_begin(&handle, counter, size);

if (ret)
return;

perf_output_put(&handle, mmap_event->event);
perf_output_copy(&handle, mmap_event->file_name,
mmap_event->file_size);
perf_output_end(&handle, 0);
}

static int perf_counter_mmap_match(struct perf_counter *counter,
struct perf_mmap_event *mmap_event)
{
if (counter->hw_event.mmap &&
mmap_event->event.header.type == PERF_EVENT_MMAP)
return 1;

if (counter->hw_event.munmap &&
mmap_event->event.header.type == PERF_EVENT_MUNMAP)
return 1;

return 0;
}

static void perf_counter_mmap_ctx(struct perf_counter_context *ctx,
struct perf_mmap_event *mmap_event)
{
struct perf_counter *counter;

if (system_state != SYSTEM_RUNNING || list_empty(&ctx->event_list))
return;

rcu_read_lock();
list_for_each_entry_rcu(counter, &ctx->event_list, event_entry) {
if (perf_counter_mmap_match(counter, mmap_event))
perf_counter_mmap_output(counter, mmap_event);
}
rcu_read_unlock();
}

static void perf_counter_mmap_event(struct perf_mmap_event *mmap_event)
{
struct perf_cpu_context *cpuctx;
struct file *file = mmap_event->file;
unsigned int size;
char tmp[16];
char *buf = NULL;
char *name;

if (file) {
buf = kzalloc(PATH_MAX, GFP_KERNEL);
if (!buf) {
name = strncpy(tmp, "//enomem", sizeof(tmp));
goto got_name;
}
name = dentry_path(file->f_dentry, buf, PATH_MAX);
if (IS_ERR(name)) {
name = strncpy(tmp, "//toolong", sizeof(tmp));
goto got_name;
}
} else {
name = strncpy(tmp, "//anon", sizeof(tmp));
goto got_name;
}

got_name:
size = ALIGN(strlen(name), sizeof(u64));

mmap_event->file_name = name;
mmap_event->file_size = size;

mmap_event->event.header.size = sizeof(mmap_event->event) + size;

cpuctx = &get_cpu_var(perf_cpu_context);
perf_counter_mmap_ctx(&cpuctx->ctx, mmap_event);
put_cpu_var(perf_cpu_context);

perf_counter_mmap_ctx(&current->perf_counter_ctx, mmap_event);

kfree(buf);
}

void perf_counter_mmap(unsigned long addr, unsigned long len,
unsigned long pgoff, struct file *file)
{
struct perf_mmap_event mmap_event = {
.file = file,
.event = {
.header = { .type = PERF_EVENT_MMAP, },
.pid = current->group_leader->pid,
.tid = current->pid,
.start = addr,
.len = len,
.pgoff = pgoff,
},
};

perf_counter_mmap_event(&mmap_event);
}

void perf_counter_munmap(unsigned long addr, unsigned long len,
unsigned long pgoff, struct file *file)
{
struct perf_mmap_event mmap_event = {
.file = file,
.event = {
.header = { .type = PERF_EVENT_MUNMAP, },
.pid = current->group_leader->pid,
.tid = current->pid,
.start = addr,
.len = len,
.pgoff = pgoff,
},
};

perf_counter_mmap_event(&mmap_event);
}

/*
* Generic software counter infrastructure
*/
Expand Down
10 changes: 10 additions & 0 deletions trunk/mm/mmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <linux/mempolicy.h>
#include <linux/rmap.h>
#include <linux/mmu_notifier.h>
#include <linux/perf_counter.h>

#include <asm/uaccess.h>
#include <asm/cacheflush.h>
Expand Down Expand Up @@ -1223,6 +1224,9 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
if (correct_wcount)
atomic_inc(&inode->i_writecount);
out:
if (vm_flags & VM_EXEC)
perf_counter_mmap(addr, len, pgoff, file);

mm->total_vm += len >> PAGE_SHIFT;
vm_stat_account(mm, vm_flags, file, len >> PAGE_SHIFT);
if (vm_flags & VM_LOCKED) {
Expand Down Expand Up @@ -1756,6 +1760,12 @@ static void remove_vma_list(struct mm_struct *mm, struct vm_area_struct *vma)
do {
long nrpages = vma_pages(vma);

if (vma->vm_flags & VM_EXEC) {
perf_counter_munmap(vma->vm_start,
nrpages << PAGE_SHIFT,
vma->vm_pgoff, vma->vm_file);
}

mm->total_vm -= nrpages;
vm_stat_account(mm, vma->vm_flags, vma->vm_file, -nrpages);
vma = remove_vma(vma);
Expand Down

0 comments on commit b8c3774

Please sign in to comment.