Skip to contentSkip to conversation

2.4: variable HZ

PATCH In review Robert Love 3 participants 5 messages Oct 15, 2002 – Oct 18, 2002

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 2.4: variable HZ

I backported the jiffies_to_clock_t() code from 2.5 to 2.4, mostly just for fun.

It works fine, and I have successfully used HZ=1000 on my machines. It is the same API as 2.5, used in the same places - we export a static HZ=100 to user-space and convert from the real HZ as needed. The only difference is I added a CONFIG_HZ to allow the user to set the value.

There are probably some HZ values you cannot use due to NTP issues. I suggest HZ=1000, since I know that works, and 2.5 is using it. RedHat is supposedly shipping their kernel with HZ=512 but I do not know if they did anything else special.

Oh, and I did not backport 64-bit jiffies yet. So HZ=1000 will wrap around in just under 50 days. If you just cannot have that, stick with a lower value.

Patch is against 2.4.20-pre10-ac2 but applies OK to all 2.4.20-pre and 2.4.19 kernels.

Enjoy,

Robert Love

arch/i386/config.in +1 -0
diff -urN linux-2.4.20-pre10-ac2/arch/i386/config.in linux/arch/i386/config.in
@@ -244,6 +244,7 @@
 mainmenu_option next_comment
 comment 'General setup'
 
+int 'Timer frequency (HZ) (100)' CONFIG_HZ 100
 bool 'Networking support' CONFIG_NET
 
 # Visual Workstation support is utterly broken.
Documentation/Configure.help +12 -0
diff -urN linux-2.4.20-pre10-ac2/Documentation/Configure.help linux/Documentation/Configure.help
@@ -2411,6 +2411,18 @@
   behaviour is platform-dependent, but normally the flash frequency is
   a hyperbolic function of the 5-minute load average.
 
+Timer frequency
+CONFIG_HZ
+  The frequency the system timer interrupt pops.  Higher tick values provide
+  improved granularity of timers, improved select() and poll() performance,
+  and lower scheduling latency.  Higher values, however, increase interrupt
+  overhead and will allow jiffie wraparound sooner.  For compatibility, the
+  tick count is always exported as if HZ=100.
+
+  The default value, which was the value for all of eternity, is 100.  If
+  you are looking to provide better timer granularity or increased desktop
+  performance, try 500 or 1000.  In unsure, go with the default of 100.
+
 Networking support
 CONFIG_NET
   Unless you really know what you are doing, you should say Y here.
fs/proc/array.c +10 -10
diff -urN linux-2.4.20-pre10-ac2/fs/proc/array.c linux/fs/proc/array.c
@@ -360,15 +360,15 @@
 		task->cmin_flt,
 		task->maj_flt,
 		task->cmaj_flt,
-		task->times.tms_utime,
-		task->times.tms_stime,
-		task->times.tms_cutime,
-		task->times.tms_cstime,
+		jiffies_to_clock_t(task->times.tms_utime),
+		jiffies_to_clock_t(task->times.tms_stime),
+		jiffies_to_clock_t(task->times.tms_cutime),
+		jiffies_to_clock_t(task->times.tms_cstime),
 		priority,
 		nice,
 		0UL /* removed */,
-		task->it_real_value,
-		task->start_time,
+		jiffies_to_clock_t(task->it_real_value),
+		jiffies_to_clock_t(task->start_time),
 		vsize,
 		mm ? mm->rss : 0, /* you might want to shift this left 3 */
 		task->rlim[RLIMIT_RSS].rlim_cur,
@@ -686,14 +686,14 @@
 
 	len = sprintf(buffer,
 		"cpu  %lu %lu\n",
-		task->times.tms_utime,
-		task->times.tms_stime);
+		jiffies_to_clock_t(task->times.tms_utime),
+		jiffies_to_clock_t(task->times.tms_stime));
 		
 	for (i = 0 ; i < smp_num_cpus; i++)
 		len += sprintf(buffer + len, "cpu%d %lu %lu\n",
 			i,
-			task->per_cpu_utime[cpu_logical_map(i)],
-			task->per_cpu_stime[cpu_logical_map(i)]);
+			jiffies_to_clock_t(task->per_cpu_utime[cpu_logical_map(i)]),
+			jiffies_to_clock_t(task->per_cpu_stime[cpu_logical_map(i)]));
 
 	return len;
 }
