Re: [PATCH] i386 No Idle Hz - aka Dynticks v051122-1

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Con,

I have a improved version of timertop and a C timertop user space
instead of perl, much improved. Tested against your last patch for
2.6.15-rc1.

The kernel patch I am sending in this email and the C utility I will
release very soon and post here. This new version of the patch is not
compatible with the perl script.

BTW I am testing the dyn-tick and it seems that the calculations get
much better this time around.

On 11/22/05, Con Kolivas <[email protected]> wrote:
> Here is an updated version of the dynticks patch for i386 built on 2.6.15-rc2.
>

Thanks for the support,

Daniel
--
INdT - Manaus - Brazil
diff -uprN linux-2.6.15-rc2-orig/kernel/Makefile linux-2.6.15-rc2-tt/kernel/Makefile
--- linux-2.6.15-rc2-orig/kernel/Makefile	2005-11-21 11:08:49.000000000 -0400
+++ linux-2.6.15-rc2-tt/kernel/Makefile	2005-11-21 13:21:44.000000000 -0400
@@ -32,7 +32,7 @@ obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
 obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
 obj-$(CONFIG_SECCOMP) += seccomp.o
 obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
-obj-$(CONFIG_NO_IDLE_HZ) += dyn-tick.o
+obj-$(CONFIG_NO_IDLE_HZ) += dyn-tick.o timer_top.o
 
 ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <[email protected]>, the -fno-omit-frame-pointer is
diff -uprN linux-2.6.15-rc2-orig/kernel/timer.c linux-2.6.15-rc2-tt/kernel/timer.c
--- linux-2.6.15-rc2-orig/kernel/timer.c	2005-11-21 11:08:50.000000000 -0400
+++ linux-2.6.15-rc2-tt/kernel/timer.c	2005-11-21 12:09:13.000000000 -0400
@@ -477,6 +477,10 @@ static inline void __run_timers(tvec_bas
 }
 
 #ifdef CONFIG_NO_IDLE_HZ
