Blame SOURCES/v8-3.14.5.10-use-clock_gettime.patch

e93883
From f9ced08de30c37838756e8227bd091f80ad9cafa Mon Sep 17 00:00:00 2001
e93883
From: Ben Noordhuis <ben@strongloop.com>
e93883
Date: Thu, 24 Apr 2014 04:27:40 +0200
e93883
Subject: [PATCH] deps: make v8 use CLOCK_REALTIME_COARSE
e93883
e93883
Date.now() indirectly calls gettimeofday() on Linux and that's a system
e93883
call that is extremely expensive on virtualized systems when the host
e93883
operating system has to emulate access to the hardware clock.
e93883
e93883
Case in point: output from `perf record -c 10000 -e cycles:u -g -i`
e93883
for a benchmark/http_simple bytes/8 benchmark with a light load of
e93883
50 concurrent clients:
e93883
e93883
    53.69%     node  node                 [.] v8::internal::OS::TimeCurrentMillis()
e93883
               |
e93883
               --- v8::internal::OS::TimeCurrentMillis()
e93883
                  |
e93883
                  |--99.77%-- v8::internal::Runtime_DateCurrentTime(v8::internal::Arguments, v8::internal::Isolate*)
e93883
                  |          0x23587880618e
e93883
e93883
That's right - over half of user time spent inside the V8 function that
e93883
calls gettimeofday().
e93883
e93883
Notably, nearly all system time gets attributed to acpi_pm_read(), the
e93883
kernel function that reads the ACPI power management timer:
e93883
e93883
    32.49%     node  [kernel.kallsyms]    [k] acpi_pm_read
e93883
               |
e93883
               --- acpi_pm_read
e93883
                  |
e93883
                  |--98.40%-- __getnstimeofday
e93883
                  |          getnstimeofday
e93883
                  |          |
e93883
                  |          |--71.61%-- do_gettimeofday
e93883
                  |          |          sys_gettimeofday
e93883
                  |          |          system_call_fastpath
e93883
                  |          |          0x7fffbbaf6dbc
e93883
                  |          |          |
e93883
                  |          |          |--98.72%-- v8::internal::OS::TimeCurrentMillis()
e93883
e93883
The cost of the gettimeofday() system call is normally measured in
e93883
nanoseconds but we were seeing 100 us averages and spikes >= 1000 us.
e93883
The numbers were so bad, my initial hunch was that the node process was
e93883
continuously getting rescheduled inside the system call...
e93883
e93883
v8::internal::OS::TimeCurrentMillis()'s most frequent caller is
e93883
v8::internal::Runtime_DateCurrentTime(), the V8 run-time function
e93883
that's behind Date.now().  The timeout handling logic in lib/http.js
e93883
and lib/net.js calls into lib/timers.js and that module will happily
e93883
call Date.now() hundreds or even thousands of times per second.
e93883
If you saw exports._unrefActive() show up in --prof output a lot,
e93883
now you know why.
e93883
e93883
That's why this commit makes V8 switch over to clock_gettime() on Linux.
e93883
In particular, it checks if CLOCK_REALTIME_COARSE is available and has
e93883
a resolution <= 1 ms because in that case the clock_gettime() call can
e93883
be fully serviced from the vDSO.
e93883
e93883
It speeds up the aforementioned benchmark by about 100% on the affected
e93883
systems and should go a long way toward addressing the latency issues
e93883
that StrongLoop customers have been reporting.
e93883
e93883
This patch will be upstreamed as a CR against V8 3.26.  I'm sending it
e93883
as a pull request for v0.10 first because that's what our users are
e93883
running and because the delta between 3.26 and 3.14 is too big to
e93883
reasonably back-port the patch.  I'll open a pull request for the
e93883
master branch once the CR lands upstream.
e93883
e93883
Signed-off-by: Trevor Norris <trev.norris@gmail.com>
e93883
Signed-off-by: Fedor Indutny <fedor@indutny.com>
e93883
---
e93883
 src/platform-posix.cc | 26 ++++++++++++++++++++++----
e93883
 1 file changed, 22 insertions(+), 4 deletions(-)
e93883
e93883
diff --git a/src/platform-posix.cc b/src/platform-posix.cc
e93883
index ad74eba..3c86868 100644
e93883
--- a/src/platform-posix.cc
e93883
+++ b/src/platform-posix.cc
e93883
@@ -188,19 +188,37 @@ int OS::GetUserTime(uint32_t* secs,  uint32_t* usecs) {
e93883
 
e93883
 
e93883
 double OS::TimeCurrentMillis() {
e93883
-  struct timeval tv;
e93883
-  if (gettimeofday(&tv, NULL) < 0) return 0.0;
e93883
-  return (static_cast<double>(tv.tv_sec) * 1000) +
e93883
-         (static_cast<double>(tv.tv_usec) / 1000);
e93883
+  return static_cast<double>(Ticks()) / 1000;
e93883
 }
e93883
 
e93883
 
e93883
 int64_t OS::Ticks() {
e93883
+#if defined(__linux__)
e93883
+  static clockid_t clock_id = static_cast<clockid_t>(-1);
e93883
+  struct timespec spec;
e93883
+  if (clock_id == static_cast<clockid_t>(-1)) {
e93883
+    // CLOCK_REALTIME_COARSE may not be defined by the system headers but
e93883
+    // might still be supported by the kernel so use the clock id directly.
e93883
+    // Only use CLOCK_REALTIME_COARSE when its granularity <= 1 ms.
e93883
+    const clockid_t clock_realtime_coarse = 5;
e93883
+    if (clock_getres(clock_realtime_coarse, &spec) == 0 &&
e93883
+        spec.tv_nsec <= 1000 * 1000) {
e93883
+      clock_id = clock_realtime_coarse;
e93883
+    } else {
e93883
+      clock_id = CLOCK_REALTIME;
e93883
+    }
e93883
+  }
e93883
+  if (clock_gettime(clock_id, &spec) != 0) {
e93883
+    return 0;  // Not really possible.
e93883
+  }
e93883
+  return static_cast<int64_t>(spec.tv_sec) * 1000000 + (spec.tv_nsec / 1000);
e93883
+#else
e93883
   // gettimeofday has microsecond resolution.
e93883
   struct timeval tv;
e93883
   if (gettimeofday(&tv, NULL) < 0)
e93883
     return 0;
e93883
   return (static_cast<int64_t>(tv.tv_sec) * 1000000) + tv.tv_usec;
e93883
+#endif
e93883
 }
e93883
 
e93883
 
e93883
-- 
e93883
1.9.1