Commit 5f518c69 authored by Nick Mathewson's avatar Nick Mathewson 🦀
Browse files

Merge remote-tracking branch 'public/monotime_coarse_stamps'

parents c470a6d2 9c37e8c8
Loading
Loading
Loading
Loading
+3 −3
Original line number Original line Diff line number Diff line
@@ -472,7 +472,7 @@ buf_add_chunk_with_capacity(buf_t *buf, size_t capacity, int capped)
    chunk = chunk_new_with_alloc_size(buf_preferred_chunk_size(capacity));
    chunk = chunk_new_with_alloc_size(buf_preferred_chunk_size(capacity));
  }
  }


  chunk->inserted_time = (uint32_t)monotime_coarse_absolute_msec();
  chunk->inserted_time = monotime_coarse_get_stamp();


  if (buf->tail) {
  if (buf->tail) {
    tor_assert(buf->head);
    tor_assert(buf->head);
@@ -487,8 +487,8 @@ buf_add_chunk_with_capacity(buf_t *buf, size_t capacity, int capped)
}
}


/** Return the age of the oldest chunk in the buffer <b>buf</b>, in
/** Return the age of the oldest chunk in the buffer <b>buf</b>, in
 * milliseconds.  Requires the current monotonic time, in truncated msec,
 * timestamp units.  Requires the current monotonic timestamp as its
 * as its input <b>now</b>.
 * input <b>now</b>.
 */
 */
uint32_t
uint32_t
buf_get_oldest_chunk_timestamp(const buf_t *buf, uint32_t now)
buf_get_oldest_chunk_timestamp(const buf_t *buf, uint32_t now)
+1 −2
Original line number Original line Diff line number Diff line
@@ -86,8 +86,7 @@ typedef struct chunk_t {
  size_t DBG_alloc;
  size_t DBG_alloc;
#endif
#endif
  char *data; /**< A pointer to the first byte of data stored in <b>mem</b>. */
  char *data; /**< A pointer to the first byte of data stored in <b>mem</b>. */
  uint32_t inserted_time; /**< Timestamp in truncated ms since epoch
  uint32_t inserted_time; /**< Timestamp when this chunk was inserted. */
                           * when this chunk was inserted. */
  char mem[FLEXIBLE_ARRAY_MEMBER]; /**< The actual memory used for storage in
  char mem[FLEXIBLE_ARRAY_MEMBER]; /**< The actual memory used for storage in
                * this chunk. */
                * this chunk. */
} chunk_t;
} chunk_t;
+76 −0
Original line number Original line Diff line number Diff line
@@ -279,6 +279,7 @@ monotime_reset_ratchets_for_testing(void)
 * nanoseconds.
 * nanoseconds.
 */
 */
static struct mach_timebase_info mach_time_info;
static struct mach_timebase_info mach_time_info;
static int monotime_shift = 0;


static void
static void
monotime_init_internal(void)
monotime_init_internal(void)
@@ -287,6 +288,14 @@ monotime_init_internal(void)
  int r = mach_timebase_info(&mach_time_info);
  int r = mach_timebase_info(&mach_time_info);
  tor_assert(r == 0);
  tor_assert(r == 0);
  tor_assert(mach_time_info.denom != 0);
  tor_assert(mach_time_info.denom != 0);

  {
    // approximate only.
    uint64_t ns_per_tick = mach_time_info.numer / mach_time_info.denom;
    uint64_t ms_per_tick = ns_per_tick * ONE_MILLION;
    // requires that tor_log2(0) == 0.
    monotime_shift = tor_log2(ms_per_tick);
  }
}
}


/**
/**
@@ -321,6 +330,12 @@ monotime_diff_nsec(const monotime_t *start,
  return diff_nsec;
  return diff_nsec;
}
}


uint32_t
monotime_coarse_to_stamp(const monotime_coarse_t *t)
{
  return (uint32_t)(t->abstime_ >> monotime_shift);
}

/* end of "__APPLE__" */
/* end of "__APPLE__" */
#elif defined(HAVE_CLOCK_GETTIME)
#elif defined(HAVE_CLOCK_GETTIME)


