Messages in this thread Patch in this message | | | Subject | Detailed Stack Information Patch [2/3] | From | Stefani Seibold <> | Date | Tue, 20 Jan 2009 11:16:42 +0100 |
| |
diff -u -N -r linux-2.6.28.1.orig/fs/proc/Makefile linux-2.6.28.1/fs/proc/Makefile --- linux-2.6.28.1.orig/fs/proc/Makefile 2009-01-18 19:45:37.000000000 +0100 +++ linux-2.6.28.1/fs/proc/Makefile 2009-01-20 09:14:11.000000000 +0100 @@ -25,3 +25,4 @@ proc-$(CONFIG_PROC_DEVICETREE) += proc_devtree.o proc-$(CONFIG_PRINTK) += kmsg.o proc-$(CONFIG_PROC_PAGE_MONITOR) += page.o +proc-$(CONFIG_PROC_STACK_MONITOR) += stackmon.o diff -u -N -r linux-2.6.28.1.orig/fs/proc/stackmon.c linux-2.6.28.1/fs/proc/stackmon.c --- linux-2.6.28.1.orig/fs/proc/stackmon.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.28.1/fs/proc/stackmon.c 2009-01-20 09:13:19.000000000 +0100 @@ -0,0 +1,254 @@ +/* + * detailed stack monitoring + * + * Copyright (C) 2009 Stefani Seibold for NSN + * This Source is under GPL Licence + * + * enabled when CONFIG_PROC_STACK_MONITOR is set + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/proc_fs.h> +#include <linux/pagemap.h> +#include <linux/init.h> +#include <linux/stddef.h> +#include <linux/mutex.h> +#include <linux/kthread.h> +#include <linux/freezer.h> +#include <linux/seq_file.h> + +#define PROC_STACKMON "stackmon" + +#define BUF_SIZE 1024 + +static struct mutex lock; + +static struct proc_dir_entry *proc_ent; + +#ifdef CONFIG_STACK_GROWSUP +static inline unsigned long get_top(struct vm_area_struct *vma, + unsigned long end) +{ + unsigned long i; + struct page *page; + + for (i = vma->vm_end; i-PAGE_SIZE > end; i -= PAGE_SIZE) { + + page = follow_page(vma, i-PAGE_SIZE, 0); + + if ((!IS_ERR(page) == 0) || (page)) + break; + } + return (i-end)/PAGE_SIZE; +} +#else +static inline unsigned long get_top(struct vm_area_struct *vma, + unsigned long end) +{ + unsigned long i; + struct page *page; + + for (i = vma->vm_start; i+PAGE_SIZE <= end; i += PAGE_SIZE) { + + page = follow_page(vma, i, 0); + + if ((!IS_ERR(page) == 0) || (page)) + break; + } + return (end-i)/PAGE_SIZE; +} +#endif + +#ifdef CONFIG_STACK_GROWSUP +#define STACK_PAGE(x) (((x)+PAGE_SIZE-1)/PAGE_SIZE) +#else +#define STACK_PAGE(x) (((x)-PAGE_SIZE-1)/PAGE_SIZE) +#endif + +static inline int dump_usage(struct task_struct *t, char *buf) +{ + struct vm_area_struct *vma; + struct mm_struct *mm; + + *buf = 0; + + mm = get_task_mm(t); + + if (mm) { + vma = find_vma(mm, t->stack_start); + + if (vma) { + unsigned long esp; + unsigned long cur_stack; + unsigned long real_stack; + + esp = KSTK_ESP(t); + +#ifdef CONFIG_STACK_GROWSUP + cur_stack = esp-t->stack_start; + real_stack = + STACK_PAGE(esp)-STACK_PAGE(t->stack_start)+1; +#else + cur_stack = t->stack_start-esp; + real_stack = + STACK_PAGE(t->stack_start)-STACK_PAGE(esp)+1; +#endif + snprintf( + buf, + BUF_SIZE, + " %7lu %7lu %7lu %08lx-%08lx pid:%5d " + "tid:%5d %s\n", + cur_stack, + real_stack, + (real_stack+get_top(vma, esp)), + vma->vm_start, + vma->vm_end, + t->tgid, + t->pid, + t->comm + ); + } + mmput(mm); + } + return 0; +} + +static void *stackmon_find(loff_t pos, char *buf) +{ + struct task_struct *g; + struct task_struct *t; + + loff_t off = 0; + + read_lock(&tasklist_lock); + + do_each_thread(g, t) { + if (pos == off++) + goto found; + } while_each_thread(g, t); + + read_unlock(&tasklist_lock); + return 0; +found: + task_lock(t); + dump_usage(t, buf); + task_unlock(t); + read_unlock(&tasklist_lock); + return buf; +} + +static void *stackmon_seq_start(struct seq_file *s, loff_t *pos) +{ + if (*pos == 0) + return SEQ_START_TOKEN; + + return stackmon_find(*pos, s->private); +} + + +static void *stackmon_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + ++*pos; + + return stackmon_find(*pos, s->private); +} + +static int stackmon_seq_show(struct seq_file *s, void *v) +{ + if (v == SEQ_START_TOKEN) { + return seq_puts(s, + " bytes pages maxpages vm_start vm_end " + "processid threadid name\n"); + } + + return seq_puts(s, v); +} + +static void stackmon_seq_stop(struct seq_file *s, void *v) +{ +} + +static const struct seq_operations stackmon_seq_ops = { + .start = stackmon_seq_start, + .next = stackmon_seq_next, + .stop = stackmon_seq_stop, + .show = stackmon_seq_show +}; + +static int stackmon_open(struct inode *inode, struct file *file) +{ + int ret; + char *buffer; + struct seq_file *s; + + ret = -ENOMEM; + + buffer = kmalloc(BUF_SIZE, GFP_KERNEL); + if (!buffer) + goto out; + + ret = seq_open(file, &stackmon_seq_ops); + if (ret) + goto out_kfree; + + s = file->private_data; + s->private = buffer; + +out: + return ret; + +out_kfree: + kfree(buffer); + return ret; +} + +static const struct file_operations stackmon_file_ops = { + .owner = THIS_MODULE, + .open = stackmon_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private, +}; + +static int __init stackmon_init(void) +{ + int ret = 0; + + mutex_init(&lock); + + proc_ent = create_proc_entry(PROC_STACKMON, 0440, NULL); + + if (proc_ent == NULL) + goto exit; + + proc_ent->owner = THIS_MODULE; + proc_ent->data = NULL; + proc_ent->proc_fops = &stackmon_file_ops; + + return ret; + +exit: + return -ENOMEM; +} + +static void __exit stackmon_exit(void) +{ + mutex_lock(&lock); + remove_proc_entry(PROC_STACKMON, NULL); + mutex_unlock(&lock); +} + +module_init(stackmon_init); +module_exit(stackmon_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Stefani Seibold <stefani@seibold.net>"); +MODULE_DESCRIPTION("detailed stack monitoring"); + diff -u -N -r linux-2.6.28.1.orig/init/Kconfig linux-2.6.28.1/init/Kconfig --- linux-2.6.28.1.orig/init/Kconfig 2009-01-20 09:12:43.000000000 +0100 +++ linux-2.6.28.1/init/Kconfig 2009-01-20 09:13:19.000000000 +0100 @@ -826,6 +826,16 @@ Disabling these interfaces will reduce the size of the kernel by approximately 1kb. +config PROC_STACK_MONITOR + default y + depends on PROC_STACK + bool "Enable /proc/stackmon detailed stack monitoring" + help + This enables detailed monitoring of process and thread stack + utilization via the /proc/stackmon interface. + Disabling these interfaces will reduce the size of the kernel by + approximately 2kb. + endmenu # General setup config HAVE_GENERIC_DMA_COHERENT
| |