예제 #1
0
int NaClClockGetTime(nacl_clockid_t           clk_id,
                     struct nacl_abi_timespec *tp) {
  int                     rv = -NACL_ABI_EINVAL;
  struct nacl_abi_timeval tv;
  uint64_t                t_mono_prev_us;
  uint64_t                t_mono_cur_us;

  if (!g_NaClClock_is_initialized) {
    NaClLog(LOG_FATAL,
            "NaClClockGetTime invoked without successful NaClClockInit\n");
  }
  switch (clk_id) {
    case NACL_CLOCK_REALTIME:
      rv = NaClGetTimeOfDay(&tv);
      if (0 == rv) {
        tp->tv_sec = tv.nacl_abi_tv_sec;
        tp->tv_nsec = tv.nacl_abi_tv_usec * 1000;
      }
      break;
    case NACL_CLOCK_MONOTONIC:
      /*
       * Get real time, compare with last monotonic time.  If later
       * than last monotonic time, set last monotonic time to real
       * time timestamp; otherwise we leave last monotonoic time
       * alone.  In either case, return last monotonic time.
       *
       * The interpretation used here is that "monotonic" means
       * monotonic non-decreasing, as opposed to monotonic increasing.
       * We don't assume that GetTimeOfDay only yields high-order bits
       * so we can replace low-order bits of the time value with a
       * counter to fake monotonicity.  We are dangerously close to
       * the resolution limit of 1ns imposed by the timespec structure
       * already -- it's only a few Moore's Law generations away where
       * we may have to return the same time stamp for repeated calls
       * to clock_gettime (if CPU frequency clock is continued to be
       * used to drive performance counters; RTDSC is moving to a
       * fixed rate [constant_tsc], fortunately).
       */
      rv = NaClGetTimeOfDay(&tv);
      if (0 == rv) {
        NaClXMutexLock(&g_nacl_clock_mu);
        t_mono_prev_us = g_nacl_clock_tv.nacl_abi_tv_sec * 1000000
            + g_nacl_clock_tv.nacl_abi_tv_usec;
        t_mono_cur_us  = tv.nacl_abi_tv_sec * 1000000
            + tv.nacl_abi_tv_usec;
        if (t_mono_cur_us >= t_mono_cur_us) {
          g_nacl_clock_tv = tv;
        }
        tp->tv_sec = g_nacl_clock_tv.nacl_abi_tv_sec + MAGIC_OFFSET;
        tp->tv_nsec = g_nacl_clock_tv.nacl_abi_tv_usec * 1000;
        NaClXMutexUnlock(&g_nacl_clock_mu);
        rv = 0;
      }
      break;
    case NACL_CLOCK_PROCESS_CPUTIME_ID:
    case NACL_CLOCK_THREAD_CPUTIME_ID:
      break;
  }
  return rv;
}
void TestAbsWait(void *arg) {
  uint64_t                  sleep_usec;
  struct nacl_abi_timeval   now;
  struct nacl_abi_timespec  t;

  sleep_usec = ((struct TestFunctorArg *) arg)->sleep_usec;
  (void) NaClGetTimeOfDay(&now);
  t.tv_sec = (nacl_abi_time_t) (now.nacl_abi_tv_sec + sleep_usec / kMicroXinX);
  t.tv_nsec = (long int) (kNanoXinMicroX * (now.nacl_abi_tv_usec
                                            + (sleep_usec % kMicroXinX)));
  while (t.tv_nsec > kNanoXinX) {
    t.tv_nsec -= kNanoXinX;
    ++t.tv_sec;
  }
  if (gVerbosity > 1) {
    printf("TestAbsWait: locking\n");
  }
  NaClXMutexLock(&gMu);
  if (gVerbosity > 1) {
    printf("TestAbsWait: waiting\n");
  }
  NaClXCondVarTimedWaitAbsolute(&gCv, &gMu, &t);
  if (gVerbosity > 1) {
    printf("TestAbsWait: unlocking\n");
  }
  NaClXMutexUnlock(&gMu);
}
예제 #3
0
int NaClClockInit(void) {
  if (0 != NaClGetTimeOfDay(&g_nacl_clock_tv)) {
    return 0;
  }
  g_NaClClock_is_initialized = NaClMutexCtor(&g_nacl_clock_mu);
  return g_NaClClock_is_initialized;
}
예제 #4
0
/*
 * Records the time in sv and  returns its index in sv
 * Note that the first time this routine is called on a sv that was just
 * constructed via NaClPerfCounterCtor(), it will return 1, but that
 * is actually the SECOND sample.
 */
