bin/109413: [PATCH] top shows at least 50% idle when hyperthreading is disabled

Craig Leres leres at ee.lbl.gov
Wed Feb 21 23:50:08 UTC 2007


>Number:         109413
>Category:       bin
>Synopsis:       [PATCH] top shows at least 50% idle when hyperthreading is disabled
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Feb 21 23:50:08 GMT 2007
>Closed-Date:
>Last-Modified:
>Originator:     Craig Leres
>Release:        FreeBSD 6.2-RELEASE i386
>Organization:
Lawrence Berkeley National Laboratory
>Environment:
	% uname -a
	FreeBSD fun.ee.lbl.gov 6.2-RELEASE FreeBSD 6.2-RELEASE #1: Mon Jan 15 11:31:32 PST 2007     leres at fox.ee.lbl.gov:/usr/src/6.2-RELEASE/sys/i386/compile/LBLSMP  i386

>Description:
	If the hardware and kernel support hyperthreading but
	hyperthreading is disabled (which is the default), top
	always reports at least 50% idle time even all cpus completely
	busy.

>How-To-Repeat:
	Insure hyperthreading is disabled:

	    # sysctl machdep.hyperthreading_allowed=0
	    machdep.hyperthreading_allowed: 0 -> 0

	Note that if sysctl says "unknown oid" then your test system
	does not support hyperthreading and you need to find a
	different system that does.

	Launch top and then start some cpu bound processes; observe
	that idle never goes below 50%.

	Another way to see this effect is to look at the cp_time
	vector on the number of ticks tallied in a second.

	Here's a single processor Pentium III:

	    CPU: Intel(R) Pentium(R) III CPU family      1266MHz (1266.07-MHz 686-class CPU)
	      Origin = "GenuineIntel"  Id = 0x6b1  Stepping = 1
	      Features=0x383fbff<FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,MMX,FXSR,SSE>
	    real memory  = 2147418112 (2047 MB)
	    avail memory = 2096291840 (1999 MB)
	    [...]
	    cpu0: <ACPI CPU> on acpi0

	It see about 133 ticks in a second:

	    % sysctl kern.cp_time ; sleep 1 ; sysctl kern.cp_time
	    kern.cp_time: 386 142 8685 210 9844275
	    kern.cp_time: 386 142 8686 210 9844408

	Here's a dual processor Xeon system with hyperthreading (4
	logical CPUs):

	    CPU: Intel(R) Xeon(TM) CPU 3.20GHz (3200.13-MHz 686-class CPU)
	      Origin = "GenuineIntel"  Id = 0xf34  Stepping = 4
	      Features=0xbfebfbff<FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CLFLUSH,DTS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,PBE>
	      Features2=0x441d<SSE3,RSVD2,MON,DS_CPL,CNTX-ID,<b14>>
	      AMD Features=0x20000000<LM>
	      Logical CPUs per core: 2
	    real memory  = 2146893824 (2047 MB)
	    avail memory = 2095759360 (1998 MB)
	    FreeBSD/SMP: Multiprocessor System Detected: 4 CPUs
	     cpu0 (BSP): APIC ID:  0
	     cpu1 (AP): APIC ID:  1
	     cpu2 (AP): APIC ID:  6
	     cpu3 (AP): APIC ID:  7

	It see about 534 ticks in a second:

	    % sysctl kern.cp_time ; sleep 1 ; sysctl kern.cp_time
	    kern.cp_time: 31410710 498316 11249090 2058151 1597290413
	    kern.cp_time: 31410710 498316 11249091 2058151 1597290946

	So with 4 times as many logical processors, we see 4 times
	as many ticks. What's interesting is that the number of
	ticks per second is independent of the setting of
	hyperthreading_allowed. But when hyperthreading is disabled,
	two of the processors can only contribute to CP_IDLE ticks
	while the other two can contribute to all types of ticks.

>Fix:
	The appended patch to usr.bin/top/machine.c checks to see
	if hyperthreading is possible but disabled and if so,
	subtracts ticks from cp_time[CP_IDLE].

===================================================================
RCS file: RCS/machine.c,v
retrieving revision 1.1
diff -c -r1.1 machine.c
*** machine.c	2007/02/21 22:56:13	1.1
--- machine.c	2007/02/21 23:07:52
***************
*** 150,155 ****
--- 150,156 ----
  static long cp_time[CPUSTATES];
  static long cp_old[CPUSTATES];
  static long cp_diff[CPUSTATES];
+ static int hyperthread_hack;
  
  /* these are for detailing the process states */
  
***************
*** 226,240 ****
  machine_init(struct statics *statics)
  {
  	int pagesize;
! 	size_t modelen;
  	struct passwd *pw;
  
! 	modelen = sizeof(smpmode);
! 	if ((sysctlbyname("machdep.smp_active", &smpmode, &modelen, NULL, 0) < 0 &&
! 		sysctlbyname("kern.smp.active", &smpmode, &modelen, NULL, 0) < 0) ||
! 	    modelen != sizeof(smpmode))
  		smpmode = 0;
  
  	while ((pw = getpwent()) != NULL) {
  		if (strlen(pw->pw_name) > namelength)
  			namelength = strlen(pw->pw_name);
--- 227,250 ----
  machine_init(struct statics *statics)
  {
  	int pagesize;
! 	size_t len;
! 	int hyperthreading_allowed;
  	struct passwd *pw;
  
! 	len = sizeof(smpmode);
! 	if ((sysctlbyname("machdep.smp_active", &smpmode, &len, NULL, 0) < 0 &&
! 		sysctlbyname("kern.smp.active", &smpmode, &len, NULL, 0) < 0) ||
! 	    len != sizeof(smpmode))
  		smpmode = 0;
  
+ 	/* Determine if hyperthreading is supported but disabled */
+ 	len = sizeof(hyperthreading_allowed);
+ 	if (sysctlbyname("machdep.hyperthreading_allowed",
+ 	    &hyperthreading_allowed, &len, NULL, 0) >= 0 &&
+ 	    len == sizeof(hyperthreading_allowed) &&
+ 	    !hyperthreading_allowed)
+ 	    ++hyperthread_hack;
+ 
  	while ((pw = getpwent()) != NULL) {
  		if (strlen(pw->pw_name) > namelength)
  			namelength = strlen(pw->pw_name);
***************
*** 330,335 ****
--- 340,360 ----
  	GETSYSCTL("kern.cp_time", cp_time);
  	GETSYSCTL("vm.loadavg", sysload);
  	GETSYSCTL("kern.lastpid", lastpid);
+ 
+ 	/*
+ 	 * If hyperthreading is supported but disabled, at most 1/2
+ 	 * of the total ticks can be non-idle. To avoid having idle
+ 	 * always displayed as at least 50%, subtract out the phantom
+ 	 * idle ticks out.
+ 	 */
+ 	if (hyperthread_hack) {
+ 		total = 0;
+ 		for (i = 0; i < CPUSTATES; ++i)
+ 			total += cp_time[i];
+ 		cp_time[CP_IDLE] -= total / 2;
+ 		if (cp_time[CP_IDLE] < 0)
+ 			cp_time[CP_IDLE] = 0;
+ 	}
  
  	/* convert load averages to doubles */
  	for (i = 0; i < 3; i++)
>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list