mirror of
https://github.com/varun-r-mallya/sysprof.git
synced 2025-12-31 20:36:25 +00:00
Performance improvements
This commit is contained in:
179
sysprof-module.c
179
sysprof-module.c
@ -37,89 +37,92 @@ static void on_timer(unsigned long);
|
|||||||
/*
|
/*
|
||||||
* Wrappers to cover up kernel differences in timer handling
|
* Wrappers to cover up kernel differences in timer handling
|
||||||
*/
|
*/
|
||||||
#ifdef KERNEL24
|
|
||||||
static struct tq_struct timer_task =
|
|
||||||
{
|
|
||||||
{ NULL, NULL },
|
|
||||||
0,
|
|
||||||
on_timer,
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
int exiting = 0;
|
|
||||||
#else
|
|
||||||
|
|
||||||
static struct timer_list timer;
|
static struct timer_list timer;
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
init_timeout (void)
|
init_timeout (void)
|
||||||
{
|
{
|
||||||
#ifdef KERNEL24
|
|
||||||
/* no setup needed */
|
|
||||||
#else
|
|
||||||
init_timer(&timer);
|
init_timer(&timer);
|
||||||
timer.function = on_timer;
|
timer.function = on_timer;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
remove_timeout(void)
|
remove_timeout(void)
|
||||||
{
|
{
|
||||||
#ifdef KERNEL24
|
|
||||||
exiting = 1;
|
|
||||||
sleep_on (&wait_for_exit);
|
|
||||||
#else
|
|
||||||
del_timer (&timer);
|
del_timer (&timer);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
add_timeout(unsigned int interval,
|
add_timeout(unsigned int interval,
|
||||||
TimeoutFunc f)
|
TimeoutFunc f)
|
||||||
{
|
{
|
||||||
#ifdef KERNEL24
|
|
||||||
queue_task(&timer_task, &tq_timer);
|
|
||||||
#else
|
|
||||||
mod_timer(&timer, jiffies + INTERVAL);
|
mod_timer(&timer, jiffies + INTERVAL);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
typedef struct userspace_reader userspace_reader;
|
||||||
* The portable part of the driver starts here
|
struct userspace_reader
|
||||||
*/
|
{
|
||||||
|
struct task_struct *task;
|
||||||
|
unsigned long user_page;
|
||||||
|
unsigned long kernel_page;
|
||||||
|
struct page *page;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
init_userspace_reader (userspace_reader *reader,
|
||||||
|
struct task_struct *task)
|
||||||
|
{
|
||||||
|
reader->task = task;
|
||||||
|
reader->user_page = 0;
|
||||||
|
reader->kernel_page = 0;
|
||||||
|
reader->page = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
read_task_address (struct task_struct *task, unsigned long address, int *result)
|
read_user_space (userspace_reader *reader,
|
||||||
|
unsigned long address,
|
||||||
|
unsigned long *result)
|
||||||
{
|
{
|
||||||
unsigned long page_addr = (address & PAGE_MASK);
|
unsigned long user_page = (address & PAGE_MASK);
|
||||||
int found;
|
|
||||||
struct page *page;
|
|
||||||
void *kaddr;
|
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
if (!task || !task->mm)
|
if (user_page == 0)
|
||||||
return 0;
|
|
||||||
|
|
||||||
found = get_user_pages (task, task->mm, page_addr, 1, 0, 0, &page, NULL);
|
|
||||||
if (!found)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
kaddr = kmap_atomic (page, KM_SOFTIRQ0);
|
if (!reader->user_page || user_page != reader->user_page) {
|
||||||
|
int found;
|
||||||
|
struct page *page;
|
||||||
|
|
||||||
|
if (reader->user_page)
|
||||||
|
kunmap (reader->page);
|
||||||
|
|
||||||
if (get_user (res, (int *)kaddr + (address - page_addr) / 4)) {
|
reader->user_page = user_page;
|
||||||
kunmap_atomic (page, KM_SOFTIRQ0);
|
|
||||||
return 0;
|
found = get_user_pages (reader->task, reader->task->mm, user_page,
|
||||||
|
1, 0, 0, &page, NULL);
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
reader->kernel_page = (unsigned long)kmap (page);
|
||||||
|
reader->page = page;
|
||||||
}
|
}
|
||||||
|
|
||||||
kunmap_atomic (page, KM_SOFTIRQ0);
|
if (__get_user (res, (int *)(reader->kernel_page + (address - user_page))) != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
*result = res;
|
*result = res;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
done_userspace_reader (userspace_reader *reader)
|
||||||
|
{
|
||||||
|
if (reader->user_page)
|
||||||
|
kunmap (reader->page);
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct StackFrame StackFrame;
|
typedef struct StackFrame StackFrame;
|
||||||
struct StackFrame {
|
struct StackFrame {
|
||||||
unsigned long next;
|
unsigned long next;
|
||||||
@ -127,7 +130,7 @@ struct StackFrame {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
read_frame (struct task_struct *task, unsigned long addr, StackFrame *frame)
|
read_frame (userspace_reader *reader, unsigned long addr, StackFrame *frame)
|
||||||
{
|
{
|
||||||
if (!addr || !frame)
|
if (!addr || !frame)
|
||||||
return 0;
|
return 0;
|
||||||
@ -135,10 +138,10 @@ read_frame (struct task_struct *task, unsigned long addr, StackFrame *frame)
|
|||||||
frame->next = 0;
|
frame->next = 0;
|
||||||
frame->return_address = 0;
|
frame->return_address = 0;
|
||||||
|
|
||||||
if (!read_task_address (task, addr, (int *)&(frame->next)))
|
if (!read_user_space (reader, addr, &(frame->next)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!read_task_address (task, addr + 4, (int *)&(frame->return_address)))
|
if (!read_user_space (reader, addr + 4, &(frame->return_address)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@ -156,6 +159,7 @@ generate_stack_trace(struct task_struct *task,
|
|||||||
struct pt_regs *regs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) task->thread_info)) - 1;
|
struct pt_regs *regs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) task->thread_info)) - 1;
|
||||||
StackFrame frame;
|
StackFrame frame;
|
||||||
unsigned long addr;
|
unsigned long addr;
|
||||||
|
userspace_reader reader;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
memset(trace, 0, sizeof (SysprofStackTrace));
|
memset(trace, 0, sizeof (SysprofStackTrace));
|
||||||
@ -169,55 +173,13 @@ generate_stack_trace(struct task_struct *task,
|
|||||||
|
|
||||||
addr = regs->ebp;
|
addr = regs->ebp;
|
||||||
|
|
||||||
#if 0
|
init_userspace_reader (&reader, task);
|
||||||
printk (KERN_ALERT "in generate\n");
|
while (i < SYSPROF_MAX_ADDRESSES && read_frame (&reader, addr, &frame) &&
|
||||||
#endif
|
addr < START_OF_STACK && addr >= regs->esp) {
|
||||||
#if 0
|
|
||||||
read_frame (task, addr, &frame);
|
|
||||||
#endif
|
|
||||||
while (i < SYSPROF_MAX_ADDRESSES && read_frame (task, addr, &frame)) {
|
|
||||||
trace->addresses[i++] = (void *)frame.return_address;
|
trace->addresses[i++] = (void *)frame.return_address;
|
||||||
|
|
||||||
addr = frame.next;
|
addr = frame.next;
|
||||||
}
|
}
|
||||||
|
done_userspace_reader (&reader);
|
||||||
#if 0
|
|
||||||
printk (KERN_ALERT "done (frame.next = %p)\n", frame.next);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
read_frame (task, regs->ebp, &frame);
|
|
||||||
|
|
||||||
while (i < SYSPROF_MAX_ADDRESSES &&
|
|
||||||
(long)frame < (long)START_OF_STACK &&
|
|
||||||
(long)frame >= regs->esp) {
|
|
||||||
void *next = NULL;
|
|
||||||
|
|
||||||
printk(KERN_ALERT "esp: %lx\n", regs->esp);
|
|
||||||
printk(KERN_ALERT "ebp: %lx\n", regs->ebp);
|
|
||||||
|
|
||||||
if (verify_area(VERIFY_READ, frame, sizeof(StackFrame)) == 0) {
|
|
||||||
void *return_address;
|
|
||||||
|
|
||||||
read_task_address (task, (unsigned long)return_address, (int *)&(frame->return_address));
|
|
||||||
read_task_address (task, (unsigned long)next, (int *)&(frame->next));
|
|
||||||
|
|
||||||
trace->addresses[i++] = return_address;
|
|
||||||
|
|
||||||
if ((long)next <= (long)frame)
|
|
||||||
next = NULL;
|
|
||||||
else
|
|
||||||
printk(KERN_ALERT "bad next\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
printk(KERN_ALERT "couldn't verify\n");
|
|
||||||
|
|
||||||
frame = next;
|
|
||||||
if (frame == NULL)
|
|
||||||
printk(KERN_ALERT "frame %d is null\n", i);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
trace->n_addresses = i;
|
trace->n_addresses = i;
|
||||||
if (i == SYSPROF_MAX_ADDRESSES)
|
if (i == SYSPROF_MAX_ADDRESSES)
|
||||||
@ -269,29 +231,10 @@ on_timer(unsigned long dong)
|
|||||||
{
|
{
|
||||||
static int n_ticks = 0;
|
static int n_ticks = 0;
|
||||||
|
|
||||||
#ifdef KERNEL24
|
|
||||||
if (exiting) {
|
|
||||||
wake_up (&wait_for_exit);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
++n_ticks;
|
++n_ticks;
|
||||||
|
|
||||||
if (
|
if (current && current->pid != 0)
|
||||||
#ifdef KERNEL24
|
|
||||||
current && current->pid != 0 &&
|
|
||||||
(n_ticks % (HZ / SAMPLES_PER_SECOND)) == 0
|
|
||||||
#else
|
|
||||||
current && current->pid != 0
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
#ifdef KERNEL24
|
|
||||||
struct pt_regs *regs = (struct pt_regs *)(
|
|
||||||
(long)current + THREAD_SIZE - sizeof (struct pt_regs));
|
|
||||||
#endif
|
|
||||||
queue_stack (current);
|
queue_stack (current);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,10 +249,6 @@ procfile_read(char *buffer,
|
|||||||
int *eof,
|
int *eof,
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
if (buffer_len < sizeof (SysprofStackTrace))
|
|
||||||
return -ENOMEM;
|
|
||||||
#endif
|
|
||||||
wait_event_interruptible (wait_for_trace, head != tail);
|
wait_event_interruptible (wait_for_trace, head != tail);
|
||||||
*buffer_location = (char *)tail;
|
*buffer_location = (char *)tail;
|
||||||
if (tail++ == &stack_traces[N_TRACES - 1])
|
if (tail++ == &stack_traces[N_TRACES - 1])
|
||||||
|
|||||||
Reference in New Issue
Block a user