int NaClPerfCounterMark(struct NaClPerfCounter *sv, const char *ev_name)
{
  if((NULL == sv) || (NULL == ev_name))
  {
    ZLOG(LOG_ERROR, "NaClPerfCounterMark received null args");
    return -1;
  }
  if(sv->samples >= NACL_MAX_PERF_COUNTER_SAMPLES)
  {
    ZLOG(LOG_ERROR, "NaClPerfCounterMark going beyond buffer size");
    return -1;
  }
  /* busy loop until we succeed, damn it */
  while(0 != NaClGetTimeOfDay(&(sv->sample_list[sv->samples])))
    ;

  /*
   * This relies upon memset() inside NaClPerfCounterCtor() for
   * correctness
   */

  NACL_ASSERT_IS_ARRAY(sv->sample_names[sv->samples]);

  strncpy(sv->sample_names[sv->samples], ev_name, LAST_IDX(sv->sample_names[sv->samples]));
  /* Being explicit about string termination */
  sv->sample_names[sv->samples][LAST_IDX(sv->sample_names[sv->samples])] = '\0';

  return (sv->samples)++;
}
예제 #5
0
void NaClPerfCounterCtor(struct NaClPerfCounter *sv, const char *app_name)
{
  if(NULL == sv)
  {
    ZLOG(LOG_ERROR, "NaClPerfCounterStart received null pointer");
    return;
  };

  memset(sv, 0, sizeof(struct NaClPerfCounter));

  if(NULL == app_name)
  {
    app_name = "__unknown_app__";
  }

  NACL_ASSERT_IS_ARRAY(sv->app_name);
  strncpy(sv->app_name, app_name, LAST_IDX(sv->app_name));

  /* Being explicit about string termination */
  sv->app_name[LAST_IDX(sv->app_name)] = '\0';

  strncpy(sv->sample_names[0], "__start__", LAST_IDX(sv->sample_names[0]));

  while(0 != NaClGetTimeOfDay(&sv->sample_list[sv->samples]))
  {
    /* repeat until we get a sample */
  }

  sv->samples++;
}
예제 #6
0
int32_t NaClSysGetTimeOfDay(struct NaClAppThread      *natp,
                            struct nacl_abi_timeval   *tv,
                            struct nacl_abi_timezone  *tz) {
  int32_t                 retval;
  uintptr_t               sysaddr;
  UNREFERENCED_PARAMETER(tz);

  NaClSysCommonThreadSyscallEnter(natp);

  sysaddr = NaClUserToSysAddrRange(natp->nap, (uintptr_t) tv, sizeof tv);

  /*
   * tz is not supported in linux, nor is it supported by glibc, since
   * tzset(3) and the zoneinfo file should be used instead.
   *
   * TODO(bsy) Do we make the zoneinfo directory available to
   * applications?
   */

  if (kNaClBadAddress == sysaddr) {
    retval = -NACL_ABI_EFAULT;
    goto cleanup;
  }

  retval = NaClGetTimeOfDay((struct nacl_abi_timeval *) sysaddr);
cleanup:
  NaClSysCommonThreadSyscallLeave(natp);
  return retval;
}
/*
 * ClockRealtimeAccuracyTest compares the time returned by
 * NACL_ABI_CLOCK_REALTIME against that returned by NaClGetTimeOfDay.
 */
