kernel - Permanently fix FP bug - completely remove lazy heuristic
authorMatthew Dillon <dillon@apollo.backplane.com>
Fri, 3 May 2019 20:24:13 +0000 (13:24 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Fri, 3 May 2019 20:24:13 +0000 (13:24 -0700)
* Remove the FP lazy heuristic.  When the FP unit is being used by a
  thread, it will now *always* be actively saved and restored on
  context switch.

  This means that if a process uses the FP unit at all, its context
  switches (to another thread) will active save/restore the state forever
  more.

* This fixes a known hardware bug on Intel CPUs that we thought was fixed
  before (by not saving The FP context from thread A from the DNA interrupt
  on thread B)...  but it turns out it wasn't.

  We could tickle the bug on Intel CPUs by forcing synth to regenerate
  its flavor index over and over again.  This regeneration fork/exec's
  about 60,000 make's, sequencing concurrently on all cores, and usually
  hits the bug in less than 5 minutes.

* We no longer support lazy FP restores, period.  This is like the fourth
  time I've tried to deal with this, so now its time to give up and not
  use lazy restoration at all, ever again.

sys/platform/pc64/x86_64/genassym.c
sys/platform/pc64/x86_64/npx.c
sys/platform/pc64/x86_64/swtch.s
sys/sys/thread.h

index feed32d..f9a1248 100644 (file)
@@ -195,14 +195,12 @@ ASSYM(TD_NEST_COUNT, offsetof(struct thread, td_nest_count));
 ASSYM(TD_FLAGS, offsetof(struct thread, td_flags));
 ASSYM(TD_TYPE, offsetof(struct thread, td_type));
 ASSYM(TD_PREEMPTED, offsetof(struct thread, td_preempted));
-ASSYM(TD_FPU_HEUR, offsetof(struct thread, td_fpu_heur));
 
 ASSYM(TD_SAVEFPU, offsetof(struct thread, td_savefpu));
 ASSYM(TDF_RUNNING, TDF_RUNNING);
 ASSYM(TDF_USINGFP, TDF_USINGFP);
 ASSYM(TDF_KERNELFP, TDF_KERNELFP);
 ASSYM(TDF_PREEMPT_DONE, TDF_PREEMPT_DONE);
-ASSYM(TDF_FPU_HEUR, TDF_FPU_HEUR);
 
 ASSYM(FIRST_SOFTINT, FIRST_SOFTINT);
 ASSYM(MDGLOBALDATA_BASEALLOC_PAGES, MDGLOBALDATA_BASEALLOC_PAGES);
index add3a7b..240af8e 100644 (file)
@@ -90,11 +90,6 @@ static       void    fpurstor        (union savefpu *);
 
 uint32_t npx_mxcsr_mask = 0xFFBF;      /* this is the default */
 
-static int npx_fpu_heuristic = 32;
-SYSCTL_INT(_machdep, OID_AUTO, npx_fpu_heuristic, CTLFLAG_RW,
-        &npx_fpu_heuristic, 0, "FPU active restore 0=never 1=always N=after-N");
-
-
 /*
  * Probe the npx_mxcsr_mask as described in the intel document
  * "Intel processor identification and the CPUID instruction" Section 7
@@ -372,15 +367,6 @@ npxdna(void)
                didinit = 1;
        }
 
-       /*
-        * Actively restore the fpu state after N npxdna faults instead of
-        * soaking the npxdna fault overhead on each switch.
-        */
-       if (npx_fpu_heuristic && ++td->td_fpu_heur >= npx_fpu_heuristic) {
-               td->td_fpu_heur = npx_fpu_heuristic;
-               td->td_flags |= TDF_FPU_HEUR;
-       }
-
        /*
         * The setting of gd_npxthread and the call to fpurstor() must not
         * be preempted by an interrupt thread or we will take an npxdna
@@ -442,19 +428,6 @@ npxdna_quick(thread_t newtd)
                lwpsignal(newtd->td_proc, newtd->td_lwp, SIGFPE);
        }
        fpurstor(newtd->td_savefpu);
-
-       /*
-        * If npx_fpu_heuristic is larger than 1 we reset the heuristic
-        * after N switches and shift to probe mode.  Any npxdna trap will
-        * retrigger active fpu state loading, then probe again after N
-        * switches.
-        *
-        * If npx_fpu_heuristic is 1 active mode is simply left on forever.
-        */
-       if (npx_fpu_heuristic > 1 && --newtd->td_fpu_heur <= 0) {
-               newtd->td_fpu_heur = npx_fpu_heuristic - 1;
-               newtd->td_flags &= ~TDF_FPU_HEUR;
-       }
 }
 
 /*
index 0689248..37dc132 100644 (file)
@@ -542,9 +542,8 @@ ENTRY(cpu_heavy_restore)
        testq   %r13,%r13
        jnz     6f
        movl    TD_FLAGS(%r12),%r13d
-       andq    $TDF_FPU_HEUR|TDF_USINGFP,%r13
-       cmpq    $TDF_FPU_HEUR|TDF_USINGFP,%r13
-       jne     6f
+       andq    $TDF_USINGFP,%r13
+       jz      6f
        movq    %r12,%rdi               /* npxdna_quick(newtd) */
        call    npxdna_quick
 6:
index a8088c6..ec33f5a 100644 (file)
@@ -280,8 +280,7 @@ struct thread {
     int                td_type;        /* thread type, TD_TYPE_ */
     int                td_tracker;     /* for callers to debug lock counts */
     int                td_fdcache_lru;
-    int                td_fpu_heur;    /* active restore on switch heuristic */
-    int                td_unused03[2]; /* for future fields */
+    int                td_unused03[3]; /* for future fields */
     struct iosched_data td_iosdata;    /* Dynamic I/O scheduling data */
     struct timeval td_start;   /* start time for a thread/process */
     char       td_comm[MAXCOMLEN+1]; /* typ 16+1 bytes */