Sat Jun 18 22:45:04 2005  Søren Sandmann  <sandmann@redhat.com>

	* TODO: Updates

	* configure.ac: Check for Linux 2.6.11

	* process.c (get_pidname): Present pid=-1 as [kernel].

	* module/sysprof-module.c: Use register_timer_hook() instead of
	a kernel timer. Set trace.pid to -1 if interrupt happens in
	kernel.
This commit is contained in:
Søren Sandmann
2005-06-19 02:46:19 +00:00
committed by Søren Sandmann Pedersen
parent fb7e1ddc47
commit 18abd9e1e6
7 changed files with 192 additions and 14 deletions

View File

@ -1,3 +1,15 @@
Sat Jun 18 22:45:04 2005 Søren Sandmann <sandmann@redhat.com>
* TODO: Updates
* configure.ac: Check for Linux 2.6.11
* process.c (get_pidname): Present pid=-1 as [kernel].
* module/sysprof-module.c: Use register_timer_hook() instead of
a kernel timer. Set trace.pid to -1 if interrupt happens in
kernel.
Sun Jun 12 20:30:37 2005 Soeren Sandmann <sandmann@redhat.com>
* sysprof.c (build_gui): Disable type-ahead search for all the

2
README
View File

@ -6,7 +6,7 @@ See http://www.daimi.au.dk/~sandmann/sysprof/ for more information
- You need gtk+ 2.6.0 or better.
- You need a 2.6 kernel. On SMP kernels the module produces unreliable data.
- You need at least Linux 2.6.11
- The module must be compiled with the same compiler that compiled the
kernel it is going to be used with. For most systems that is just

23
TODO
View File

@ -14,11 +14,17 @@ Before 1.0:
- Announce on Advogato
- Announce on gnome-announce
- Announce on devtools list (?)
Before 1.2:
Before 1.2:
* See if the auto-expanding can be made more intelligent
* Send entire stack to user space, then do stackwalking there
* If interrupt happens in kernel mode, send both
kernel stack and user space stack, have userspace stitch them
together.
* Correctness
- When the module is unloaded, kill all processes blocking in read
- or block unloading until all processes have exited
@ -41,13 +47,17 @@ Before 1.2:
UI: "generate screenshot" menu item pops up a window with
a text area + a radio buttons "text/html". When you flick
them, the text area is automatically updated.
- Fixing the oops in kernels < 2.6.11
- Probably just require 2.6.11 (necessary for timer interrupt
based anyway).
- Make the process waiting in poll() responsible for extracting
the backtrace. Give a copy of the entire stack rather than doing
the walk inside the kernel. That would allow us to do more complex
algorithms in userspace (though we'd lose the ability to do non-racy
file naming).
algorithms in userspace. Though we'd lose the ability to do non-racy
file naming. We could pass a list of the process mappings though.
New model:
- Two arrays,
@ -201,6 +211,9 @@ http://www.linuxbase.org/spec/booksets/LSB-Embedded/LSB-Embedded/ehframe.html
Later:
- See if it is possible to group the X server activity under the process that
generated it.
- .desktop file
[Is this worth it? You will often want to start it as root,
and you will need to insert the module from the command line]
@ -348,6 +361,8 @@ Later:
DONE:
* Timer interrupt based
* Interface
- Consider expanding a few more levels of a new descendants tree
- Algorithm should be expand in proportion to the

View File

@ -61,6 +61,7 @@ AC_CHECK_LIB(bfd, bfd_get_error, [DEP_LIBS="$DEP_LIBS -lbfd -liberty"],
AC_MSG_ERROR([libbfd is required to compile sysprof]),
-liberty)
# emit files
AC_SUBST(DEP_LIBS)
@ -69,4 +70,19 @@ AC_CONFIG_FILES([
Makefile
])
# Kernel version
KMAJOR=`uname -r | cut -d"." -f 1`
KMINOR=`uname -r | cut -d"." -f 2`
KMICRO=`uname -r | cut -d"." -f 3 | cut -d"-" -f 1`
if [[ $KMICRO -lt 11 ]] ; then
if [[ $KMICRO -gt 8 ]]; then
echo
echo Linux \>= 2.6.11 is required
echo
exit 1
fi
fi
AC_OUTPUT

