Re: [PATCH] fs/devfs/base.c

Andrew Morton (andrewm@uow.edu.au)
Tue, 05 Jun 2001 21:37:00 +1000


Alan Cox wrote:
>
> > It's trivial to calculate for DAGs -- directed acyclic graphs. It's
> > when the "acyclic" constraint is violated that you have problems!
>
> It may well be that interrupt stacks are a win anyway. If we can get the kernel
> struct out of the stack pages (which would fix some very unpleasant cache
> colour problems) and take the non irq stack down to 4K then irq stacks would
> pay off once you had 25 or so processes on a system

All this talk about stack utilisation, we may as well fix
up the current (ly broken) instrumentation.

The patch enables the display of least-ever stack headroom
in the sysrq-T handler. Also prints a little summary at
the end of the SYSRQ-T output which shows:

a) which currently-running pid has used the most stack and

b) the name of the process which used the most stack since
the machine booted.

On my super-stripped-down development box, the answer is

Minimum ever: `zsh' with 3908 bytes

Against -ac7, it's all dependent upon CONFIG_DEBUG_SLAB.

--- linux-2.4.5-ac7/include/asm-i386/processor.h Tue Jun 5 17:46:37 2001
+++ ac/include/asm-i386/processor.h Tue Jun 5 21:20:47 2001
@@ -446,7 +446,21 @@
#define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1022])

#define THREAD_SIZE (2*PAGE_SIZE)
+#ifdef CONFIG_DEBUG_SLAB /* For tracking max stack utilisation */
+#define HAVE_STACK_PREFILL
+unsigned min_stack_headroom(struct task_struct *tsk);
+#define alloc_task_struct() \
+ ({ \
+ struct task_struct *p = \
+ ((struct task_struct *) __get_free_pages(GFP_KERNEL,1)); \
+ if (p) \
+ memset(p+1, 0xa5, PAGE_SIZE*2 - sizeof(*p)); \
+ p; \
+ })
+#else
#define alloc_task_struct() ((struct task_struct *) __get_free_pages(GFP_KERNEL,1))
+#endif
+
#define free_task_struct(p) free_pages((unsigned long) (p), 1)
#define get_task_struct(tsk) atomic_inc(&virt_to_page(tsk)->count)

--- linux-2.4.5-ac7/kernel/sched.c Tue Jun 5 17:46:37 2001
+++ ac/kernel/sched.c Tue Jun 5 21:30:02 2001
@@ -1101,9 +1101,31 @@
return retval;
}

-static void show_task(struct task_struct * p)
+#ifdef HAVE_STACK_PREFILL
+
+static unsigned min_ever_stack_headroom = ~0U;
+static char min_stack_name[16];
+
+/* tasklist_lock needed if tsk != current */
+unsigned min_stack_headroom(struct task_struct *tsk)
+{
+ unsigned long *p = (unsigned long *)(tsk + 1);
+ unsigned ret;
+ while (*p == 0xa5a5a5a5)
+ p++;
+ ret = (unsigned long)p - (unsigned long)(tsk + 1);
+ if (ret < min_ever_stack_headroom) {
+ min_ever_stack_headroom = ret;
+ strncpy(min_stack_name, tsk->comm, sizeof(min_stack_name));
+ }
+ return ret;
+}
+
+#endif
+
+static void show_task(struct task_struct * p,
+ unsigned *least_spare_stack, pid_t *pid)
{
- unsigned long free = 0;
int state;
static const char * stat_nam[] = { "R", "S", "D", "Z", "T", "W" };

@@ -1124,13 +1146,19 @@
else
printk(" %016lx ", thread_saved_pc(&p->thread));
#endif
+#ifdef HAVE_STACK_PREFILL
{
- unsigned long * n = (unsigned long *) (p+1);
- while (!*n)
- n++;
- free = (unsigned long) n - (unsigned long)(p+1);
+ unsigned long free = min_stack_headroom(p);
+
+ printk("%5lu %5d %6d ", free, p->pid, p->p_pptr->pid);
+ if (free < *least_spare_stack) {
+ *least_spare_stack = free;
+ *pid = p->pid;
+ }
}
- printk("%5lu %5d %6d ", free, p->pid, p->p_pptr->pid);
+#else
+ printk("%5d ????? %6d ", p->pid, p->p_pptr->pid);
+#endif
if (p->p_cptr)
printk("%5d ", p->p_cptr->pid);
else
@@ -1175,6 +1203,8 @@
void show_state(void)
{
struct task_struct *p;
+ unsigned least_spare_stack;
+ pid_t pid;

#if (BITS_PER_LONG == 32)
printk("\n"
@@ -1185,6 +1215,8 @@
" free sibling\n");
printk(" task PC stack pid father child younger older\n");
#endif
+ least_spare_stack = ~0U;
+ pid = -1;
read_lock(&tasklist_lock);
for_each_task(p) {
/*
@@ -1192,9 +1224,17 @@
* console might take alot of time:
*/
touch_nmi_watchdog();
- show_task(p);
+ show_task(p, &least_spare_stack, &pid);
}
read_unlock(&tasklist_lock);
+#ifdef HAVE_STACK_PREFILL
+ if (pid != -1) {
+ printk("Minimum stack headroom: pid %d with %u bytes\n",
+ pid, least_spare_stack);
+ printk("Minimum ever: `%s' with %u bytes\n",
+ min_stack_name, min_ever_stack_headroom);
+ }
+#endif
}

/*
--- linux-2.4.5-ac7/kernel/exit.c Mon May 28 13:31:49 2001
+++ ac/kernel/exit.c Tue Jun 5 21:07:34 2001
@@ -455,6 +455,9 @@

tsk->exit_code = code;
exit_notify();
+#ifdef HAVE_STACK_PREFILL
+ min_stack_headroom(current);
+#endif
schedule();
BUG();
/*
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/