@@ -399,6 +414,18 @@ monotime_diff_nsec(const monotime_t *start,
  return diff_nsec;
  return diff_nsec;
}
}


/* This value is ONE_BILLION >> 20. */
const uint32_t STAMP_TICKS_PER_SECOND = 953;

uint32_t
monotime_coarse_to_stamp(const monotime_coarse_t *t)
{
  uint32_t nsec = (uint32_t)t->ts_.tv_nsec;
  uint32_t sec = (uint32_t)t->ts_.tv_sec;

  return (sec * STAMP_TICKS_PER_SECOND) + (nsec >> 20);
}

/* end of "HAVE_CLOCK_GETTIME" */
/* end of "HAVE_CLOCK_GETTIME" */
#elif defined (_WIN32)
#elif defined (_WIN32)


@@ -531,6 +558,14 @@ monotime_coarse_diff_nsec(const monotime_coarse_t *start,
  return monotime_coarse_diff_msec(start, end) * ONE_MILLION;
  return monotime_coarse_diff_msec(start, end) * ONE_MILLION;
}
}


const uint32_t STAMP_TICKS_PER_SECOND = 1000;

uint32_t
monotime_coarse_to_stamp(const monotime_coarse_t *t)
{
  return (uint32_t) t->tick_count;
}

/* end of "_WIN32" */
/* end of "_WIN32" */
#elif defined(MONOTIME_USING_GETTIMEOFDAY)
#elif defined(MONOTIME_USING_GETTIMEOFDAY)


@@ -567,6 +602,17 @@ monotime_diff_nsec(const monotime_t *start,
  return (diff.tv_sec * ONE_BILLION + diff.tv_usec * 1000);
  return (diff.tv_sec * ONE_BILLION + diff.tv_usec * 1000);
}
}


/* This value is ONE_MILLION >> 10. */
const uint32_t STAMP_TICKS_PER_SECOND = 976;

uint32_t
monotime_coarse_to_stamp(const monotime_coarse_t *t)
{
  const uint32_t usec = (uint32_t)t->tv_.tv_usec;
  const uint32_t sec = (uint32_t)t->tv_.tv_sec;
  return (sec * STAMP_TICKS_PER_SECOND) | (nsec >> 10);
}

/* end of "MONOTIME_USING_GETTIMEOFDAY" */
/* end of "MONOTIME_USING_GETTIMEOFDAY" */
#else
#else
#error "No way to implement monotonic timers."
#error "No way to implement monotonic timers."
@@ -653,5 +699,35 @@ monotime_coarse_absolute_msec(void)
{
{
  return monotime_coarse_absolute_nsec() / ONE_MILLION;
  return monotime_coarse_absolute_nsec() / ONE_MILLION;
}
}
#else
#define initalized_at_coarse initialized_at
#endif /* defined(MONOTIME_COARSE_FN_IS_DIFFERENT) */
#endif /* defined(MONOTIME_COARSE_FN_IS_DIFFERENT) */


/**
 * Return the current time "stamp" as described by monotime_coarse_to_stamp.
 */
uint32_t
monotime_coarse_get_stamp(void)
{
  monotime_coarse_t now;
  monotime_coarse_get(&now);
  return monotime_coarse_to_stamp(&now);
}

#ifdef __APPLE__
uint64_t
monotime_coarse_stamp_units_to_approx_msec(uint64_t units)
{
  /* Recover as much precision as we can. */
  uint64_t abstime_diff = (units << monotime_shift);
  return (abstime_diff * mach_time_info.numer) /
    (mach_time_info.denom * ONE_MILLION);
}
#else
uint64_t
monotime_coarse_stamp_units_to_approx_msec(uint64_t units)
{
  return (units * 1000) / STAMP_TICKS_PER_SECOND;
}
#endif
+17 −0
Original line number Original line Diff line number Diff line
@@ -117,6 +117,23 @@ uint64_t monotime_coarse_absolute_msec(void);
#define monotime_coarse_absolute_msec monotime_absolute_msec
#define monotime_coarse_absolute_msec monotime_absolute_msec
#endif /* defined(MONOTIME_COARSE_FN_IS_DIFFERENT) */
#endif /* defined(MONOTIME_COARSE_FN_IS_DIFFERENT) */