+extern struct timer_top_info top_info;
+extern int account_timer(unsigned long function,
+			 unsigned long data,
+	       		struct timer_top_info * top_info);
 /*
  * Find out when the next timer event is due to happen. This
  * is used on S/390 to stop all activity when a cpus is idle.
@@ -540,6 +544,7 @@ found:
 				expires = nte->expires;
 		}
 	}
+	account_timer((unsigned long)nte->function, nte->data, &top_info);
 	spin_unlock(&base->t_base.lock);
 	return expires;
 }
diff -uprN linux-2.6.15-rc2-orig/kernel/timer_top.c linux-2.6.15-rc2-tt/kernel/timer_top.c
--- linux-2.6.15-rc2-orig/kernel/timer_top.c	1969-12-31 20:00:00.000000000 -0400
+++ linux-2.6.15-rc2-tt/kernel/timer_top.c	2005-11-21 13:30:35.000000000 -0400
@@ -0,0 +1,207 @@
+/*
+ * kernel/timer_top.c
+ *
+ * Export Timers information to /proc/timer_info
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus
+ * Written by Daniel Petrini <[email protected]>
+ *
+ * This utility should be used to get information from the system timers
+ * and maybe optimize the system once you know which timers are being used
+ * and the process which starts them.
+ * This is particular useful above dynamic tick implementation. One can 
+ * see who is starting timers and make the HZ value increase.
+ *
+ * We export the addresses and counting of timer functions being called,
+ * the pid and cmdline from the owner process if applicable.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+
+#include <linux/list.h>
+#include <linux/proc_fs.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <asm/uaccess.h>
+
+#define VERSION		"Timer Top v0.9.5"
+
+static LIST_HEAD(timer_list);
+
+struct timer_top_info {
+	unsigned int		func_pointer;
+	unsigned long		counter;
+	pid_t			pid;
+	char 			comm[TASK_COMM_LEN];
+	struct list_head 	list;      	
+};
+
+struct timer_top_info top_info;
+
+static spinlock_t timer_lock = SPIN_LOCK_UNLOCKED;
+static unsigned long flags;
+static int start_flag = 0; 	/* signs if will collect data or not */
+
+int account_timer(unsigned long function, unsigned long data, struct timer_top_info * top_info)
+{
+	struct timer_top_info *top;
+	struct task_struct * task_info;
+	pid_t pid_info = 0;
+	char name[TASK_COMM_LEN] = "";
+	
+	if (start_flag == 0)
+		goto out;
+	
+	spin_lock_irqsave(&timer_lock, flags);
+
+	if (data) { 
+	       	task_info = (struct task_struct *) data;
+		/* little sanity ... not enough yet */
+		if ((task_info->pid > 0) && (task_info->pid < PID_MAX_LIMIT)) {
+			pid_info = task_info->pid;
+			strncpy(name, task_info->comm, sizeof(task_info->comm));
+		}
+	}
+	
+	list_for_each_entry(top, &timer_list, list) {
+		/* if it is in the list increment its count */
+		if (top->func_pointer == function && top->pid == pid_info) {
+			top->counter++;
+			//top->pid = pid_info;
+			//strncpy(top->comm, name, sizeof(name));
+			spin_unlock_irqrestore(&timer_lock, flags);
+			goto out;
+		}
+	}
+	
+	/* if you are here then it didnt find so inserts in the list */
+
+	top = kmalloc(sizeof(struct timer_top_info), GFP_ATOMIC);
+	if (!top) 
+		return -ENOMEM;
+	top->func_pointer = function;
+	top->counter = 1;
+	top->pid = pid_info;
+	strncpy(top->comm, name, sizeof(name));
+	list_add(&top->list, &timer_list);
+
+	spin_unlock_irqrestore(&timer_lock, flags);
+
+out:	
+	return 0;
+}
+
+EXPORT_SYMBOL(account_timer);
+
+int timer_list_del(void)
+{
+	struct list_head *aux1, *aux2;
+	struct timer_top_info *entry;
+
+	spin_lock_irqsave(&timer_lock, flags);
+	list_for_each_safe(aux1, aux2, &timer_list) {
+		entry = list_entry(aux1, struct timer_top_info, list);
+		//printk("Deleting: %d\n", entry->pid);
+		list_del(aux1);
+		kfree(entry);
+	}
+	spin_unlock_irqrestore(&timer_lock, flags);
+	return 0;
+}
+
+/* PROC_FS_SECTION  */
+
+static struct proc_dir_entry *top_info_file;
+static struct proc_dir_entry *top_info_file_out;
+
+static int proc_read_top_info(struct seq_file *m, void *v)
+{
+	struct timer_top_info *top;
+	
+	seq_printf(m, "Function counter - %s\n", VERSION);
+
+	list_for_each_entry(top, &timer_list, list) {
+		seq_printf(m, "%x %lu %d %s\n", top->func_pointer, top->counter, top->pid, top->comm);
+	}
+	
+	if (start_flag == 0) {
+		seq_printf(m, "Disabled\n");
+		//return 0;
+	}
+
+	return 0;
+} 
+
+static int proc_timertop_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, proc_read_top_info, NULL);
+}
+
+static struct file_operations proc_timertop_operations = {
+	.open		= proc_timertop_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+#define MAX_INPUT_TOP	10
+
+/* Receive some commands from user */
+static int proc_write_top_info(struct file *file, const char *page,
+                                 unsigned long count, void *data)
+{
+	int len;
+	char input_data[MAX_INPUT_TOP];
+
+	/* input size checking */
+	if(count > MAX_INPUT_TOP - 1)
+		len = MAX_INPUT_TOP - 1;
+	else
+		len = count;
+
+	if (copy_from_user(input_data, page, len)) 
+		return -EFAULT;
+
+	input_data[len] = '\0';
+
+	if(!strncmp(input_data, "clear", 5))
+		timer_list_del();
+	else if(!strncmp(input_data, "start", 5))
+		start_flag = 1;
+	else if(!strncmp(input_data, "stop", 4))
+		start_flag = 0;
+  
+	printk("\n %s", input_data);
+
+	return len;
+}
+
+static int __init init_top_info(void)
+{
+	top_info_file = create_proc_entry("timer_info", 0444, NULL);
+	if (top_info_file == NULL) {
+		return -ENOMEM;
+	}
+
+	top_info_file_out = create_proc_entry("timer_input", 0666, NULL);
+	if (top_info_file_out == NULL) {
+		return -ENOMEM;
+	}
+
+	/* Read support */
+	top_info_file->proc_fops = &proc_timertop_operations;
+	
+	/* Write support */	
+	top_info_file_out->write_proc = &proc_write_top_info;
+	top_info_file_out->owner = THIS_MODULE;
+	
+	return 0;
+}
+
+module_init(init_top_info);
+//module_exit();

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux