timers: improve Timer.now() performance
authorBen Noordhuis <info@bnoordhuis.nl>
Mon, 27 Jul 2015 21:29:03 +0000 (23:29 +0200)
committerBen Noordhuis <info@bnoordhuis.nl>
Mon, 27 Jul 2015 22:13:30 +0000 (00:13 +0200)
Record the start time so we can make the return value of Timer.now()
relative to it, increasing the chances that it fits in a tagged integer
instead of a heap-allocated double, at least for the first one or two
billion milliseconds.

PR-URL: https://github.com/nodejs/io.js/pull/2256
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
src/env-inl.h
src/env.h
src/timer_wrap.cc
test/parallel/test-timers-now.js [new file with mode: 0644]

index 0feefdb..e316185 100644 (file)
@@ -171,6 +171,7 @@ inline Environment::Environment(v8::Local<v8::Context> context,
                                 uv_loop_t* loop)
     : isolate_(context->GetIsolate()),
       isolate_data_(IsolateData::GetOrCreate(context->GetIsolate(), loop)),
+      timer_base_(uv_now(loop)),
       using_smalloc_alloc_cb_(false),
       using_domains_(false),
       using_abort_on_uncaught_exc_(false),
@@ -286,6 +287,10 @@ inline Environment::TickInfo* Environment::tick_info() {
   return &tick_info_;
 }
 
+inline uint64_t Environment::timer_base() const {
+  return timer_base_;
+}
+
 inline bool Environment::using_smalloc_alloc_cb() const {
   return using_smalloc_alloc_cb_;
 }
index b53ff87..7289521 100644 (file)
--- a/src/env.h
+++ b/src/env.h
@@ -398,6 +398,7 @@ class Environment {
   inline AsyncHooks* async_hooks();
   inline DomainFlag* domain_flag();
   inline TickInfo* tick_info();
+  inline uint64_t timer_base() const;
 
   static inline Environment* from_cares_timer_handle(uv_timer_t* handle);
   inline uv_timer_t* cares_timer_handle();
@@ -501,6 +502,7 @@ class Environment {
   AsyncHooks async_hooks_;
   DomainFlag domain_flag_;
   TickInfo tick_info_;
+  const uint64_t timer_base_;
   uv_timer_t cares_timer_handle_;
   ares_channel cares_channel_;
   ares_task_list cares_task_list_;
index 3f2fff1..f3d5d1f 100644 (file)
@@ -101,6 +101,8 @@ class TimerWrap : public HandleWrap {
     Environment* env = Environment::GetCurrent(args);
     uv_update_time(env->event_loop());
     uint64_t now = uv_now(env->event_loop());
+    CHECK(now >= env->timer_base());
+    now -= env->timer_base();
     if (now <= 0xfffffff)
       args.GetReturnValue().Set(static_cast<uint32_t>(now));
     else
diff --git a/test/parallel/test-timers-now.js b/test/parallel/test-timers-now.js
new file mode 100644 (file)
index 0000000..466bd06
--- /dev/null
@@ -0,0 +1,8 @@
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+
+// Return value of Timer.now() should easily fit in a SMI right after start-up.
+const Timer = process.binding('timer_wrap').Timer;
+assert(Timer.now() < 0x3ffffff);