/**
 * Return a "timestamp" approximation for a coarse monotonic timer.
 * This timestamp is meant to be fast to calculate and easy to
 * compare, and have a unit of something roughly around 1 msec.
 *
 * It will wrap over from time to time.
 *
 * It has no defined zero point.
 */
uint32_t monotime_coarse_to_stamp(const monotime_coarse_t *t);
/**
 * Convert a difference, expressed in the units of monotime_coarse_to_stamp,
 * into an approximate number of milliseconds.
 */
uint64_t monotime_coarse_stamp_units_to_approx_msec(uint64_t units);
uint32_t monotime_coarse_get_stamp(void);

#if defined(MONOTIME_COARSE_TYPE_IS_DIFFERENT)
#if defined(MONOTIME_COARSE_TYPE_IS_DIFFERENT)
int64_t monotime_coarse_diff_nsec(const monotime_coarse_t *start,
int64_t monotime_coarse_diff_nsec(const monotime_coarse_t *start,
    const monotime_coarse_t *end);
    const monotime_coarse_t *end);
+28 −29
Original line number Original line Diff line number Diff line
@@ -2176,12 +2176,12 @@ n_cells_in_circ_queues(const circuit_t *c)
}
}


/**
/**
 * Return the age of the oldest cell queued on <b>c</b>, in milliseconds.
 * Return the age of the oldest cell queued on <b>c</b>, in timestamp units.
 * Return 0 if there are no cells queued on c.  Requires that <b>now</b> be
 * Return 0 if there are no cells queued on c.  Requires that <b>now</b> be
 * the current time in milliseconds since the epoch, truncated.
 * the current coarse timestamp.
 *
 *
 * This function will return incorrect results if the oldest cell queued on
 * This function will return incorrect results if the oldest cell queued on
 * the circuit is older than 2**32 msec (about 49 days) old.
 * the circuit is older than about 2**32 msec (about 49 days) old.
 */
 */
STATIC uint32_t
STATIC uint32_t
circuit_max_queued_cell_age(const circuit_t *c, uint32_t now)
circuit_max_queued_cell_age(const circuit_t *c, uint32_t now)
@@ -2190,12 +2190,12 @@ circuit_max_queued_cell_age(const circuit_t *c, uint32_t now)
  packed_cell_t *cell;
  packed_cell_t *cell;


  if (NULL != (cell = TOR_SIMPLEQ_FIRST(&c->n_chan_cells.head)))
  if (NULL != (cell = TOR_SIMPLEQ_FIRST(&c->n_chan_cells.head)))
    age = now - cell->inserted_time;
    age = now - cell->inserted_timestamp;


  if (! CIRCUIT_IS_ORIGIN(c)) {
  if (! CIRCUIT_IS_ORIGIN(c)) {
    const or_circuit_t *orcirc = CONST_TO_OR_CIRCUIT(c);
    const or_circuit_t *orcirc = CONST_TO_OR_CIRCUIT(c);
    if (NULL != (cell = TOR_SIMPLEQ_FIRST(&orcirc->p_chan_cells.head))) {
    if (NULL != (cell = TOR_SIMPLEQ_FIRST(&orcirc->p_chan_cells.head))) {
      uint32_t age2 = now - cell->inserted_time;
      uint32_t age2 = now - cell->inserted_timestamp;
      if (age2 > age)
      if (age2 > age)
        return age2;
        return age2;
    }
    }
@@ -2203,31 +2203,30 @@ circuit_max_queued_cell_age(const circuit_t *c, uint32_t now)
  return age;
  return age;
}
}