fs/proc/proc_misc.c +9 -6
diff -urN linux-2.4.20-pre10-ac2/fs/proc/proc_misc.c linux/fs/proc/proc_misc.c
@@ -317,7 +317,7 @@
 {
 	int i, len = 0;
 	extern unsigned long total_forks;
-	unsigned long jif = jiffies;
+	unsigned long jif = jiffies_to_clock_t(jiffies);
 	unsigned int sum = 0, user = 0, nice = 0, system = 0;
 	int major, disk;
 
@@ -334,16 +334,19 @@
 	}
 
 	proc_sprintf(page, &off, &len,
-		      "cpu  %u %u %u %lu\n", user, nice, system,
+		      "cpu  %u %u %u %lu\n",
+		      jiffies_to_clock_t(user),
+		      jiffies_to_clock_t(nice),
+		      jiffies_to_clock_t(system),
 		      jif * smp_num_cpus - (user + nice + system));
 	for (i = 0 ; i < smp_num_cpus; i++)
 		proc_sprintf(page, &off, &len,
 			"cpu%d %u %u %u %lu\n",
 			i,
-			kstat.per_cpu_user[cpu_logical_map(i)],
-			kstat.per_cpu_nice[cpu_logical_map(i)],
-			kstat.per_cpu_system[cpu_logical_map(i)],
-			jif - (  kstat.per_cpu_user[cpu_logical_map(i)] \
+			jiffies_to_clock_t(kstat.per_cpu_user[cpu_logical_map(i)]),
+			jiffies_to_clock_t(kstat.per_cpu_nice[cpu_logical_map(i)]),
+			jiffies_to_clock_t(kstat.per_cpu_system[cpu_logical_map(i)]),
+			jif - jiffies_to_clock_t(kstat.per_cpu_user[cpu_logical_map(i)] \
 				   + kstat.per_cpu_nice[cpu_logical_map(i)] \
 				   + kstat.per_cpu_system[cpu_logical_map(i)]));
 	proc_sprintf(page, &off, &len,
include/asm-i386/param.h +10 -5
diff -urN linux-2.4.20-pre10-ac2/include/asm-i386/param.h linux/include/asm-i386/param.h
@@ -1,8 +1,17 @@
 #ifndef _ASMi386_PARAM_H
 #define _ASMi386_PARAM_H
 
+#include <linux/config.h>
+
+#ifdef __KERNEL__
+# define HZ		CONFIG_HZ	/* internal kernel timer frequency */
+# define USER_HZ	100		/* some user interfaces are in ticks */
+# define CLOCKS_PER_SEC	(USER_HZ)	/* like times() */
+# define jiffies_to_clock_t(x)	((x) / ((HZ) / (USER_HZ)))
+#endif
+
 #ifndef HZ
-#define HZ 100
+#define HZ 100				/* if userspace cheats, give them 100 */
 #endif
 
 #define EXEC_PAGESIZE	4096
@@ -17,8 +26,4 @@
 
 #define MAXHOSTNAMELEN	64	/* max length of hostname */
 
-#ifdef __KERNEL__
-# define CLOCKS_PER_SEC	100	/* frequency at which times() counts */
-#endif
-
 #endif
kernel/signal.c +3 -3
diff -urN linux-2.4.20-pre10-ac2/kernel/signal.c linux/kernel/signal.c
@@ -13,7 +13,7 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/sched.h>
-
+#include <asm/param.h>
 #include <asm/uaccess.h>
 
 /*
@@ -775,8 +775,8 @@
 	info.si_uid = tsk->uid;
 
 	/* FIXME: find out whether or not this is supposed to be c*time. */
-	info.si_utime = tsk->times.tms_utime;
-	info.si_stime = tsk->times.tms_stime;
+	info.si_utime = jiffies_to_clock_t(tsk->times.tms_utime);
+	info.si_stime = jiffies_to_clock_t(tsk->times.tms_stime);
 
 	status = tsk->exit_code & 0x7f;
 	why = SI_KERNEL;	/* shouldn't happen */
kernel/sys.c +11 -4
diff -urN linux-2.4.20-pre10-ac2/kernel/sys.c linux/kernel/sys.c
@@ -15,7 +15,7 @@
 #include <linux/prctl.h>
 #include <linux/init.h>
 #include <linux/highuid.h>
-
+#include <asm/param.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
@@ -792,16 +792,23 @@
 
 asmlinkage long sys_times(struct tms * tbuf)
 {
+	struct tms temp;
+
 	/*
 	 *	In the SMP world we might just be unlucky and have one of
 	 *	the times increment as we use it. Since the value is an
 	 *	atomically safe type this is just fine. Conceptually its
 	 *	as if the syscall took an instant longer to occur.
 	 */
-	if (tbuf)
-		if (copy_to_user(tbuf, &current->times, sizeof(struct tms)))
+	if (tbuf) {
+		temp.tms_utime = jiffies_to_clock_t(current->times.tms_utime);
+		temp.tms_stime = jiffies_to_clock_t(current->times.tms_stime);
+		temp.tms_cutime = jiffies_to_clock_t(current->times.tms_cutime);
+		temp.tms_cstime = jiffies_to_clock_t(current->times.tms_cstime);
+		if (copy_to_user(tbuf, &temp, sizeof(struct tms)))
 			return -EFAULT;
-	return jiffies;
+	}
+	return jiffies_to_clock_t(jiffies);
 }
 
 /*
#1 lore raw
Quoted 1 line · Robert Love

It works fine, and I have successfully used HZ=1000 on my machines.

Except processor usage output was screwy.

Attached is an updated patch which fixes the problem.

Robert Love

arch/i386/config.in +1 -0
diff -urN linux-2.4.20-pre10-ac2/arch/i386/config.in linux/arch/i386/config.in
@@ -244,6 +244,7 @@
 mainmenu_option next_comment
 comment 'General setup'
 
+int 'Timer frequency (HZ) (100)' CONFIG_HZ 100
 bool 'Networking support' CONFIG_NET
 
 # Visual Workstation support is utterly broken.
Documentation/Configure.help +12 -0
diff -urN linux-2.4.20-pre10-ac2/Documentation/Configure.help linux/Documentation/Configure.help
@@ -2411,6 +2411,18 @@
   behaviour is platform-dependent, but normally the flash frequency is
   a hyperbolic function of the 5-minute load average.
 
+Timer frequency
+CONFIG_HZ
+  The frequency the system timer interrupt pops.  Higher tick values provide
+  improved granularity of timers, improved select() and poll() performance,
+  and lower scheduling latency.  Higher values, however, increase interrupt
+  overhead and will allow jiffie wraparound sooner.  For compatibility, the
+  tick count is always exported as if HZ=100.
+
+  The default value, which was the value for all of eternity, is 100.  If
+  you are looking to provide better timer granularity or increased desktop
+  performance, try 500 or 1000.  In unsure, go with the default of 100.
+
 Networking support
 CONFIG_NET
   Unless you really know what you are doing, you should say Y here.
fs/proc/array.c +10 -10
diff -urN linux-2.4.20-pre10-ac2/fs/proc/array.c linux/fs/proc/array.c
@@ -360,15 +360,15 @@
 		task->cmin_flt,
 		task->maj_flt,
 		task->cmaj_flt,
-		task->times.tms_utime,
-		task->times.tms_stime,
-		task->times.tms_cutime,
-		task->times.tms_cstime,
+		jiffies_to_clock_t(task->times.tms_utime),
+		jiffies_to_clock_t(task->times.tms_stime),
+		jiffies_to_clock_t(task->times.tms_cutime),
+		jiffies_to_clock_t(task->times.tms_cstime),
 		priority,
 		nice,
 		0UL /* removed */,
-		task->it_real_value,
-		task->start_time,
+		jiffies_to_clock_t(task->it_real_value),
+		jiffies_to_clock_t(task->start_time),
 		vsize,
 		mm ? mm->rss : 0, /* you might want to shift this left 3 */
 		task->rlim[RLIMIT_RSS].rlim_cur,
@@ -686,14 +686,14 @@
 
 	len = sprintf(buffer,
 		"cpu  %lu %lu\n",
-		task->times.tms_utime,
-		task->times.tms_stime);
+		jiffies_to_clock_t(task->times.tms_utime),
+		jiffies_to_clock_t(task->times.tms_stime));
 		
 	for (i = 0 ; i < smp_num_cpus; i++)
 		len += sprintf(buffer + len, "cpu%d %lu %lu\n",
 			i,
-			task->per_cpu_utime[cpu_logical_map(i)],
-			task->per_cpu_stime[cpu_logical_map(i)]);
+			jiffies_to_clock_t(task->per_cpu_utime[cpu_logical_map(i)]),
+			jiffies_to_clock_t(task->per_cpu_stime[cpu_logical_map(i)]));
 
 	return len;
 }
