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