Branch: Tag:

2010-10-24

2010-10-24 14:51:35 by Martin Stjernholm <mast@lysator.liu.se>

Use a tick interval as tsc target instead of an absolute count.

This avoids errors at the beginning of time slices after blocking or
thread switching. Should otherwise be functionally equivalent.

350: Inside #if undefined(CONFIGURE_TEST) and #if defined(HAVE_CLOCK) && \
  static clock_t thread_start_clock = 0;   static THREAD_T last_clocked_thread = 0;   #define USE_CLOCK_FOR_SLICES + #ifdef RDTSC + static int use_tsc_for_slices; + #define TSC_START_INTERVAL 100000 + static INT64 prev_tsc;   #endif -  + #endif      #define THIS_THREAD ((struct thread_state *)CURRENT_STORAGE)   
520:    ts->debug_flags = 0;   #endif   #ifdef USE_CLOCK_FOR_SLICES +  /* Initialize thread_start_clock to zero instead of clock() since we +  * don't know for how long the thread already has run. */    thread_start_clock = 0;    last_clocked_thread = ts->id; -  + #ifdef RDTSC +  prev_tsc = 0;   #endif -  + #endif   }      PMOD_EXPORT void pike_swap_out_thread (struct thread_state *ts
600: Inside #if defined(USE_CLOCK_FOR_SLICES)
   if (last_clocked_thread != ts->id) {    thread_start_clock = clock();    last_clocked_thread = ts->id; + #ifdef RDTSC +  RDTSC (prev_tsc); + #endif    }   #endif   }
1249:      /* #define PROFILE_CHECK_THREADS */    - #if defined(RDTSC) && defined(USE_CLOCK_FOR_SLICES) - static int use_tsc_for_slices; - #define TSC_START_INTERVAL (1000 * 1000) - #endif -  +    static void check_threads(struct callback *cb, void *arg, void * arg2)   {   #if defined(RDTSC) && defined(USE_CLOCK_FOR_SLICES)
1261:   #endif      #ifdef PROFILE_CHECK_THREADS -  static INT64 prev_now; +     static unsigned long calls = 0, clock_checks = 0;    static unsigned long slice_int_n = 0;    static double slice_int_mean = 0.0, slice_int_m2 = 0.0;
1284: Inside #if defined(RDTSC) && defined(USE_CLOCK_FOR_SLICES)
   time when we decided to yield. */       if (use_tsc_for_slices) { -  static INT64 target; -  INT64 now; +  static INT64 target_int; +  INT64 now, tsc_elapsed;    clock_t elapsed;    -  +  /* prev_tsc is normally always valid here, but it can be zero +  * after a tsc jump reset and just after a thread has been +  * "pike-ified" with INIT_THREAD_STATE (in which case +  * thread_start_clock is zero too). */ +     RDTSC(now); -  +  tsc_elapsed = now - prev_tsc;    -  if ((target-now)>0) { -  if ((target-now)>tsc_mincycles) { -  /* The counter jumped back in time (since target == -  * previous_now + tsc_mincycles), so reset and continue. In the -  * worst case this keeps happening all the time, and then the -  * only effect is that we always fall back to clock(3). */ +  if ((target_int - tsc_elapsed)>0) { +  if (tsc_elapsed < 0) { +  /* The counter jumped back in time, so reset and continue. In +  * the worst case this keeps happening all the time, and then +  * the only effect is that we always fall back to +  * clock(3). */   #ifdef PROFILE_CHECK_THREADS    fprintf (stderr, "TSC jump detected (now: %"PRINTINT64"d, " -  "target: %"PRINTINT64"d, tsc_mincycles: %"PRINTINT64"d) - " -  "resetting\n", now, target, tsc_mincycles); +  "target_int: %"PRINTINT64"d, tsc_mincycles: %"PRINTINT64"d) - " +  "resetting\n", now, target_int, tsc_mincycles);   #endif    tsc_mincycles = TSC_START_INTERVAL; -  +  prev_tsc = 0;    }    else    return;    }      #ifdef PROFILE_CHECK_THREADS -  if (prev_now) { -  INT64 tsc_interval = now - prev_now; -  double delta = tsc_interval - tsc_int_mean; +  if (prev_tsc) { +  double delta = tsc_elapsed - tsc_int_mean;    tsc_int_n++;    tsc_int_mean += delta / tsc_int_n; -  tsc_int_m2 += delta * (tsc_interval - tsc_int_mean); +  tsc_int_m2 += delta * (tsc_elapsed - tsc_int_mean);    } -  prev_now = now; +     clock_checks++;   #endif   
1323: Inside #if defined(RDTSC) && defined(USE_CLOCK_FOR_SLICES)
      if (elapsed < (clock_t) (CLOCKS_PER_SEC/30)) {    tsc_mincycles |= 0xffff; -  if ((now-target)<=(tsc_mincycles<<4)) +  if ((tsc_elapsed - target_int)<=(tsc_mincycles<<4))    tsc_mincycles += (tsc_mincycles>>1); -  target = now + (tsc_mincycles>>1); +  target_int = (tsc_mincycles>>1);    return;    }    if (elapsed > (clock_t) (CLOCKS_PER_SEC/18)) {
1333: Inside #if defined(RDTSC) && defined(USE_CLOCK_FOR_SLICES)
   if (elapsed > (clock_t) (CLOCKS_PER_SEC/10))    tsc_mincycles >>= 2;    } -  target = now + tsc_mincycles; +  target_int = tsc_mincycles; +  prev_tsc = now;    goto do_yield;    }   #endif /* RDTSC && USE_CLOCK_FOR_SLICES */
1450:    }       /* Cannot use this with the first tsc reading after the yield. */ -  prev_now = 0; +  prev_tsc = 0;    }   #endif   
1476: Inside #if defined(USE_CLOCK_FOR_SLICES)
   * did yield then thread_start_clock is the current clock anyway    * after the thread swap in. */    thread_start_clock = clock(); + #ifdef RDTSC +  RDTSC (prev_tsc); + #endif   #ifdef PIKE_DEBUG    if (last_clocked_thread != th_self())    Pike_fatal ("Stale thread %08lx in last_clocked_thread (self is %08lx)\n",