int ClockRealtimeAccuracyTest(void) {
  int                       num_failures = 0;

  int                       err;
  struct nacl_abi_timespec  t_now_ts;
  struct nacl_abi_timeval   t_now_tv;

  uint64_t                  t_now_ts_nanos;
  uint64_t                  t_now_tv_nanos;
  int64_t                   t_now_diff_nanos;

  printf("\nCLOCK_REALTIME accuracy test:\n");

  if (0 != (err = NaClClockGetTime(NACL_ABI_CLOCK_REALTIME, &t_now_ts))) {
    fprintf(stderr,
            "nacl_clock_test: NaClClockGetTime (now) failed, error %d\n",
            err);
    num_failures++;
    goto done;
  }
  if (0 != (err = NaClGetTimeOfDay(&t_now_tv))) {
    fprintf(stderr,
            "nacl_clock_test: NaClGetTimeOfDay (now) failed, error %d\n",
            err);
    num_failures++;
    goto done;
  }

  t_now_ts_nanos = t_now_ts.tv_sec * NANOS_PER_UNIT + t_now_ts.tv_nsec;
  t_now_tv_nanos = t_now_tv.nacl_abi_tv_sec * NANOS_PER_UNIT
      + t_now_tv.nacl_abi_tv_usec * NANOS_PER_MICRO;

  printf("clock_gettime:   %20"NACL_PRIu64" nS\n", t_now_ts_nanos);
  printf("gettimeofday:    %20"NACL_PRIu64" nS\n", t_now_tv_nanos);

  t_now_diff_nanos = t_now_ts_nanos - t_now_tv_nanos;
  if (t_now_diff_nanos < 0) {
    t_now_diff_nanos = -t_now_diff_nanos;
  }
  printf("time difference: %20"NACL_PRId64" nS\n", t_now_diff_nanos);

  if (t_now_ts_nanos < g_syscall_overhead) {
    printf("discrepancy too large\n");
    num_failures++;
  }
 done:
  printf((0 == num_failures) ? "PASSED\n" : "FAILED\n");
  return num_failures;
}
예제 #8
0
int32_t NaClSysGetTimeOfDay(struct NaClAppThread      *natp,
                            struct nacl_abi_timeval   *tv,
                            struct nacl_abi_timezone  *tz) {
  uintptr_t               sysaddr;
  int                     retval;
  struct nacl_abi_timeval now;

  UNREFERENCED_PARAMETER(tz);

  NaClLog(3,
          ("Entered NaClSysGetTimeOfDay(%08"NACL_PRIxPTR
           ", 0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxPTR")\n"),
          (uintptr_t) natp, (uintptr_t) tv, (uintptr_t) tz);
  NaClSysCommonThreadSyscallEnter(natp);

  sysaddr = NaClUserToSysAddrRange(natp->nap, (uintptr_t) tv, sizeof tv);

  /*
   * tz is not supported in linux, nor is it supported by glibc, since
   * tzset(3) and the zoneinfo file should be used instead.
   *
   * TODO(bsy) Do we make the zoneinfo directory available to
   * applications?
   */

  if (kNaClBadAddress == sysaddr) {
    retval = -NACL_ABI_EFAULT;
    goto cleanup;
  }

  retval = NaClGetTimeOfDay(&now);
  if (0 == retval) {
    /*
     * To make it harder to distinguish Linux platforms from Windows,
     * coarsen the time to the same level we get on Windows -
     * milliseconds, unless in "debug" mode.
     */
    if (!NaClHighResolutionTimerEnabled()) {
      now.nacl_abi_tv_usec = (now.nacl_abi_tv_usec / 1000) * 1000;
    }
    CHECK(now.nacl_abi_tv_usec >= 0);
    CHECK(now.nacl_abi_tv_usec < NACL_MICROS_PER_UNIT);
    *(struct nacl_abi_timeval *) sysaddr = now;
  }
cleanup:
  NaClSysCommonThreadSyscallLeave(natp);
  return retval;
}
void TimerCheckElapsed(struct Timer             *self,
                       uint64_t                 cond_timeout_usec,
                       uint64_t                 min_elapsed_usec,
                       uint64_t                 max_elapsed_usec) {
  struct nacl_abi_timeval now;
  uint64_t                elapsed_usec;
  int                     failed;

  (void) NaClGetTimeOfDay(&now);
  elapsed_usec = kMicroXinX * (now.nacl_abi_tv_sec - self->base.nacl_abi_tv_sec)
      + now.nacl_abi_tv_usec - self->base.nacl_abi_tv_usec;

  /*
   * NB: De Morgan's thm on ASSERT args so that there will be some output
   * on failure.
   */
  failed = (min_elapsed_usec > elapsed_usec
            || elapsed_usec > max_elapsed_usec);
  if (gVerbosity || failed) {
    printf("condvar timeout was %"NACL_PRId64".%06"NACL_PRId64" sec\n",
           cond_timeout_usec / kMicroXinX,
           cond_timeout_usec % kMicroXinX);
    printf("min elapsed %"NACL_PRId64".%06"NACL_PRId64" sec\n",
           min_elapsed_usec / kMicroXinX,
           min_elapsed_usec % kMicroXinX);
    printf("max elapsed %"NACL_PRId64".%06"NACL_PRId64" sec\n",
           max_elapsed_usec / kMicroXinX,
           max_elapsed_usec % kMicroXinX);
    printf("actual elapsed %"NACL_PRId64".%06"NACL_PRId64" sec\n",
           elapsed_usec / kMicroXinX,
           elapsed_usec % kMicroXinX);
    if (failed) {
      PrintFailureSuggestions();
    }
  }
  ASSERT(min_elapsed_usec <= elapsed_usec);
  ASSERT(elapsed_usec <= max_elapsed_usec);
}
void TimerStart(struct Timer *self) {
  (void) NaClGetTimeOfDay(&self->base);
}