View File

@ -42,7 +42,7 @@
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Soeren Sandmann (sandmann@daimi.au.dk)");
#define SAMPLES_PER_SECOND (100)
#define SAMPLES_PER_SECOND (256)
#define INTERVAL (HZ / SAMPLES_PER_SECOND)
#define N_TRACES 256
@ -52,8 +52,12 @@ static SysprofStackTrace * tail = &stack_traces[0];
DECLARE_WAIT_QUEUE_HEAD (wait_for_trace);
DECLARE_WAIT_QUEUE_HEAD (wait_for_exit);
#if 0
static void on_timer(unsigned long);
#endif
#if 0
static struct timer_list timer;
#endif
typedef struct userspace_reader userspace_reader;
struct userspace_reader
@ -63,6 +67,7 @@ struct userspace_reader
unsigned long *cache;
};
#if 0
/* This function was mostly cutted and pasted from ptrace.c
*/
@ -93,7 +98,9 @@ put_mm (struct mm_struct *mm)
mmput(mm);
#endif
}
#endif
#if 0
static int
x_access_process_vm (struct task_struct *tsk,
unsigned long addr,
@ -153,7 +160,9 @@ x_access_process_vm (struct task_struct *tsk,
return buf - old_buf;
}
#endif
#if 0
static int
init_userspace_reader (userspace_reader *reader,
struct task_struct *task)
@ -165,7 +174,9 @@ init_userspace_reader (userspace_reader *reader,
reader->cache_address = 0x0;
return 1;
}
#endif
#if 0
static int
page_readable (userspace_reader *reader, unsigned long address)
{
@ -188,7 +199,9 @@ page_readable (userspace_reader *reader, unsigned long address)
return 1;
}
#endif
#if 0
static int
read_user_space (userspace_reader *reader,
unsigned long address,
@ -219,12 +232,15 @@ read_user_space (userspace_reader *reader,
*result = reader->cache[index];
return 1;
}
#endif
#if 0
static void
done_userspace_reader (userspace_reader *reader)
{
kfree (reader->cache);
}
#endif
typedef struct StackFrame StackFrame;
struct StackFrame {
@ -232,6 +248,7 @@ struct StackFrame {
unsigned long return_address;
};
#if 0
static int
read_frame (userspace_reader *reader, unsigned long addr, StackFrame *frame)
{
@ -249,7 +266,9 @@ read_frame (userspace_reader *reader, unsigned long addr, StackFrame *frame)
return 1;
}
#endif
#if 0
static struct pt_regs *
get_regs (struct task_struct *task)
{
@ -268,16 +287,13 @@ get_regs (struct task_struct *task)
return task_pt_regs (task);
#endif
}
#endif
#if 0
static void
generate_stack_trace(struct task_struct *task,
SysprofStackTrace *trace)
{
#ifdef CONFIG_HIGHMEM
# define START_OF_STACK 0xFF000000
#else
# define START_OF_STACK 0xBFFFFFFF
#endif
struct pt_regs *regs = get_regs (task); // task->thread.regs;
StackFrame frame;
@ -319,14 +335,16 @@ generate_stack_trace(struct task_struct *task,
else
trace->truncated = 0;
}
#endif
#if 0
static void
do_generate (void *data)
{
struct task_struct *task = data;
generate_stack_trace(task, head);
if (head++ == &stack_traces[N_TRACES - 1])
head = &stack_traces[0];
@ -341,9 +359,11 @@ do_generate (void *data)
mod_timer(&timer, jiffies + INTERVAL);
}
#endif
struct work_struct work;
#if 0
static void
on_timer(unsigned long dong)
{
@ -360,6 +380,110 @@ on_timer(unsigned long dong)
mod_timer(&timer, jiffies + INTERVAL);
}
}
#endif
/**
* pages_present() from OProfile
*
* Copyright 2002 OProfile authors
*
* author John Levon
* author David Smith
*/
#ifdef CONFIG_X86_4G
/* With a 4G kernel/user split, user pages are not directly
* accessible from the kernel, so don't try
*/
static int pages_present(StackFrame * head)
{
return 0;
}
#else
/* check that the page(s) containing the frame head are present */
static int pages_present(StackFrame * head)
{
struct mm_struct * mm = current->mm;
/* FIXME: only necessary once per page */
if (!check_user_page_readable(mm, (unsigned long)head))
return 0;
return check_user_page_readable(mm, (unsigned long)(head + 1));
}
#endif /* CONFIG_X86_4G */
static int
timer_notify (struct pt_regs *regs)
{
#ifdef CONFIG_HIGHMEM
# define START_OF_STACK 0xFF000000
#else
# define START_OF_STACK 0xBFFFFFFF
#endif
StackFrame *frame;
static int n_samples;
SysprofStackTrace *trace = head;
int i;
int is_user;
if ((n_samples++ % INTERVAL) != 0)
return 0;
is_user = user_mode(regs);
if (!current || current->pid == 0)
return 0;
if (is_user && current->state != TASK_RUNNING)
return 0;
if (!is_user)
{
/* kernel */
trace->pid = -1;
trace->truncated = 0;
trace->n_addresses = 1;
trace->addresses[0] = 0x0;
}
else
{
memset(trace, 0, sizeof (SysprofStackTrace));
trace->pid = current->pid;
trace->truncated = 0;
trace->addresses[0] = (void *)regs->eip;
i = 1;
frame = (StackFrame *)regs->ebp;
while (pages_present (frame) &&
i < SYSPROF_MAX_ADDRESSES &&
((unsigned long)frame) < START_OF_STACK &&
(unsigned long)frame >= regs->esp)
{
trace->addresses[i++] = (void *)frame->return_address;
frame = (StackFrame *)frame->next;
}
trace->n_addresses = i;
if (i == SYSPROF_MAX_ADDRESSES)
trace->truncated = 1;
else
trace->truncated = 0;
}
if (head++ == &stack_traces[N_TRACES - 1])
head = &stack_traces[0];
wake_up (&wait_for_trace);
return 0;
}
static int
procfile_read(char *buffer,
@ -407,10 +531,14 @@ init_module(void)
trace_proc_file->read_proc = procfile_read;
trace_proc_file->proc_fops->poll = procfile_poll;
trace_proc_file->size = sizeof (SysprofStackTrace);
register_timer_hook (timer_notify);
#if 0
init_timer(&timer);
timer.function = on_timer;
mod_timer(&timer, jiffies + INTERVAL);
#endif
printk(KERN_ALERT "starting sysprof module\n");
@ -420,8 +548,12 @@ init_module(void)
void
cleanup_module(void)
{
#if 0
del_timer (&timer);
#endif
unregister_timer_hook (timer_notify);
remove_proc_entry("sysprof-trace", &proc_root);
}

View File

@ -26,7 +26,7 @@ typedef struct SysprofStackTrace SysprofStackTrace;
struct SysprofStackTrace
{
int pid;
int pid; /* -1 if in kernel */
int truncated;
int n_addresses; /* note: this can be 1 if the process was compiled
* with -fomit-frame-pointer or is otherwise weird

View File

@ -292,7 +292,10 @@ get_statname (int pid)
static char *
get_pidname (int pid)
{
return g_strdup_printf ("[pid %d]", pid);
if (pid == -1)
return g_strdup_printf ("kernel", pid);
else
return g_strdup_printf ("pid %d", pid);
}
static char *