fs/proc/proc_misc.c +8 -8
diff -urN linux-2.4.20-pre10-ac2/fs/proc/proc_misc.c linux/fs/proc/proc_misc.c
@@ -317,16 +317,16 @@
 {
 	int i, len = 0;
 	extern unsigned long total_forks;
-	unsigned long jif = jiffies;
+	unsigned long jif = jiffies_to_clock_t(jiffies);
 	unsigned int sum = 0, user = 0, nice = 0, system = 0;
 	int major, disk;
 
 	for (i = 0 ; i < smp_num_cpus; i++) {
 		int cpu = cpu_logical_map(i), j;
 
-		user += kstat.per_cpu_user[cpu];
-		nice += kstat.per_cpu_nice[cpu];
-		system += kstat.per_cpu_system[cpu];
+		user += jiffies_to_clock_t(kstat.per_cpu_user[cpu]);
+		nice += jiffies_to_clock_t(kstat.per_cpu_nice[cpu]);
+		system += jiffies_to_clock_t(kstat.per_cpu_system[cpu]);
 #if !defined(CONFIG_ARCH_S390)
 		for (j = 0 ; j < NR_IRQS ; j++)
 			sum += kstat.irqs[cpu][j];
@@ -340,10 +340,10 @@
 		proc_sprintf(page, &off, &len,
 			"cpu%d %u %u %u %lu\n",
 			i,
-			kstat.per_cpu_user[cpu_logical_map(i)],
-			kstat.per_cpu_nice[cpu_logical_map(i)],
-			kstat.per_cpu_system[cpu_logical_map(i)],
-			jif - (  kstat.per_cpu_user[cpu_logical_map(i)] \
+			jiffies_to_clock_t(kstat.per_cpu_user[cpu_logical_map(i)]),
+			jiffies_to_clock_t(kstat.per_cpu_nice[cpu_logical_map(i)]),
+			jiffies_to_clock_t(kstat.per_cpu_system[cpu_logical_map(i)]),
+			jif - jiffies_to_clock_t(kstat.per_cpu_user[cpu_logical_map(i)] \
 				   + kstat.per_cpu_nice[cpu_logical_map(i)] \
 				   + kstat.per_cpu_system[cpu_logical_map(i)]));
 	proc_sprintf(page, &off, &len,
include/asm-i386/param.h +10 -5
diff -urN linux-2.4.20-pre10-ac2/include/asm-i386/param.h linux/include/asm-i386/param.h
@@ -1,8 +1,17 @@
 #ifndef _ASMi386_PARAM_H
 #define _ASMi386_PARAM_H
 
+#include <linux/config.h>
+
+#ifdef __KERNEL__
+# define HZ		CONFIG_HZ	/* internal kernel timer frequency */
+# define USER_HZ	100		/* some user interfaces are in ticks */
+# define CLOCKS_PER_SEC	(USER_HZ)	/* like times() */
+# define jiffies_to_clock_t(x)	((x) / ((HZ) / (USER_HZ)))
+#endif
+
 #ifndef HZ
-#define HZ 100
+#define HZ 100				/* if userspace cheats, give them 100 */
 #endif
 
 #define EXEC_PAGESIZE	4096
@@ -17,8 +26,4 @@
 
 #define MAXHOSTNAMELEN	64	/* max length of hostname */
 
-#ifdef __KERNEL__
-# define CLOCKS_PER_SEC	100	/* frequency at which times() counts */
-#endif
-
 #endif
kernel/signal.c +3 -3
diff -urN linux-2.4.20-pre10-ac2/kernel/signal.c linux/kernel/signal.c
@@ -13,7 +13,7 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/sched.h>
-
+#include <asm/param.h>
 #include <asm/uaccess.h>
 
 /*
@@ -775,8 +775,8 @@
 	info.si_uid = tsk->uid;
 
 	/* FIXME: find out whether or not this is supposed to be c*time. */
-	info.si_utime = tsk->times.tms_utime;
-	info.si_stime = tsk->times.tms_stime;
+	info.si_utime = jiffies_to_clock_t(tsk->times.tms_utime);
+	info.si_stime = jiffies_to_clock_t(tsk->times.tms_stime);
 
 	status = tsk->exit_code & 0x7f;
 	why = SI_KERNEL;	/* shouldn't happen */
kernel/sys.c +11 -4
diff -urN linux-2.4.20-pre10-ac2/kernel/sys.c linux/kernel/sys.c
@@ -15,7 +15,7 @@
 #include <linux/prctl.h>
 #include <linux/init.h>
 #include <linux/highuid.h>
-
+#include <asm/param.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
@@ -792,16 +792,23 @@
 
 asmlinkage long sys_times(struct tms * tbuf)
 {
+	struct tms temp;
+
 	/*
 	 *	In the SMP world we might just be unlucky and have one of
 	 *	the times increment as we use it. Since the value is an
 	 *	atomically safe type this is just fine. Conceptually its
 	 *	as if the syscall took an instant longer to occur.
 	 */
-	if (tbuf)
-		if (copy_to_user(tbuf, &current->times, sizeof(struct tms)))
+	if (tbuf) {
+		temp.tms_utime = jiffies_to_clock_t(current->times.tms_utime);
+		temp.tms_stime = jiffies_to_clock_t(current->times.tms_stime);
+		temp.tms_cutime = jiffies_to_clock_t(current->times.tms_cutime);
+		temp.tms_cstime = jiffies_to_clock_t(current->times.tms_cstime);
+		if (copy_to_user(tbuf, &temp, sizeof(struct tms)))
 			return -EFAULT;
-	return jiffies;
+	}
+	return jiffies_to_clock_t(jiffies);
 }
 
 /*
#2 lore raw

Re: [PATCH] 2.4: variable HZ (broken?)

Quoted 5 lines · Robert Love
Quoted 1 line · Robert Love

It works fine, and I have successfully used HZ=1000 on my machines.

Except processor usage output was screwy.

and except that it somehow breaks compiling serial.c?

gcc -D__KERNEL__ -I/usr/src/prontux-0.1.9/include -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fno-strict-aliasing -fno-common -fomit-frame-pointer
-pipe -mpreferred-stack-boundary=2 -march=i586 -nostdinc -iwithprefix
include -DKBUILD_BASENAME=serial -c -o serial.o serial.c serial.c:231:27: serial_compat.h: No such file or directory serial.c: In function `receive_chars':
serial.c:677: warning: implicit declaration of function `queue_task_irq_off' serial.c: At top level:
serial.c:1591: warning: static declaration for `tty_get_baud_rate' follows non-static
serial.c: In function `rs_write':
serial.c:1879: warning: implicit declaration of function copy_from_user' serial.c: In function get_serial_info':
serial.c:2077: warning: implicit declaration of function copy_to_user' serial.c: In function send_break':
serial.c:2391: structure has no member named `timeout' serial.c:3843:32: linux/symtab_begin.h: No such file or directory serial.c:3846:30: linux/symtab_end.h: No such file or directory serial.c: At top level:
serial.c:3842: variable serial_syms' has initializer but incomplete type serial.c:3844: warning: implicit declaration of function X' serial.c:3844: warning: excess elements in struct initializer serial.c:3844: warning: (near initialization for serial_syms') serial.c:3845: warning: excess elements in struct initializer serial.c:3845: warning: (near initialization for serial_syms') serial.c:3331: warning: rs_read_proc' defined but not used serial.c:3842: warning: serial_syms' defined but not used make[3]: *** [serial.o] Error 1
make[3]: Leaving directory `/usr/src/prontux-0.1.9/drivers/char' make[2]: *** [first_rule] Error 2
make[2]: Leaving directory `/usr/src/prontux-0.1.9/drivers/char' make[1]: *** [_subdir_char] Error 2
make[1]: Leaving directory `/usr/src/prontux-0.1.9/drivers'
make: *** [_dir_drivers] Error 2

Signature · 6 lines
Roy Sigurd Karlsbakk, Datavaktmester
ProntoTV AS - http://www.pronto.tv/
Tel: +47 9801 3356

Computers are like air conditioners.
They stop working when you open Windows.
#3 lore raw

Re: [PATCH] 2.4: variable HZ (not broken. My fault)

sorry
this was my fault
was playing around with version numbers

Quoted 42 lines · Roy Sigurd Karlsbakk
Quoted 4 lines · Robert Love
Quoted 1 line · Robert Love

It works fine, and I have successfully used HZ=1000 on my machines.

Except processor usage output was screwy.

and except that it somehow breaks compiling serial.c?

gcc -D__KERNEL__ -I/usr/src/prontux-0.1.9/include -Wall -Wstrict-prototypes

(quoted diff) +0 -2
-Wno-trigraphs -O2 -fno-strict-aliasing -fno-common -fomit-frame-pointer
-pipe -mpreferred-stack-boundary=2 -march=i586   -nostdinc -iwithprefix

include -DKBUILD_BASENAME=serial -c -o serial.o serial.c serial.c:231:27: serial_compat.h: No such file or directory serial.c: In function `receive_chars':
serial.c:677: warning: implicit declaration of function `queue_task_irq_off' serial.c: At top level:
serial.c:1591: warning: static declaration for `tty_get_baud_rate' follows non-static
serial.c: In function `rs_write':
serial.c:1879: warning: implicit declaration of function copy_from_user' serial.c: In function get_serial_info':
serial.c:2077: warning: implicit declaration of function copy_to_user' serial.c: In function send_break':
serial.c:2391: structure has no member named `timeout' serial.c:3843:32: linux/symtab_begin.h: No such file or directory serial.c:3846:30: linux/symtab_end.h: No such file or directory serial.c: At top level:
serial.c:3842: variable serial_syms' has initializer but incomplete type serial.c:3844: warning: implicit declaration of function X' serial.c:3844: warning: excess elements in struct initializer serial.c:3844: warning: (near initialization for serial_syms') serial.c:3845: warning: excess elements in struct initializer serial.c:3845: warning: (near initialization for serial_syms') serial.c:3331: warning: rs_read_proc' defined but not used serial.c:3842: warning: serial_syms' defined but not used make[3]: *** [serial.o] Error 1
make[3]: Leaving directory `/usr/src/prontux-0.1.9/drivers/char' make[2]: *** [first_rule] Error 2
make[2]: Leaving directory `/usr/src/prontux-0.1.9/drivers/char' make[1]: *** [_subdir_char] Error 2
make[1]: Leaving directory `/usr/src/prontux-0.1.9/drivers'
make: *** [_dir_drivers] Error 2

Signature · 6 lines
Roy Sigurd Karlsbakk, Datavaktmester
ProntoTV AS - http://www.pronto.tv/
Tel: +47 9801 3356

Computers are like air conditioners.
They stop working when you open Windows.
#4 lore raw
In reply to Robert Love
Quoted 2 lines · Robert Love

I backported the jiffies_to_clock_t() code from 2.5 to 2.4, mostly just for fun.

...

Quoted 1 line

Oh, and I did not backport 64-bit jiffies yet.

If you would, how would you call the analogous function for 64 bit values? And the type it returns?

The patches to make the kernel interfaces use the 64 bit jiffies value sit in Davej's tree since around 2.5.20-dj3, just waiting for the answer to these questions.

jiffies_64_to_clock_t_64() seems a bit lengthy. My current personal favourite would be jiffies_64_to_user_HZ(), just returning an u64, so that we don't keep on inventing silly types that get used just a very few times.

Just my 0.02 euro, though.

Tim