cvs commit: src/sys/kern sched_4bsd.c

John Baldwin jhb at FreeBSD.org
Mon Jul 28 21:44:36 UTC 2008


On Monday 28 July 2008 04:39:21 pm John Baldwin wrote:
> jhb         2008-07-28 20:39:21 UTC
> 
>   FreeBSD src repository
> 
>   Modified files:
>     sys/kern             sched_4bsd.c 
>   Log:
>   SVN rev 180937 on 2008-07-28 20:39:21Z by jhb
>   
>   When choosing a CPU for a thread in a cpuset, prefer the last CPU that the
>   thread ran on if there are no other CPUs in the set with a shorter per-CPU
>   runqueue.

I used the test program below.  Prior to this change, the two child processes 
bounced between the two CPUs constantly.  With this patch on an 
otherwise-idle box, they only switched CPUs once after starting.  With ULE 
they switch CPUs occasionally (once every few seconds) but not nearly as bad 
as 4BSD before this patch (multiple switches per second).  Granted, this is a 
very contrived test. :)

Note that I ran this on a 4-CPU box and used CPUs 2 and 3.  You can change 
which CPUs are used by changing the 'cpus[]' array.  This is also quite x86 
specific. :)

#include <sys/param.h>
#include <sys/cpuset.h>
#include <err.h>
#include <stdio.h>
#include <unistd.h>
#include <machine/cpufunc.h>

int apic_ids[2];
int cpus[2] = { 2, 3 };

int
apic_id(void)
{
        u_int regs[4];

        do_cpuid(1, regs);
        return (regs[1] >> 24);
}

void
check_id(pid_t pid, int *id)
{
        int new;

        new = apic_id();
        if (*id == new)
                return;
        printf("%d: moved from APIC ID %d to APIC ID %d\n", pid, *id, new);
        *id = new;
}

void
child(void)
{
        int last_id;
        pid_t pid;
        int i;

        pid = getpid();
        last_id = apic_id();
        printf("%d: starting on APIC ID %d\n", pid, last_id);
        for (;;) {
                for (i = 0; i < 10000000; i++)
                        check_id(pid, &last_id);
                usleep(5);
                check_id(pid, &last_id);
        }
}

int
main(int ac, char **av)
{
        cpuset_t set;
        int i;

        for (i = 0; i < 2; i++) {
                CPU_ZERO(&set);
                CPU_SET(cpus[i], &set);

                if (cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1,
                    sizeof(set), &set))
                        err(1, "cpuset_affinity(%d)", cpus[i]);
                apic_ids[i] = apic_id();
                printf("CPU%d has APIC ID %d\n", cpus[i], apic_ids[i]);
        }

        CPU_ZERO(&set);
        for (i = 0; i < 2; i++)
                CPU_SET(cpus[i], &set);
        if (cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1,
            sizeof(set), &set))
                err(1, "cpuset_affinity");

        for (i = 0; i < 2; i++) {
                switch (fork()) {
                case -1:
                        err(1, "fork");
                case 0:
                        break;
                default:
                        child();
                }
        }

        for (i = 0; i < 2; i++)
                wait(NULL);

        return (0);
}

-- 
John Baldwin


More information about the cvs-all mailing list