On 20 April 2011 22:29, Sergey Kandaurov <pluk...@gmail.com> wrote:
> On 20 April 2011 21:02, Ian Smith <smi...@nimnet.asn.au> wrote:
>> On Wed, 13 Apr 2011, Ian Smith wrote:
>>  > On Tue, 12 Apr 2011, Daniel Gerzo wrote:
>>  >  > On 11.4.2011 6:08, Ian Smith wrote:
>> [..]
>>  >  > > Are those kern.cp_times values as they came, or did you remove 
>> trailing
>>  >  > > zeroes?  Reason I ask is that on my Thinkpad T23, single-core 
>> 1133/733
>>  >  > > MHz, sysctl kern.cp_time shows the usual 5 values, but kern.cp_times 
>> has
>>  >  > > the same 5 values for cpu0, but then 5 zeroes for each of cpu1 
>> through
>>  >  > > cpu31, on 8.2-PRE about early January.  I need to update the script 
>> to
>>  >  > > remove surplus data for non-existing cpus, but wonder if the extra 
>> data
>>  >  > > also appeared on your 12 core box?
>>  >  >
>>  >  > I haven't removed anything, it's a pure copy&paste.
>>  >
>>  > Thanks.  I'll check the single-cpu case again after updating to 8.2-R
>>
>> Ok, still a problem on at least my i386 single core Thinkpad T23 at
>> 8.2-R, since 8.0 I think, certainly evident in a sysctl -a at 8.1-R
>>
>> FreeBSD t23.smithi.id.au 8.2-RELEASE FreeBSD 8.2-RELEASE #1: Thu Apr 14
>> 21:45:47 EST 2011 r...@t23.smithi.id.au:/usr/obj/usr/src/sys/GENERIC i386
>>
>> Verbose dmesg: http://smithi.id.au/t23_dmesg_boot-v.8.2-R.txt
>> sysctl -a:     http://smithi.id.au/t23_sysctl-a_8.2-R.txt
>>
>> kern.ccpu: 0
>>  <cpu count="1" mask="0x1">0</cpu>
>> kern.smp.forward_signal_enabled: 1
>> kern.smp.topology: 0
>> kern.smp.cpus: 1
>> kern.smp.disabled: 0
>> kern.smp.active: 0
>> kern.smp.maxcpus: 32
>> kern.smp.maxid: 31      <<<<<<<
>> hw.ncpu: 1
>>
>> kern.cp_times: 38548 1 120437 195677 9660939 0 0 0 0 0 0 0 0 0 0 0 0 0 0
>> 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
>> 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
>> 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
>> 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
>>
>> /usr/src/sys/kern/kern_clock.c:
>> return SYSCTL_OUT(req, 0, sizeof(long) * CPUSTATES * (mp_maxid + 1));
>>
>> Consumers of kern.cp_times like powerd, top, dtrace? and others have to
>> loop over 32 cpus, all but one non-existent, and there seem to be many
>> places in the kernel doing eg: for (cpu = 0; cpu <= mp_maxid; cpu++) {
>> and while CPU_FOREACH / CPU_ABSENT will skip over them, seems wasteful
>> at best on machines least likely to have cycles to spare.
>>
>> eg: powerd parses kern.cp_times to count cpus, wasting cycles adding
>> up the 31 'empty' cpus.  I haven't explored other userland consumers.
>>
>> Clearly kern.smp.maxid (ie mp_maxid) should be 0, not 31.  On i386,
>> non-APIC i386 at least, mp_maxid is not set to (mp_ncpus - 1) as on some
>> other archs .. after having being initialised to (MAXCPU - 1) in
>> /sys/i386/i386/mp_machdep.c it's never updated for non-smp machines.
>>
>> I haven't chased all of these rabbits down all of their holes by any
>> means, but it seems that making /sys/i386/i386/mp_machdep.c do what it
>> says it's gonna do ('with an id of 0') should help.  Paste, tabs lost:
>>
>> int
>> cpu_mp_probe(void)
>> {
>>        /*
>>         * Always record BSP in CPU map so that the mbuf init code works
>>         * correctly.
>>         */
>>        all_cpus = 1;
>>        if (mp_ncpus == 0) {
>>                /*
>>                 * No CPUs were found, so this must be a UP system.  Setup
>>                 * the variables to represent a system with a single CPU
>>                 * with an id of 0.
>>                 */
>>                mp_ncpus = 1;
>> +               mp_maxid = 0;
>>                return (0);
>>        }
>>
>>        /* At least one CPU was found. */
>>        if (mp_ncpus == 1) {
>>                /*
>>                 * One CPU was found, so this must be a UP system with
>>                 * an I/O APIC.
>>                 */
>> +               mp_maxid = 0;
>>                return (0);
>>        }
>>
>>        /* At least two CPUs were found. */
>>        return (1);
>> }
>>
>> Note that the second added line above already exists in
>> /sys/amd64/amd64/mp_machdep.c, maybe to fix a similar problem, though
>> that should only apply to 'a UP system with an I/O APIC'.  Maybe better
>> could be to fix this in cpu_mp_probe's caller, /sys/kern/subr_smp.c:
>>
>> static void
>> mp_start(void *dummy)
>> {
>>        mtx_init(&smp_ipi_mtx, "smp rendezvous", NULL, MTX_SPIN);
>>
>>        /* Probe for MP hardware. */
>>        if (smp_disabled != 0 || cpu_mp_probe() == 0) {
>>                mp_ncpus = 1;
>> +               mp_maxid = 0;
>>                all_cpus = PCPU_GET(cpumask);
>>                return;
>>        }
>>
>>        cpu_mp_start();
>>        printf("FreeBSD/SMP: Multiprocessor System Detected: %d CPUs\n",
>>            mp_ncpus);
>>        cpu_mp_announce();
>> }
>>
>> I'm probably a long way off base for a solution, but think I've located
>> the problem.  Thoughts?  Is this a known issue?  Might any developers
>> actually still have a single-cpu i386 system to check this on? :)
>>
>> Very happy to test any patches etc.
>>
>
> Ouch.
> Looks like that affects a system with 2 cores as well.
> Intel Core2 E7200, 8.2-R i386 SMP:
>
> kern.smp.forward_signal_enabled: 1
> kern.smp.topology: 0
> kern.smp.cpus: 2
> kern.smp.disabled: 0
> kern.smp.active: 1
> kern.smp.maxcpus: 32
> kern.smp.maxid: 31
>
> kern.cp_times: 867360 171 429180 70114 170549535 1385294 306 176659 82618
> 170270900 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
> 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
> 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
> 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
> 0 0 0 0 0 0 0

