[beast: 51/57] SFI: platform: add timestamp handling



commit 28859da9a2331455c932233c529d53d88d6e5128
Author: Tim Janik <timj gnu org>
Date:   Wed Jul 19 02:53:28 2017 +0200

    SFI: platform: add timestamp handling
    
    Signed-off-by: Tim Janik <timj gnu org>

 sfi/platform.cc |  137 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 sfi/platform.hh |    8 +++
 2 files changed, 141 insertions(+), 4 deletions(-)
---
diff --git a/sfi/platform.cc b/sfi/platform.cc
index 260a976..d2255bc 100644
--- a/sfi/platform.cc
+++ b/sfi/platform.cc
@@ -9,9 +9,118 @@
 #include <windows.h>
 #endif  // _WIN32
 #include <cstring>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <execinfo.h>           // _EXECINFO_H
 
 namespace Bse {
 
+// == Timestamps ==
+static clockid_t monotonic_clockid = CLOCK_REALTIME;
+static uint64    monotonic_start = 0;
+static uint64    monotonic_resolution = 1000;   // assume 1µs resolution for gettimeofday fallback
+static uint64    realtime_start = 0;
+
+static void
+timestamp_init_ ()
+{
+  static const bool initialize = [] () {
+    realtime_start = timestamp_realtime();
+    struct timespec tp = { 0, 0 };
+    if (clock_getres (CLOCK_REALTIME, &tp) >= 0)
+      monotonic_resolution = tp.tv_sec * 1000000000ULL + tp.tv_nsec;
+    uint64 mstart = realtime_start;
+#ifdef CLOCK_MONOTONIC
+    // CLOCK_MONOTONIC_RAW cannot slew, but doesn't measure SI seconds accurately
+    // CLOCK_MONOTONIC may slew, but attempts to accurately measure SI seconds
+    if (monotonic_clockid == CLOCK_REALTIME && clock_getres (CLOCK_MONOTONIC, &tp) >= 0)
+      {
+        monotonic_clockid = CLOCK_MONOTONIC;
+        monotonic_resolution = tp.tv_sec * 1000000000ULL + tp.tv_nsec;
+        mstart = timestamp_benchmark(); // here, monotonic_start=0 still
+      }
+#endif
+    monotonic_start = mstart;
+    return true;
+  } ();
+  (void) initialize;
+}
+namespace { static struct Timestamper { Timestamper() { timestamp_init_(); } } realtime_startup; } // Anon
+
+/// Provides the timestamp_realtime() value from program startup.
+uint64
+timestamp_startup ()
+{
+  timestamp_init_();
+  return realtime_start;
+}
+
+/// Return the current time as uint64 in µseconds.
+uint64
+timestamp_realtime ()
+{
+  struct timespec tp = { 0, 0 };
+  if (ISLIKELY (clock_gettime (CLOCK_REALTIME, &tp) >= 0))
+    return tp.tv_sec * 1000000ULL + tp.tv_nsec / 1000;
+  else
+    {
+      struct timeval now = { 0, 0 };
+      gettimeofday (&now, NULL);
+      return now.tv_sec * 1000000ULL + now.tv_usec;
+    }
+}
+
+/// Provide resolution of timestamp_benchmark() in nano-seconds.
+uint64
+timestamp_resolution ()
+{
+  timestamp_init_();
+  return monotonic_resolution;
+}
+
+/// Returns benchmark timestamp in nano-seconds, clock starts around program startup.
+uint64
+timestamp_benchmark ()
+{
+  struct timespec tp = { 0, 0 };
+  uint64 stamp;
+  if (ISLIKELY (clock_gettime (monotonic_clockid, &tp) >= 0))
+    {
+      stamp = tp.tv_sec * 1000000000ULL + tp.tv_nsec;
+      stamp -= monotonic_start;                 // reduce number of significant bits
+    }
+  else
+    {
+      stamp = timestamp_realtime() * 1000;
+      stamp -= MIN (stamp, monotonic_start);    // reduce number of significant bits
+    }
+  return stamp;
+}
+
+/// Convert @a stamp into a string, adding µsecond fractions if space permits.
+String
+timestamp_format (uint64 stamp, uint maxlength)
+{
+  const size_t fieldwidth = std::max (maxlength, 1U);
+  const String fsecs = string_format ("%u", size_t (stamp) / 1000000);
+  const String usecs = string_format ("%06u", size_t (stamp) % 1000000);
+  String r = fsecs;
+  if (r.size() < fieldwidth)
+    r += '.';
+  if (r.size() < fieldwidth)
+    r += usecs.substr (0, fieldwidth - r.size());
+  return r;
+}
+
+/// A monotonically increasing counter, increments are atomic and visible in all threads.
+uint64
+monotonic_counter ()
+{
+  static std::atomic<uint64> global_monotonic_counter { 4294967297 };
+  return global_monotonic_counter++;
+}
+
+// == program and executable names ==
 static std::string
 get_executable_path()
 {
@@ -104,13 +213,33 @@ program_cwd ()
   return cached_program_cwd;
 }
 
-struct EarlyStartup102 {
-  EarlyStartup102()
+// == Early Startup ctors ==
+namespace {
+struct EarlyStartup {
+  EarlyStartup()
   {
+    timestamp_init_();
     program_cwd(); // initialize early, i.e. before main() changes cwd
   }
 };
-
-static EarlyStartup102 _early_startup_102 __attribute__ ((init_priority (102)));
+static EarlyStartup _early_startup __attribute__ ((init_priority (101)));
+} // Anon
+
+// == backtraces ==
+#ifdef _EXECINFO_H
+int (*backtrace_pointers) (void **buffer, int size) = &::backtrace; // GLibc only
+#else  // !_EXECINFO_H
+static int
+dummy_backtrace (void **buffer, int size)
+{
+  if (size)
+    {
+      buffer[0] = __builtin_return_address (0);
+      return 1;
+    }
+  return 0;
+}
+int (*backtrace_pointers) (void **buffer, int size) = &dummy_backtrace;
+#endif // !_EXECINFO_H
 
 } // Bse
diff --git a/sfi/platform.hh b/sfi/platform.hh
index 50e7fe0..a0e7998 100644
--- a/sfi/platform.hh
+++ b/sfi/platform.hh
@@ -6,6 +6,14 @@
 
 namespace Bse {
 
+// == Timestamp Handling ==
+uint64  timestamp_startup    ();        // µseconds
+uint64  timestamp_realtime   ();        // µseconds
+uint64  timestamp_benchmark  ();        // nseconds
+uint64  timestamp_resolution ();        // nseconds
+String  timestamp_format     (uint64 stamp, uint maxlength = 8);
+uint64  monotonic_counter    ();
+
 // == process info ==
 String      program_alias         ();                   ///< Retrieve the program name as used for logging 
or debug messages.
 void        program_alias_init    (String customname);  ///< Set program_alias to a non-localized alias 
other than program_argv0 if desired.


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]