viml/profile: switch to uv_gettimeofday() #10356

Performance of high-resolution time (clock_gettime via uv_hrtime) is
expensive on some systems.  For profiling VimL, syntax, etc., we don't
care about nanosecond-precision and monotonicity edge-cases, so avoid
uv_hrtime().

closes #10328

From the uv__hrtime() source:
0cdb4a5b4b/src/unix/linux-core.c (L442-L462)

    /* Prefer CLOCK_MONOTONIC_COARSE if available but only when it has
     * millisecond granularity or better.  CLOCK_MONOTONIC_COARSE is
     * serviced entirely from the vDSO, whereas CLOCK_MONOTONIC may
     * decide to make a costly system call.
     */

This micro-benchmark (Debug build) shows negligible differences on my
system:

    #include <sys/time.h>
    ...

    proftime_T tm = profile_start();
    int trials = 999999;
    int64_t t = 0;
    struct timeval tv;
    for (int i = 0; i < trials; i++) {
      t += gettimeofday(&tv,NULL);
    }
    tm = profile_end(tm);
    ILOG("%d trials of gettimeofday: %s", trials, profile_msg(tm));
    tm = profile_start();
    for (int i = 0; i < trials; i++) {
      t += os_hrtime();
    }
    tm = profile_end(tm);
    ILOG("%d trials of os_hrtime: %s", trials, profile_msg(tm));
    tm = profile_start();
    for (int i = 0; i < trials; i++) {
      t += os_utime();
    }
    tm = profile_end(tm);
    ILOG("%d trials of os_utime: %s", trials, profile_msg(tm));
    ILOG("%zu", t);
This commit is contained in:
Justin M. Keyes
2019-06-29 16:39:22 +02:00
committed by GitHub
parent 23a9794920
commit e2ce5ff9d6
4 changed files with 84 additions and 50 deletions

View File

@@ -9,6 +9,7 @@
#include <uv.h>
#include "nvim/assert.h"
#include "nvim/os/time.h"
#include "nvim/os/input.h"
#include "nvim/event/loop.h"
@@ -22,6 +23,7 @@ static uv_cond_t delay_cond;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/time.c.generated.h"
#endif
/// Initializes the time module
void time_init(void)
{
@@ -29,15 +31,53 @@ void time_init(void)
uv_cond_init(&delay_cond);
}
/// Obtain a high-resolution timer value
/// Gets the current time with microsecond (μs) precision.
///
/// @return a timer value, not related to the time of day and not subject
/// to clock drift. The value is expressed in nanoseconds.
/// Subject to system-clock quirks (drift, going backwards, skipping).
/// But it is much faster than os_hrtime() on some systems. #10328
///
/// @see gettimeofday(2)
///
/// @return Current time in microseconds.
uint64_t os_utime(void)
FUNC_ATTR_WARN_UNUSED_RESULT
{
uv_timeval64_t tm;
int e = uv_gettimeofday(&tm);
if (e != 0 || tm.tv_sec < 0 || tm.tv_usec < 0) {
return 0;
}
uint64_t rv = (uint64_t)tm.tv_sec * 1000 * 1000; // s => μs
STRICT_ADD(rv, tm.tv_usec, &rv, uint64_t);
return rv;
}
/// Gets a high-resolution (nanosecond), monotonically-increasing time relative
/// to an arbitrary time in the past.
///
/// Not related to the time of day and therefore not subject to clock drift.
///
/// @return Relative time value with nanosecond precision.
uint64_t os_hrtime(void)
FUNC_ATTR_WARN_UNUSED_RESULT
{
return uv_hrtime();
}
/// Gets a millisecond-resolution, monotonically-increasing time relative to an
/// arbitrary time in the past.
///
/// Not related to the time of day and therefore not subject to clock drift.
/// The value is cached by the loop, it will not change until the next
/// loop-tick (unless uv_update_time is called).
///
/// @return Relative time value with millisecond precision.
uint64_t os_now(void)
FUNC_ATTR_WARN_UNUSED_RESULT
{
return uv_now(&main_loop.uv);
}
/// Sleeps for `ms` milliseconds.
///
/// @param ms Number of milliseconds to sleep