aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator')
-rw-r--r--erts/emulator/beam/erl_gc.c21
-rw-r--r--erts/emulator/beam/erl_time.h9
-rw-r--r--erts/emulator/beam/erl_time_sup.c507
-rw-r--r--erts/emulator/beam/sys.h10
-rw-r--r--erts/emulator/beam/time.c66
-rw-r--r--erts/emulator/sys/unix/erl_unix_sys.h6
-rw-r--r--erts/emulator/sys/unix/sys_time.c433
-rw-r--r--erts/emulator/sys/win32/erl_poll.c1
-rw-r--r--erts/emulator/sys/win32/erl_win_sys.h2
-rw-r--r--erts/emulator/sys/win32/sys_time.c16
-rw-r--r--erts/emulator/test/after_SUITE.erl29
-rw-r--r--erts/emulator/test/alloc_SUITE.erl21
-rw-r--r--erts/emulator/test/binary_SUITE.erl4
-rw-r--r--erts/emulator/test/busy_port_SUITE.erl8
-rw-r--r--erts/emulator/test/decode_packet_SUITE.erl4
-rw-r--r--erts/emulator/test/distribution_SUITE.erl23
-rw-r--r--erts/emulator/test/driver_SUITE.erl37
-rw-r--r--erts/emulator/test/erl_link_SUITE.erl7
-rw-r--r--erts/emulator/test/estone_SUITE.erl25
-rw-r--r--erts/emulator/test/float_SUITE.erl7
-rw-r--r--erts/emulator/test/gc_SUITE.erl10
-rw-r--r--erts/emulator/test/map_SUITE.erl4
-rw-r--r--erts/emulator/test/monitor_SUITE.erl6
-rw-r--r--erts/emulator/test/mtx_SUITE.erl6
-rw-r--r--erts/emulator/test/nif_SUITE.erl4
-rw-r--r--erts/emulator/test/node_container_SUITE.erl24
-rw-r--r--erts/emulator/test/old_scheduler_SUITE.erl24
-rw-r--r--erts/emulator/test/port_SUITE.erl6
-rw-r--r--erts/emulator/test/process_SUITE.erl20
-rw-r--r--erts/emulator/test/scheduler_SUITE.erl25
-rw-r--r--erts/emulator/test/signal_SUITE.erl6
-rw-r--r--erts/emulator/test/smoke_test_SUITE.erl7
-rw-r--r--erts/emulator/test/system_info_SUITE.erl7
-rw-r--r--erts/emulator/test/time_SUITE.erl75
-rw-r--r--erts/emulator/test/timer_bif_SUITE.erl5
-rw-r--r--erts/emulator/test/trace_call_time_SUITE.erl18
36 files changed, 912 insertions, 571 deletions
diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c
index 0b18d2b9e8..eadd558dda 100644
--- a/erts/emulator/beam/erl_gc.c
+++ b/erts/emulator/beam/erl_gc.c
@@ -404,7 +404,7 @@ erts_garbage_collect(Process* p, int need, Eterm* objv, int nobj)
Uint reclaimed_now = 0;
int done = 0;
int off_heap_msgs;
- Uint ms1, s1, us1;
+ ErtsMonotonicTime start_time = 0; /* Shut up faulty warning... */
erts_aint32_t state;
ErtsSchedulerData *esdp;
#ifdef USE_VM_PROBES
@@ -424,9 +424,8 @@ erts_garbage_collect(Process* p, int need, Eterm* objv, int nobj)
state = erts_smp_atomic32_read_bor_nob(&p->state, ERTS_PSFLG_GC);
off_heap_msgs = state & ERTS_PSFLG_OFF_HEAP_MSGS;
- if (erts_system_monitor_long_gc != 0) {
- get_now(&ms1, &s1, &us1);
- }
+ if (erts_system_monitor_long_gc != 0)
+ start_time = erts_get_monotonic_time();
ERTS_CHK_OFFHEAP(p);
@@ -474,16 +473,14 @@ erts_garbage_collect(Process* p, int need, Eterm* objv, int nobj)
}
if (erts_system_monitor_long_gc != 0) {
- Uint ms2, s2, us2;
- Sint t;
+ ErtsMonotonicTime end_time;
+ Uint gc_time;
if (erts_test_long_gc_sleep)
while (0 != erts_milli_sleep(erts_test_long_gc_sleep));
- get_now(&ms2, &s2, &us2);
- t = ms2 - ms1;
- t = t*1000000 + s2 - s1;
- t = t*1000 + ((Sint) (us2 - us1))/1000;
- if (t > 0 && (Uint)t > erts_system_monitor_long_gc) {
- monitor_long_gc(p, t);
+ end_time = erts_get_monotonic_time();
+ gc_time = (Uint) ERTS_MONOTONIC_TO_MSEC(end_time - start_time);
+ if (gc_time && gc_time > erts_system_monitor_long_gc) {
+ monitor_long_gc(p, gc_time);
}
}
if (erts_system_monitor_large_heap != 0) {
diff --git a/erts/emulator/beam/erl_time.h b/erts/emulator/beam/erl_time.h
index cb7764addc..5af3c21d40 100644
--- a/erts/emulator/beam/erl_time.h
+++ b/erts/emulator/beam/erl_time.h
@@ -26,6 +26,12 @@
#define ERTS_TIME_ASSERT(B) ((void) 1)
#endif
+typedef enum {
+ ERTS_NO_TIME_WARP_MODE,
+ ERTS_SINGLE_TIME_WARP_MODE,
+ ERTS_MULTI_TIME_WARP_MODE
+} ErtsTimeWarpMode;
+
typedef struct ErtsTimerWheel_ ErtsTimerWheel;
typedef erts_atomic64_t * ErtsNextTimeoutRef;
extern ErtsTimerWheel *erts_default_timer_wheel;
@@ -38,7 +44,6 @@ extern SysTimeval erts_first_emu_time;
typedef struct erl_timer {
struct erl_timer* next; /* next entry tiw slot or chain */
struct erl_timer* prev; /* prev entry tiw slot or chain */
- Uint slot; /* slot in timer wheel */
erts_smp_atomic_t wheel;
ErtsMonotonicTime timeout_pos; /* Timeout in absolute clock ticks */
/* called when timeout */
@@ -46,6 +51,7 @@ typedef struct erl_timer {
/* called when cancel (may be NULL) */
void (*cancel)(void*);
void* arg; /* argument to timeout/cancel procs */
+ int slot; /* slot in timer wheel */
} ErlTimer;
typedef void (*ErlTimeoutProc)(void*);
@@ -77,6 +83,7 @@ void erts_cancel_smp_ptimer(ErtsSmpPTimer *ptimer);
void erts_monitor_time_offset(Eterm id, Eterm ref);
int erts_demonitor_time_offset(Eterm ref);
+int erts_init_time_sup(int, ErtsTimeWarpMode);
void erts_late_init_time_sup(void);
/* timer-wheel api */
diff --git a/erts/emulator/beam/erl_time_sup.c b/erts/emulator/beam/erl_time_sup.c
index 9a7466ff48..2b6abcda55 100644
--- a/erts/emulator/beam/erl_time_sup.c
+++ b/erts/emulator/beam/erl_time_sup.c
@@ -133,6 +133,7 @@ struct time_sup_read_only__ {
ErtsTimeWarpMode warp_mode;
#ifdef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT
ErtsMonotonicTime moffset;
+ int os_corrected_monotonic_time;
int os_monotonic_time_disable;
char *os_monotonic_time_func;
char *os_monotonic_time_clock_id;
@@ -159,12 +160,16 @@ struct time_sup_read_only__ {
ErtsMonotonicTime large_diff;
ErtsMonotonicTime small_diff;
} adj;
+ struct {
+ ErtsMonotonicTime error;
+ ErtsMonotonicTime resolution;
+ int intervals;
+ int use_avg;
+ } drift_adj;
};
typedef struct {
-#ifndef ERTS_HAVE_CORRECTED_OS_MONOTONIC
ErtsMonotonicTime drift; /* Correction for os monotonic drift */
-#endif
ErtsMonotonicTime error; /* Correction for error between system times */
} ErtsMonotonicCorrection;
@@ -174,7 +179,7 @@ typedef struct {
ErtsMonotonicCorrection correction;
} ErtsMonotonicCorrectionInstance;
-#define ERTS_DRIFT_INTERVALS 5
+#define ERTS_MAX_DRIFT_INTERVALS 50
typedef struct {
struct {
struct {
@@ -185,7 +190,7 @@ typedef struct {
ErtsMonotonicTime sys;
ErtsMonotonicTime mon;
} time;
- } intervals[ERTS_DRIFT_INTERVALS];
+ } intervals[ERTS_MAX_DRIFT_INTERVALS];
struct {
ErtsMonotonicTime sys;
ErtsMonotonicTime mon;
@@ -197,9 +202,7 @@ typedef struct {
typedef struct {
ErtsMonotonicCorrectionInstance prev;
ErtsMonotonicCorrectionInstance curr;
-#ifndef ERTS_HAVE_CORRECTED_OS_MONOTONIC
ErtsMonotonicDriftData drift;
-#endif
ErtsMonotonicTime last_check;
int short_check_interval;
} ErtsMonotonicCorrectionData;
@@ -213,10 +216,11 @@ struct time_sup_infrequently_changed__ {
} parmon;
ErtsMonotonicTime minit;
#endif
- int finalized_offset;
ErtsSystemTime sinit;
ErtsMonotonicTime not_corrected_moffset;
- erts_atomic64_t offset;
+ erts_smp_atomic64_t offset;
+ ErtsMonotonicTime shadow_offset;
+ erts_smp_atomic32_t preliminary_offset;
};
struct time_sup_frequently_changed__ {
@@ -254,19 +258,19 @@ erts_get_approx_time(void)
static ERTS_INLINE void
init_time_offset(ErtsMonotonicTime offset)
{
- erts_atomic64_init_nob(&time_sup.inf.c.offset, (erts_aint64_t) offset);
+ erts_smp_atomic64_init_nob(&time_sup.inf.c.offset, (erts_aint64_t) offset);
}
static ERTS_INLINE void
set_time_offset(ErtsMonotonicTime offset)
{
- erts_atomic64_set_relb(&time_sup.inf.c.offset, (erts_aint64_t) offset);
+ erts_smp_atomic64_set_relb(&time_sup.inf.c.offset, (erts_aint64_t) offset);
}
static ERTS_INLINE ErtsMonotonicTime
get_time_offset(void)
{
- return (ErtsMonotonicTime) erts_atomic64_read_acqb(&time_sup.inf.c.offset);
+ return (ErtsMonotonicTime) erts_smp_atomic64_read_acqb(&time_sup.inf.c.offset);
}
@@ -290,16 +294,38 @@ get_time_offset(void)
#define ERTS_TIME_DRIFT_MAX_ADJ_DIFF ERTS_USEC_TO_MONOTONIC(50)
#define ERTS_TIME_DRIFT_MIN_ADJ_DIFF ERTS_USEC_TO_MONOTONIC(5)
+/*
+ * Maximum drift of the OS monotonic clock expected.
+ *
+ * We use 1 milli second per second. If the monotonic
+ * clock drifts more than this we will fail to adjust for
+ * drift, and error correction will kick in instead.
+ * If it is larger than this, one could argue that the
+ * primitive is to poor to be used...
+ */
+#define ERTS_MAX_MONOTONIC_DRIFT ERTS_MSEC_TO_MONOTONIC(1)
+
+/*
+ * We assume that precision is 32 times worse than the
+ * resolution. This is a wild guess, but there are no
+ * practical way to determine actual precision.
+ */
+#define ERTS_ASSUMED_PRECISION_DROP 32
+
+#define ERTS_MIN_MONOTONIC_DRIFT_MEASUREMENT \
+ (ERTS_SHORT_TIME_CORRECTION_CHECK - 2*ERTS_MAX_MONOTONIC_DRIFT)
+
+
static ERTS_INLINE ErtsMonotonicTime
calc_corrected_erl_mtime(ErtsMonotonicTime os_mtime,
ErtsMonotonicCorrectionInstance *cip,
- ErtsMonotonicTime *os_mdiff_p)
+ ErtsMonotonicTime *os_mdiff_p,
+ int os_drift_corrected)
{
ErtsMonotonicTime erl_mtime, diff = os_mtime - cip->os_mtime;
ERTS_TIME_ASSERT(diff >= 0);
-#ifndef ERTS_HAVE_CORRECTED_OS_MONOTONIC
- diff += (cip->correction.drift*diff)/ERTS_MONOTONIC_TIME_UNIT;
-#endif
+ if (!os_drift_corrected)
+ diff += (cip->correction.drift*diff)/ERTS_MONOTONIC_TIME_UNIT;
erl_mtime = cip->erl_mtime;
erl_mtime += diff;
erl_mtime += cip->correction.error*(diff/ERTS_TCORR_ERR_UNIT);
@@ -308,7 +334,8 @@ calc_corrected_erl_mtime(ErtsMonotonicTime os_mtime,
return erl_mtime;
}
-static ErtsMonotonicTime get_corrected_time(void)
+static ERTS_INLINE ErtsMonotonicTime
+read_corrected_time(int os_drift_corrected)
{
ErtsMonotonicTime os_mtime;
ErtsMonotonicCorrectionData cdata;
@@ -331,7 +358,18 @@ static ErtsMonotonicTime get_corrected_time(void)
cip = &cdata.prev;
}
- return calc_corrected_erl_mtime(os_mtime, cip, NULL);
+ return calc_corrected_erl_mtime(os_mtime, cip, NULL,
+ os_drift_corrected);
+}
+
+static ErtsMonotonicTime get_os_drift_corrected_time(void)
+{
+ return read_corrected_time(!0);
+}
+
+static ErtsMonotonicTime get_corrected_time(void)
+{
+ return read_corrected_time(0);
}
#ifdef ERTS_TIME_CORRECTION_PRINT
@@ -352,66 +390,42 @@ print_correction(int change,
usec_sdiff = ERTS_MONOTONIC_TO_USEC(sdiff);
if (!change)
- fprintf(stderr,
- "sdiff = %lld usec : [ec=%lld ppm, dc=%lld ppb] : "
- "tmo = %lld msec\r\n",
- (long long) usec_sdiff,
- (long long) (1000000*old_ecorr) / ERTS_TCORR_ERR_UNIT,
- (long long) (1000000000*old_dcorr) / ERTS_MONOTONIC_TIME_UNIT,
- (long long) tmo);
+ erts_fprintf(stderr,
+ "sdiff = %b64d usec : [ec=%b64d ppm, dc=%b64d ppb] : "
+ "tmo = %bpu msec\r\n",
+ usec_sdiff,
+ (1000000*old_ecorr) / ERTS_TCORR_ERR_UNIT,
+ (1000000000*old_dcorr) / ERTS_MONOTONIC_TIME_UNIT,
+ tmo);
else
- fprintf(stderr,
- "sdiff = %lld usec : [ec=%lld ppm, dc=%lld ppb] "
- "-> [ec=%lld ppm, dc=%lld ppb] : tmo = %lld msec\r\n",
- (long long) usec_sdiff,
- (long long) (1000000*old_ecorr) / ERTS_TCORR_ERR_UNIT,
- (long long) (1000000000*old_dcorr) / ERTS_MONOTONIC_TIME_UNIT,
- (long long) (1000000*new_ecorr) / ERTS_TCORR_ERR_UNIT,
- (long long) (1000000000*new_dcorr) / ERTS_MONOTONIC_TIME_UNIT,
- (long long) tmo);
-
+ erts_fprintf(stderr,
+ "sdiff = %b64d usec : [ec=%b64d ppm, dc=%b64d ppb] "
+ "-> [ec=%b64d ppm, dc=%b64d ppb] : tmo = %bpu msec\r\n",
+ usec_sdiff,
+ (1000000*old_ecorr) / ERTS_TCORR_ERR_UNIT,
+ (1000000000*old_dcorr) / ERTS_MONOTONIC_TIME_UNIT,
+ (1000000*new_ecorr) / ERTS_TCORR_ERR_UNIT,
+ (1000000000*new_dcorr) / ERTS_MONOTONIC_TIME_UNIT,
+ tmo);
}
#endif
static void
-check_time_correction(void *unused)
+check_time_correction(void *idap)
{
-#ifndef ERTS_TIME_CORRECTION_PRINT
-# define ERTS_PRINT_CORRECTION
-#else
-# ifdef ERTS_HAVE_CORRECTED_OS_MONOTONIC
-# define ERTS_PRINT_CORRECTION \
- print_correction(set_new_correction, \
- sdiff, \
- cip->correction.error, \
- 0, \
- new_correction.error, \
- 0, \
- timeout)
-# else
-# define ERTS_PRINT_CORRECTION \
- print_correction(set_new_correction, \
- sdiff, \
- cip->correction.error, \
- cip->correction.drift, \
- new_correction.error, \
- new_correction.drift, \
- timeout)
-# endif
-#endif
+ UWord init_drift_adj = (UWord) idap;
ErtsMonotonicCorrectionData cdata;
ErtsMonotonicCorrection new_correction;
ErtsMonotonicCorrectionInstance *cip;
ErtsMonotonicTime mdiff, sdiff, os_mtime, erl_mtime, os_stime,
erl_stime, time_offset;
Uint timeout;
- int set_new_correction, begin_short_intervals = 0;
+ int os_drift_corrected = time_sup.r.o.os_corrected_monotonic_time;
+ int set_new_correction = 0, begin_short_intervals = 0;
erts_smp_rwmtx_rlock(&time_sup.inf.c.parmon.rwmtx);
- ASSERT(time_sup.inf.c.finalized_offset);
-
erts_os_times(&os_mtime, &os_stime);
cdata = time_sup.inf.c.parmon.cdata;
@@ -423,14 +437,23 @@ check_time_correction(void *unused)
"OS monotonic time stepped backwards\n");
cip = &cdata.curr;
- erl_mtime = calc_corrected_erl_mtime(os_mtime, cip, &mdiff);
+ erl_mtime = calc_corrected_erl_mtime(os_mtime, cip, &mdiff,
+ os_drift_corrected);
time_offset = get_time_offset();
erl_stime = erl_mtime + time_offset;
sdiff = erl_stime - os_stime;
+ if (time_sup.inf.c.shadow_offset) {
+ ERTS_TIME_ASSERT(time_sup.r.o.warp_mode == ERTS_SINGLE_TIME_WARP_MODE);
+ if (erts_smp_atomic32_read_nob(&time_sup.inf.c.preliminary_offset))
+ sdiff += time_sup.inf.c.shadow_offset;
+ else
+ time_sup.inf.c.shadow_offset = 0;
+ }
+
new_correction = cip->correction;
-
+
if (time_sup.r.o.warp_mode == ERTS_MULTI_TIME_WARP_MODE
&& (sdiff < -2*time_sup.r.o.adj.small_diff
|| 2*time_sup.r.o.adj.small_diff < sdiff)) {
@@ -440,9 +463,24 @@ check_time_correction(void *unused)
set_time_offset(time_offset);
schedule_send_time_offset_changed_notifications(time_offset);
begin_short_intervals = 1;
- if (cdata.curr.correction.error == 0)
- set_new_correction = 0;
- else {
+ if (cdata.curr.correction.error != 0) {
+ set_new_correction = 1;
+ new_correction.error = 0;
+ }
+ }
+ else if ((time_sup.r.o.warp_mode == ERTS_SINGLE_TIME_WARP_MODE
+ && erts_smp_atomic32_read_nob(&time_sup.inf.c.preliminary_offset))
+ && (sdiff < -2*time_sup.r.o.adj.small_diff
+ || 2*time_sup.r.o.adj.small_diff < sdiff)) {
+ /*
+ * System time diff exeeded limits; change shadow offset
+ * and let OS system time leap away from Erlang system
+ * time.
+ */
+ time_sup.inf.c.shadow_offset -= sdiff;
+ sdiff = 0;
+ begin_short_intervals = 1;
+ if (cdata.curr.correction.error != 0) {
set_new_correction = 1;
new_correction.error = 0;
}
@@ -462,16 +500,11 @@ check_time_correction(void *unused)
else
new_correction.error = -ERTS_TCORR_ERR_SMALL_ADJ;
}
- else {
- set_new_correction = 0;
- }
}
else if (cdata.curr.correction.error > 0) {
if (sdiff < 0) {
- if (cdata.curr.correction.error == ERTS_TCORR_ERR_LARGE_ADJ
- || -time_sup.r.o.adj.large_diff <= sdiff)
- set_new_correction = 0;
- else {
+ if (cdata.curr.correction.error != ERTS_TCORR_ERR_LARGE_ADJ
+ && sdiff < -time_sup.r.o.adj.large_diff) {
new_correction.error = ERTS_TCORR_ERR_LARGE_ADJ;
set_new_correction = 1;
}
@@ -490,14 +523,11 @@ check_time_correction(void *unused)
}
else /* if (cdata.curr.correction.error < 0) */ {
if (0 < sdiff) {
- if (cdata.curr.correction.error == -ERTS_TCORR_ERR_LARGE_ADJ
- || sdiff <= time_sup.r.o.adj.large_diff)
- set_new_correction = 0;
- else {
+ if (cdata.curr.correction.error != -ERTS_TCORR_ERR_LARGE_ADJ
+ && time_sup.r.o.adj.large_diff < sdiff) {
new_correction.error = -ERTS_TCORR_ERR_LARGE_ADJ;
set_new_correction = 1;
}
- set_new_correction = 0;
}
else if (sdiff < -time_sup.r.o.adj.small_diff) {
set_new_correction = 1;
@@ -512,8 +542,7 @@ check_time_correction(void *unused)
}
}
-#ifndef ERTS_HAVE_CORRECTED_OS_MONOTONIC
- {
+ if (!os_drift_corrected) {
ErtsMonotonicDriftData *ddp = &time_sup.inf.c.parmon.cdata.drift;
int ix = ddp->ix;
ErtsMonotonicTime mtime_diff, old_os_mtime;
@@ -521,25 +550,26 @@ check_time_correction(void *unused)
old_os_mtime = ddp->intervals[ix].time.mon;
mtime_diff = os_mtime - old_os_mtime;
- if (mtime_diff >= ERTS_SEC_TO_MONOTONIC(10)) {
+ if ((mtime_diff >= ERTS_MIN_MONOTONIC_DRIFT_MEASUREMENT)
+ | init_drift_adj) {
ErtsMonotonicTime drift_adj, drift_adj_diff, old_os_stime,
- stime_diff, mtime_acc, stime_acc, avg_drift_adj;
+ smtime_diff, stime_diff, mtime_acc, stime_acc,
+ avg_drift_adj, max_drift;
old_os_stime = ddp->intervals[ix].time.sys;
mtime_acc = ddp->acc.mon;
stime_acc = ddp->acc.sys;
- avg_drift_adj = (((stime_acc - mtime_acc)*ERTS_MONOTONIC_TIME_UNIT)
+ avg_drift_adj = (((stime_acc - mtime_acc)
+ * ERTS_MONOTONIC_TIME_UNIT)
/ mtime_acc);
mtime_diff = os_mtime - old_os_mtime;
stime_diff = os_stime - old_os_stime;
- drift_adj = (((stime_diff - mtime_diff)*ERTS_MONOTONIC_TIME_UNIT)
- / mtime_diff);
-
+ smtime_diff = stime_diff - mtime_diff;
ix++;
- if (ix >= ERTS_DRIFT_INTERVALS)
+ if (ix >= time_sup.r.o.drift_adj.intervals)
ix = 0;
mtime_acc -= ddp->intervals[ix].diff.mon;
mtime_acc += mtime_diff;
@@ -555,24 +585,50 @@ check_time_correction(void *unused)
ddp->acc.mon = mtime_acc;
ddp->acc.sys = stime_acc;
- drift_adj_diff = avg_drift_adj - drift_adj;
- if (drift_adj_diff < -ERTS_TIME_DRIFT_MAX_ADJ_DIFF
- || ERTS_TIME_DRIFT_MAX_ADJ_DIFF < drift_adj_diff) {
- ddp->dirty_counter = ERTS_DRIFT_INTERVALS;
+ max_drift = ERTS_MAX_MONOTONIC_DRIFT;
+ max_drift *= ERTS_MONOTONIC_TO_SEC(mtime_diff);
+
+ if (smtime_diff > time_sup.r.o.drift_adj.error + max_drift
+ || smtime_diff < -1*time_sup.r.o.drift_adj.error - max_drift) {
+ dirty_intervals:
+ /*
+ * We had a leap in system time. Mark array as
+ * dirty to ensure that dirty values are rotated
+ * out before we use it again...
+ */
+ ddp->dirty_counter = time_sup.r.o.drift_adj.intervals;
begin_short_intervals = 1;
}
- else {
- if (ddp->dirty_counter <= 0) {
- drift_adj = ((stime_acc - mtime_acc)
- *ERTS_MONOTONIC_TIME_UNIT) / mtime_acc;
+ else if (ddp->dirty_counter > 0) {
+ if (init_drift_adj) {
+ new_correction.drift = ((smtime_diff
+ * ERTS_MONOTONIC_TIME_UNIT)
+ / mtime_diff);
+ set_new_correction = 1;
}
- if (ddp->dirty_counter >= 0) {
- if (ddp->dirty_counter == 0) {
- /* Force set new drift correction... */
- set_new_correction = 1;
- }
+ ddp->dirty_counter--;
+ }
+ else {
+ if (ddp->dirty_counter == 0) {
+ /* Force set new drift correction... */
+ set_new_correction = 1;
ddp->dirty_counter--;
}
+
+ if (time_sup.r.o.drift_adj.use_avg)
+ drift_adj = (((stime_acc - mtime_acc)
+ * ERTS_MONOTONIC_TIME_UNIT)
+ / mtime_acc);
+ else
+ drift_adj = ((smtime_diff
+ * ERTS_MONOTONIC_TIME_UNIT)
+ / mtime_diff);
+
+ drift_adj_diff = avg_drift_adj - drift_adj;
+ if (drift_adj_diff < -ERTS_TIME_DRIFT_MAX_ADJ_DIFF
+ || ERTS_TIME_DRIFT_MAX_ADJ_DIFF < drift_adj_diff)
+ goto dirty_intervals;
+
drift_adj_diff = drift_adj - new_correction.drift;
if (drift_adj_diff) {
if (drift_adj_diff > ERTS_TIME_DRIFT_MAX_ADJ_DIFF)
@@ -580,7 +636,6 @@ check_time_correction(void *unused)
else if (drift_adj_diff < -ERTS_TIME_DRIFT_MAX_ADJ_DIFF)
drift_adj_diff = -ERTS_TIME_DRIFT_MAX_ADJ_DIFF;
new_correction.drift += drift_adj_diff;
-
if (drift_adj_diff < -ERTS_TIME_DRIFT_MIN_ADJ_DIFF
|| ERTS_TIME_DRIFT_MIN_ADJ_DIFF < drift_adj_diff) {
set_new_correction = 1;
@@ -589,7 +644,6 @@ check_time_correction(void *unused)
}
}
}
-#endif
begin_short_intervals |= set_new_correction;
@@ -608,25 +662,34 @@ check_time_correction(void *unused)
timeout = ERTS_MONOTONIC_TO_MSEC(ERTS_LONG_TIME_CORRECTION_CHECK);
else {
ErtsMonotonicTime ecorr = new_correction.error;
- if (sdiff < 0)
- sdiff = -1*sdiff;
+ ErtsMonotonicTime abs_sdiff;
+ abs_sdiff = (sdiff < 0) ? -1*sdiff : sdiff;
if (ecorr < 0)
ecorr = -1*ecorr;
- if (sdiff > ecorr*(ERTS_LONG_TIME_CORRECTION_CHECK/ERTS_TCORR_ERR_UNIT))
+ if (abs_sdiff > ecorr*(ERTS_LONG_TIME_CORRECTION_CHECK/ERTS_TCORR_ERR_UNIT))
timeout = ERTS_MONOTONIC_TO_MSEC(ERTS_LONG_TIME_CORRECTION_CHECK);
else {
- timeout = ERTS_MONOTONIC_TO_MSEC((ERTS_TCORR_ERR_UNIT*sdiff)/ecorr);
+ timeout = ERTS_MONOTONIC_TO_MSEC((ERTS_TCORR_ERR_UNIT*abs_sdiff)/ecorr);
if (timeout < 10)
timeout = 10;
}
}
if (timeout > ERTS_MONOTONIC_TO_MSEC(ERTS_SHORT_TIME_CORRECTION_CHECK)
- && time_sup.inf.c.parmon.cdata.short_check_interval) {
+ && (time_sup.inf.c.parmon.cdata.short_check_interval
+ || time_sup.inf.c.parmon.cdata.drift.dirty_counter >= 0)) {
timeout = ERTS_MONOTONIC_TO_MSEC(ERTS_SHORT_TIME_CORRECTION_CHECK);
}
- ERTS_PRINT_CORRECTION;
+#ifdef ERTS_TIME_CORRECTION_PRINT
+ print_correction(set_new_correction,
+ sdiff,
+ cip->correction.error,
+ cip->correction.drift,
+ new_correction.error,
+ new_correction.drift,
+ timeout);
+#endif
if (set_new_correction) {
erts_smp_rwmtx_rwlock(&time_sup.inf.c.parmon.rwmtx);
@@ -638,16 +701,17 @@ check_time_correction(void *unused)
/*
* Current correction instance begin when
- * OS monotonic time has increased one unit.
+ * OS monotonic time has increased two units.
*/
- os_mtime++;
+ os_mtime += 2;
/*
* Erlang monotonic time corresponding to
* next OS monotonic time using previous
* correction.
*/
- erl_mtime = calc_corrected_erl_mtime(os_mtime, cip, NULL);
+ erl_mtime = calc_corrected_erl_mtime(os_mtime, cip, NULL,
+ os_drift_corrected);
/*
* Save new current correction instance.
@@ -664,18 +728,60 @@ check_time_correction(void *unused)
NULL,
NULL,
timeout);
+}
-#undef ERTS_PRINT_CORRECTION
+static ErtsMonotonicTime get_os_corrected_time(void)
+{
+ ASSERT(time_sup.r.o.warp_mode == ERTS_MULTI_TIME_WARP_MODE);
+ return erts_os_monotonic_time() + time_sup.r.o.moffset;
}
-#ifndef ERTS_HAVE_CORRECTED_OS_MONOTONIC
+static void
+check_time_offset(void *unused)
+{
+ ErtsMonotonicTime sdiff, os_mtime, erl_mtime, os_stime,
+ erl_stime, time_offset;
+
+ ASSERT(time_sup.r.o.warp_mode == ERTS_MULTI_TIME_WARP_MODE);
+
+ erts_os_times(&os_mtime, &os_stime);
+
+ erl_mtime = os_mtime + time_sup.r.o.moffset;
+ time_offset = get_time_offset();
+ erl_stime = erl_mtime + time_offset;
+
+ sdiff = erl_stime - os_stime;
+
+ if ((sdiff < -2*time_sup.r.o.adj.small_diff
+ || 2*time_sup.r.o.adj.small_diff < sdiff)) {
+ /* System time diff exeeded limits; change time offset... */
+#ifdef ERTS_TIME_CORRECTION_PRINT
+ erts_fprintf(stderr, "sdiff = %b64d nsec -> 0 nsec\n",
+ ERTS_MONOTONIC_TO_NSEC(sdiff));
+#endif
+ time_offset -= sdiff;
+ sdiff = 0;
+ set_time_offset(time_offset);
+ schedule_send_time_offset_changed_notifications(time_offset);
+ }
+#ifdef ERTS_TIME_CORRECTION_PRINT
+ else erts_fprintf(stderr, "sdiff = %b64d nsec\n",
+ ERTS_MONOTONIC_TO_NSEC(sdiff));
+#endif
+
+ erts_set_timer(&time_sup.inf.c.parmon.timer,
+ check_time_offset,
+ NULL,
+ NULL,
+ ERTS_MONOTONIC_TO_MSEC(ERTS_LONG_TIME_CORRECTION_CHECK));
+}
static void
-init_check_time_correction(void *unused)
+init_check_time_correction(void *quick_init_drift)
{
ErtsMonotonicDriftData *ddp;
ErtsMonotonicTime old_mtime, old_stime, mtime, stime, mtime_diff,
- stime_diff;
+ stime_diff, smtime_diff, max_drift;
int ix;
ddp = &time_sup.inf.c.parmon.cdata.drift;
@@ -687,7 +793,13 @@ init_check_time_correction(void *unused)
mtime_diff = mtime - old_mtime;
stime_diff = stime - old_stime;
- if (100*stime_diff < 80*mtime_diff || 120*mtime_diff < 100*stime_diff ) {
+ smtime_diff = stime_diff - mtime_diff;
+
+ max_drift = ERTS_MAX_MONOTONIC_DRIFT;
+ max_drift *= ERTS_MONOTONIC_TO_SEC(mtime_diff);
+
+ if (smtime_diff > time_sup.r.o.drift_adj.error + max_drift
+ || smtime_diff < -1*time_sup.r.o.drift_adj.error - max_drift) {
/* Had a system time leap... pretend no drift... */
stime_diff = mtime_diff;
}
@@ -697,29 +809,28 @@ init_check_time_correction(void *unused)
* a drift adjustment, and repeat this interval
* in all slots...
*/
- for (ix = 0; ix < ERTS_DRIFT_INTERVALS; ix++) {
+ for (ix = 0; ix < time_sup.r.o.drift_adj.intervals; ix++) {
ddp->intervals[ix].diff.mon = mtime_diff;
ddp->intervals[ix].diff.sys = stime_diff;
ddp->intervals[ix].time.mon = old_mtime;
ddp->intervals[ix].time.sys = old_stime;
}
- ddp->acc.sys = stime_diff*ERTS_DRIFT_INTERVALS;
- ddp->acc.mon = mtime_diff*ERTS_DRIFT_INTERVALS;
+ ddp->acc.sys = stime_diff*time_sup.r.o.drift_adj.intervals;
+ ddp->acc.mon = mtime_diff*time_sup.r.o.drift_adj.intervals;
ddp->ix = 0;
- ddp->dirty_counter = ERTS_DRIFT_INTERVALS;
+ ddp->dirty_counter = time_sup.r.o.drift_adj.intervals;
- check_time_correction(NULL);
+ check_time_correction(quick_init_drift);
}
-#endif
-
static ErtsMonotonicTime
finalize_corrected_time_offset(ErtsSystemTime *stimep)
{
ErtsMonotonicTime os_mtime;
ErtsMonotonicCorrectionData cdata;
ErtsMonotonicCorrectionInstance *cip;
+ int os_drift_corrected = time_sup.r.o.os_corrected_monotonic_time;
erts_smp_rwmtx_rlock(&time_sup.inf.c.parmon.rwmtx);
@@ -734,25 +845,38 @@ finalize_corrected_time_offset(ErtsSystemTime *stimep)
"OS monotonic time stepped backwards\n");
cip = &cdata.curr;
- return calc_corrected_erl_mtime(os_mtime, cip, NULL);
+ return calc_corrected_erl_mtime(os_mtime, cip, NULL,
+ os_drift_corrected);
}
static void
late_init_time_correction(void)
{
- if (time_sup.inf.c.finalized_offset) {
+ Uint timeout;
+ Uint quick_init_drift_adj;
+ void (*check_func)(void *);
- erts_init_timer(&time_sup.inf.c.parmon.timer);
- erts_set_timer(&time_sup.inf.c.parmon.timer,
-#ifndef ERTS_HAVE_CORRECTED_OS_MONOTONIC
- init_check_time_correction,
-#else
- check_time_correction,
-#endif
- NULL,
- NULL,
- ERTS_MONOTONIC_TO_MSEC(ERTS_SHORT_TIME_CORRECTION_CHECK));
- }
+ quick_init_drift_adj =
+ (Uint) ERTS_MONOTONIC_TO_USEC(time_sup.r.o.drift_adj.error) == 0;
+
+ if (quick_init_drift_adj)
+ timeout = ERTS_MONOTONIC_TO_MSEC(ERTS_SHORT_TIME_CORRECTION_CHECK/10);
+ else
+ timeout = ERTS_MONOTONIC_TO_MSEC(ERTS_SHORT_TIME_CORRECTION_CHECK);
+
+ if (!time_sup.r.o.os_corrected_monotonic_time)
+ check_func = init_check_time_correction;
+ else if (time_sup.r.o.get_time == get_os_corrected_time)
+ check_func = check_time_offset;
+ else
+ check_func = check_time_correction;
+
+ erts_init_timer(&time_sup.inf.c.parmon.timer);
+ erts_set_timer(&time_sup.inf.c.parmon.timer,
+ check_func,
+ NULL,
+ (void *) quick_init_drift_adj,
+ timeout);
}
#endif /* ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT */
@@ -832,6 +956,8 @@ void erts_init_sys_time_sup(void)
#ifdef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT
time_sup.r.o.os_monotonic_time_disable
= !sys_init_time_res.have_os_monotonic_time;
+ time_sup.r.o.os_corrected_monotonic_time =
+ sys_init_time_res.have_corrected_os_monotonic_time;
time_sup.r.o.os_monotonic_time_func
= sys_init_time_res.os_monotonic_time_info.func;
time_sup.r.o.os_monotonic_time_clock_id
@@ -856,7 +982,7 @@ void erts_init_sys_time_sup(void)
int
erts_init_time_sup(int time_correction, ErtsTimeWarpMode time_warp_mode)
{
- ErtsMonotonicTime resolution;
+ ErtsMonotonicTime resolution, ilength, intervals, short_isecs;
#if !ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT
ErtsMonotonicTime abs_native_offset, native_offset;
#endif
@@ -870,9 +996,10 @@ erts_init_time_sup(int time_correction, ErtsTimeWarpMode time_warp_mode)
time_sup.r.o.warp_mode = time_warp_mode;
if (time_warp_mode == ERTS_SINGLE_TIME_WARP_MODE)
- time_sup.inf.c.finalized_offset = 0;
+ erts_smp_atomic32_init_nob(&time_sup.inf.c.preliminary_offset, 1);
else
- time_sup.inf.c.finalized_offset = ~0;
+ erts_smp_atomic32_init_nob(&time_sup.inf.c.preliminary_offset, 0);
+ time_sup.inf.c.shadow_offset = 0;
#if !ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT
@@ -882,7 +1009,7 @@ erts_init_time_sup(int time_correction, ErtsTimeWarpMode time_warp_mode)
time_sup.r.o.start *= ERTS_MONOTONIC_TIME_UNIT;
time_sup.r.o.start += ERTS_MONOTONIC_TIME_UNIT;
native_offset = time_sup.r.o.start - ERTS_MONOTONIC_TIME_UNIT;
- native_offset = native_offset;
+ abs_native_offset = native_offset;
#else /* ARCH_64 */
if (ERTS_MONOTONIC_TIME_UNIT <= 10*1000*1000) {
time_sup.r.o.start = 0;
@@ -938,17 +1065,66 @@ erts_init_time_sup(int time_correction, ErtsTimeWarpMode time_warp_mode)
time_sup.r.o.adj.large_diff = ERTS_USEC_TO_MONOTONIC(500);
time_sup.r.o.adj.small_diff = time_sup.r.o.adj.large_diff/10;
+ time_sup.r.o.drift_adj.resolution = resolution;
+
+ if (time_sup.r.o.os_corrected_monotonic_time) {
+ time_sup.r.o.drift_adj.use_avg = 0;
+ time_sup.r.o.drift_adj.intervals = 0;
+ time_sup.r.o.drift_adj.error = 0;
+ time_sup.inf.c.parmon.cdata.drift.dirty_counter = -1;
+ }
+ else {
+ /*
+ * Calculate length of the interval in seconds needed
+ * in order to get an error that is at most 1 micro second.
+ * If this interval is longer than the short time correction
+ * check interval we use the average of all values instead
+ * of the latest value.
+ */
+ short_isecs = ERTS_MONOTONIC_TO_SEC(ERTS_SHORT_TIME_CORRECTION_CHECK);
+ ilength = ERTS_ASSUMED_PRECISION_DROP * ERTS_MONOTONIC_TIME_UNIT;
+ ilength /= (resolution * ERTS_USEC_TO_MONOTONIC(1));
+ time_sup.r.o.drift_adj.use_avg = ilength > short_isecs;
+
+ if (ilength == 0)
+ intervals = 5;
+ else {
+ intervals = ilength / short_isecs;
+ if (intervals > ERTS_MAX_DRIFT_INTERVALS)
+ intervals = ERTS_MAX_DRIFT_INTERVALS;
+ else if (intervals < 5)
+ intervals = 5;
+ }
+ time_sup.r.o.drift_adj.intervals = (int) intervals;
+
+ /*
+ * drift_adj.error equals maximum assumed error
+ * over a short time interval. We use this value also
+ * when examining a large interval. In this case the
+ * error will be smaller, but we do not want to
+ * recalculate this over and over again.
+ */
+
+ time_sup.r.o.drift_adj.error = ERTS_MONOTONIC_TIME_UNIT;
+ time_sup.r.o.drift_adj.error *= ERTS_ASSUMED_PRECISION_DROP;
+ time_sup.r.o.drift_adj.error /= resolution * short_isecs;
+ }
#ifdef ERTS_TIME_CORRECTION_PRINT
- fprintf(stderr, "start = %lld\n\r", (long long) ERTS_MONOTONIC_TIME_START);
- fprintf(stderr, "native offset = %lld\n\r", (long long) ERTS_MONOTONIC_OFFSET_NATIVE);
- fprintf(stderr, "nsec offset = %lld\n\r", (long long) ERTS_MONOTONIC_OFFSET_NSEC);
- fprintf(stderr, "usec offset = %lld\n\r", (long long) ERTS_MONOTONIC_OFFSET_USEC);
- fprintf(stderr, "msec offset = %lld\n\r", (long long) ERTS_MONOTONIC_OFFSET_MSEC);
- fprintf(stderr, "sec offset = %lld\n\r", (long long) ERTS_MONOTONIC_OFFSET_SEC);
- fprintf(stderr, "large diff = %lld usec\r\n",
- (long long) ERTS_MONOTONIC_TO_USEC(time_sup.r.o.adj.large_diff));
- fprintf(stderr, "small diff = %lld usec\r\n",
- (long long) ERTS_MONOTONIC_TO_USEC(time_sup.r.o.adj.small_diff));
+ erts_fprintf(stderr, "resolution = %b64d\n", resolution);
+ erts_fprintf(stderr, "adj large diff = %b64d usec\n",
+ ERTS_MONOTONIC_TO_USEC(time_sup.r.o.adj.large_diff));
+ erts_fprintf(stderr, "adj small diff = %b64d usec\n",
+ ERTS_MONOTONIC_TO_USEC(time_sup.r.o.adj.small_diff));
+ if (!time_sup.r.o.os_corrected_monotonic_time) {
+ erts_fprintf(stderr, "drift intervals = %d\n",
+ time_sup.r.o.drift_adj.intervals);
+ erts_fprintf(stderr, "drift adj error = %b64d usec\n",
+ ERTS_MONOTONIC_TO_USEC(time_sup.r.o.drift_adj.error));
+ erts_fprintf(stderr, "drift adj max diff = %b64d nsec\n",
+ ERTS_MONOTONIC_TO_NSEC(ERTS_TIME_DRIFT_MAX_ADJ_DIFF));
+ erts_fprintf(stderr, "drift adj min diff = %b64d nsec\n",
+ ERTS_MONOTONIC_TO_NSEC(ERTS_TIME_DRIFT_MIN_ADJ_DIFF));
+ }
#endif
if (ERTS_MONOTONIC_TIME_UNIT < ERTS_CLKTCK_RESOLUTION)
@@ -967,6 +1143,7 @@ erts_init_time_sup(int time_correction, ErtsTimeWarpMode time_warp_mode)
erts_os_times(&time_sup.inf.c.minit,
&time_sup.inf.c.sinit);
time_sup.r.o.moffset = -1*time_sup.inf.c.minit;
+ time_sup.r.o.moffset += ERTS_MONOTONIC_TIME_UNIT;
offset = time_sup.inf.c.sinit;
offset -= ERTS_MONOTONIC_TIME_UNIT;
init_time_offset(offset);
@@ -979,11 +1156,9 @@ erts_init_time_sup(int time_correction, ErtsTimeWarpMode time_warp_mode)
cdatap = &time_sup.inf.c.parmon.cdata;
-#ifndef ERTS_HAVE_CORRECTED_OS_MONOTONIC
cdatap->drift.intervals[0].time.sys = time_sup.inf.c.sinit;
cdatap->drift.intervals[0].time.mon = time_sup.inf.c.minit;
cdatap->curr.correction.drift = 0;
-#endif
cdatap->curr.correction.error = 0;
cdatap->curr.erl_mtime = ERTS_MONOTONIC_TIME_UNIT;
cdatap->curr.os_mtime = time_sup.inf.c.minit;
@@ -991,7 +1166,12 @@ erts_init_time_sup(int time_correction, ErtsTimeWarpMode time_warp_mode)
cdatap->short_check_interval = ERTS_INIT_SHORT_INTERVAL_COUNTER;
cdatap->prev = cdatap->curr;
- time_sup.r.o.get_time = get_corrected_time;
+ if (!time_sup.r.o.os_corrected_monotonic_time)
+ time_sup.r.o.get_time = get_corrected_time;
+ else if (time_sup.r.o.warp_mode == ERTS_MULTI_TIME_WARP_MODE)
+ time_sup.r.o.get_time = get_os_corrected_time;
+ else
+ time_sup.r.o.get_time = get_os_drift_corrected_time;
}
else
#endif
@@ -1020,8 +1200,8 @@ void
erts_late_init_time_sup(void)
{
#ifdef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT
- /* Timer wheel must be initialized */
- if (time_sup.r.o.get_time == get_corrected_time)
+ /* Timer wheel must have beeen initialized */
+ if (time_sup.r.o.get_time != get_not_corrected_time)
late_init_time_correction();
#endif
erts_late_sys_init_time();
@@ -1038,9 +1218,9 @@ ErtsTimeOffsetState erts_time_offset_state(void)
case ERTS_NO_TIME_WARP_MODE:
return ERTS_TIME_OFFSET_FINAL;
case ERTS_SINGLE_TIME_WARP_MODE:
- if (time_sup.inf.c.finalized_offset)
- return ERTS_TIME_OFFSET_FINAL;
- return ERTS_TIME_OFFSET_PRELIMINARY;
+ if (erts_smp_atomic32_read_nob(&time_sup.inf.c.preliminary_offset))
+ return ERTS_TIME_OFFSET_PRELIMINARY;
+ return ERTS_TIME_OFFSET_FINAL;
case ERTS_MULTI_TIME_WARP_MODE:
return ERTS_TIME_OFFSET_VOLATILE;
default:
@@ -1073,7 +1253,7 @@ erts_finalize_time_offset(void)
erts_smp_mtx_lock(&erts_get_time_mtx);
- if (!time_sup.inf.c.finalized_offset) {
+ if (erts_smp_atomic32_read_nob(&time_sup.inf.c.preliminary_offset)) {
ErtsMonotonicTime mtime, new_offset;
#ifdef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT
@@ -1110,19 +1290,12 @@ erts_finalize_time_offset(void)
set_time_offset(new_offset);
schedule_send_time_offset_changed_notifications(new_offset);
- time_sup.inf.c.finalized_offset = ~0;
+ erts_smp_atomic32_set_nob(&time_sup.inf.c.preliminary_offset, 0);
res = ERTS_TIME_OFFSET_PRELIMINARY;
}
erts_smp_mtx_unlock(&erts_get_time_mtx);
-#ifdef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT
- if (res == ERTS_TIME_OFFSET_PRELIMINARY
- && time_sup.r.o.get_time == get_corrected_time) {
- late_init_time_correction();
- }
-#endif
-
return res;
}
default:
diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h
index 251b39508f..f7a21406f3 100644
--- a/erts/emulator/beam/sys.h
+++ b/erts/emulator/beam/sys.h
@@ -703,14 +703,9 @@ extern char *erts_default_arg0;
extern char os_type[];
-typedef enum {
- ERTS_NO_TIME_WARP_MODE,
- ERTS_SINGLE_TIME_WARP_MODE,
- ERTS_MULTI_TIME_WARP_MODE
-} ErtsTimeWarpMode;
-
typedef struct {
int have_os_monotonic_time;
+ int have_corrected_os_monotonic_time;
ErtsMonotonicTime os_monotonic_time_unit;
ErtsMonotonicTime sys_clock_resolution;
struct {
@@ -729,14 +724,13 @@ typedef struct {
} ErtsSysInitTimeResult;
#define ERTS_SYS_INIT_TIME_RESULT_INITER \
- {0, (ErtsMonotonicTime) -1, (ErtsMonotonicTime) 1}
+ {0, 0, (ErtsMonotonicTime) -1, (ErtsMonotonicTime) 1}
extern void erts_init_sys_time_sup(void);
extern void sys_init_time(ErtsSysInitTimeResult *);
extern void erts_late_sys_init_time(void);
extern void erts_deliver_time(void);
extern void erts_time_remaining(SysTimeval *);
-extern int erts_init_time_sup(int, ErtsTimeWarpMode);
extern void erts_sys_init_float(void);
extern void erts_thread_init_float(void);
extern void erts_thread_disable_fpe(void);
diff --git a/erts/emulator/beam/time.c b/erts/emulator/beam/time.c
index 2bdda6c8af..1fffb5f357 100644
--- a/erts/emulator/beam/time.c
+++ b/erts/emulator/beam/time.c
@@ -115,7 +115,7 @@ struct ErtsTimerWheel_ {
Uint nto;
struct {
ErlTimer *head;
- ErlTimer **tail;
+ ErlTimer *tail;
Uint nto;
} at_once;
int true_next_timeout_time;
@@ -235,23 +235,39 @@ found_next:
static void
remove_timer(ErtsTimerWheel *tiw, ErlTimer *p)
{
- /* first */
- if (!p->prev) {
- tiw->w[p->slot] = p->next;
+ if (p->slot >= 0) {
+ /* Timer in wheel... */
+ ASSERT(p->slot < TIW_SIZE);
+ if (p->prev)
+ p->prev->next = p->next;
+ else {
+ ASSERT(tiw->w[p->slot] == p);
+ tiw->w[p->slot] = p->next;
+ }
if(p->next)
- p->next->prev = NULL;
- } else {
- p->prev->next = p->next;
+ p->next->prev = p->prev;
}
-
- /* last */
- if (!p->next) {
+ else {
+ /* Timer in "at once" queue... */
+ ASSERT(p->slot == -1);
if (p->prev)
- p->prev->next = NULL;
- } else {
- p->next->prev = p->prev;
+ p->prev->next = p->next;
+ else {
+ ASSERT(tiw->at_once.head == p);
+ tiw->at_once.head = p->next;
+ }
+ if (p->next)
+ p->next->prev = p->prev;
+ else {
+ ASSERT(tiw->at_once.tail == p);
+ tiw->at_once.tail = p->prev;
+ }
+ ASSERT(tiw->at_once.nto > 0);
+ tiw->at_once.nto--;
}
+ p->slot = -2;
+
p->next = NULL;
p->prev = NULL;
@@ -337,11 +353,17 @@ erts_bump_timers(ErtsTimerWheel *tiw, ErtsMonotonicTime curr_time)
}
else {
ASSERT(tiw->nto >= tiw->at_once.nto);
- timeout_head = tiw->at_once.head;
- timeout_tail = tiw->at_once.tail;
+ p = timeout_head = tiw->at_once.head;
+ while (1) {
+ set_timer_wheel(p, NULL);
+ if (!p->next) {
+ timeout_tail = &p->next;
+ break;
+ }
+ }
tiw->nto -= tiw->at_once.nto;
tiw->at_once.head = NULL;
- tiw->at_once.tail = &tiw->at_once.head;
+ tiw->at_once.tail = NULL;
tiw->at_once.nto = 0;
}
@@ -458,7 +480,7 @@ erts_create_timer_wheel(int no)
tiw->pos = ERTS_MONOTONIC_TO_CLKTCKS(mtime);
tiw->nto = 0;
tiw->at_once.head = NULL;
- tiw->at_once.tail = &tiw->at_once.head;
+ tiw->at_once.tail = NULL;
tiw->at_once.nto = 0;
tiw->true_next_timeout_time = 0;
tiw->next_timeout_time = mtime + ERTS_MONOTONIC_DAY;
@@ -523,10 +545,13 @@ erts_set_timer(ErlTimer *p, ErlTimeoutProc timeout,
timeout_pos = ERTS_MONOTONIC_TO_CLKTCKS(curr_time);
tiw->nto++;
tiw->at_once.nto++;
- *tiw->at_once.tail = p;
- tiw->at_once.tail = &p->next;
p->next = NULL;
+ p->prev = tiw->at_once.tail;
+ tiw->at_once.tail = p;
+ if (!tiw->at_once.head)
+ tiw->at_once.head = p;
p->timeout_pos = timeout_pos;
+ p->slot = -1;
timeout_time = ERTS_CLKTCKS_TO_MONOTONIC(timeout_pos);
}
else {
@@ -538,7 +563,7 @@ erts_set_timer(ErlTimer *p, ErlTimeoutProc timeout,
/* calculate slot */
tm = (int) (timeout_pos & (TIW_SIZE-1));
- p->slot = (Uint) tm;
+ p->slot = tm;
/* insert at head of list at slot */
p->next = tiw->w[tm];
@@ -587,7 +612,6 @@ erts_cancel_timer(ErlTimer *p)
cancel = NULL;
else {
remove_timer(tiw, p);
- p->slot = 0;
cancel = p->cancel;
arg = p->arg;
diff --git a/erts/emulator/sys/unix/erl_unix_sys.h b/erts/emulator/sys/unix/erl_unix_sys.h
index 94adcc00c8..1942b631fc 100644
--- a/erts/emulator/sys/unix/erl_unix_sys.h
+++ b/erts/emulator/sys/unix/erl_unix_sys.h
@@ -177,10 +177,10 @@ typedef ErtsMonotonicTime ErtsSystemTime;
/*
* OS monotonic time and OS system time
*/
-
#undef ERTS_OS_TIMES_INLINE_FUNC_PTR_CALL__
-#if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME)
+#if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) \
+ && defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME)
# if defined(__linux__)
# define ERTS_OS_TIMES_INLINE_FUNC_PTR_CALL__ 1
# endif
@@ -191,13 +191,11 @@ ErtsSystemTime erts_os_system_time(void);
#undef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT
#undef ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT
#undef ERTS_OS_MONOTONIC_INLINE_FUNC_PTR_CALL__
-#undef ERTS_HAVE_CORRECTED_OS_MONOTONIC
#if defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME)
# define ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT 1
# define ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT (1000*1000*1000)
# if defined(__linux__)
-# define ERTS_HAVE_CORRECTED_OS_MONOTONIC 1
# define ERTS_OS_MONOTONIC_INLINE_FUNC_PTR_CALL__ 1
# endif
#elif defined(OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME)
diff --git a/erts/emulator/sys/unix/sys_time.c b/erts/emulator/sys/unix/sys_time.c
index d535457977..dc1822b21c 100644
--- a/erts/emulator/sys/unix/sys_time.c
+++ b/erts/emulator/sys/unix/sys_time.c
@@ -31,6 +31,7 @@
# undef _FILE_OFFSET_BITS
#endif
+#include <stdlib.h>
#include "sys.h"
#include "global.h"
#include "erl_os_monotonic_time_extender.h"
@@ -39,14 +40,11 @@
#undef ERTS_HAVE_ERTS_SYS_HRTIME_IMPL__
#if defined(OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME) \
- || defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME)
-# include <mach/clock.h>
-# include <mach/mach.h>
-# ifdef HAVE_CLOCK_GET_ATTRIBUTES
-# define ERTS_HAVE_MACH_CLOCK_GETRES
-static Sint64
-mach_clock_getres(clock_id_t clkid, char *clkid_str);
-# endif
+ || defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME) \
+ || defined(SYS_HRTIME_USING_MACH_CLOCK_GET_TIME)
+# include <mach/clock.h>
+# include <mach/mach.h>
+# define ERTS_MACH_CLOCKS
#endif
#ifdef NO_SYSCONF
@@ -99,20 +97,53 @@ ErtsSysTimeData__ erts_sys_time_data__ erts_align_attribute(ERTS_CACHE_LINE_SIZE
#define ERTS_SYS_TIME_INTERNAL_STATE_WRITE_FREQ__
-static ErtsMonotonicTime clock_gettime_monotonic_raw(void);
+static ErtsMonotonicTime clock_gettime_monotonic(void);
static ErtsMonotonicTime clock_gettime_monotonic_verified(void);
+#if defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW)
+static ErtsMonotonicTime clock_gettime_monotonic_raw(void);
+#endif
#if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME)
-static void clock_gettime_times_raw(ErtsMonotonicTime *, ErtsSystemTime *);
+static void clock_gettime_times(ErtsMonotonicTime *, ErtsSystemTime *);
static void clock_gettime_times_verified(ErtsMonotonicTime *, ErtsSystemTime *);
+#if defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW)
+static void clock_gettime_times_raw(ErtsMonotonicTime *, ErtsSystemTime *);
+#endif
#endif
#endif /* defined(__linux__) && defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME) */
+#ifdef ERTS_MACH_CLOCKS
+# define ERTS_SYS_TIME_INTERNAL_STATE_READ_ONLY__
+typedef struct {
+ clock_id_t id;
+ clock_serv_t srv;
+ char *name;
+} ErtsMachClock;
+
+typedef struct {
+ host_name_port_t host;
+ struct {
+ ErtsMachClock monotonic;
+ ErtsMachClock wall;
+ } clock;
+} ErtsMachClocks;
+static void mach_clocks_init(void);
+static void mach_clocks_fini(void);
+# ifdef HAVE_CLOCK_GET_ATTRIBUTES
+# define ERTS_HAVE_MACH_CLOCK_GETRES
+static Sint64
+mach_clock_getres(ErtsMachClock *clk);
+# endif
+#endif /* ERTS_MACH_CLOCKS */
+
#ifdef ERTS_SYS_TIME_INTERNAL_STATE_READ_ONLY__
struct sys_time_internal_state_read_only__ {
#if defined(OS_MONOTONIC_TIME_USING_TIMES)
int times_shift;
#endif
+#ifdef ERTS_MACH_CLOCKS
+ ErtsMachClocks mach;
+#endif
};
#endif
@@ -166,13 +197,23 @@ static struct {
void
sys_init_time(ErtsSysInitTimeResult *init_resp)
{
+#if defined(ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT)
+ int major, minor, build, vsn;
+#endif
+#if defined(ERTS_MACH_CLOCKS)
+ mach_clocks_init();
+#endif
#if !defined(ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT)
init_resp->have_os_monotonic_time = 0;
#else /* defined(ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT) */
- int major, minor, build, vsn;
+#ifdef ERTS_HAVE_CORRECTED_OS_MONOTONIC_TIME
+ init_resp->have_corrected_os_monotonic_time = 1;
+#else
+ init_resp->have_corrected_os_monotonic_time = 0;
+#endif
init_resp->os_monotonic_time_info.resolution = (Uint64) 1000*1000*1000;
#if defined(HAVE_CLOCK_GETRES) && defined(MONOTONIC_CLOCK_ID)
@@ -187,7 +228,7 @@ sys_init_time(ErtsSysInitTimeResult *init_resp)
}
#elif defined(ERTS_HAVE_MACH_CLOCK_GETRES) && defined(MONOTONIC_CLOCK_ID)
init_resp->os_monotonic_time_info.resolution
- = mach_clock_getres(MONOTONIC_CLOCK_ID, MONOTONIC_CLOCK_ID_STR);
+ = mach_clock_getres(&internal_state.r.o.mach.clock.monotonic);
#endif
#ifdef MONOTONIC_CLOCK_ID_STR
@@ -220,29 +261,52 @@ sys_init_time(ErtsSysInitTimeResult *init_resp)
#if defined(__linux__) && defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME)
if (vsn >= ERTS_MK_VSN_INT(2, 6, 33)) {
erts_sys_time_data__.r.o.os_monotonic_time =
- clock_gettime_monotonic_raw;
+ clock_gettime_monotonic;
#if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME)
erts_sys_time_data__.r.o.os_times =
- clock_gettime_times_raw;
+ clock_gettime_times;
#endif
}
else {
/*
* Linux versions prior to 2.6.33 have a
- * known bug that sometimes cause monotonic
- * time to take small steps backwards.
+ * known bug that sometimes cause the NTP
+ * adjusted monotonic clock to take small
+ * steps backwards. Use raw monotonic clock
+ * if it is present; otherwise, fall back
+ * on locked verification of values.
*/
- erts_sys_time_data__.r.o.os_monotonic_time =
- clock_gettime_monotonic_verified;
+ init_resp->have_corrected_os_monotonic_time = 0;
+#if defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW)
+ /* We know that CLOCK_MONOTONIC_RAW is defined,
+ but we don't know if we got a kernel that
+ supports it. Support for CLOCK_MONOTONIC_RAW
+ appeared in kernel 2.6.28... */
+ if (vsn >= ERTS_MK_VSN_INT(2, 6, 28)) {
+ erts_sys_time_data__.r.o.os_monotonic_time =
+ clock_gettime_monotonic_raw;
#if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME)
- erts_sys_time_data__.r.o.os_times =
- clock_gettime_times_verified;
+ erts_sys_time_data__.r.o.os_times =
+ clock_gettime_times_raw;
#endif
- erts_smp_mtx_init(&internal_state.w.f.mtx,
- "os_monotonic_time");
- internal_state.w.f.last_delivered
- = clock_gettime_monotonic_raw();
- init_resp->os_monotonic_time_info.locked_use = 1;
+ init_resp->os_monotonic_time_info.clock_id =
+ "CLOCK_MONOTONIC_RAW";
+ }
+ else
+#endif /* defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW) */
+ {
+ erts_sys_time_data__.r.o.os_monotonic_time =
+ clock_gettime_monotonic_verified;
+#if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME)
+ erts_sys_time_data__.r.o.os_times =
+ clock_gettime_times_verified;
+#endif
+ erts_smp_mtx_init(&internal_state.w.f.mtx,
+ "os_monotonic_time");
+ internal_state.w.f.last_delivered
+ = clock_gettime_monotonic();
+ init_resp->os_monotonic_time_info.locked_use = 1;
+ }
}
#else /* !(defined(__linux__) && defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME)) */
{
@@ -324,7 +388,7 @@ sys_init_time(ErtsSysInitTimeResult *init_resp)
}
#elif defined(ERTS_HAVE_MACH_CLOCK_GETRES) && defined(WALL_CLOCK_ID)
init_resp->os_system_time_info.resolution
- = mach_clock_getres(WALL_CLOCK_ID, WALL_CLOCK_ID_STR);
+ = mach_clock_getres(&internal_state.r.o.mach.clock.wall);
#endif
#if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME)
@@ -366,6 +430,10 @@ adj_stime_time_unit(ErtsSystemTime stime, Uint32 res)
(Uint32) ERTS_MONOTONIC_TIME_UNIT));
}
+#define ERTS_TimeSpec2Sint64(TS) \
+ ((((Sint64) (TS)->tv_sec) * ((Sint64) 1000*1000*1000)) \
+ + ((Sint64) (TS)->tv_nsec))
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* POSIX clock_gettime() *
\* */
@@ -373,17 +441,7 @@ adj_stime_time_unit(ErtsSystemTime stime, Uint32 res)
#if defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME) \
|| defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME)
-static ERTS_INLINE ErtsMonotonicTime
-timespec2montime(struct timespec *ts)
-{
- ErtsMonotonicTime time;
- time = (ErtsMonotonicTime) ts->tv_sec;
- time *= (ErtsMonotonicTime) 1000*1000*1000;
- time += (ErtsMonotonicTime) ts->tv_nsec;
- return time;
-}
-
-static ERTS_INLINE ErtsMonotonicTime
+static ERTS_INLINE Sint64
posix_clock_gettime(clockid_t id, char *name)
{
struct timespec ts;
@@ -395,7 +453,7 @@ posix_clock_gettime(clockid_t id, char *name)
"clock_gettime(%s, _) failed: %s (%d)\n",
name, errstr, err);
}
- return timespec2montime(&ts);
+ return ERTS_TimeSpec2Sint64(&ts);
}
#endif /* defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME) \
@@ -406,11 +464,10 @@ posix_clock_gettime(clockid_t id, char *name)
ErtsSystemTime
erts_os_system_time(void)
{
- ErtsSystemTime stime;
-
- stime = (ErtsSystemTime) posix_clock_gettime(WALL_CLOCK_ID,
- WALL_CLOCK_ID_STR);
- return adj_stime_time_unit(stime, (Uint32) 1000*1000*1000);
+ Sint64 stime = posix_clock_gettime(WALL_CLOCK_ID,
+ WALL_CLOCK_ID_STR);
+ return adj_stime_time_unit((ErtsSystemTime) stime,
+ (Uint32) 1000*1000*1000);
}
#endif /* defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) */
@@ -422,32 +479,34 @@ erts_os_system_time(void)
#define ERTS_HAVE_ERTS_OS_TIMES_IMPL__
static ERTS_INLINE void
-posix_clock_gettime_times(ErtsMonotonicTime *mtimep,
+posix_clock_gettime_times(clockid_t mid, char *mname,
+ ErtsMonotonicTime *mtimep,
+ clockid_t sid, char *sname,
ErtsSystemTime *stimep)
{
struct timespec mts, sts;
int mres, sres, merr, serr;
- mres = clock_gettime(MONOTONIC_CLOCK_ID, &mts);
+ mres = clock_gettime(mid, &mts);
merr = errno;
- sres = clock_gettime(WALL_CLOCK_ID, &sts);
+ sres = clock_gettime(sid, &sts);
serr = errno;
if (mres != 0) {
char *errstr = merr ? strerror(merr) : "unknown";
erl_exit(ERTS_ABORT_EXIT,
"clock_gettime(%s, _) failed: %s (%d)\n",
- MONOTONIC_CLOCK_ID_STR, errstr, merr);
+ mname, errstr, merr);
}
if (sres != 0) {
char *errstr = serr ? strerror(serr) : "unknown";
erl_exit(ERTS_ABORT_EXIT,
"clock_gettime(%s, _) failed: %s (%d)\n",
- WALL_CLOCK_ID_STR, errstr, serr);
+ sname, errstr, serr);
}
- *mtimep = timespec2montime(&mts);
- *stimep = (ErtsSystemTime) timespec2montime(&sts);
+ *mtimep = (ErtsMonotonicTime) ERTS_TimeSpec2Sint64(&mts);
+ *stimep = (ErtsSystemTime) ERTS_TimeSpec2Sint64(&sts);
}
#endif /* defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) */
@@ -456,8 +515,10 @@ posix_clock_gettime_times(ErtsMonotonicTime *mtimep,
static ErtsMonotonicTime clock_gettime_monotonic_verified(void)
{
- ErtsMonotonicTime mtime = posix_clock_gettime(MONOTONIC_CLOCK_ID,
- MONOTONIC_CLOCK_ID_STR);
+ ErtsMonotonicTime mtime;
+
+ mtime = (ErtsMonotonicTime) posix_clock_gettime(MONOTONIC_CLOCK_ID,
+ MONOTONIC_CLOCK_ID_STR);
erts_smp_mtx_lock(&internal_state.w.f.mtx);
if (mtime < internal_state.w.f.last_delivered)
@@ -474,7 +535,12 @@ static ErtsMonotonicTime clock_gettime_monotonic_verified(void)
static void clock_gettime_times_verified(ErtsMonotonicTime *mtimep,
ErtsSystemTime *stimep)
{
- posix_clock_gettime_times(mtimep, stimep);
+ posix_clock_gettime_times(MONOTONIC_CLOCK_ID,
+ MONOTONIC_CLOCK_ID_STR,
+ mtimep,
+ WALL_CLOCK_ID,
+ WALL_CLOCK_ID_STR,
+ stimep);
erts_smp_mtx_lock(&internal_state.w.f.mtx);
if (*mtimep < internal_state.w.f.last_delivered)
@@ -486,20 +552,50 @@ static void clock_gettime_times_verified(ErtsMonotonicTime *mtimep,
#endif /* defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) */
+static ErtsMonotonicTime clock_gettime_monotonic(void)
+{
+ return (ErtsMonotonicTime) posix_clock_gettime(MONOTONIC_CLOCK_ID,
+ MONOTONIC_CLOCK_ID_STR);
+}
+
+#if defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW)
+
static ErtsMonotonicTime clock_gettime_monotonic_raw(void)
{
- return posix_clock_gettime(MONOTONIC_CLOCK_ID,
- MONOTONIC_CLOCK_ID_STR);
+ return (ErtsMonotonicTime) posix_clock_gettime(CLOCK_MONOTONIC_RAW,
+ "CLOCK_MONOTONIC_RAW");
}
+#endif /* defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW) */
+
#if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME)
+static void clock_gettime_times(ErtsMonotonicTime *mtimep,
+ ErtsSystemTime *stimep)
+{
+ posix_clock_gettime_times(MONOTONIC_CLOCK_ID,
+ MONOTONIC_CLOCK_ID_STR,
+ mtimep,
+ WALL_CLOCK_ID,
+ WALL_CLOCK_ID_STR,
+ stimep);
+}
+
+#if defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW)
+
static void clock_gettime_times_raw(ErtsMonotonicTime *mtimep,
ErtsSystemTime *stimep)
{
- posix_clock_gettime_times(mtimep, stimep);
+ posix_clock_gettime_times(CLOCK_MONOTONIC_RAW,
+ "CLOCK_MONOTONIC_RAW",
+ mtimep,
+ WALL_CLOCK_ID,
+ WALL_CLOCK_ID_STR,
+ stimep);
}
+#endif /* defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW) */
+
#endif /* defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) */
#else /* !defined(__linux__) */
@@ -514,61 +610,116 @@ ErtsMonotonicTime erts_os_monotonic_time(void)
void erts_os_times(ErtsMonotonicTime *mtimep, ErtsSystemTime *stimep)
{
- posix_clock_gettime_times(mtimep, stimep);
+ posix_clock_gettime_times(MONOTONIC_CLOCK_ID,
+ MONOTONIC_CLOCK_ID_STR,
+ mtimep,
+ WALL_CLOCK_ID,
+ WALL_CLOCK_ID_STR,
+ stimep);
}
#endif /* defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) */
#endif /* !defined(__linux__) */
-#define ERTS_HAVE_ERTS_SYS_HRTIME_IMPL__
+#endif /* defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME) */
+
+#if defined(SYS_HRTIME_USING_CLOCK_GETTIME)
+# define ERTS_HAVE_ERTS_SYS_HRTIME_IMPL__
ErtsSysHrTime
erts_sys_hrtime(void)
{
- return (ErtsSysHrTime) posix_clock_gettime(MONOTONIC_CLOCK_ID,
- MONOTONIC_CLOCK_ID_STR);
+ return (ErtsSysHrTime) posix_clock_gettime(HRTIME_CLOCK_ID,
+ HRTIME_CLOCK_ID_STR);
}
-#endif /* defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME) */
+#endif /* defined(SYS_HRTIME_USING_CLOCK_GETTIME) */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* MACH clock_get_time() *
\* */
-#if defined(OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME) \
- || defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME)
+#if defined(ERTS_MACH_CLOCKS)
-#ifdef ERTS_HAVE_MACH_CLOCK_GETRES
+static void
+mach_clocks_fini(void)
+{
+ mach_port_t task = mach_task_self();
+ mach_port_deallocate(task, internal_state.r.o.mach.host);
+#if defined(OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME)
+ mach_port_deallocate(task, internal_state.r.o.mach.clock.monotonic.srv);
+#endif
+#if defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME)
+ mach_port_deallocate(task, internal_state.r.o.mach.clock.wall.srv);
+#endif
+}
-static Sint64
-mach_clock_getres(clock_id_t clkid, char *clkid_str)
+static void
+mach_clocks_init(void)
{
- mach_port_t task;
- host_name_port_t host;
- natural_t attr[1];
kern_return_t kret;
- clock_serv_t clk_srv;
- mach_msg_type_number_t cnt;
+ host_name_port_t host;
+ clock_id_t id;
+ clock_serv_t *clck_srv_p;
+ char *name;
+
+ host = internal_state.r.o.mach.host = mach_host_self();
- host = mach_host_self();
- kret = host_get_clock_service(host, clkid, &clk_srv);
+#if defined(OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME) \
+ || defined(SYS_HRTIME_USING_MACH_CLOCK_GET_TIME)
+ id = internal_state.r.o.mach.clock.monotonic.id = MONOTONIC_CLOCK_ID;
+ name = internal_state.r.o.mach.clock.monotonic.name = MONOTONIC_CLOCK_ID_STR;
+ clck_srv_p = &internal_state.r.o.mach.clock.monotonic.srv;
+ kret = host_get_clock_service(host, id, clck_srv_p);
if (kret != KERN_SUCCESS) {
erl_exit(ERTS_ABORT_EXIT,
"host_get_clock_service(_, %s, _) failed\n",
- clkid_str);
+ name);
}
+#endif
- cnt = sizeof(attr);
- kret = clock_get_attributes(clk_srv, CLOCK_GET_TIME_RES, (clock_attr_t) attr, &cnt);
+#if defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME)
+ id = internal_state.r.o.mach.clock.wall.id = WALL_CLOCK_ID;
+ name = internal_state.r.o.mach.clock.wall.name = WALL_CLOCK_ID_STR;
+ clck_srv_p = &internal_state.r.o.mach.clock.wall.srv;
+ kret = host_get_clock_service(host, id, clck_srv_p);
if (kret != KERN_SUCCESS) {
+ erl_exit(ERTS_ABORT_EXIT,
+ "host_get_clock_service(_, %s, _) failed\n",
+ name);
+ }
+#endif
+
+ if (atexit(mach_clocks_fini) != 0) {
+ int err = errno;
+ char *errstr = err ? strerror(err) : "unknown";
+ erl_exit(ERTS_ABORT_EXIT,
+ "Failed to register mach_clocks_fini() "
+ "for call at exit: %s (%d)\n",
+ errstr, err);
+ }
+}
+
+#ifdef ERTS_HAVE_MACH_CLOCK_GETRES
+
+static Sint64
+mach_clock_getres(ErtsMachClock *clk)
+{
+ kern_return_t kret;
+ natural_t attr[1];
+ mach_msg_type_number_t cnt;
+
+ cnt = sizeof(attr);
+ kret = clock_get_attributes(clk->srv,
+ CLOCK_GET_TIME_RES,
+ (clock_attr_t) attr,
+ &cnt);
+ if (kret != KERN_SUCCESS || cnt != 1) {
erl_exit(ERTS_ABORT_EXIT,
"clock_get_attributes(%s, _) failed\n",
- clkid_str);
+ clk->name);
}
- task = mach_task_self();
- mach_port_deallocate(task, host);
- mach_port_deallocate(task, clk_srv);
return (Sint64) attr[0];
}
@@ -576,41 +727,19 @@ mach_clock_getres(clock_id_t clkid, char *clkid_str)
#endif /* ERTS_HAVE_MACH_CLOCK_GETRES */
static ERTS_INLINE Sint64
-mach_clock_gettime(clock_id_t clkid, char *clkid_str)
+mach_clock_get_time(ErtsMachClock *clk)
{
- Sint64 time;
- mach_port_t task;
- host_name_port_t host;
kern_return_t kret;
- clock_serv_t clk_srv;
mach_timespec_t time_spec;
- host = mach_host_self();
- kret = host_get_clock_service(host, clkid, &clk_srv);
- if (kret != KERN_SUCCESS) {
- erl_exit(ERTS_ABORT_EXIT,
- "host_get_clock_service(_, %s, _) failed\n",
- clkid_str);
- }
- errno = 0;
- kret = clock_get_time(clk_srv, &time_spec);
- if (kret != KERN_SUCCESS) {
- erl_exit(ERTS_ABORT_EXIT,
- "clock_get_time(%s, _) failed\n",
- clkid_str);
- }
- task = mach_task_self();
- mach_port_deallocate(task, host);
- mach_port_deallocate(task, clk_srv);
+ kret = clock_get_time(clk->srv, &time_spec);
+ if (kret != KERN_SUCCESS)
+ erl_exit(ERTS_ABORT_EXIT, "clock_get_time(%s, _) failed\n", clk->name);
- time = (Sint64) time_spec.tv_sec;
- time *= (Sint64) 1000*1000*1000;
- time += (Sint64) time_spec.tv_nsec;
- return time;
+ return ERTS_TimeSpec2Sint64(&time_spec);
}
-#endif /* defined(OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME) \
- || defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME) */
+#endif /* defined(ERTS_MACH_CLOCKS) */
#if defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME)
@@ -619,10 +748,9 @@ mach_clock_gettime(clock_id_t clkid, char *clkid_str)
ErtsSystemTime
erts_os_system_time(void)
{
- ErtsSystemTime stime;
- stime = (ErtsSystemTime) mach_clock_gettime(WALL_CLOCK_ID,
- WALL_CLOCK_ID_STR);
- return adj_stime_time_unit(stime, (Uint32) 1000*1000*1000);
+ Sint64 stime = mach_clock_get_time(&internal_state.r.o.mach.clock.wall);
+ return adj_stime_time_unit((ErtsSystemTime) stime,
+ (Uint32) 1000*1000*1000);
}
#endif /* defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME) */
@@ -632,17 +760,8 @@ erts_os_system_time(void)
ErtsMonotonicTime
erts_os_monotonic_time(void)
{
- return (ErtsMonotonicTime) mach_clock_gettime(MONOTONIC_CLOCK_ID,
- MONOTONIC_CLOCK_ID_STR);
-}
-
-#define ERTS_HAVE_ERTS_SYS_HRTIME_IMPL__
-
-ErtsSysHrTime
-erts_sys_hrtime(void)
-{
- return (ErtsMonotonicTime) mach_clock_gettime(MONOTONIC_CLOCK_ID,
- MONOTONIC_CLOCK_ID_STR);
+ return (ErtsMonotonicTime)
+ mach_clock_get_time(&internal_state.r.o.mach.clock.monotonic);
}
#if defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME)
@@ -652,58 +771,44 @@ erts_sys_hrtime(void)
void
erts_os_times(ErtsMonotonicTime *mtimep, ErtsSystemTime *stimep)
{
- ErtsMonotonicTime mtime;
- ErtsSystemTime stime;
- mach_port_t task;
- host_name_port_t host;
kern_return_t mkret, skret;
- clock_serv_t mclk_srv, sclk_srv;
mach_timespec_t mon_time_spec, sys_time_spec;
- host = mach_host_self();
- mkret = host_get_clock_service(host, MONOTONIC_CLOCK_ID, &mclk_srv);
- skret = host_get_clock_service(host, WALL_CLOCK_ID, &sclk_srv);
- if (mkret != KERN_SUCCESS) {
- erl_exit(ERTS_ABORT_EXIT,
- "host_get_clock_service(_, %s, _) failed\n",
- MONOTONIC_CLOCK_ID);
- }
- if (skret != KERN_SUCCESS) {
- erl_exit(ERTS_ABORT_EXIT,
- "host_get_clock_service(_, %s, _) failed\n",
- WALL_CLOCK_ID);
- }
- mkret = clock_get_time(mclk_srv, &mon_time_spec);
- skret = clock_get_time(sclk_srv, &sys_time_spec);
- if (mkret != KERN_SUCCESS) {
+ mkret = clock_get_time(internal_state.r.o.mach.clock.monotonic.srv,
+ &mon_time_spec);
+ skret = clock_get_time(internal_state.r.o.mach.clock.wall.srv,
+ &sys_time_spec);
+
+ if (mkret != KERN_SUCCESS)
erl_exit(ERTS_ABORT_EXIT,
"clock_get_time(%s, _) failed\n",
- MONOTONIC_CLOCK_ID);
- }
- if (skret != KERN_SUCCESS) {
+ internal_state.r.o.mach.clock.monotonic.name);
+ if (skret != KERN_SUCCESS)
erl_exit(ERTS_ABORT_EXIT,
"clock_get_time(%s, _) failed\n",
- WALL_CLOCK_ID);
- }
- task = mach_task_self();
- mach_port_deallocate(task, host);
- mach_port_deallocate(task, mclk_srv);
- mach_port_deallocate(task, sclk_srv);
+ internal_state.r.o.mach.clock.wall.name);
- mtime = (ErtsMonotonicTime) mon_time_spec.tv_sec;
- mtime *= (ErtsMonotonicTime) 1000*1000*1000;
- mtime += (ErtsMonotonicTime) mon_time_spec.tv_nsec;
- stime = (ErtsSystemTime) sys_time_spec.tv_sec;
- stime *= (ErtsSystemTime) 1000*1000*1000;
- stime += (ErtsSystemTime) sys_time_spec.tv_nsec;
- *mtimep = mtime;
- *stimep = stime;
+ *mtimep = (ErtsMonotonicTime) ERTS_TimeSpec2Sint64(&mon_time_spec);
+ *stimep = (ErtsSystemTime) ERTS_TimeSpec2Sint64(&sys_time_spec);
}
#endif /* defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME) */
#endif /* defined(OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME) */
+#if defined(SYS_HRTIME_USING_MACH_CLOCK_GET_TIME)
+
+#define ERTS_HAVE_ERTS_SYS_HRTIME_IMPL__
+
+ErtsSysHrTime
+erts_sys_hrtime(void)
+{
+ return (ErtsSysHrTime)
+ mach_clock_get_time(&internal_state.r.o.mach.clock.monotonic);
+}
+
+#endif /* defined(SYS_HRTIME_USING_MACH_CLOCK_GET_TIME) */
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* Solaris gethrtime() - OS monotonic time *
\* */
@@ -715,6 +820,10 @@ ErtsMonotonicTime erts_os_monotonic_time(void)
return (ErtsMonotonicTime) gethrtime();
}
+#endif /* defined(OS_MONOTONIC_TIME_USING_GETHRTIME) */
+
+#if defined(SYS_HRTIME_USING_GETHRTIME)
+
#define ERTS_HAVE_ERTS_SYS_HRTIME_IMPL__
ErtsSysHrTime
@@ -723,7 +832,7 @@ erts_sys_hrtime(void)
return (ErtsSysHrTime) gethrtime();
}
-#endif /* defined(OS_MONOTONIC_TIME_USING_GETHRTIME) */
+#endif /* defined(SYS_HRTIME_USING_GETHRTIME) */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* gettimeofday() - OS system time *
diff --git a/erts/emulator/sys/win32/erl_poll.c b/erts/emulator/sys/win32/erl_poll.c
index 5a62b00a68..937a678702 100644
--- a/erts/emulator/sys/win32/erl_poll.c
+++ b/erts/emulator/sys/win32/erl_poll.c
@@ -25,6 +25,7 @@
#include "sys.h"
#include "erl_alloc.h"
#include "erl_poll.h"
+#include "erl_time.h"
/*
* Some debug macros
diff --git a/erts/emulator/sys/win32/erl_win_sys.h b/erts/emulator/sys/win32/erl_win_sys.h
index 714e7357d4..a9e37e47a7 100644
--- a/erts/emulator/sys/win32/erl_win_sys.h
+++ b/erts/emulator/sys/win32/erl_win_sys.h
@@ -224,7 +224,7 @@ erts_os_monotonic_time(void)
ERTS_GLB_INLINE void
erts_os_times(ErtsMonotonicTime *mtimep, ErtsSystemTime *stimep)
{
- return (*erts_sys_time_data__.r.o.os_times)(mtimep, stimep);
+ (*erts_sys_time_data__.r.o.os_times)(mtimep, stimep);
}
ERTS_GLB_INLINE ErtsSysHrTime
diff --git a/erts/emulator/sys/win32/sys_time.c b/erts/emulator/sys/win32/sys_time.c
index b292d9279e..7da060a7a7 100644
--- a/erts/emulator/sys/win32/sys_time.c
+++ b/erts/emulator/sys/win32/sys_time.c
@@ -28,6 +28,9 @@
#include "erl_os_monotonic_time_extender.h"
#include "erl_time.h"
+/* Need to look more closely at qpc before use... */
+#define ERTS_DISABLE_USE_OF_QPC_FOR_MONOTONIC_TIME 1
+
#define LL_LITERAL(X) ERTS_I64_LITERAL(X)
/******************* Routines for time measurement *********************/
@@ -362,10 +365,11 @@ sys_init_time(ErtsSysInitTimeResult *init_resp)
if (!internal_state.r.o.pQueryPerformanceCounter)
goto get_tick_count64;
- if (pf.QuadPart < (((LONGLONG) 1) << 32)) {
- internal_state.r.o.pcf = (Uint32) pf.QuadPart;
- sys_hrtime_func = sys_hrtime_qpc;
- }
+ if (pf.QuadPart > (((LONGLONG) 1) << 32))
+ goto get_tick_count64;
+
+ internal_state.r.o.pcf = (Uint32) pf.QuadPart;
+ sys_hrtime_func = sys_hrtime_qpc;
/*
* We only use QueryPerformanceCounter() for
@@ -377,6 +381,9 @@ sys_init_time(ErtsSysInitTimeResult *init_resp)
if (pf.QuadPart < (LONGLONG) 1000*1000*1000)
goto get_tick_count64;
+ if (ERTS_DISABLE_USE_OF_QPC_FOR_MONOTONIC_TIME)
+ goto get_tick_count64;
+
init_resp->os_monotonic_time_info.func = "QueryPerformanceCounter";
init_resp->os_monotonic_time_info.locked_use = 0;
time_unit = (ErtsMonotonicTime) pf.QuadPart;
@@ -391,6 +398,7 @@ sys_init_time(ErtsSysInitTimeResult *init_resp)
erts_sys_time_data__.r.o.os_times = os_times_func;
init_resp->os_monotonic_time_unit = time_unit;
init_resp->have_os_monotonic_time = 1;
+ init_resp->have_corrected_os_monotonic_time = 0;
init_resp->sys_clock_resolution = 1;
init_resp->os_system_time_info.func = "GetSystemTime";
diff --git a/erts/emulator/test/after_SUITE.erl b/erts/emulator/test/after_SUITE.erl
index 7cc329cc69..699a1436ce 100644
--- a/erts/emulator/test/after_SUITE.erl
+++ b/erts/emulator/test/after_SUITE.erl
@@ -70,30 +70,23 @@ end_per_testcase(_Func, Config) ->
t_after(Config) when is_list(Config) ->
?line spawn(fun frequent_process/0),
?line Period = test_server:minutes(1),
- ?line Before = erlang:now(),
+ ?line Before = erlang:monotonic_time(),
receive
after Period ->
- ?line After = erlang:now(),
+ ?line After = erlang:monotonic_time(),
?line report(Period, Before, After)
end.
-
report(Period, Before, After) ->
- ?line Elapsed = (element(1, After)*1000000000
- +element(2, After)*1000
- +element(3, After) div 1000) -
- (element(1,Before)*1000000000
- + element(2,Before)*1000 + element(3,Before) div 1000),
- ?line case Elapsed*100 / Period of
- Percent when Percent > 100.10 ->
- ?line test_server:fail({too_inaccurate, Percent});
- Percent when Percent < 100.0 ->
- ?line test_server:fail({too_early, Percent});
- Percent ->
- ?line Comment = io_lib:format("Elapsed/expected: ~.2f %",
- [Percent]),
- {comment, lists:flatten(Comment)}
- end.
+ case erlang:convert_time_unit(After - Before, native, 100*1000) / Period of
+ Percent when Percent > 100.10 ->
+ test_server:fail({too_inaccurate, Percent});
+ Percent when Percent < 100.0 ->
+ test_server:fail({too_early, Percent});
+ Percent ->
+ Comment = io_lib:format("Elapsed/expected: ~.2f %", [Percent]),
+ {comment, lists:flatten(Comment)}
+ end.
frequent_process() ->
receive
diff --git a/erts/emulator/test/alloc_SUITE.erl b/erts/emulator/test/alloc_SUITE.erl
index 35c44c229a..12a48cc484 100644
--- a/erts/emulator/test/alloc_SUITE.erl
+++ b/erts/emulator/test/alloc_SUITE.erl
@@ -241,18 +241,15 @@ receive_drv_result(Port, CaseName) ->
start_node(Config) ->
start_node(Config, []).
start_node(Config, Opts) when is_list(Config), is_list(Opts) ->
- ?line Pa = filename:dirname(code:which(?MODULE)),
- ?line {A, B, C} = now(),
- ?line Name = list_to_atom(atom_to_list(?MODULE)
- ++ "-"
- ++ atom_to_list(?config(testcase, Config))
- ++ "-"
- ++ integer_to_list(A)
- ++ "-"
- ++ integer_to_list(B)
- ++ "-"
- ++ integer_to_list(C)),
- ?line ?t:start_node(Name, slave, [{args, Opts++" -pa "++Pa}]).
+ Pa = filename:dirname(code:which(?MODULE)),
+ Name = list_to_atom(atom_to_list(?MODULE)
+ ++ "-"
+ ++ atom_to_list(?config(testcase, Config))
+ ++ "-"
+ ++ integer_to_list(erlang:system_time(seconds))
+ ++ "-"
+ ++ integer_to_list(erlang:unique_integer([positive]))),
+ ?t:start_node(Name, slave, [{args, Opts++" -pa "++Pa}]).
stop_node(Node) ->
?t:stop_node(Node).
diff --git a/erts/emulator/test/binary_SUITE.erl b/erts/emulator/test/binary_SUITE.erl
index 44e9e4f243..5911652447 100644
--- a/erts/emulator/test/binary_SUITE.erl
+++ b/erts/emulator/test/binary_SUITE.erl
@@ -520,7 +520,9 @@ external_size_1(Term, Size0, Limit) when Size0 < Limit ->
external_size_1(_, _, _) -> ok.
t_iolist_size(Config) when is_list(Config) ->
- ?line Seed = now(),
+ ?line Seed = {erlang:monotonic_time(),
+ erlang:time_offset(),
+ erlang:unique_integer([positive])},
?line io:format("Seed: ~p", [Seed]),
?line random:seed(Seed),
?line Base = <<0:(1 bsl 20)/unit:8>>,
diff --git a/erts/emulator/test/busy_port_SUITE.erl b/erts/emulator/test/busy_port_SUITE.erl
index 2ed5aaa0d0..d44a03516a 100644
--- a/erts/emulator/test/busy_port_SUITE.erl
+++ b/erts/emulator/test/busy_port_SUITE.erl
@@ -516,13 +516,13 @@ hs_busy_pcmd(Prt, Opts, StartFun, EndFun) ->
P = spawn_link(fun () ->
erlang:yield(),
Tester ! {self(), doing_port_command},
- Start = now(),
+ Start = erlang:monotonic_time(micro_seconds),
Res = try {return,
port_command(Prt, [], Opts)}
catch Exception:Error -> {Exception, Error}
end,
- End = now(),
- Time = round(timer:now_diff(End, Start)/1000),
+ End = erlang:monotonic_time(micro_seconds),
+ Time = round((End - Start)/1000),
Tester ! {self(), port_command_result, Res, Time}
end),
receive
@@ -776,7 +776,7 @@ run_command(_M,spawn,{Args,Opts}) ->
run_command(M,spawn,Args) ->
run_command(M,spawn,{Args,[]});
run_command(Mod,Func,Args) ->
- erlang:display({{Mod,Func,Args},now()}),
+ erlang:display({{Mod,Func,Args}, erlang:system_time(micro_seconds)}),
apply(Mod,Func,Args).
validate_scenario(Data,[{print,Var}|T]) ->
diff --git a/erts/emulator/test/decode_packet_SUITE.erl b/erts/emulator/test/decode_packet_SUITE.erl
index 2baf91cf29..330ad299e5 100644
--- a/erts/emulator/test/decode_packet_SUITE.erl
+++ b/erts/emulator/test/decode_packet_SUITE.erl
@@ -52,7 +52,9 @@ end_per_group(_GroupName, Config) ->
init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) ->
- Seed = {S1,S2,S3} = now(),
+ Seed = {S1,S2,S3} = {erlang:monotonic_time(),
+ erlang:time_offset(),
+ erlang:unique_integer()},
random:seed(S1,S2,S3),
io:format("*** SEED: ~p ***\n", [Seed]),
Dog=?t:timetrap(?t:minutes(1)),
diff --git a/erts/emulator/test/distribution_SUITE.erl b/erts/emulator/test/distribution_SUITE.erl
index aa6cf2b881..33cb56c0b9 100644
--- a/erts/emulator/test/distribution_SUITE.erl
+++ b/erts/emulator/test/distribution_SUITE.erl
@@ -1337,10 +1337,7 @@ unwanted_cixs() ->
get_conflicting_atoms(_CIX, 0) ->
[];
get_conflicting_atoms(CIX, N) ->
- {A, B, C} = now(),
- Atom = list_to_atom("atom" ++ integer_to_list(A*1000000000000
- + B*1000000
- + C)),
+ Atom = list_to_atom("atom" ++ integer_to_list(erlang:unique_integer([positive]))),
case erts_debug:get_internal_state({atom_out_cache_index, Atom}) of
CIX ->
[Atom|get_conflicting_atoms(CIX, N-1)];
@@ -1351,10 +1348,7 @@ get_conflicting_atoms(CIX, N) ->
get_conflicting_unicode_atoms(_CIX, 0) ->
[];
get_conflicting_unicode_atoms(CIX, N) ->
- {A, B, C} = now(),
- Atom = string_to_atom([16#1f608] ++ "atom" ++ integer_to_list(A*1000000000000
- + B*1000000
- + C)),
+ Atom = string_to_atom([16#1f608] ++ "atom" ++ integer_to_list(erlang:unique_integer([positive]))),
case erts_debug:get_internal_state({atom_out_cache_index, Atom}) of
CIX ->
[Atom|get_conflicting_unicode_atoms(CIX, N-1)];
@@ -1967,8 +1961,7 @@ dmsg_bad_atom_cache_ref() ->
%%% Utilities
timestamp() ->
- {A,B,C} = erlang:now(),
- (C div 1000) + (B * 1000) + (A * 1000000000).
+ erlang:monotonic_time(milli_seconds).
start_node(X) ->
start_node(X, [], []).
@@ -1992,7 +1985,9 @@ start_node(Config, Args, Rel) when is_list(Config), is_list(Rel) ->
++ "-"
++ atom_to_list(?config(testcase, Config))
++ "-"
- ++ integer_to_list(timestamp()))),
+ ++ integer_to_list(erlang:system_time(seconds))
+ ++ "-"
+ ++ integer_to_list(erlang:unique_integer([positive])))),
start_node(Name, Args, Rel).
stop_node(Node) ->
@@ -2109,7 +2104,7 @@ node_monitor(Master) ->
Master ! {nodeup, node(), Node}
end,
Nodes0),
- ?t:format("~p ~p: ~p~n", [node(), erlang:now(), Nodes0]),
+ ?t:format("~p ~p: ~p~n", [node(), erlang:system_time(micro_seconds), Nodes0]),
node_monitor_loop(Master);
false ->
net_kernel:monitor_nodes(false, Opts),
@@ -2130,7 +2125,7 @@ node_monitor_loop(Master) ->
receive
{nodeup, Node, _InfoList} = Msg ->
Master ! {nodeup, node(), Node},
- ?t:format("~p ~p: ~p~n", [node(), erlang:now(), Msg]),
+ ?t:format("~p ~p: ~p~n", [node(), erlang:system_time(micro_seconds), Msg]),
node_monitor_loop(Master);
{nodedown, Node, InfoList} = Msg ->
Reason = case lists:keysearch(nodedown_reason, 1, InfoList) of
@@ -2138,7 +2133,7 @@ node_monitor_loop(Master) ->
_ -> undefined
end,
Master ! {nodedown, node(), Node, Reason},
- ?t:format("~p ~p: ~p~n", [node(), erlang:now(), Msg]),
+ ?t:format("~p ~p: ~p~n", [node(), erlang:system_time(micro_seconds), Msg]),
node_monitor_loop(Master)
end.
diff --git a/erts/emulator/test/driver_SUITE.erl b/erts/emulator/test/driver_SUITE.erl
index 623d62f876..e6beda1ccf 100644
--- a/erts/emulator/test/driver_SUITE.erl
+++ b/erts/emulator/test/driver_SUITE.erl
@@ -390,12 +390,12 @@ timer_measure(Config) when is_list(Config) ->
try_timeouts(_, 0) -> ok;
try_timeouts(Port, Timeout) ->
- ?line TimeBefore = now(),
+ ?line TimeBefore = erlang:monotonic_time(),
?line erlang:port_command(Port, <<?START_TIMER,Timeout:32>>),
receive
{Port,{data,[?TIMER]}} ->
?line Elapsed = erl_millisecs() - erl_millisecs(TimeBefore),
- io:format("Elapsed: ~p Timeout: ~p\n", [Elapsed,Timeout]),
+ io:format("Elapsed: ~p Timeout: ~p\n", [Elapsed, Timeout]),
if
Elapsed < Timeout ->
?line ?t:fail(too_short);
@@ -455,7 +455,7 @@ timer_delay(Config) when is_list(Config) ->
Name = 'timer_drv',
?line Port = start_driver(Config, Name, false),
- ?line TimeBefore = now(),
+ ?line TimeBefore = erlang:monotonic_time(),
Timeout0 = 350,
?line erlang:port_command(Port, <<?DELAY_START_TIMER,Timeout0:32>>),
Timeout = Timeout0 +
@@ -499,7 +499,7 @@ timer_change(Config) when is_list(Config) ->
try_change_timer(_Port, 0) -> ok;
try_change_timer(Port, Timeout) ->
?line Timeout_3 = Timeout*3,
- ?line TimeBefore = now(),
+ ?line TimeBefore = erlang:monotonic_time(),
?line erlang:port_command(Port, <<?START_TIMER,Timeout_3:32>>),
?line erlang:port_command(Port, <<?START_TIMER,Timeout:32>>),
receive
@@ -2520,13 +2520,11 @@ uniform(N) ->
end,
random:uniform(N).
-%% return millisecs from statistics source
erl_millisecs() ->
- {Ms, S, Us} = erlang:now(),
- Ms * 1000000000 + S * 1000 + Us / 1000.
+ erl_millisecs(erlang:monotonic_time()).
-erl_millisecs({Ms,S,Us}) ->
- Ms * 1000000000 + S * 1000 + Us / 1000.
+erl_millisecs(MonotonicTime) ->
+ (1000*MonotonicTime)/erlang:convert_time_unit(1,seconds,native).
%% Start/stop drivers.
start_driver(Config, Name, Binary) ->
@@ -2575,18 +2573,15 @@ sleep(Ms) when is_integer(Ms), Ms >= 0 ->
start_node(Config) when is_list(Config) ->
- ?line Pa = filename:dirname(code:which(?MODULE)),
- ?line {A, B, C} = now(),
- ?line Name = list_to_atom(atom_to_list(?MODULE)
- ++ "-"
- ++ atom_to_list(?config(testcase, Config))
- ++ "-"
- ++ integer_to_list(A)
- ++ "-"
- ++ integer_to_list(B)
- ++ "-"
- ++ integer_to_list(C)),
- ?line ?t:start_node(Name, slave, [{args, "-pa "++Pa}]).
+ Pa = filename:dirname(code:which(?MODULE)),
+ Name = list_to_atom(atom_to_list(?MODULE)
+ ++ "-"
+ ++ atom_to_list(?config(testcase, Config))
+ ++ "-"
+ ++ integer_to_list(erlang:system_time(seconds))
+ ++ "-"
+ ++ integer_to_list(erlang:unique_integer([positive]))),
+ ?t:start_node(Name, slave, [{args, "-pa "++Pa}]).
stop_node(Node) ->
?t:stop_node(Node).
diff --git a/erts/emulator/test/erl_link_SUITE.erl b/erts/emulator/test/erl_link_SUITE.erl
index 435c0872e6..02c1d84d59 100644
--- a/erts/emulator/test/erl_link_SUITE.erl
+++ b/erts/emulator/test/erl_link_SUITE.erl
@@ -1035,16 +1035,13 @@ get_names(N, T) when is_atom(T) ->
get_names(0, _, Acc) ->
Acc;
get_names(N, T, Acc) ->
- {A, B, C} = now(),
get_names(N-1, T, [list_to_atom(atom_to_list(?MODULE)
++ "-"
++ atom_to_list(T)
++ "-"
- ++ integer_to_list(A)
+ ++ integer_to_list(erlang:system_time(seconds))
++ "-"
- ++ integer_to_list(B)
- ++ "-"
- ++ integer_to_list(C)) | Acc]).
+ ++ integer_to_list(erlang:unique_integer([positive]))) | Acc]).
start_node(Name) ->
?line start_node(Name, "").
diff --git a/erts/emulator/test/estone_SUITE.erl b/erts/emulator/test/estone_SUITE.erl
index 1de6d6fb56..67a53d94b1 100644
--- a/erts/emulator/test/estone_SUITE.erl
+++ b/erts/emulator/test/estone_SUITE.erl
@@ -339,7 +339,6 @@ micros() ->
].
macro(Ms,DataDir) ->
- erlang:now(), %% compensate for old 4.3 firsttime clock bug :-(
statistics(reductions),
statistics(runtime),
lists(500), %% fixup cache on first round
@@ -369,10 +368,9 @@ run_micro(Top, M, DataDir) ->
apply_micro(M) ->
{GC0, Words0, _} = statistics(garbage_collection),
statistics(reductions),
- Before = erlang:now(),
-
+ Before = monotonic_time(),
Compensate = apply_micro(M#micro.function, M#micro.loops),
- After = erlang:now(),
+ After = monotonic_time(),
{GC1, Words1, _} = statistics(garbage_collection),
{_, Reds} = statistics(reductions),
Elapsed = subtr(Before, After),
@@ -389,12 +387,13 @@ apply_micro(M) ->
{kilo_reductions, Reds div 1000},
{gc_intensity, gci(Elapsed, GC1 - GC0, Words1 - Words0)}].
+monotonic_time() ->
+ try erlang:monotonic_time() catch error:undef -> erlang:now() end.
-subtr(Before, After) ->
- (element(1,After)*1000000000000
- +element(2,After)*1000000+element(3,After)) -
- (element(1,Before)*1000000000000
- +element(2,Before)*1000000+element(3,Before)).
+subtr(Before, After) when is_integer(Before), is_integer(After) ->
+ erlang:convert_time_unit(After-Before, native, micro_seconds);
+subtr({_,_,_}=Before, {_,_,_}=After) ->
+ timer:now_diff(After, Before).
gci(Micros, Words, Gcs) ->
((256 * Gcs) / Micros) + (Words / Micros).
@@ -633,10 +632,10 @@ tup_trav(T, P, End) ->
%% Port I/O
port_io(I) ->
EstoneCat = get(estone_cat),
- Before = erlang:now(),
+ Before = monotonic_time(),
Pps = make_port_pids(5, I, EstoneCat), %% 5 ports
send_procs(Pps, go),
- After = erlang:now(),
+ After = monotonic_time(),
wait_for_pids(Pps),
subtr(Before, After).
@@ -854,10 +853,10 @@ handle_call(_From, State, [abc]) ->
%% Binary handling, creating, manipulating and sending binaries
binary_h(I) ->
- Before = erlang:now(),
+ Before = monotonic_time(),
P = spawn(?MODULE, echo, [self()]),
B = list_to_binary(lists:duplicate(2000, 5)),
- After = erlang:now(),
+ After = monotonic_time(),
Compensate = subtr(Before, After),
binary_h_2(I, P, B),
Compensate.
diff --git a/erts/emulator/test/float_SUITE.erl b/erts/emulator/test/float_SUITE.erl
index 4a45afa9e9..a07516b5a9 100644
--- a/erts/emulator/test/float_SUITE.erl
+++ b/erts/emulator/test/float_SUITE.erl
@@ -294,16 +294,13 @@ id(I) -> I.
start_node(Config) when is_list(Config) ->
?line Pa = filename:dirname(code:which(?MODULE)),
- ?line {A, B, C} = now(),
?line Name = list_to_atom(atom_to_list(?MODULE)
++ "-"
++ atom_to_list(?config(testcase, Config))
++ "-"
- ++ integer_to_list(A)
+ ++ integer_to_list(erlang:system_time(seconds))
++ "-"
- ++ integer_to_list(B)
- ++ "-"
- ++ integer_to_list(C)),
+ ++ integer_to_list(erlang:unique_integer([positive]))),
?line ?t:start_node(Name, slave, [{args, "-pa "++Pa}]).
stop_node(Node) ->
diff --git a/erts/emulator/test/gc_SUITE.erl b/erts/emulator/test/gc_SUITE.erl
index 36889b6c36..1b92e3198e 100644
--- a/erts/emulator/test/gc_SUITE.erl
+++ b/erts/emulator/test/gc_SUITE.erl
@@ -77,7 +77,7 @@ grow_heap1(List, MaxLen, CurLen, up) ->
grow_heap1([], _MaxLen, _, down) ->
ok;
grow_heap1([_|List], MaxLen, CurLen, down) ->
- {_,_,C} = erlang:now(),
+ C=erlang:unique_integer([positive]),
Num = C rem (length(List))+1,
Elem = lists:nth(Num, List),
NewList = lists:delete(Elem, List),
@@ -136,7 +136,7 @@ grow_stack_heap1(List, MaxLen, CurLen, up) ->
grow_stack_heap1([], _MaxLen, _, down) -> ok;
grow_stack_heap1([_|List], MaxLen, CurLen, down) ->
grow_stack1(CurLen*2,0),
- {_,_,C}=erlang:now(),
+ C=erlang:unique_integer([positive]),
Num=C rem (length(List))+1,
Elem=lists:nth(Num, List),
NewList=lists:delete(Elem, List),
@@ -146,8 +146,8 @@ grow_stack_heap1([_|List], MaxLen, CurLen, down) ->
%% Create an arbitrary element/term.
make_arbit() ->
- {AA,BB,CC}=erlang:now(),
- A=AA+1, B=BB+1, C=CC+1,
+ {AA,BB,CC}=erlang:timestamp(),
+ A=AA+1, B=BB+1, C=(CC+erlang:unique_integer([positive])) rem 1000000 + 1,
New =
case C rem 9 of
0 -> make_string((B div C) +5);
@@ -171,7 +171,7 @@ make_string(Length) ->
make_string(_, 0, Acc) ->
Acc;
make_string(Alph, Length, Acc) ->
- {_,_,C}=erlang:now(),
+ C=erlang:unique_integer([positive]),
Pos=1+(Length*C rem length(Alph)),
make_string(Alph, Length-1,
[lists:nth(Pos,Alph)|Acc]).
diff --git a/erts/emulator/test/map_SUITE.erl b/erts/emulator/test/map_SUITE.erl
index 39549282c0..527b6987fa 100644
--- a/erts/emulator/test/map_SUITE.erl
+++ b/erts/emulator/test/map_SUITE.erl
@@ -1508,7 +1508,9 @@ t_map_equal(Config) when is_list(Config) ->
t_map_compare(Config) when is_list(Config) ->
- Seed = erlang:now(),
+ Seed = {erlang:monotonic_time(),
+ erlang:time_offset(),
+ erlang:unique_integer()},
io:format("seed = ~p\n", [Seed]),
random:seed(Seed),
repeat(100, fun(_) -> float_int_compare() end, []),
diff --git a/erts/emulator/test/monitor_SUITE.erl b/erts/emulator/test/monitor_SUITE.erl
index 07e2862b2a..dc215b1529 100644
--- a/erts/emulator/test/monitor_SUITE.erl
+++ b/erts/emulator/test/monitor_SUITE.erl
@@ -763,12 +763,10 @@ named_down(doc) -> ["Test that DOWN message for a named monitor isn't"
" delivered until name has been unregistered"];
named_down(suite) -> [];
named_down(Config) when is_list(Config) ->
- ?line {A,B,C} = now(),
?line Name = list_to_atom(atom_to_list(?MODULE)
++ "-named_down-"
- ++ integer_to_list(A)
- ++ "-" ++ integer_to_list(B)
- ++ "-" ++ integer_to_list(C)),
+ ++ integer_to_list(erlang:system_time(seconds))
+ ++ "-" ++ integer_to_list(erlang:unique_integer([positive]))),
?line Prio = process_flag(priority,high),
%% Spawn a bunch of high prio cpu bound processes to prevent
%% normal prio processes from terminating during the next
diff --git a/erts/emulator/test/mtx_SUITE.erl b/erts/emulator/test/mtx_SUITE.erl
index a492501959..8dcd21f303 100644
--- a/erts/emulator/test/mtx_SUITE.erl
+++ b/erts/emulator/test/mtx_SUITE.erl
@@ -441,10 +441,10 @@ hammer_ets_rwlock_test(XOpts, UW, C, N, NP, SC) ->
receive after infinity -> ok end
end) | Ps0]
end,
- Start = now(),
+ Start = erlang:monotonic_time(),
lists:foreach(fun (P) -> P ! go end, Ps),
lists:foreach(fun (P) -> receive {done, P} -> ok end end, Ps),
- Stop = now(),
+ Stop = erlang:monotonic_time(),
lists:foreach(fun (P) ->
unlink(P),
exit(P, bang),
@@ -453,7 +453,7 @@ hammer_ets_rwlock_test(XOpts, UW, C, N, NP, SC) ->
{'DOWN', M, process, P, _} -> ok
end
end, Ps),
- Res = timer:now_diff(Stop, Start)/1000000,
+ Res = (Stop-Start)/erlang:convert_time_unit(1,seconds,native),
Caller ! {?MODULE, self(), Res}
end,
TP = spawn_link(T),
diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl
index 502ada95a1..c35c71dd5b 100644
--- a/erts/emulator/test/nif_SUITE.erl
+++ b/erts/emulator/test/nif_SUITE.erl
@@ -1190,7 +1190,9 @@ send3(Config) when is_list(Config) ->
%% Let a number of processes send random message blobs between each other
%% using enif_send. Kill and spawn new ones randomly to keep a ~constant
%% number of workers running.
- Seed = now(),
+ Seed = {erlang:monotonic_time(),
+ erlang:time_offset(),
+ erlang:unique_integer()},
io:format("seed: ~p\n",[Seed]),
random:seed(Seed),
ets:new(nif_SUITE,[named_table,public]),
diff --git a/erts/emulator/test/node_container_SUITE.erl b/erts/emulator/test/node_container_SUITE.erl
index 9c1839811a..2f505893b4 100644
--- a/erts/emulator/test/node_container_SUITE.erl
+++ b/erts/emulator/test/node_container_SUITE.erl
@@ -1120,26 +1120,18 @@ wait_until(Pred) ->
false -> receive after 100 -> wait_until(Pred) end
end.
+get_nodefirstname_string() ->
+ atom_to_list(?MODULE)
+ ++ "-"
+ ++ integer_to_list(erlang:system_time(seconds))
+ ++ "-"
+ ++ integer_to_list(erlang:unique_integer([positive])).
get_nodefirstname() ->
- {A, B, C} = now(),
- list_to_atom(atom_to_list(?MODULE)
- ++ "-"
- ++ integer_to_list(A)
- ++ "-"
- ++ integer_to_list(B)
- ++ "-"
- ++ integer_to_list(C)).
+ list_to_atom(get_nodefirstname_string()).
get_nodename() ->
- {A, B, C} = now(),
- list_to_atom(atom_to_list(?MODULE)
- ++ "-"
- ++ integer_to_list(A)
- ++ "-"
- ++ integer_to_list(B)
- ++ "-"
- ++ integer_to_list(C)
+ list_to_atom(get_nodefirstname_string()
++ "@"
++ hostname()).
diff --git a/erts/emulator/test/old_scheduler_SUITE.erl b/erts/emulator/test/old_scheduler_SUITE.erl
index 262536a068..57f6928185 100644
--- a/erts/emulator/test/old_scheduler_SUITE.erl
+++ b/erts/emulator/test/old_scheduler_SUITE.erl
@@ -116,7 +116,7 @@ equal(Config) when is_list(Config) ->
%% start controllers
?line Receiver =
- spawn(fun() -> receiver(now(), Time, Self, Normal, Low) end),
+ spawn(fun() -> receiver(erlang:monotonic_time(), Time, Self, Normal, Low) end),
?line Starter =
spawn(fun() -> starter(Normal, Low, Receiver) end),
@@ -154,7 +154,7 @@ many_low(Config) when is_list(Config) ->
Time = 30,
?line Receiver =
- spawn(fun() -> receiver(now(), Time, Self, Normal, Low) end),
+ spawn(fun() -> receiver(erlang:monotonic_time(), Time, Self, Normal, Low) end),
?line Starter =
spawn(fun() -> starter(Normal, Low, Receiver) end),
?line {NRs,NAvg,LRs,LAvg,Ratio} =
@@ -185,7 +185,7 @@ few_low(Config) when is_list(Config) ->
Time = 30,
?line Receiver =
- spawn(fun() -> receiver(now(), Time, Self, Normal, Low) end),
+ spawn(fun() -> receiver(erlang:monotonic_time(), Time, Self, Normal, Low) end),
?line Starter =
spawn(fun() -> starter(Normal, Low, Receiver) end),
?line {NRs,NAvg,LRs,LAvg,Ratio} =
@@ -220,7 +220,7 @@ max(Config) when is_list(Config) ->
Time = 30,
?line Receiver1 =
- spawn(fun() -> receiver(now(), Time, Self, Max, High) end),
+ spawn(fun() -> receiver(erlang:monotonic_time(), Time, Self, Max, High) end),
?line Starter1 =
spawn(fun() -> starter(Max, High, Receiver1) end),
?line {M1Rs,M1Avg,HRs,HAvg,Ratio1} =
@@ -238,7 +238,7 @@ max(Config) when is_list(Config) ->
end,
?line Receiver2 =
- spawn(fun() -> receiver(now(), Time, Self, Max, Normal) end),
+ spawn(fun() -> receiver(erlang:monotonic_time(), Time, Self, Max, Normal) end),
?line Starter2 =
spawn(fun() -> starter(Max, Normal, Receiver2) end),
?line {M2Rs,M2Avg,NRs,NAvg,Ratio2} =
@@ -256,7 +256,7 @@ max(Config) when is_list(Config) ->
end,
?line Receiver3 =
- spawn(fun() -> receiver(now(), Time, Self, Max, Low) end),
+ spawn(fun() -> receiver(erlang:monotonic_time(), Time, Self, Max, Low) end),
?line Starter3 =
spawn(fun() -> starter(Max, Low, Receiver3) end),
?line {M3Rs,M3Avg,LRs,LAvg,Ratio3} =
@@ -290,7 +290,7 @@ high(Config) when is_list(Config) ->
Time = 30,
?line Receiver1 =
- spawn(fun() -> receiver(now(), Time, Self, High, Normal) end),
+ spawn(fun() -> receiver(erlang:monotonic_time(), Time, Self, High, Normal) end),
?line Starter1 =
spawn(fun() -> starter(High, Normal, Receiver1) end),
?line {H1Rs,H1Avg,NRs,NAvg,Ratio1} =
@@ -308,7 +308,7 @@ high(Config) when is_list(Config) ->
end,
?line Receiver2 =
- spawn(fun() -> receiver(now(), Time, Self, High, Low) end),
+ spawn(fun() -> receiver(erlang:monotonic_time(), Time, Self, High, Low) end),
?line Starter2 =
spawn(fun() -> starter(High, Low, Receiver2) end),
?line {H2Rs,H2Avg,LRs,LAvg,Ratio2} =
@@ -337,12 +337,13 @@ receiver(T0, TimeSec, Main, {P1,P1N}, {P2,P2N}) ->
%% uncomment lines below to get life sign (debug)
receiver(T0, Time, Main, P1,P1N,P1Rs, P2,P2N,P2Rs, 0) ->
-% T = elapsed_ms(T0, now()),
+% T = erlang:convert_time_unit(erlang:monotonic_time() - T0, native, milli_seconds),
% erlang:display({round(T/1000),P1Rs,P2Rs}),
receiver(T0, Time, Main, P1,P1N,P1Rs, P2,P2N,P2Rs, 100000);
receiver(T0, Time, Main, P1,P1N,P1Rs, P2,P2N,P2Rs, C) ->
- Remain = Time - elapsed_ms(T0, now()), % test time remaining
+ Remain = Time - erlang:convert_time_unit(erlang:monotonic_time() - T0,
+ native, milli_seconds), % test time remaining
Remain1 = if Remain < 0 ->
0;
true ->
@@ -409,6 +410,3 @@ flush_loop() ->
ok
end,
flush_loop().
-
-elapsed_ms({_MS0,S0,MuS0},{_MS1,S1,MuS1}) ->
- round(((S1-S0)*1000)+((MuS1-MuS0)/1000)).
diff --git a/erts/emulator/test/port_SUITE.erl b/erts/emulator/test/port_SUITE.erl
index 6bbf93b7d7..e61c330861 100644
--- a/erts/emulator/test/port_SUITE.erl
+++ b/erts/emulator/test/port_SUITE.erl
@@ -1815,7 +1815,7 @@ exit_status_msb_test(Config, SleepSecs) when is_list(Config) ->
Parent = self(),
?t:format("SleepSecs = ~p~n", [SleepSecs]),
PortProg = "sleep " ++ integer_to_list(SleepSecs),
- Start = now(),
+ Start = erlang:monotonic_time(micro_seconds),
NoProcs = case NoSchedsOnln of
NProcs when NProcs < ?EXIT_STATUS_MSB_MAX_PROCS ->
NProcs;
@@ -1887,12 +1887,12 @@ exit_status_msb_test(Config, SleepSecs) when is_list(Config) ->
receive {P, started, SIds} -> SIds end
end,
Procs),
- StartedTime = timer:now_diff(now(), Start)/1000000,
+ StartedTime = (erlang:monotonic_time(micro_seconds) - Start)/1000000,
?t:format("StartedTime = ~p~n", [StartedTime]),
true = StartedTime < SleepSecs,
erlang:system_flag(multi_scheduling, block),
lists:foreach(fun (P) -> receive {P, done} -> ok end end, Procs),
- DoneTime = timer:now_diff(now(), Start)/1000000,
+ DoneTime = (erlang:monotonic_time(micro_seconds) - Start)/1000000,
?t:format("DoneTime = ~p~n", [DoneTime]),
true = DoneTime > SleepSecs,
ok = verify_multi_scheduling_blocked(),
diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl
index bf31655066..105d39f126 100644
--- a/erts/emulator/test/process_SUITE.erl
+++ b/erts/emulator/test/process_SUITE.erl
@@ -379,16 +379,15 @@ eat_high(Low) ->
process_flag(priority, high),
receive after 1000 -> ok end,
exit(Low, {you, are, dead}),
- {_, Sec, _} = now(),
- loop(Sec, Sec).
+ loop(erlang:monotonic_time() + erlang:convert_time_unit(5,seconds,native)).
%% Busy loop for 5 seconds.
-loop(OrigSec, CurrentSec) when CurrentSec < OrigSec+5 ->
- {_, NewSec, _} = now(),
- loop(OrigSec, NewSec);
-loop(_, _) ->
- ok.
+loop(StopTime) ->
+ case StopTime >= erlang:monotonic_time() of
+ true -> ok;
+ false -> loop(StopTime)
+ end.
%% Tries to send two different exit messages to a process.
@@ -2450,16 +2449,13 @@ start_node(Config) ->
start_node(Config, Args) when is_list(Config) ->
Pa = filename:dirname(code:which(?MODULE)),
- {A, B, C} = now(),
Name = list_to_atom(atom_to_list(?MODULE)
++ "-"
++ atom_to_list(?config(testcase, Config))
++ "-"
- ++ integer_to_list(A)
- ++ "-"
- ++ integer_to_list(B)
+ ++ integer_to_list(erlang:system_time(seconds))
++ "-"
- ++ integer_to_list(C)),
+ ++ integer_to_list(erlang:unique_integer([positive]))),
?t:start_node(Name, slave, [{args, "-pa "++Pa++" "++Args}]).
stop_node(Node) ->
diff --git a/erts/emulator/test/scheduler_SUITE.erl b/erts/emulator/test/scheduler_SUITE.erl
index 3906471f87..c5af12c6d1 100644
--- a/erts/emulator/test/scheduler_SUITE.erl
+++ b/erts/emulator/test/scheduler_SUITE.erl
@@ -1829,11 +1829,11 @@ do_it(Tracer, Low, Normal, High, Max) ->
do_it(Tracer, Low, Normal, High, Max, RedsPerSchedLimit) ->
OldPrio = process_flag(priority, max),
go_work(Low, Normal, High, Max),
- StartWait = now(),
+ StartWait = erlang:monotonic_time(milli_seconds),
%% Give the emulator a chance to balance the load...
wait_balance(5),
- EndWait = now(),
- BalanceWait = timer:now_diff(EndWait,StartWait) div 1000,
+ EndWait = erlang:monotonic_time(milli_seconds),
+ BalanceWait = EndWait-StartWait,
erlang:display({balance_wait, BalanceWait}),
Timeout = ?DEFAULT_TIMEOUT - ?t:minutes(4) - BalanceWait,
Res = case Timeout < ?MIN_SCHEDULER_TEST_TIMEOUT of
@@ -2027,17 +2027,14 @@ start_node(Config) ->
start_node(Config, "").
start_node(Config, Args) when is_list(Config) ->
- ?line Pa = filename:dirname(code:which(?MODULE)),
- ?line {A, B, C} = now(),
- ?line Name = list_to_atom(atom_to_list(?MODULE)
- ++ "-"
- ++ atom_to_list(?config(testcase, Config))
- ++ "-"
- ++ integer_to_list(A)
- ++ "-"
- ++ integer_to_list(B)
- ++ "-"
- ++ integer_to_list(C)),
+ Pa = filename:dirname(code:which(?MODULE)),
+ Name = list_to_atom(atom_to_list(?MODULE)
+ ++ "-"
+ ++ atom_to_list(?config(testcase, Config))
+ ++ "-"
+ ++ integer_to_list(erlang:system_time(seconds))
+ ++ "-"
+ ++ integer_to_list(erlang:unique_integer([positive]))),
?line ?t:start_node(Name, slave, [{args, "-pa "++Pa++" "++Args}]).
stop_node(Node) ->
diff --git a/erts/emulator/test/signal_SUITE.erl b/erts/emulator/test/signal_SUITE.erl
index 736dfe5b56..dcb10c947e 100644
--- a/erts/emulator/test/signal_SUITE.erl
+++ b/erts/emulator/test/signal_SUITE.erl
@@ -515,12 +515,10 @@ repeat(Fun, N) when is_integer(N) ->
repeat(Fun, N-1).
start_node(Config) ->
- {A, B, C} = now(),
Name = list_to_atom(atom_to_list(?MODULE)
++ "-" ++ atom_to_list(?config(testcase, Config))
- ++ "-" ++ integer_to_list(A)
- ++ "-" ++ integer_to_list(B)
- ++ "-" ++ integer_to_list(C)),
+ ++ "-" ++ integer_to_list(erlang:system_time(seconds))
+ ++ "-" ++ integer_to_list(erlang:unique_integer([positive]))),
Pa = filename:dirname(code:which(?MODULE)),
?t:start_node(Name, slave, [{args, "-pa " ++ Pa}]).
diff --git a/erts/emulator/test/smoke_test_SUITE.erl b/erts/emulator/test/smoke_test_SUITE.erl
index 10b7e16a74..4c50b8ba8c 100644
--- a/erts/emulator/test/smoke_test_SUITE.erl
+++ b/erts/emulator/test/smoke_test_SUITE.erl
@@ -167,16 +167,13 @@ start_node(Config) ->
start_node(Config, Args) when is_list(Config) ->
Pa = filename:dirname(code:which(?MODULE)),
- {A, B, C} = now(),
Name = list_to_atom(atom_to_list(?MODULE)
++ "-"
++ atom_to_list(?config(testcase, Config))
++ "-"
- ++ integer_to_list(A)
+ ++ integer_to_list(erlang:system_time(seconds))
++ "-"
- ++ integer_to_list(B)
- ++ "-"
- ++ integer_to_list(C)),
+ ++ integer_to_list(erlang:unique_integer([positive]))),
Opts = [{args, "-pa "++Pa++" "++Args}],
?t:start_node(Name, slave, Opts).
diff --git a/erts/emulator/test/system_info_SUITE.erl b/erts/emulator/test/system_info_SUITE.erl
index f959714be7..0fd6696536 100644
--- a/erts/emulator/test/system_info_SUITE.erl
+++ b/erts/emulator/test/system_info_SUITE.erl
@@ -533,16 +533,13 @@ get_ets_limit(Config, EtsMax) ->
start_node(Config, Envs) when is_list(Config) ->
Pa = filename:dirname(code:which(?MODULE)),
- {A, B, C} = now(),
Name = list_to_atom(atom_to_list(?MODULE)
++ "-"
++ atom_to_list(?config(testcase, Config))
++ "-"
- ++ integer_to_list(A)
+ ++ integer_to_list(erlang:system_time(seconds))
++ "-"
- ++ integer_to_list(B)
- ++ "-"
- ++ integer_to_list(C)),
+ ++ integer_to_list(erlang:unique_integer([positive]))),
?t:start_node(Name, peer, [{args, "-pa "++Pa}, {env, Envs}]).
stop_node(Node) ->
diff --git a/erts/emulator/test/time_SUITE.erl b/erts/emulator/test/time_SUITE.erl
index 43f7ac7f7c..d04a95b10e 100644
--- a/erts/emulator/test/time_SUITE.erl
+++ b/erts/emulator/test/time_SUITE.erl
@@ -18,6 +18,7 @@
%%
-module(time_SUITE).
+-compile({nowarn_deprecated_function, {erlang,now,0}}).
%% "Time is on my side." -- The Rolling Stones
@@ -37,6 +38,7 @@
now_unique/1, now_update/1, timestamp/1,
time_warp_modes/1,
monotonic_time_monotonicity/1,
+ monotonic_time_monotonicity_parallel/1,
time_unit_conversion/1,
signed_time_unit_conversion/1,
erlang_timestamp/1]).
@@ -79,6 +81,7 @@ all() ->
{group, now}, timestamp,
time_warp_modes,
monotonic_time_monotonicity,
+ monotonic_time_monotonicity_parallel,
time_unit_conversion,
signed_time_unit_conversion,
erlang_timestamp].
@@ -565,6 +568,78 @@ cmp_times(Done, X0) ->
cmp_times(Done, X5)
end.
+-define(NR_OF_MONOTONIC_CALLS, 100000).
+
+monotonic_time_monotonicity_parallel(Config) when is_list(Config) ->
+ Me = self(),
+ Result = make_ref(),
+ Go = make_ref(),
+ UpAndRunning = make_ref(),
+ NoOnlnScheds = erlang:system_info(schedulers_online),
+ OffsetUI = erlang:unique_integer([monotonic]),
+ OffsetMT = erlang:monotonic_time(),
+ MinHSz = ?NR_OF_MONOTONIC_CALLS*(2
+ + 3
+ + erts_debug:flat_size(OffsetUI)
+ + erts_debug:flat_size(OffsetMT)),
+ Ps = lists:map(
+ fun (Sched) ->
+ spawn_opt(
+ fun () ->
+ Me ! {self(), UpAndRunning},
+ receive Go -> ok end,
+ Res = fetch_monotonic(?NR_OF_MONOTONIC_CALLS, []),
+ Me ! {self(), Result, Sched, Res}
+ end,
+ [{scheduler, Sched},
+ {priority, max},
+ {min_heap_size, MinHSz}])
+ end,
+ lists:seq(1, NoOnlnScheds)),
+ lists:foreach(fun (P) -> receive {P, UpAndRunning} -> ok end end, Ps),
+ lists:foreach(fun (P) -> P ! Go end, Ps),
+ TMs = recv_monotonics(Result, OffsetMT, OffsetUI, NoOnlnScheds, []),
+ true = check_monotonic_result(TMs, OffsetMT, OffsetUI, true).
+
+check_monotonic_result([{_Sched, _PrevUI, _MT, _PostUI}],
+ _OffsetMT, _OffsetUI, Res) ->
+ Res;
+check_monotonic_result([{_ASched, _APrevUI, AMT, APostUI} = A,
+ {_BSched, BPrevUI, BMT, _BPostUI} = B | _] = L,
+ OffsetMT, OffsetUI, Res) ->
+ NewRes = case (AMT =< BMT) orelse (BPrevUI < APostUI) of
+ true ->
+ Res;
+ false ->
+ io:format("INCONSISTENCY: ~p ~p~n", [A, B]),
+ false
+ end,
+ check_monotonic_result(tl(L), OffsetMT, OffsetUI, NewRes).
+
+recv_monotonics(_Result, _OffsetMT, _OffsetUI, 0, Acc) ->
+ lists:keysort(2, Acc);
+recv_monotonics(Result, OffsetMT, OffsetUI, N, Acc) ->
+ receive
+ {_, Result, Sched, Res} ->
+ CRes = convert_monotonic(Sched, OffsetMT, OffsetUI, Res, []),
+ recv_monotonics(Result, OffsetMT, OffsetUI, N-1, CRes ++ Acc)
+ end.
+
+convert_monotonic(_Sched, _OffsetMT, _OffsetUI, [{_MT, _UI}], Acc) ->
+ Acc;
+convert_monotonic(Sched, OffsetMT, OffsetUI,
+ [{MT, UI}, {_PrevMT, PrevUI} | _] = L, Acc) ->
+ convert_monotonic(Sched, OffsetMT, OffsetUI, tl(L),
+ [{Sched, PrevUI-OffsetUI, MT-OffsetMT, UI-OffsetUI}
+ | Acc]).
+
+fetch_monotonic(0, Acc) ->
+ Acc;
+fetch_monotonic(N, Acc) ->
+ MT = erlang:monotonic_time(),
+ UI = erlang:unique_integer([monotonic]),
+ fetch_monotonic(N-1, [{MT, UI} | Acc]).
+
-define(CHK_RES_CONVS_TIMEOUT, 400).
time_unit_conversion(Config) when is_list(Config) ->
diff --git a/erts/emulator/test/timer_bif_SUITE.erl b/erts/emulator/test/timer_bif_SUITE.erl
index 56a1cef761..3701dd8437 100644
--- a/erts/emulator/test/timer_bif_SUITE.erl
+++ b/erts/emulator/test/timer_bif_SUITE.erl
@@ -502,9 +502,10 @@ get_msg() ->
end.
start_slave() ->
- ?line {A, B, C} = now(),
?line Pa = filename:dirname(code:which(?MODULE)),
- ?line Name = atom_to_list(?MODULE) ++ "-" ++ integer_to_list(A+B+C),
+ ?line Name = atom_to_list(?MODULE)
+ ++ "-" ++ integer_to_list(erlang:system_time(seconds))
+ ++ "-" ++ integer_to_list(erlang:unique_integer([positive])),
{ok, Node} = ?t:start_node(Name, slave, [{args, "-pa " ++ Pa}]),
Node.
diff --git a/erts/emulator/test/trace_call_time_SUITE.erl b/erts/emulator/test/trace_call_time_SUITE.erl
index 3036d2957b..9c444ed682 100644
--- a/erts/emulator/test/trace_call_time_SUITE.erl
+++ b/erts/emulator/test/trace_call_time_SUITE.erl
@@ -326,10 +326,10 @@ combo(Config) when is_list(Config) ->
%%
?line [3,2,1] = seq_r(1, 3, fun(X) -> X+1 end),
- ?line T0 = now(),
+ ?line T0 = erlang:monotonic_time(),
?line with_bif(Nbc),
- ?line T1 = now(),
- ?line TimeB = timer:now_diff(T1,T0),
+ ?line T1 = erlang:monotonic_time(),
+ ?line TimeB = erlang:convert_time_unit(T1-T0, native, micro_seconds),
%%
?line List = collect(100),
@@ -695,17 +695,17 @@ setup(Opts) ->
Pid.
execute(Pids, Mfa) when is_list(Pids) ->
- T0 = now(),
+ T0 = erlang:monotonic_time(),
[P ! {self(), execute, Mfa} || P <- Pids],
As = [receive {P, answer, Answer} -> Answer end || P <- Pids],
- T1 = now(),
- {As, timer:now_diff(T1,T0)};
+ T1 = erlang:monotonic_time(),
+ {As, erlang:convert_time_unit(T1-T0, native, micro_seconds)};
execute(P, Mfa) ->
- T0 = now(),
+ T0 = erlang:monotonic_time(),
P ! {self(), execute, Mfa},
A = receive {P, answer, Answer} -> Answer end,
- T1 = now(),
- {A, timer:now_diff(T1,T0)}.
+ T1 = erlang:monotonic_time(),
+ {A, erlang:convert_time_unit(T1-T0, native, micro_seconds)}.