[patch] Auto-setting hz to 100 inside QEMU/VMWare

Mike Silbersack silby at silby.com
Sat Dec 29 16:01:46 PST 2007


On Fri, 28 Dec 2007, Robert Watson wrote:

> I like the general idea, but one thing that does worry me is that this 
> prevents me from using config to set HZ at all, I have to set it at runtime 
> using the tunable.  Could we add an:

Attached is a patch which attempts to address all of Robert's concerns and 
includes all the strings for the various VMs that people have mailed in to 
me.

Please test/review. :)

Mike "Silby" Silbersack
-------------- next part --------------
diff -u -r /usr/src/sys.old/amd64/amd64/machdep.c /usr/src/sys/amd64/amd64/machdep.c
--- /usr/src/sys.old/amd64/amd64/machdep.c	2007-12-29 03:01:02.000000000 -0600
+++ /usr/src/sys/amd64/amd64/machdep.c	2007-12-29 18:57:01.000000000 -0600
@@ -1935,3 +1935,33 @@
 }
 
 #endif /* KDB */
+
+/* kenv strings used to identify various VM environments */
+
+static char *vm_strings[] = {
+		"hint.acpi.0.oem", "QEMU",
+		"hint.acpi.0.oem", "VBOX", /* VirtualBox */
+		"smbios.system.maker", "VMware, Inc.",
+		"smbios.bios.vendor", "Parallels Software International Inc.",
+		NULL
+		};
+
+int
+detect_virtualmachine(void)
+{
+	char *envptr;
+	int i;
+	for (i = 0; ; i += 2) {
+		if (vm_strings[i] == NULL)
+			break;
+		envptr = getenv(vm_strings[i]);
+		if (envptr) {
+			if (strncmp(envptr, vm_strings[i+1], strlen(vm_strings[i+1])) == 0) {
+				freeenv(envptr);
+				return 1;
+			}
+			freeenv(envptr);
+		}
+	}
+	return 0;
+}
diff -u -r /usr/src/sys.old/arm/arm/machdep.c /usr/src/sys/arm/arm/machdep.c
--- /usr/src/sys.old/arm/arm/machdep.c	2007-12-29 03:01:06.000000000 -0600
+++ /usr/src/sys/arm/arm/machdep.c	2007-12-29 18:57:21.000000000 -0600
@@ -631,3 +631,9 @@
 	pcb->un_32.pcb32_lr = tf->tf_usr_lr;
 	pcb->un_32.pcb32_sp = tf->tf_usr_sp;
 }
+
+int
+detect_virtualmachine(void)
+{
+	return 0;
+}
diff -u -r /usr/src/sys.old/conf/NOTES /usr/src/sys/conf/NOTES
--- /usr/src/sys.old/conf/NOTES	2007-12-29 03:01:19.000000000 -0600
+++ /usr/src/sys/conf/NOTES	2007-12-29 18:54:40.000000000 -0600
@@ -1115,6 +1115,7 @@
 # the accuracy of operation.
 
 options 	HZ=100
+options 	VIRTUAL_HZ=100
 
 # Enable support for the kernel PLL to use an external PPS signal,
 # under supervision of [x]ntpd(8)
diff -u -r /usr/src/sys.old/conf/options /usr/src/sys/conf/options
--- /usr/src/sys.old/conf/options	2007-12-29 03:01:19.000000000 -0600
+++ /usr/src/sys/conf/options	2007-12-29 03:06:22.000000000 -0600
@@ -262,6 +262,7 @@
 
 # Options used only in subr_param.c.
 HZ		opt_param.h
+VIRTUAL_HZ	opt_param.h
 MAXFILES	opt_param.h
 NBUF		opt_param.h
 NSFBUFS		opt_param.h
diff -u -r /usr/src/sys.old/i386/i386/machdep.c /usr/src/sys/i386/i386/machdep.c
--- /usr/src/sys.old/i386/i386/machdep.c	2007-12-29 03:01:29.000000000 -0600
+++ /usr/src/sys/i386/i386/machdep.c	2007-12-29 03:59:05.000000000 -0600
@@ -3110,3 +3110,33 @@
 }
 
 #endif /* KDB */
+
+/* kenv strings used to identify various VM environments */
+
+static char *vm_strings[] = {
+		"hint.acpi.0.oem", "QEMU",
+		"hint.acpi.0.oem", "VBOX", /* VirtualBox */
+		"smbios.system.maker", "VMware, Inc.",
+		"smbios.bios.vendor", "Parallels Software International Inc.",
+		NULL
+		};
+
+int
+detect_virtualmachine(void)
+{
+	char *envptr;
+	int i;
+	for (i = 0; ; i += 2) {
+		if (vm_strings[i] == NULL)
+			break;
+		envptr = getenv(vm_strings[i]);
+		if (envptr) {
+			if (strncmp(envptr, vm_strings[i+1], strlen(vm_strings[i+1])) == 0) {
+				freeenv(envptr);
+				return 1;
+			}
+			freeenv(envptr);
+		}
+	}
+	return 0;
+}
diff -u -r /usr/src/sys.old/ia64/ia64/machdep.c /usr/src/sys/ia64/ia64/machdep.c
--- /usr/src/sys.old/ia64/ia64/machdep.c	2007-12-29 03:01:29.000000000 -0600
+++ /usr/src/sys/ia64/ia64/machdep.c	2007-12-29 19:02:23.000000000 -0600
@@ -1531,3 +1531,9 @@
 {
 	return (ENODEV);
 }