/** Return the age in milliseconds of the oldest buffer chunk on <b>conn</b>,
/** Return the age of the oldest buffer chunk on <b>conn</b>, where age is
 * where age is taken in milliseconds before the time <b>now</b> (in truncated
 * taken in timestamp units before the time <b>now</b>.  If the connection has
 * absolute monotonic msec).  If the connection has no data, treat
 * no data, treat it as having age zero.
 * it as having age zero.
 **/
 **/
static uint32_t
static uint32_t
conn_get_buffer_age(const connection_t *conn, uint32_t now)
conn_get_buffer_age(const connection_t *conn, uint32_t now_ts)
{
{
  uint32_t age = 0, age2;
  uint32_t age = 0, age2;
  if (conn->outbuf) {
  if (conn->outbuf) {
    age2 = buf_get_oldest_chunk_timestamp(conn->outbuf, now);
    age2 = buf_get_oldest_chunk_timestamp(conn->outbuf, now_ts);
    if (age2 > age)
    if (age2 > age)
      age = age2;
      age = age2;
  }
  }
  if (conn->inbuf) {
  if (conn->inbuf) {
    age2 = buf_get_oldest_chunk_timestamp(conn->inbuf, now);
    age2 = buf_get_oldest_chunk_timestamp(conn->inbuf, now_ts);
    if (age2 > age)
    if (age2 > age)
      age = age2;
      age = age2;
  }
  }
  return age;
  return age;
}
}


/** Return the age in milliseconds of the oldest buffer chunk on any stream in
/** Return the age in timestamp units of the oldest buffer chunk on any stream
 * the linked list <b>stream</b>, where age is taken in milliseconds before
 * in the linked list <b>stream</b>, where age is taken in timestamp units
 * the time <b>now</b> (in truncated milliseconds since the epoch). */
 * before the timestamp <b>now</b>. */
static uint32_t
static uint32_t
circuit_get_streams_max_data_age(const edge_connection_t *stream, uint32_t now)
circuit_get_streams_max_data_age(const edge_connection_t *stream, uint32_t now)
{
{
@@ -2246,9 +2245,9 @@ circuit_get_streams_max_data_age(const edge_connection_t *stream, uint32_t now)
  return age;
  return age;
}
}


/** Return the age in milliseconds of the oldest buffer chunk on any stream
/** Return the age in timestamp units of the oldest buffer chunk on any stream
 * attached to the circuit <b>c</b>, where age is taken in milliseconds before
 * attached to the circuit <b>c</b>, where age is taken before the timestamp
 * the time <b>now</b> (in truncated milliseconds since the epoch). */
 * <b>now</b>. */
STATIC uint32_t
STATIC uint32_t
circuit_max_queued_data_age(const circuit_t *c, uint32_t now)
circuit_max_queued_data_age(const circuit_t *c, uint32_t now)
{
{
@@ -2262,8 +2261,8 @@ circuit_max_queued_data_age(const circuit_t *c, uint32_t now)
}
}


/** Return the age of the oldest cell or stream buffer chunk on the circuit
/** Return the age of the oldest cell or stream buffer chunk on the circuit
 * <b>c</b>, where age is taken in milliseconds before the time <b>now</b> (in
 * <b>c</b>, where age is taken in timestamp units before the timestamp
 * truncated milliseconds since the epoch). */
 * <b>now</b> */
STATIC uint32_t
STATIC uint32_t
circuit_max_queued_item_age(const circuit_t *c, uint32_t now)
circuit_max_queued_item_age(const circuit_t *c, uint32_t now)
{
{
@@ -2293,7 +2292,7 @@ circuits_compare_by_oldest_queued_item_(const void **a_, const void **b_)
    return -1;
    return -1;
}
}


static uint32_t now_ms_for_buf_cmp;
static uint32_t now_ts_for_buf_cmp;


/** Helper to sort a list of circuit_t by age of oldest item, in descending
/** Helper to sort a list of circuit_t by age of oldest item, in descending
 * order. */
 * order. */
