mirror of
https://github.com/varun-r-mallya/sysprof.git
synced 2026-02-11 23:51:06 +00:00
Port to 2.6 - remove non-working disk crap
This commit is contained in:
33
Makefile
33
Makefile
@ -1,12 +1,20 @@
|
|||||||
CFLAGS = `pkg-config --cflags gtk+-2.0 libglade-2.0` -Wall -g
|
ifneq ($(KERNELRELEASE),)
|
||||||
LIBS = `pkg-config --libs gtk+-2.0 libglade-2.0` -lbfd -liberty
|
|
||||||
C_FILES = sysprof.c binfile.c stackstash.c watch.c process.c profile.c treeviewutils.c
|
obj-m := sysprof-module.o
|
||||||
OBJS = $(addsuffix .o, $(basename $(C_FILES)))
|
CFLAGS += $(MODCFLAGS) -DKERNEL26
|
||||||
BINARY = sysprof
|
|
||||||
|
else
|
||||||
|
|
||||||
|
CFLAGS := $(shell pkg-config --cflags gtk+-2.0 libglade-2.0) -Wall -g
|
||||||
|
LIBS := $(shell pkg-config --libs gtk+-2.0 libglade-2.0) -lbfd -liberty
|
||||||
|
C_FILES := sysprof.c binfile.c stackstash.c watch.c process.c profile.c treeviewutils.c
|
||||||
|
OBJS := $(addsuffix .o, $(basename $(C_FILES)))
|
||||||
|
BINARY := sysprof
|
||||||
MODULE := sysprof-module
|
MODULE := sysprof-module
|
||||||
INCLUDE := -isystem /lib/modules/`uname -r`/build/include
|
INCLUDE := -isystem /lib/modules/`uname -r`/build/include
|
||||||
MODCFLAGS := -O2 -DMODULE -D__KERNEL__ -Wall ${INCLUDE}
|
MODCFLAGS := -O2 -DMODULE -D__KERNEL__ -Wall ${INCLUDE}
|
||||||
|
KDIR := /lib/modules/$(shell uname -r)/build
|
||||||
|
MODULE := sysprof-module
|
||||||
|
|
||||||
all: $(BINARY) $(MODULE).o
|
all: $(BINARY) $(MODULE).o
|
||||||
|
|
||||||
@ -26,7 +34,20 @@ include depend.mk
|
|||||||
|
|
||||||
.PHONY: depend all
|
.PHONY: depend all
|
||||||
|
|
||||||
|
ifeq ($(shell (uname -r | grep 2.6) > /dev/null ; echo -n $$?),0)
|
||||||
|
|
||||||
|
# if kernel 2.6
|
||||||
|
$(MODULE).o: $(MODULE).c
|
||||||
|
echo birnan $(MODCFLAGS)
|
||||||
|
|
||||||
|
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
|
||||||
|
else
|
||||||
|
|
||||||
|
MODCFLAGS += KERNEL24
|
||||||
|
|
||||||
$(MODULE).o: $(MODULE).c
|
$(MODULE).o: $(MODULE).c
|
||||||
gcc $(MODCFLAGS) $(MODULE).c -c -o$(MODULE).o
|
gcc $(MODCFLAGS) $(MODULE).c -c -o$(MODULE).o
|
||||||
|
|
||||||
|
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|||||||
5
README
5
README
@ -6,9 +6,8 @@ program "sysprof".
|
|||||||
|
|
||||||
- There is no auto* stuff. Just type "make" and hope for the best.
|
- There is no auto* stuff. Just type "make" and hope for the best.
|
||||||
|
|
||||||
- It does not work on Linux 2.6. Feel free to port it and send me the
|
|
||||||
patch.
|
|
||||||
|
|
||||||
- You need gtk+ 2.4.0 or better, and you need libglade
|
- You need gtk+ 2.4.0 or better, and you need libglade
|
||||||
|
|
||||||
|
- Thanks to Kristian H<>gsberg, it now works on the 2.6 kernel.
|
||||||
|
|
||||||
S<EFBFBD>ren
|
S<EFBFBD>ren
|
||||||
565
sysprof-module.c
565
sysprof-module.c
@ -1,3 +1,5 @@
|
|||||||
|
/* -*- c-basic-offset: 8 -*- */
|
||||||
|
|
||||||
#include <linux/config.h>
|
#include <linux/config.h>
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
# define __SMP__
|
# define __SMP__
|
||||||
@ -5,451 +7,238 @@
|
|||||||
#include <asm/atomic.h>
|
#include <asm/atomic.h>
|
||||||
#include <linux/kernel.h> /* Needed for KERN_ALERT */
|
#include <linux/kernel.h> /* Needed for KERN_ALERT */
|
||||||
#include <linux/module.h> /* Needed by all modules */
|
#include <linux/module.h> /* Needed by all modules */
|
||||||
#include <linux/tqueue.h>
|
#ifdef KERNEL24
|
||||||
|
# include <linux/tqueue.h>
|
||||||
|
#endif
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/proc_fs.h>
|
#include <linux/proc_fs.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <linux/poll.h>
|
#include <linux/poll.h>
|
||||||
#include <asm/unistd.h>
|
|
||||||
#include <linux/pagemap.h>
|
|
||||||
|
|
||||||
#include "sysprof-module.h"
|
#include "sysprof-module.h"
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_AUTHOR("Soeren Sandmann (sandmann@daimi.au.dk)");
|
MODULE_AUTHOR("Soeren Sandmann (sandmann@daimi.au.dk)");
|
||||||
|
|
||||||
#define SAMPLES_PER_SECOND 50 /* must divide HZ */
|
#define SAMPLES_PER_SECOND (50)
|
||||||
|
#define INTERVAL (HZ / SAMPLES_PER_SECOND)
|
||||||
static const int cpu_profiler = 1; /* 0: page faults, 1: cpu */
|
|
||||||
|
|
||||||
static void on_timer_interrupt (void *);
|
|
||||||
|
|
||||||
static struct tq_struct timer_task =
|
|
||||||
{
|
|
||||||
{ NULL, NULL },
|
|
||||||
0,
|
|
||||||
on_timer_interrupt,
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
int exiting = 0;
|
|
||||||
DECLARE_WAIT_QUEUE_HEAD (wait_for_exit);
|
|
||||||
|
|
||||||
#define N_TRACES 256
|
#define N_TRACES 256
|
||||||
|
|
||||||
static SysprofStackTrace stack_traces[N_TRACES];
|
static SysprofStackTrace stack_traces[N_TRACES];
|
||||||
static SysprofStackTrace * head = &stack_traces[0];
|
static SysprofStackTrace * head = &stack_traces[0];
|
||||||
static SysprofStackTrace * tail = &stack_traces[0];
|
static SysprofStackTrace * tail = &stack_traces[0];
|
||||||
DECLARE_WAIT_QUEUE_HEAD (wait_for_trace);
|
DECLARE_WAIT_QUEUE_HEAD (wait_for_trace);
|
||||||
|
DECLARE_WAIT_QUEUE_HEAD (wait_for_exit);
|
||||||
|
|
||||||
|
typedef void (* TimeoutFunc)(unsigned long data);
|
||||||
|
static void on_timer(unsigned long);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wrappers to cover up kernel differences in timer handling
|
||||||
|
*/
|
||||||
|
#ifdef KERNEL24
|
||||||
|
static struct tq_struct timer_task =
|
||||||
|
{
|
||||||
|
{ NULL, NULL },
|
||||||
|
0,
|
||||||
|
on_timer,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static struct timer_list timer;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
generate_stack_trace (struct task_struct *task,
|
init_timeout (void)
|
||||||
SysprofStackTrace *trace)
|
{
|
||||||
|
#ifdef KERNEL24
|
||||||
|
/* no setup needed */
|
||||||
|
#else
|
||||||
|
init_timer(&timer);
|
||||||
|
timer.function = on_timer;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
remove_timeout(void)
|
||||||
|
{
|
||||||
|
#ifdef KERNEL24
|
||||||
|
exiting = 1;
|
||||||
|
sleep_on (&wait_for_exit);
|
||||||
|
#else
|
||||||
|
del_timer (&timer);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_timeout(unsigned int interval,
|
||||||
|
TimeoutFunc f)
|
||||||
|
{
|
||||||
|
#ifdef KERNEL24
|
||||||
|
queue_task(&timer_task, &tq_timer);
|
||||||
|
#else
|
||||||
|
mod_timer(&timer, jiffies + INTERVAL);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The portable part of the driver starts here
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
generate_stack_trace(struct pt_regs *regs,
|
||||||
|
SysprofStackTrace *trace)
|
||||||
{
|
{
|
||||||
#define START_OF_STACK 0xBFFFFFFF
|
#define START_OF_STACK 0xBFFFFFFF
|
||||||
|
|
||||||
typedef struct StackFrame StackFrame;
|
typedef struct StackFrame StackFrame;
|
||||||
struct StackFrame {
|
struct StackFrame {
|
||||||
StackFrame *next;
|
StackFrame *next;
|
||||||
void *return_address;
|
void *return_address;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pt_regs *regs = (struct pt_regs *)(
|
StackFrame *frame;
|
||||||
(long)current + THREAD_SIZE - sizeof (struct pt_regs));
|
int i;
|
||||||
|
|
||||||
StackFrame *frame;
|
memset(trace, 0, sizeof (SysprofStackTrace));
|
||||||
int i;
|
|
||||||
|
|
||||||
memset (trace, 0, sizeof (SysprofStackTrace));
|
trace->pid = current->pid;
|
||||||
|
|
||||||
trace->pid = current->pid;
|
|
||||||
trace->truncated = 0;
|
|
||||||
|
|
||||||
trace->addresses[0] = (void *)regs->eip;
|
|
||||||
i = 1;
|
|
||||||
|
|
||||||
frame = (StackFrame *)regs->ebp;
|
|
||||||
|
|
||||||
while (frame && i < SYSPROF_MAX_ADDRESSES - 1 &&
|
|
||||||
(long)frame < (long)START_OF_STACK &&
|
|
||||||
(long)frame >= regs->esp)
|
|
||||||
{
|
|
||||||
void *next = NULL;
|
|
||||||
|
|
||||||
if (verify_area(VERIFY_READ, frame, sizeof(StackFrame)) == 0)
|
|
||||||
{
|
|
||||||
void *return_address;
|
|
||||||
|
|
||||||
__get_user (return_address, &(frame->return_address));
|
|
||||||
__get_user (next, &(frame->next));
|
|
||||||
trace->addresses[i++] = return_address;
|
|
||||||
|
|
||||||
if ((long)next <= (long)frame)
|
|
||||||
next = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
frame = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
trace->n_addresses = i;
|
|
||||||
if (i == SYSPROF_MAX_ADDRESSES)
|
|
||||||
trace->truncated = 1;
|
|
||||||
else
|
|
||||||
trace->truncated = 0;
|
trace->truncated = 0;
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
trace->addresses[0] = (void *)regs->eip;
|
||||||
disk_access (struct vm_area_struct *area,
|
i = 1;
|
||||||
unsigned long address)
|
frame = (StackFrame *)regs->ebp;
|
||||||
{
|
|
||||||
struct file *file = area->vm_file;
|
|
||||||
struct address_space *mapping = file->f_dentry->d_inode->i_mapping;
|
|
||||||
struct inode *inode = mapping->host;
|
|
||||||
struct page *page, **hash;
|
|
||||||
unsigned long size, pgoff, endoff;
|
|
||||||
int disk_access = 1;
|
|
||||||
|
|
||||||
pgoff = ((address - area->vm_start) >> PAGE_CACHE_SHIFT) + area->vm_pgoff;
|
while (frame && i < SYSPROF_MAX_ADDRESSES &&
|
||||||
endoff = ((area->vm_end - area->vm_start) >> PAGE_CACHE_SHIFT) + area->vm_pgoff;
|
(long)frame < (long)START_OF_STACK &&
|
||||||
|
(long)frame >= regs->esp) {
|
||||||
|
void *next = NULL;
|
||||||
|
|
||||||
/*
|
if (verify_area(VERIFY_READ, frame, sizeof(StackFrame)) == 0) {
|
||||||
* An external ptracer can access pages that normally aren't
|
void *return_address;
|
||||||
* accessible..
|
|
||||||
*/
|
|
||||||
size = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
|
|
||||||
if ((pgoff >= size) && (area->vm_mm == current->mm))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* The "size" of the file, as far as mmap is concerned, isn't bigger than the mapping */
|
__get_user (return_address, &(frame->return_address));
|
||||||
if (size > endoff)
|
__get_user (next, &(frame->next));
|
||||||
size = endoff;
|
trace->addresses[i++] = return_address;
|
||||||
|
|
||||||
/*
|
if ((long)next <= (long)frame)
|
||||||
* Do we have something in the page cache already?
|
next = NULL;
|
||||||
*/
|
}
|
||||||
hash = page_hash(mapping, pgoff);
|
|
||||||
|
|
||||||
page = __find_get_page(mapping, pgoff, hash);
|
frame = next;
|
||||||
if (page)
|
|
||||||
/*
|
|
||||||
* Ok, found a page in the page cache, now we need to check
|
|
||||||
* that it's up-to-date.
|
|
||||||
*/
|
|
||||||
if (Page_Uptodate(page))
|
|
||||||
disk_access = 0;
|
|
||||||
|
|
||||||
return disk_access;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct page *
|
|
||||||
hijacked_nopage (struct vm_area_struct * area,
|
|
||||||
unsigned long address,
|
|
||||||
int unused)
|
|
||||||
{
|
|
||||||
struct page *result;
|
|
||||||
int disk;
|
|
||||||
|
|
||||||
disk = disk_access (area, address);
|
|
||||||
|
|
||||||
printk (KERN_ALERT "disk access: %d\n", disk);
|
|
||||||
|
|
||||||
result = filemap_nopage (area, address, unused);
|
|
||||||
|
|
||||||
if (current && disk)
|
|
||||||
{
|
|
||||||
generate_stack_trace (current, head);
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
memset (head, 0, sizeof (SysprofStackTrace));
|
|
||||||
|
|
||||||
head->pid = current->pid;
|
|
||||||
head->addresses[0] = (void *)address;
|
|
||||||
head->truncated = 0;
|
|
||||||
head->n_addresses = 1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
memmove (&(head->addresses[1]), &(head->addresses[0]),
|
|
||||||
head->n_addresses * 4);
|
|
||||||
head->n_addresses++;
|
|
||||||
head->addresses[0] = address;
|
|
||||||
|
|
||||||
if (area->vm_file)
|
|
||||||
{
|
|
||||||
char *line = d_path (area->vm_file->f_dentry,
|
|
||||||
area->vm_file->f_vfsmnt,
|
|
||||||
head->filename, PAGE_SIZE);
|
|
||||||
|
|
||||||
strncpy (head->filename, line, sizeof (head->filename) - 1);
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
if (line == head->filename)
|
|
||||||
printk (KERN_ALERT "got name\n");
|
|
||||||
else if (line == NULL)
|
|
||||||
printk (KERN_ALERT "noasdf\n");
|
|
||||||
else
|
|
||||||
printk (KERN_ALERT "%s\n", line);
|
|
||||||
#endif
|
|
||||||
head->map_start = area->vm_start;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (head++ == &stack_traces[N_TRACES - 1])
|
trace->n_addresses = i;
|
||||||
head = &stack_traces[0];
|
if (i == SYSPROF_MAX_ADDRESSES)
|
||||||
|
trace->truncated = 1;
|
||||||
wake_up (&wait_for_trace);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
hijack_nopage (struct vm_area_struct *vma)
|
|
||||||
{
|
|
||||||
if (vma->vm_ops && vma->vm_ops->nopage == filemap_nopage)
|
|
||||||
vma->vm_ops->nopage = hijacked_nopage;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
hijack_nopages (struct task_struct *task)
|
|
||||||
{
|
|
||||||
struct mm_struct *mm = task->mm;
|
|
||||||
struct vm_area_struct *vma;
|
|
||||||
|
|
||||||
if (!mm)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (vma = mm->mmap; vma != NULL; vma = vma->vm_next)
|
|
||||||
hijack_nopage (vma);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
clean_hijacked_nopages (void)
|
|
||||||
{
|
|
||||||
struct task_struct *task;
|
|
||||||
|
|
||||||
for_each_process (task)
|
|
||||||
{
|
|
||||||
struct mm_struct *mm = task->mm;
|
|
||||||
|
|
||||||
if (mm)
|
|
||||||
{
|
|
||||||
struct vm_area_struct *vma;
|
|
||||||
|
|
||||||
for (vma = mm->mmap; vma != NULL; vma = vma->vm_next)
|
|
||||||
{
|
|
||||||
if (vma->vm_ops && vma->vm_ops->nopage == hijacked_nopage)
|
|
||||||
vma->vm_ops->nopage = filemap_nopage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct mmap_arg_struct {
|
|
||||||
unsigned long addr;
|
|
||||||
unsigned long len;
|
|
||||||
unsigned long prot;
|
|
||||||
unsigned long flags;
|
|
||||||
unsigned long fd;
|
|
||||||
unsigned long offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef asmlinkage int (* old_mmap_func) (struct mmap_arg_struct *arg);
|
|
||||||
typedef asmlinkage long (* mmap2_func) (
|
|
||||||
unsigned long addr, unsigned long len,
|
|
||||||
unsigned long prot, unsigned long flags,
|
|
||||||
unsigned long fd, unsigned long pgoff);
|
|
||||||
|
|
||||||
static mmap2_func orig_mmap2;
|
|
||||||
static old_mmap_func orig_mmap;
|
|
||||||
|
|
||||||
static void
|
|
||||||
after_mmap (long res, unsigned long len)
|
|
||||||
{
|
|
||||||
struct vm_area_struct *vma;
|
|
||||||
unsigned long start;
|
|
||||||
|
|
||||||
if (res == -1 || !current || current->pid == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
start = res;
|
|
||||||
|
|
||||||
vma = find_vma (current->mm, start);
|
|
||||||
|
|
||||||
if (vma && vma->vm_end >= start + len)
|
|
||||||
hijack_nopage (vma);
|
|
||||||
#if 0
|
|
||||||
else if (vma)
|
|
||||||
{
|
|
||||||
printk (KERN_ALERT "nope: vm_start: %x, vm_end: %x\n"
|
|
||||||
"start: %p, len: %x, start + len: %x\n",
|
|
||||||
vma->vm_start, vma->vm_end, start, len, start + len);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
printk (KERN_ALERT "no vma\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static long
|
|
||||||
new_mmap2 (unsigned long addr, unsigned long len,
|
|
||||||
unsigned long prot, unsigned long flags,
|
|
||||||
unsigned long fd, unsigned long pgoff)
|
|
||||||
{
|
|
||||||
int res = orig_mmap2 (addr, len, prot, flags, fd, pgoff);
|
|
||||||
|
|
||||||
after_mmap (res, len);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
new_mmap (struct mmap_arg_struct *arg)
|
|
||||||
{
|
|
||||||
int res = orig_mmap (arg);
|
|
||||||
|
|
||||||
after_mmap (res, arg->len);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void **sys_call_table = (void **)0xc0347df0;
|
|
||||||
|
|
||||||
static void
|
|
||||||
hijack_mmaps (void)
|
|
||||||
{
|
|
||||||
orig_mmap2 = sys_call_table[__NR_mmap2];
|
|
||||||
sys_call_table[__NR_mmap2] = new_mmap2;
|
|
||||||
|
|
||||||
orig_mmap = sys_call_table[__NR_mmap];
|
|
||||||
sys_call_table[__NR_mmap] = new_mmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
restore_mmaps (void)
|
|
||||||
{
|
|
||||||
sys_call_table[__NR_mmap2] = orig_mmap2;
|
|
||||||
sys_call_table[__NR_mmap] = orig_mmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_timer_interrupt (void *data)
|
|
||||||
{
|
|
||||||
static int n_ticks = 0;
|
|
||||||
|
|
||||||
if (exiting)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
if (!cpu_profiler)
|
|
||||||
{
|
|
||||||
restore_mmaps();
|
|
||||||
|
|
||||||
clean_hijacked_nopages ();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
wake_up (&wait_for_exit);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++n_ticks;
|
|
||||||
|
|
||||||
if (current && current->pid != 0 &&
|
|
||||||
(n_ticks % (HZ / SAMPLES_PER_SECOND)) == 0)
|
|
||||||
{
|
|
||||||
if (cpu_profiler)
|
|
||||||
{
|
|
||||||
generate_stack_trace (current, head);
|
|
||||||
|
|
||||||
if (head++ == &stack_traces[N_TRACES - 1])
|
|
||||||
head = &stack_traces[0];
|
|
||||||
|
|
||||||
wake_up (&wait_for_trace);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
trace->truncated = 0;
|
||||||
#if 0
|
}
|
||||||
hijack_nopages (current);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
queue_task (&timer_task, &tq_timer);
|
static void
|
||||||
|
on_timer(unsigned long dong)
|
||||||
|
{
|
||||||
|
static int n_ticks = 0;
|
||||||
|
|
||||||
|
#ifdef KERNEL24
|
||||||
|
if (exiting) {
|
||||||
|
wake_up (&wait_for_exit);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
++n_ticks;
|
||||||
|
|
||||||
|
if (
|
||||||
|
#ifdef KERNEL24
|
||||||
|
current && current->pid != 0 &&
|
||||||
|
(n_ticks % (HZ / SAMPLES_PER_SECOND)) == 0
|
||||||
|
#else
|
||||||
|
current && current->pid != 0
|
||||||
|
#endif
|
||||||
|
)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct pt_regs *regs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) current->thread_info)) - 1;
|
||||||
|
#if 0
|
||||||
|
struct pt_regs *regs = (struct pt_regs *)(
|
||||||
|
(long)current + THREAD_SIZE - sizeof (struct pt_regs));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
generate_stack_trace (regs, head);
|
||||||
|
|
||||||
|
if (head++ == &stack_traces[N_TRACES - 1])
|
||||||
|
head = &stack_traces[0];
|
||||||
|
|
||||||
|
wake_up (&wait_for_trace);
|
||||||
|
}
|
||||||
|
|
||||||
|
add_timeout (INTERVAL, on_timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
procfile_read (char *buffer,
|
procfile_read(char *buffer,
|
||||||
char **buffer_location,
|
char **buffer_location,
|
||||||
off_t offset,
|
off_t offset,
|
||||||
int buffer_length,
|
int buffer_len,
|
||||||
int *eof,
|
int *eof,
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
#if 0
|
wait_event_interruptible(wait_for_trace, head != tail);
|
||||||
if (offset > 0)
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
wait_event_interruptible (wait_for_trace, head != tail);
|
if (buffer_len < sizeof (SysprofStackTrace))
|
||||||
*buffer_location = (char *)tail;
|
return -ENOMEM;
|
||||||
if (tail++ == &stack_traces[N_TRACES - 1])
|
|
||||||
tail = &stack_traces[0];
|
memcpy (buffer, (char *)tail, sizeof (SysprofStackTrace));
|
||||||
return sizeof (SysprofStackTrace);
|
if (tail++ == &stack_traces[N_TRACES - 1])
|
||||||
|
tail = &stack_traces[0];
|
||||||
|
*buffer_location = buffer;
|
||||||
|
|
||||||
|
return sizeof (SysprofStackTrace);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct proc_dir_entry *trace_proc_file;
|
struct proc_dir_entry *trace_proc_file;
|
||||||
|
|
||||||
static unsigned int
|
static unsigned int
|
||||||
procfile_poll (struct file *filp, poll_table *poll_table)
|
procfile_poll(struct file *filp, poll_table *poll_table)
|
||||||
{
|
{
|
||||||
if (head != tail)
|
poll_wait(filp, &wait_for_trace, poll_table);
|
||||||
{
|
if (head != tail) {
|
||||||
return POLLIN;
|
return POLLIN | POLLRDNORM;
|
||||||
}
|
}
|
||||||
poll_wait (filp, &wait_for_trace, poll_table);
|
return 0;
|
||||||
if (head != tail)
|
|
||||||
{
|
|
||||||
return POLLIN;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
init_module (void)
|
init_module(void)
|
||||||
{
|
{
|
||||||
struct task_struct *task;
|
trace_proc_file =
|
||||||
trace_proc_file =
|
create_proc_entry ("sysprof-trace", S_IFREG | S_IRUGO, &proc_root);
|
||||||
create_proc_entry ("sysprof-trace", S_IFREG | S_IRUGO, &proc_root);
|
|
||||||
|
|
||||||
if (!trace_proc_file)
|
if (!trace_proc_file)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
trace_proc_file->read_proc = procfile_read;
|
trace_proc_file->read_proc = procfile_read;
|
||||||
trace_proc_file->proc_fops->poll = procfile_poll;
|
trace_proc_file->proc_fops->poll = procfile_poll;
|
||||||
trace_proc_file->size = sizeof (SysprofStackTrace);
|
trace_proc_file->size = sizeof (SysprofStackTrace);
|
||||||
|
|
||||||
#if 0
|
init_timeout();
|
||||||
if (!cpu_profiler)
|
|
||||||
{
|
|
||||||
hijack_mmaps ();
|
|
||||||
|
|
||||||
for_each_process (task)
|
add_timeout(INTERVAL, on_timer);
|
||||||
{
|
|
||||||
hijack_nopages (task);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
queue_task(&timer_task, &tq_timer);
|
printk(KERN_ALERT "starting sysprof module\n");
|
||||||
|
|
||||||
printk (KERN_ALERT "starting sysprof module\n");
|
return 0;
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
cleanup_module(void)
|
cleanup_module(void)
|
||||||
{
|
{
|
||||||
exiting = 1;
|
remove_timeout();
|
||||||
sleep_on (&wait_for_exit);
|
|
||||||
remove_proc_entry ("sysprof-trace", &proc_root);
|
|
||||||
|
|
||||||
printk (KERN_ALERT "stopping sysprof module\n");
|
remove_proc_entry("sysprof-trace", &proc_root);
|
||||||
|
|
||||||
|
printk(KERN_ALERT "stopping sysprof module\n");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
typedef struct SysprofStackTrace SysprofStackTrace;
|
typedef struct SysprofStackTrace SysprofStackTrace;
|
||||||
|
|
||||||
#define SYSPROF_MAX_ADDRESSES 1024
|
#define SYSPROF_MAX_ADDRESSES 512
|
||||||
|
|
||||||
struct SysprofStackTrace
|
struct SysprofStackTrace
|
||||||
{
|
{
|
||||||
@ -13,9 +13,6 @@ struct SysprofStackTrace
|
|||||||
* with -fomit-frame-pointer or is otherwise weird
|
* with -fomit-frame-pointer or is otherwise weird
|
||||||
*/
|
*/
|
||||||
void *addresses[SYSPROF_MAX_ADDRESSES];
|
void *addresses[SYSPROF_MAX_ADDRESSES];
|
||||||
|
|
||||||
char filename[8192];
|
|
||||||
int map_start;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -109,7 +109,7 @@ on_read (gpointer data)
|
|||||||
|
|
||||||
rd = read (app->input_fd, &trace, sizeof (trace));
|
rd = read (app->input_fd, &trace, sizeof (trace));
|
||||||
|
|
||||||
if (app->profiling && !app->generating_profile)
|
if (rd > 0 && app->profiling && !app->generating_profile)
|
||||||
{
|
{
|
||||||
Process *process = process_get_from_pid (trace.pid);
|
Process *process = process_get_from_pid (trace.pid);
|
||||||
int i;
|
int i;
|
||||||
@ -693,11 +693,14 @@ main (int argc, char **argv)
|
|||||||
if (app->input_fd < 0)
|
if (app->input_fd < 0)
|
||||||
{
|
{
|
||||||
disaster ("Can't open /proc/sysprof-trace. You need to insert\n"
|
disaster ("Can't open /proc/sysprof-trace. You need to insert\n"
|
||||||
"the sysprof kernel module. Type\n"
|
"the sysprof kernel module. As root type\n"
|
||||||
"\n"
|
"\n"
|
||||||
" insmod sysprof-module.o\n"
|
" insmod sysprof-module.o\n"
|
||||||
"\n"
|
"\n"
|
||||||
"as root\n");
|
"or if you are using a 2.6 kernel:\n"
|
||||||
|
"\n"
|
||||||
|
" insmod sysprof-module.ko\n"
|
||||||
|
"\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
fd_add_watch (app->input_fd, app);
|
fd_add_watch (app->input_fd, app);
|
||||||
|
|||||||
Reference in New Issue
Block a user