diff -Nru linux-2.5.1-pre11.vanilla/Makefile linux-2.5.1-pre11.ls/Makefile --- linux-2.5.1-pre11.vanilla/Makefile Thu Dec 13 11:05:02 2001 +++ linux-2.5.1-pre11.ls/Makefile Thu Dec 13 14:47:27 2001 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 5 SUBLEVEL = 1 -EXTRAVERSION =-pre11 +EXTRAVERSION = -pre11-ls KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff -Nru linux-2.5.1-pre11.vanilla/drivers/char/Makefile linux-2.5.1-pre11.ls/drivers/char/Makefile --- linux-2.5.1-pre11.vanilla/drivers/char/Makefile Sun Nov 11 10:09:32 2001 +++ linux-2.5.1-pre11.ls/drivers/char/Makefile Thu Dec 13 14:46:37 2001 @@ -16,7 +16,7 @@ O_TARGET := char.o -obj-y += mem.o tty_io.o n_tty.o tty_ioctl.o raw.o pty.o misc.o random.o +obj-y += mem.o tty_io.o n_tty.o tty_ioctl.o raw.o pty.o misc.o random.o latsched.o # All of the (potential) objects that export symbols. # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. diff -Nru linux-2.5.1-pre11.vanilla/drivers/char/latsched.c linux-2.5.1-pre11.ls/drivers/char/latsched.c --- linux-2.5.1-pre11.vanilla/drivers/char/latsched.c Wed Dec 31 16:00:00 1969 +++ linux-2.5.1-pre11.ls/drivers/char/latsched.c Thu Dec 13 14:46:37 2001 @@ -0,0 +1,176 @@ +/* + * linux/kernel/latsched.c + * + * Kernel scheduler latency tester + * + * Copyright (C) 2001, Davide Libenzi + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + + + + +#define DEBUG 0 +#ifdef DEBUG +#define DPRINTK(x) printk x +#define DNPRINTK(n,x) if (n <= DEBUG) printk x +#else +#define DPRINTK(x) +#define DNPRINTK(n,x) +#endif + + + +struct latsched { + +}; + + + +static int open_latsched(struct inode *inode, struct file *file); +static int close_latsched(struct inode *inode, struct file *file); +static int ioctl_latsched(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); + + +static struct file_operations latsched_fops = { + ioctl: ioctl_latsched, + open: open_latsched, + release: close_latsched +}; + +static struct miscdevice latsched = { + LATSCHED_MINOR, "latsched", &latsched_fops +}; + + + + + + + +static int open_latsched(struct inode *inode, struct file *file) +{ + int res; + struct latsched *ls; + + if (!(ls = kmalloc(sizeof(struct latsched), GFP_KERNEL))) + return -ENOMEM; + + memset(ls, 0, sizeof(*ls)); + + + file->private_data = ls; + + MOD_INC_USE_COUNT; + + DNPRINTK(3, (KERN_INFO "[%p] /dev/latsched: open() ls=%p\n", current, ls)); + return 0; +} + + +static int close_latsched(struct inode *inode, struct file *file) +{ + struct latsched *ls = (struct latsched *) file->private_data; + + kfree(ls); + + MOD_DEC_USE_COUNT; + + DNPRINTK(3, (KERN_INFO "[%p] /dev/latsched: close() ls=%p\n", current, ls)); + return 0; +} + + +static int ioctl_latsched(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int res; + struct latsched *ls = (struct latsched *) file->private_data; + struct lsctl_getdata lsgd; + + switch (cmd) { + case LS_START: + res = latsched_start(1); + + DNPRINTK(3, (KERN_INFO "[%p] /dev/latsched: ioctl(%p, LS_START) == %d\n", + current, ls, res)); + return res; + + case LS_STOP: + res = latsched_start(0); + + DNPRINTK(3, (KERN_INFO "[%p] /dev/latsched: ioctl(%p, LS_STOP) == %d\n", + current, ls, res)); + return res; + + case LS_FETCH: + if ((res = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct lsctl_getdata)))) + return res; + __copy_from_user(&lsgd, (void *) arg, sizeof(struct lsctl_getdata)); + if ((res = verify_area(VERIFY_WRITE, (void *) lsgd.data, lsgd.size * sizeof(struct latsched_sample)))) + return res; + + if (!(res = latsched_getdata(&lsgd))) + __copy_to_user((void *) arg, &lsgd, sizeof(struct lsctl_getdata)); + + DNPRINTK(3, (KERN_INFO "[%p] /dev/latsched: ioctl(%p, LS_FETCH, %d) == %d\n", + current, ls, lsgd.cpu, res)); + return res; + + case LS_SAMPLES: + res = latsched_setsamples((int) arg); + + DNPRINTK(3, (KERN_INFO "[%p] /dev/latsched: ioctl(%p, LS_SAMPLES, %lu) == %d\n", + current, ls, arg, res)); + return res; + } + + return -EINVAL; +} + + + + +int __init init_latsched(void) +{ + + misc_register(&latsched); + + printk(KERN_INFO "[%p] /dev/latsched: driver installed.\n", current); + + return 0; +} + + +module_init(init_latsched); + diff -Nru linux-2.5.1-pre11.vanilla/include/linux/latsched.h linux-2.5.1-pre11.ls/include/linux/latsched.h --- linux-2.5.1-pre11.vanilla/include/linux/latsched.h Wed Dec 31 16:00:00 1969 +++ linux-2.5.1-pre11.ls/include/linux/latsched.h Sun Dec 16 14:47:44 2001 @@ -0,0 +1,41 @@ +/* + * linux/include/linux/latsched.h + * + * Kernel scheduler latency tester + * + * Copyright (C) 2001, Davide Libenzi + * + */ + +#ifndef _LINUX_LATSCHED_H +#define _LINUX_LATSCHED_H + +#include + +#define LATSCHED_MINOR 117 +#define STD_LATSCHED_SAMPLES 1024 + +struct latsched_sample { + cycles_t lss_in, lss_out; + pid_t lss_pid; +}; +struct latsched_data { + struct latsched_sample *ls_data; + int ls_size; + int ls_curr; +}; +struct lsctl_getdata { + int cpu; + int size; + struct latsched_sample *data; + int rsize; +}; + +#define LS_START _IO('P', 1) +#define LS_STOP _IO('P', 2) +#define LS_FETCH _IOWR('P', 3, struct lsctl_getdata) +#define LS_SAMPLES _IOR('P', 4, int) + + +#endif /* #ifndef _LINUX_LATSCHED_H */ + diff -Nru linux-2.5.1-pre11.vanilla/include/linux/sched.h linux-2.5.1-pre11.ls/include/linux/sched.h --- linux-2.5.1-pre11.vanilla/include/linux/sched.h Thu Dec 13 14:28:40 2001 +++ linux-2.5.1-pre11.ls/include/linux/sched.h Sun Dec 16 14:47:44 2001 @@ -25,6 +25,7 @@ #include #include #include +#include struct exec_domain; @@ -141,6 +142,10 @@ extern spinlock_t runqueue_lock; extern spinlock_t mmlist_lock; +extern void latsched_init(void); +extern int latsched_start(int on); +extern int latsched_setsamples(int nsamps); +extern int latsched_getdata(struct lsctl_getdata *lsgd); extern void sched_init(void); extern void init_idle(void); extern void show_state(void); diff -Nru linux-2.5.1-pre11.vanilla/init/main.c linux-2.5.1-pre11.ls/init/main.c --- linux-2.5.1-pre11.vanilla/init/main.c Thu Dec 13 11:05:12 2001 +++ linux-2.5.1-pre11.ls/init/main.c Thu Dec 13 14:46:37 2001 @@ -427,6 +427,7 @@ * make syscalls (and thus be locked). */ smp_init(); + latsched_init(); rest_init(); } diff -Nru linux-2.5.1-pre11.vanilla/kernel/sched.c linux-2.5.1-pre11.ls/kernel/sched.c --- linux-2.5.1-pre11.vanilla/kernel/sched.c Wed Nov 21 16:25:48 2001 +++ linux-2.5.1-pre11.ls/kernel/sched.c Sun Dec 16 14:44:22 2001 @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include @@ -531,7 +533,7 @@ * tasks can run. It can not be killed, and it cannot sleep. The 'state' * information in task[0] is never used. */ -asmlinkage void schedule(void) +static inline void __schedule(void) { struct schedule_data * sched_data; struct task_struct *prev, *next, *p; @@ -1327,3 +1329,164 @@ atomic_inc(&init_mm.mm_count); enter_lazy_tlb(&init_mm, current, cpu); } + + + +#ifdef CONFIG_SMP + +#define latsched_data(cpu) lss[(cpu)].ls_data +#define latsched_samp(cpu, idx) lss[(cpu)].ls_data[(idx)] +#define latsched_size(cpu) lss[(cpu)].ls_size +#define latsched_curr(cpu) lss[(cpu)].ls_curr + +#else /* #ifdef CONFIG_SMP */ + +#define latsched_data(cpu) lss[0].ls_data +#define latsched_samp(cpu, idx) lss[0].ls_data[(idx)] +#define latsched_size(cpu) lss[0].ls_size +#define latsched_curr(cpu) lss[0].ls_curr + +#endif /* #ifdef CONFIG_SMP */ + +static struct latsched_data lss[NR_CPUS] __cacheline_aligned; +static atomic_t lss_enabled = ATOMIC_INIT(0); + + +void __init latsched_init(void) +{ + int ii, size; + + size = STD_LATSCHED_SAMPLES; + for (ii = 0; ii < smp_num_cpus; ii++) { + if ((latsched_data(ii) = kmalloc(size * sizeof(struct latsched_sample), GFP_KERNEL))) + memset(latsched_data(ii), 0, size * sizeof(struct latsched_sample)); + latsched_size(ii) = size; + latsched_curr(ii) = 0; + } +} + + +asmlinkage void schedule(void) +{ + int this_cpu; + unsigned long flags; + cycles_t cycls; + + if (atomic_read(&lss_enabled)) { + local_irq_save(flags); + this_cpu = current->processor; + latsched_samp(this_cpu, latsched_curr(this_cpu)).lss_pid = -1; + latsched_samp(this_cpu, latsched_curr(this_cpu)).lss_in = get_cycles(); + local_irq_restore(flags); + } + + __schedule(); + + cycls = get_cycles(); + if (atomic_read(&lss_enabled)) { + local_irq_save(flags); + this_cpu = current->processor; + if (latsched_samp(this_cpu, latsched_curr(this_cpu)).lss_pid == -1) { + latsched_samp(this_cpu, latsched_curr(this_cpu)).lss_out = cycls; + latsched_samp(this_cpu, latsched_curr(this_cpu)).lss_pid = current->pid; + if (++latsched_curr(this_cpu) >= latsched_size(this_cpu)) + latsched_curr(this_cpu) = 0; + } + local_irq_restore(flags); + } +} + + +int latsched_start(int on) +{ + int res; + + cli(); + if (on) { + if (!atomic_read(&lss_enabled)) { + int ii; + + for (ii = 0; ii < smp_num_cpus; ii++) { + res = -ENOMEM; + if (!latsched_data(ii) && + !(latsched_data(ii) = kmalloc(latsched_size(ii) * sizeof(struct latsched_sample), GFP_KERNEL))) + goto out; + memset(latsched_data(ii), 0, latsched_size(ii) * sizeof(struct latsched_sample)); + latsched_curr(ii) = 0; + } + atomic_set(&lss_enabled, 1); + } + } else + atomic_set(&lss_enabled, 0); + res = 0; +out: + sti(); + return res; +} + + +int latsched_setsamples(int nsamps) +{ + int ii, res, size = nsamps; + + cli(); + res = -EBUSY; + if (atomic_read(&lss_enabled)) + goto out; + for (ii = 0; ii < smp_num_cpus; ii++) { + if (latsched_data(ii)) + kfree(latsched_data(ii)); + res = -ENOMEM; + if (!(latsched_data(ii) = kmalloc(size * sizeof(struct latsched_sample), GFP_KERNEL))) + goto out; + memset(latsched_data(ii), 0, size * sizeof(struct latsched_sample)); + latsched_size(ii) = size; + latsched_curr(ii) = 0; + } + res = 0; +out: + sti(); + return res; +} + + +int latsched_getdata(struct lsctl_getdata *lsgd) +{ + int res; + + cli(); + res = -EBUSY; + if (atomic_read(&lss_enabled)) + goto out; + res = -EINVAL; + if (lsgd->cpu < 0 || lsgd->cpu >= smp_num_cpus) + goto out; + if (latsched_samp(lsgd->cpu, latsched_size(lsgd->cpu) - 1).lss_pid != 0) { + int size, csize; + struct latsched_sample *data = lsgd->data; + + lsgd->rsize = size = latsched_size(lsgd->cpu); + if (lsgd->rsize > lsgd->size) + lsgd->rsize = size = lsgd->size; + csize = latsched_size(lsgd->cpu) - latsched_curr(lsgd->cpu); + if (csize > size) + csize = size; + if (csize) + __copy_to_user(data, &latsched_samp(lsgd->cpu, latsched_curr(lsgd->cpu)), + csize * sizeof(struct latsched_sample)); + data += csize; + size -= csize; + if (size) + __copy_to_user(data, &latsched_samp(lsgd->cpu, 0), + size * sizeof(struct latsched_sample)); + } else { + lsgd->rsize = latsched_curr(lsgd->cpu); + __copy_to_user(lsgd->data, &latsched_samp(lsgd->cpu, 0), + lsgd->rsize * sizeof(struct latsched_sample)); + } + res = 0; +out: + sti(); + return res; +} +