@@ -2302,8 +2301,8 @@ conns_compare_by_buffer_age_(const void **a_, const void **b_)
{
{
  const connection_t *a = *a_;
  const connection_t *a = *a_;
  const connection_t *b = *b_;
  const connection_t *b = *b_;
  time_t age_a = conn_get_buffer_age(a, now_ms_for_buf_cmp);
  time_t age_a = conn_get_buffer_age(a, now_ts_for_buf_cmp);
  time_t age_b = conn_get_buffer_age(b, now_ms_for_buf_cmp);
  time_t age_b = conn_get_buffer_age(b, now_ts_for_buf_cmp);


  if (age_a < age_b)
  if (age_a < age_b)
    return 1;
    return 1;
@@ -2328,7 +2327,7 @@ circuits_handle_oom(size_t current_allocation)
  size_t mem_recovered=0;
  size_t mem_recovered=0;
  int n_circuits_killed=0;
  int n_circuits_killed=0;
  int n_dirconns_killed=0;
  int n_dirconns_killed=0;
  uint32_t now_ms;
  uint32_t now_ts;
  log_notice(LD_GENERAL, "We're low on memory.  Killing circuits with "
  log_notice(LD_GENERAL, "We're low on memory.  Killing circuits with "
             "over-long queues. (This behavior is controlled by "
             "over-long queues. (This behavior is controlled by "
             "MaxMemInQueues.)");
             "MaxMemInQueues.)");
@@ -2341,11 +2340,11 @@ circuits_handle_oom(size_t current_allocation)
    mem_to_recover = current_allocation - mem_target;
    mem_to_recover = current_allocation - mem_target;
  }
  }


  now_ms = (uint32_t)monotime_coarse_absolute_msec();
  now_ts = monotime_coarse_get_stamp();


  circlist = circuit_get_global_list();
  circlist = circuit_get_global_list();
  SMARTLIST_FOREACH_BEGIN(circlist, circuit_t *, circ) {
  SMARTLIST_FOREACH_BEGIN(circlist, circuit_t *, circ) {
    circ->age_tmp = circuit_max_queued_item_age(circ, now_ms);
    circ->age_tmp = circuit_max_queued_item_age(circ, now_ts);
  } SMARTLIST_FOREACH_END(circ);
  } SMARTLIST_FOREACH_END(circ);


  /* This is O(n log n); there are faster algorithms we could use instead.
  /* This is O(n log n); there are faster algorithms we could use instead.
@@ -2358,9 +2357,9 @@ circuits_handle_oom(size_t current_allocation)
  } SMARTLIST_FOREACH_END(circ);
  } SMARTLIST_FOREACH_END(circ);


  /* Now sort the connection array ... */
  /* Now sort the connection array ... */
  now_ms_for_buf_cmp = now_ms;
  now_ts_for_buf_cmp = now_ts;
  smartlist_sort(connection_array, conns_compare_by_buffer_age_);
  smartlist_sort(connection_array, conns_compare_by_buffer_age_);
  now_ms_for_buf_cmp = 0;
  now_ts_for_buf_cmp = 0;


  /* Fix up the connection array to its new order. */
  /* Fix up the connection array to its new order. */
  SMARTLIST_FOREACH_BEGIN(connection_array, connection_t *, conn) {
  SMARTLIST_FOREACH_BEGIN(connection_array, connection_t *, conn) {
@@ -2379,7 +2378,7 @@ circuits_handle_oom(size_t current_allocation)
     * data older than this circuit. */
     * data older than this circuit. */
    while (conn_idx < smartlist_len(connection_array)) {
    while (conn_idx < smartlist_len(connection_array)) {
      connection_t *conn = smartlist_get(connection_array, conn_idx);
      connection_t *conn = smartlist_get(connection_array, conn_idx);
      uint32_t conn_age = conn_get_buffer_age(conn, now_ms);
      uint32_t conn_age = conn_get_buffer_age(conn, now_ts);
      if (conn_age < circ->age_tmp) {
      if (conn_age < circ->age_tmp) {
        break;
        break;
      }
      }
Loading