Perhaps that was so from the begging: the problem is seen also on
6.4 i386 SMP 8 core. Here it was just set to (MAXCPU-1).

The buggy mp_maxid was fixed in HEAD with r215009, though not merged.
The patch works on my 8.2 Core2 SMP i386 system.

-- 
wbr,
pluknet
Index: x86/x86/mptable.c
===================================================================
--- x86/x86/mptable.c	(revision 215008)
+++ x86/x86/mptable.c	(revision 215009)
@@ -389,7 +389,8 @@
 
 	apic_register_enumerator(&mptable_enumerator);
 }
-SYSINIT(mptable_register, SI_SUB_MPTBL, SI_ORDER_FIRST, mptable_register, NULL);
+SYSINIT(mptable_register, SI_SUB_TUNABLES - 1, SI_ORDER_FIRST, mptable_register,
+    NULL);
 
 /*
  * Call the handler routine for each entry in the MP config table.
Index: x86/x86/local_apic.c
===================================================================
--- x86/x86/local_apic.c	(revision 215008)
+++ x86/x86/local_apic.c	(revision 215009)
@@ -1285,7 +1285,7 @@
 	if (resource_disabled("apic", 0))
 		return;
 
-	/* First, probe all the enumerators to find the best match. */
+	/* Probe all the enumerators to find the best match. */
 	best_enum = NULL;
 	best = 0;
 	SLIST_FOREACH(enumerator, &enumerators, apic_next) {
@@ -1321,13 +1321,12 @@
 	}
 #endif
 
