diff --git a/src/common/buffers.c b/src/common/buffers.c index a21cf2ab5b..e5d3664638 100644 --- a/src/common/buffers.c +++ b/src/common/buffers.c @@ -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->inserted_time = (uint32_t)monotime_coarse_absolute_msec(); + chunk->inserted_time = monotime_coarse_get_stamp(); if (buf->tail) { 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 buf, in - * milliseconds. Requires the current monotonic time, in truncated msec, - * as its input now. + * timestamp units. Requires the current monotonic timestamp as its + * input now. */ uint32_t buf_get_oldest_chunk_timestamp(const buf_t *buf, uint32_t now) diff --git a/src/common/buffers.h b/src/common/buffers.h index dd96ddcb6c..8e938eec38 100644 --- a/src/common/buffers.h +++ b/src/common/buffers.h @@ -86,8 +86,7 @@ typedef struct chunk_t { size_t DBG_alloc; #endif char *data; /**< A pointer to the first byte of data stored in mem. */ - uint32_t inserted_time; /**< Timestamp in truncated ms since epoch - * when this chunk was inserted. */ + uint32_t inserted_time; /**< Timestamp when this chunk was inserted. */ char mem[FLEXIBLE_ARRAY_MEMBER]; /**< The actual memory used for storage in * this chunk. */ } chunk_t; diff --git a/src/common/compat_time.c b/src/common/compat_time.c index 7fd4281ade..7c89881667 100644 --- a/src/common/compat_time.c +++ b/src/common/compat_time.c @@ -279,6 +279,7 @@ monotime_reset_ratchets_for_testing(void) * nanoseconds. */ static struct mach_timebase_info mach_time_info; +static int monotime_shift = 0; static void monotime_init_internal(void) @@ -287,6 +288,14 @@ monotime_init_internal(void) int r = mach_timebase_info(&mach_time_info); tor_assert(r == 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; } +uint32_t +monotime_coarse_to_stamp(const monotime_coarse_t *t) +{ + return (uint32_t)(t->abstime_ >> monotime_shift); +} + /* end of "__APPLE__" */ #elif defined(HAVE_CLOCK_GETTIME) @@ -399,6 +414,18 @@ monotime_diff_nsec(const monotime_t *start, 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" */ #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; } +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" */ #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); } +/* 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" */ #else #error "No way to implement monotonic timers." @@ -653,5 +699,35 @@ monotime_coarse_absolute_msec(void) { return monotime_coarse_absolute_nsec() / ONE_MILLION; } +#else +#define initalized_at_coarse initialized_at #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 + diff --git a/src/common/compat_time.h b/src/common/compat_time.h index 5ea4aae42b..462dceccea 100644 --- a/src/common/compat_time.h +++ b/src/common/compat_time.h @@ -117,6 +117,23 @@ uint64_t monotime_coarse_absolute_msec(void); #define monotime_coarse_absolute_msec monotime_absolute_msec #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) int64_t monotime_coarse_diff_nsec(const monotime_coarse_t *start, const monotime_coarse_t *end); diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index d37d986f17..fa19c0afd0 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -2176,12 +2176,12 @@ n_cells_in_circ_queues(const circuit_t *c) } /** - * Return the age of the oldest cell queued on c, in milliseconds. + * Return the age of the oldest cell queued on c, in timestamp units. * Return 0 if there are no cells queued on c. Requires that now 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 - * 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 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; 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)) { const or_circuit_t *orcirc = CONST_TO_OR_CIRCUIT(c); 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) return age2; } @@ -2203,31 +2203,30 @@ circuit_max_queued_cell_age(const circuit_t *c, uint32_t now) return age; } -/** Return the age in milliseconds of the oldest buffer chunk on conn, - * where age is taken in milliseconds before the time now (in truncated - * absolute monotonic msec). If the connection has no data, treat - * it as having age zero. +/** Return the age of the oldest buffer chunk on conn, where age is + * taken in timestamp units before the time now. If the connection has + * no data, treat it as having age zero. **/ 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; 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) age = age2; } 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) age = age2; } return age; } -/** Return the age in milliseconds of the oldest buffer chunk on any stream in - * the linked list stream, where age is taken in milliseconds before - * the time now (in truncated milliseconds since the epoch). */ +/** Return the age in timestamp units of the oldest buffer chunk on any stream + * in the linked list stream, where age is taken in timestamp units + * before the timestamp now. */ static uint32_t 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 the age in milliseconds of the oldest buffer chunk on any stream - * attached to the circuit c, where age is taken in milliseconds before - * the time now (in truncated milliseconds since the epoch). */ +/** Return the age in timestamp units of the oldest buffer chunk on any stream + * attached to the circuit c, where age is taken before the timestamp + * now. */ STATIC uint32_t 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 - * c, where age is taken in milliseconds before the time now (in - * truncated milliseconds since the epoch). */ + * c, where age is taken in timestamp units before the timestamp + * now */ STATIC uint32_t 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; } -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 * order. */ @@ -2302,8 +2301,8 @@ conns_compare_by_buffer_age_(const void **a_, const void **b_) { const connection_t *a = *a_; const connection_t *b = *b_; - time_t age_a = conn_get_buffer_age(a, now_ms_for_buf_cmp); - time_t age_b = conn_get_buffer_age(b, 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_ts_for_buf_cmp); if (age_a < age_b) return 1; @@ -2328,7 +2327,7 @@ circuits_handle_oom(size_t current_allocation) size_t mem_recovered=0; int n_circuits_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 " "over-long queues. (This behavior is controlled by " "MaxMemInQueues.)"); @@ -2341,11 +2340,11 @@ circuits_handle_oom(size_t current_allocation) 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(); 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); /* 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); /* 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_); - now_ms_for_buf_cmp = 0; + now_ts_for_buf_cmp = 0; /* Fix up the connection array to its new order. */ SMARTLIST_FOREACH_BEGIN(connection_array, connection_t *, conn) { @@ -2379,7 +2378,7 @@ circuits_handle_oom(size_t current_allocation) * data older than this circuit. */ while (conn_idx < smartlist_len(connection_array)) { 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) { break; } diff --git a/src/or/or.h b/src/or/or.h index e10decf734..b078022326 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1166,8 +1166,8 @@ typedef struct packed_cell_t { /** Next cell queued on this circuit. */ TOR_SIMPLEQ_ENTRY(packed_cell_t) next; char body[CELL_MAX_NETWORK_SIZE]; /**< Cell as packed for network. */ - uint32_t inserted_time; /**< Time (in milliseconds since epoch, with high - * bits truncated) when this cell was inserted. */ + uint32_t inserted_timestamp; /**< Time (in timestamp units) when this cell + * was inserted */ } packed_cell_t; /** A queue of cells on a circuit, waiting to be added to the diff --git a/src/or/relay.c b/src/or/relay.c index 09f70793d3..bbaf4ee785 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -2482,7 +2482,7 @@ cell_queue_append_packed_copy(circuit_t *circ, cell_queue_t *queue, (void)exitward; (void)use_stats; - copy->inserted_time = (uint32_t) monotime_coarse_absolute_msec(); + copy->inserted_timestamp = monotime_coarse_get_stamp(); cell_queue_append(queue, copy); } @@ -2789,9 +2789,10 @@ channel_flush_from_first_active_circuit, (channel_t *chan, int max)) /* Calculate the exact time that this cell has spent in the queue. */ if (get_options()->CellStatistics || get_options()->TestingEnableCellStatsEvent) { - uint32_t msec_waiting; - uint32_t msec_now = (uint32_t)monotime_coarse_absolute_msec(); - msec_waiting = msec_now - cell->inserted_time; + uint32_t timestamp_now = monotime_coarse_get_stamp(); + uint32_t msec_waiting = + (uint32_t) monotime_coarse_stamp_units_to_approx_msec( + timestamp_now - cell->inserted_timestamp); if (get_options()->CellStatistics && !CIRCUIT_IS_ORIGIN(circ)) { or_circ = TO_OR_CIRCUIT(circ); diff --git a/src/test/test_buffers.c b/src/test/test_buffers.c index 9f4e19bc5f..057d9fa2dc 100644 --- a/src/test/test_buffers.c +++ b/src/test/test_buffers.c @@ -450,52 +450,54 @@ test_buffer_time_tracking(void *arg) tt_assert(buf); monotime_coarse_set_mock_time_nsec(START_NSEC); - const uint32_t START_MSEC = (uint32_t)monotime_coarse_absolute_msec(); + const uint32_t START_TS = monotime_coarse_get_stamp(); /* Empty buffer means the timestamp is 0. */ - tt_int_op(0, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC)); - tt_int_op(0, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+1000)); + tt_int_op(0, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_TS)); + tt_int_op(0, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_TS+1000)); buf_add(buf, "ABCDEFG", 7); - tt_int_op(1000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+1000)); + tt_int_op(1000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_TS+1000)); buf2 = buf_copy(buf); tt_assert(buf2); tt_int_op(1234, OP_EQ, - buf_get_oldest_chunk_timestamp(buf2, START_MSEC+1234)); + buf_get_oldest_chunk_timestamp(buf2, START_TS+1234)); /* Now add more bytes; enough to overflow the first chunk. */ monotime_coarse_set_mock_time_nsec(START_NSEC + 123 * (uint64_t)1000000); + const uint32_t TS2 = monotime_coarse_get_stamp(); for (i = 0; i < 600; ++i) buf_add(buf, "ABCDEFG", 7); tt_int_op(4207, OP_EQ, buf_datalen(buf)); /* The oldest bytes are still in the front. */ - tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2000)); + tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_TS+2000)); /* Once those bytes are dropped, the chunk is still on the first * timestamp. */ buf_get_bytes(buf, tmp, 100); - tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2000)); + tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_TS+2000)); /* But once we discard the whole first chunk, we get the data in the second * chunk. */ buf_get_bytes(buf, tmp, 4000); tt_int_op(107, OP_EQ, buf_datalen(buf)); - tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2123)); + tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, TS2+2000)); /* This time we'll be grabbing a chunk from the freelist, and making sure its time gets updated */ monotime_coarse_set_mock_time_nsec(START_NSEC + 5617 * (uint64_t)1000000); + const uint32_t TS3 = monotime_coarse_get_stamp(); for (i = 0; i < 600; ++i) buf_add(buf, "ABCDEFG", 7); tt_int_op(4307, OP_EQ, buf_datalen(buf)); - tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2123)); + tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, TS2+2000)); buf_get_bytes(buf, tmp, 4000); buf_get_bytes(buf, tmp, 306); - tt_int_op(0, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+5617)); - tt_int_op(383, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+6000)); + tt_int_op(0, OP_EQ, buf_get_oldest_chunk_timestamp(buf, TS3)); + tt_int_op(383, OP_EQ, buf_get_oldest_chunk_timestamp(buf, TS3+383)); done: buf_free(buf); diff --git a/src/test/test_oom.c b/src/test/test_oom.c index cf28690a28..973501c3d7 100644 --- a/src/test/test_oom.c +++ b/src/test/test_oom.c @@ -202,7 +202,7 @@ test_oom_streambuf(void *arg) { or_options_t *options = get_options_mutable(); circuit_t *c1 = NULL, *c2 = NULL, *c3 = NULL, *c4 = NULL, *c5 = NULL; - uint32_t tvms; + uint32_t tvts; int i; smartlist_t *edgeconns = smartlist_new(); const uint64_t start_ns = 1389641159 * (uint64_t)1000000000; @@ -270,22 +270,28 @@ test_oom_streambuf(void *arg) now_ns -= now_ns % 1000000000; now_ns += 1000000000; monotime_coarse_set_mock_time_nsec(now_ns); - tvms = (uint32_t) monotime_coarse_absolute_msec(); + tvts = monotime_coarse_get_stamp(); - tt_int_op(circuit_max_queued_cell_age(c1, tvms), OP_EQ, 500); - tt_int_op(circuit_max_queued_cell_age(c2, tvms), OP_EQ, 490); - tt_int_op(circuit_max_queued_cell_age(c3, tvms), OP_EQ, 480); - tt_int_op(circuit_max_queued_cell_age(c4, tvms), OP_EQ, 0); +#define ts_is_approx(ts, val) do { \ + uint32_t x_ = (uint32_t) monotime_coarse_stamp_units_to_approx_msec(ts); \ + tt_int_op(x_, OP_GE, val - 5); \ + tt_int_op(x_, OP_LE, val + 5); \ + } while (0) - tt_int_op(circuit_max_queued_data_age(c1, tvms), OP_EQ, 390); - tt_int_op(circuit_max_queued_data_age(c2, tvms), OP_EQ, 380); - tt_int_op(circuit_max_queued_data_age(c3, tvms), OP_EQ, 0); - tt_int_op(circuit_max_queued_data_age(c4, tvms), OP_EQ, 370); + ts_is_approx(circuit_max_queued_cell_age(c1, tvts), 500); + ts_is_approx(circuit_max_queued_cell_age(c2, tvts), 490); + ts_is_approx(circuit_max_queued_cell_age(c3, tvts), 480); + ts_is_approx(circuit_max_queued_cell_age(c4, tvts), 0); - tt_int_op(circuit_max_queued_item_age(c1, tvms), OP_EQ, 500); - tt_int_op(circuit_max_queued_item_age(c2, tvms), OP_EQ, 490); - tt_int_op(circuit_max_queued_item_age(c3, tvms), OP_EQ, 480); - tt_int_op(circuit_max_queued_item_age(c4, tvms), OP_EQ, 370); + ts_is_approx(circuit_max_queued_data_age(c1, tvts), 390); + ts_is_approx(circuit_max_queued_data_age(c2, tvts), 380); + ts_is_approx(circuit_max_queued_data_age(c3, tvts), 0); + ts_is_approx(circuit_max_queued_data_age(c4, tvts), 370); + + ts_is_approx(circuit_max_queued_item_age(c1, tvts), 500); + ts_is_approx(circuit_max_queued_item_age(c2, tvts), 490); + ts_is_approx(circuit_max_queued_item_age(c3, tvts), 480); + ts_is_approx(circuit_max_queued_item_age(c4, tvts), 370); tt_int_op(cell_queues_get_total_allocation(), OP_EQ, packed_cell_mem_cost() * 80); @@ -301,7 +307,7 @@ test_oom_streambuf(void *arg) smartlist_add(edgeconns, ec); } tt_int_op(buf_get_total_allocation(), OP_EQ, 4096*17*2); - tt_int_op(circuit_max_queued_item_age(c4, tvms), OP_EQ, 1000); + ts_is_approx(circuit_max_queued_item_age(c4, tvts), 1000); tt_int_op(cell_queues_check_size(), OP_EQ, 0); diff --git a/src/test/test_util.c b/src/test/test_util.c index 0519a4758f..7856b506ba 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -5801,6 +5801,7 @@ test_util_monotonic_time(void *arg) monotime_coarse_t mtc1, mtc2; uint64_t nsec1, nsec2, usec1, msec1; uint64_t nsecc1, nsecc2, usecc1, msecc1; + uint32_t stamp1, stamp2; monotime_init(); @@ -5812,6 +5813,7 @@ test_util_monotonic_time(void *arg) nsecc1 = monotime_coarse_absolute_nsec(); usecc1 = monotime_coarse_absolute_usec(); msecc1 = monotime_coarse_absolute_msec(); + stamp1 = monotime_coarse_to_stamp(&mtc1); tor_sleep_msec(200); @@ -5819,6 +5821,7 @@ test_util_monotonic_time(void *arg) monotime_coarse_get(&mtc2); nsec2 = monotime_absolute_nsec(); nsecc2 = monotime_coarse_absolute_nsec(); + stamp2 = monotime_coarse_to_stamp(&mtc2); /* We need to be a little careful here since we don't know the system load. */ @@ -5840,6 +5843,11 @@ test_util_monotonic_time(void *arg) tt_u64_op(msecc1, OP_LE, nsecc1 / 1000000 + 1); tt_u64_op(usecc1, OP_LE, nsecc1 / 1000 + 1000); + uint64_t coarse_stamp_diff = + monotime_coarse_stamp_units_to_approx_msec(stamp2-stamp1); + tt_u64_op(coarse_stamp_diff, OP_GE, 120); + tt_u64_op(coarse_stamp_diff, OP_LE, 1200); + done: ; }