+
+int
+detect_virtualmachine(void)
+{
+	return 0;
+}
diff -u -r /usr/src/sys.old/kern/subr_param.c /usr/src/sys/kern/subr_param.c
--- /usr/src/sys.old/kern/subr_param.c	2007-12-29 03:01:29.000000000 -0600
+++ /usr/src/sys/kern/subr_param.c	2007-12-29 03:14:23.000000000 -0600
@@ -58,6 +58,9 @@
 #    define	HZ 100
 #  endif
 #endif
+#ifndef VIRTUAL_HZ
+#  define	VIRTUAL_HZ 100
+#endif
 #define	NPROC (20 + 16 * maxusers)
 #ifndef NBUF
 #define NBUF 0
@@ -109,7 +112,16 @@
 init_param1(void)
 {
 
-	hz = HZ;
+	/* Virtualization environments can't keep up with a
+	 * 1000hz tick rate, leading to highly inaccurate
+	 * timekeeping by FreeBSD guests.  To fix this problem,
+	 * drop back to 100hz when we detect that we are running
+	 * inside a virtual machine.
+	 */
+	if (detect_virtualmachine())
+		hz = VIRTUAL_HZ;
+	else
+		hz = HZ;
 	TUNABLE_INT_FETCH("kern.hz", &hz);
 	tick = 1000000 / hz;
 
diff -u -r /usr/src/sys.old/pc98/pc98/machdep.c /usr/src/sys/pc98/pc98/machdep.c
--- /usr/src/sys.old/pc98/pc98/machdep.c	2007-12-29 03:01:34.000000000 -0600
+++ /usr/src/sys/pc98/pc98/machdep.c	2007-12-29 19:01:49.000000000 -0600
@@ -2791,3 +2791,9 @@
 }
 
 #endif /* KDB */
+
+int
+detect_virtualmachine(void)
+{
+	return 0;
+}
diff -u -r /usr/src/sys.old/powerpc/powerpc/intr_machdep.c /usr/src/sys/powerpc/powerpc/intr_machdep.c
--- /usr/src/sys.old/powerpc/powerpc/intr_machdep.c	2007-12-29 03:01:34.000000000 -0600
+++ /usr/src/sys/powerpc/powerpc/intr_machdep.c	2007-12-29 18:59:36.000000000 -0600
@@ -304,3 +304,9 @@
 	if (i != NULL)
 		PIC_MASK(pic, i->irq);
 }
+
+int
+detect_virtualmachine(void)
+{
+	return 0;
+}
diff -u -r /usr/src/sys.old/sparc64/sparc64/machdep.c /usr/src/sys/sparc64/sparc64/machdep.c
--- /usr/src/sys.old/sparc64/sparc64/machdep.c	2007-12-29 03:01:35.000000000 -0600
+++ /usr/src/sys/sparc64/sparc64/machdep.c	2007-12-29 19:01:33.000000000 -0600
@@ -910,3 +910,9 @@
 	mtx_pool_unlock(mtxpool_sleep, ut);
 	return (ut);
 }
+
+int
+detect_virtualmachine(void)
+{
+	return 0;
+}
diff -u -r /usr/src/sys.old/sun4v/sun4v/machdep.c /usr/src/sys/sun4v/sun4v/machdep.c
--- /usr/src/sys.old/sun4v/sun4v/machdep.c	2007-12-29 03:01:01.000000000 -0600
+++ /usr/src/sys/sun4v/sun4v/machdep.c	2007-12-29 18:58:49.000000000 -0600
@@ -999,3 +999,9 @@
 	if (rdpr(pil) < PIL_TICK)
 		hv_cpu_yield();
 }
+
+int
+detect_virtualmachine(void)
+{
+	return 0;
+}
diff -u -r /usr/src/sys.old/sys/systm.h /usr/src/sys/sys/systm.h
--- /usr/src/sys.old/sys/systm.h	2007-12-29 03:01:35.000000000 -0600
+++ /usr/src/sys/sys/systm.h	2007-12-29 03:50:59.000000000 -0600
@@ -245,6 +245,8 @@
 int	unsetenv(const char *name);
 int	testenv(const char *name);
 
+int	detect_virtualmachine(void);
+
 typedef uint64_t (cpu_tick_f)(void);
 void set_cputicker(cpu_tick_f *func, uint64_t freq, unsigned var);
 extern cpu_tick_f *cpu_ticks;


More information about the freebsd-current mailing list