-	/* Second, probe the CPU's in the system. */
+	/* Probe the CPU's in the system. */
 	retval = best_enum->apic_probe_cpus();
 	if (retval != 0)
 		printf("%s: Failed to probe CPUs: returned %d\n",
 		    best_enum->apic_name, retval);
 
-#ifdef __amd64__
 }
 SYSINIT(apic_init, SI_SUB_TUNABLES - 1, SI_ORDER_SECOND, apic_init, NULL);
 
@@ -1342,19 +1341,14 @@
  
 	if (best_enum == NULL)
 		return;
-#endif
-	/* Third, initialize the local APIC. */
+
+	/* Initialize the local APIC. */
 	retval = best_enum->apic_setup_local();
 	if (retval != 0)
 		printf("%s: Failed to setup the local APIC: returned %d\n",
 		    best_enum->apic_name, retval);
 }
-#ifdef __amd64__
-SYSINIT(apic_setup_local, SI_SUB_CPU, SI_ORDER_SECOND, apic_setup_local,
-    NULL);
-#else
-SYSINIT(apic_init, SI_SUB_CPU, SI_ORDER_SECOND, apic_init, NULL);
-#endif
+SYSINIT(apic_setup_local, SI_SUB_CPU, SI_ORDER_SECOND, apic_setup_local, NULL);
 
 /*
  * Setup the I/O APICs.
Index: i386/acpica/madt.c
===================================================================
--- i386/acpica/madt.c	(revision 215008)
+++ i386/acpica/madt.c	(revision 215009)
@@ -203,7 +203,7 @@
 
 	apic_register_enumerator(&madt_enumerator);
 }
-SYSINIT(madt_register, SI_SUB_CPU - 1, SI_ORDER_SECOND, madt_register, NULL);
+SYSINIT(madt_register, SI_SUB_TUNABLES - 1, SI_ORDER_FIRST, madt_register, NULL);
 
 /*
  * Call the handler routine for each entry in the MADT table.
Index: i386/i386/mp_machdep.c
===================================================================
--- i386/i386/mp_machdep.c	(revision 215008)
+++ i386/i386/mp_machdep.c	(revision 215009)
@@ -465,8 +465,10 @@
 		boot_cpu_id = apic_id;
 		cpu_info[apic_id].cpu_bsp = 1;
 	}
-	if (mp_ncpus < MAXCPU)
+	if (mp_ncpus < MAXCPU) {
 		mp_ncpus++;
+		mp_maxid = mp_ncpus - 1;
+	}
 	if (bootverbose)
 		printf("SMP: Added CPU %d (%s)\n", apic_id, boot_cpu ? "BSP" :
 		    "AP");
@@ -476,7 +478,19 @@
 cpu_mp_setmaxid(void)
 {
 
-	mp_maxid = MAXCPU - 1;
+	/*
+	 * mp_maxid should be already set by calls to cpu_add().
+	 * Just sanity check its value here.
+	 */
+	if (mp_ncpus == 0)
+		KASSERT(mp_maxid == 0,
+		    ("%s: mp_ncpus is zero, but mp_maxid is not", __func__));
+	else if (mp_ncpus == 1)
+		mp_maxid = 0;
+	else
+		KASSERT(mp_maxid >= mp_ncpus - 1,
+		    ("%s: counters out of sync: max %d, count %d", __func__,
+			mp_maxid, mp_ncpus));
 }
 
 int
@@ -504,6 +518,7 @@
 		 * One CPU was found, so this must be a UP system with
 		 * an I/O APIC.
 		 */
+		mp_maxid = 0;
 		return (0);
 	}
 
Index: i386/xen/mptable.c
===================================================================
--- i386/xen/mptable.c	(revision 215008)
+++ i386/xen/mptable.c	(revision 215009)
@@ -109,7 +109,7 @@
 
 	apic_register_enumerator(&mptable_enumerator);
 }
-SYSINIT(mptable_register, SI_SUB_CPU - 1, SI_ORDER_FIRST, mptable_register,
+SYSINIT(mptable_register, SI_SUB_TUNABLES - 1, SI_ORDER_FIRST, mptable_register,
     NULL);
 
 
_______________________________________________
freebsd-stable@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-stable
To unsubscribe, send any mail to "freebsd-stable-unsubscr...@freebsd.org"

Reply via email to