- 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
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,
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]
DONE:
+* Timer interrupt based
+
* Interface
- Consider expanding a few more levels of a new descendants tree
- Algorithm should be expand in proportion to the
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
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
unsigned long *cache;
};
+#if 0
/* This function was mostly cutted and pasted from ptrace.c
*/
mmput(mm);
#endif
}
+#endif
+#if 0
static int
x_access_process_vm (struct task_struct *tsk,
unsigned long addr,
return buf - old_buf;
}
+#endif
+#if 0
static int
init_userspace_reader (userspace_reader *reader,
struct task_struct *task)
reader->cache_address = 0x0;
return 1;
}
+#endif
+#if 0
static int
page_readable (userspace_reader *reader, unsigned long address)
{
return 1;
}
+#endif
+#if 0
static int
read_user_space (userspace_reader *reader,
unsigned long address,
*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 {
unsigned long return_address;
};
+#if 0
static int
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)
{
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;
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];
mod_timer(&timer, jiffies + INTERVAL);
}
+#endif
struct work_struct work;
+#if 0
static void
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,
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");
void
cleanup_module(void)
{
+#if 0
del_timer (&timer);
+#endif
+ unregister_timer_hook (timer_notify);
+
remove_proc_entry("sysprof-trace", &proc_root);
}