Add nanosecond timer.

I've been finding it hard to get enough resolution out of our existing timers when measuring really tiny pictures.

BUG=skia:2378
R=bsalomon@google.com, mtklein@google.com, bungeman@google.com

Author: mtklein@chromium.org

Review URL: https://codereview.chromium.org/250243002

git-svn-id: http://skia.googlecode.com/svn/trunk@14362 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkTime.h b/include/core/SkTime.h
index 51616d4..c4a7d06 100644
--- a/include/core/SkTime.h
+++ b/include/core/SkTime.h
@@ -28,7 +28,9 @@
     };
     static void GetDateTime(DateTime*);
 
-    static SkMSec GetMSecs();
+    static SkMSec GetMSecs() { return GetNSecs() / 1000000; }
+
+    static SkNSec GetNSecs();
 };
 
 #if defined(SK_DEBUG) && defined(SK_BUILD_FOR_WIN32)
diff --git a/include/core/SkTypes.h b/include/core/SkTypes.h
index 13450cd..3a512ab 100644
--- a/include/core/SkTypes.h
+++ b/include/core/SkTypes.h
@@ -315,6 +315,10 @@
 */
 #define SkMSec_LE(a, b)     ((int32_t)(a) - (int32_t)(b) <= 0)
 
+/** 64 bit value to hold nanosecond count
+*/
+typedef uint64_t SkNSec;
+
 /** The generation IDs in Skia reserve 0 has an invalid marker.
  */
 #define SK_InvalidGenID     0
diff --git a/src/ports/SkTime_Unix.cpp b/src/ports/SkTime_Unix.cpp
index f519a69..cdf7f3d 100644
--- a/src/ports/SkTime_Unix.cpp
+++ b/src/ports/SkTime_Unix.cpp
@@ -12,10 +12,8 @@
 #include <sys/time.h>
 #include <time.h>
 
-void SkTime::GetDateTime(DateTime* dt)
-{
-    if (dt)
-    {
+void SkTime::GetDateTime(DateTime* dt) {
+    if (dt) {
         time_t m_time;
         time(&m_time);
         struct tm* tstruct;
@@ -31,9 +29,33 @@
     }
 }
 
-SkMSec SkTime::GetMSecs()
-{
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-    return (SkMSec) (tv.tv_sec * 1000 + tv.tv_usec / 1000 ); // microseconds to milliseconds
+#ifdef __MACH__
+#  include <mach/mach_time.h>
+
+namespace {
+
+struct ConversionFactor {
+    ConversionFactor() {
+        mach_timebase_info_data_t timebase;
+        mach_timebase_info(&timebase);
+        toNanos = (double) timebase.numer / timebase.denom;
+    }
+    double toNanos;
+};
+
+}  // namespace
+
+SkNSec SkTime::GetNSecs() {
+    static ConversionFactor convert;  // Since already know we're on Mac, this is threadsafe.
+    return mach_absolute_time() * convert.toNanos;
 }
+
+#else  // Linux, presumably all others too
+
+SkNSec SkTime::GetNSecs() {
+    struct timespec time;
+    clock_gettime(CLOCK_MONOTONIC, &time);
+    return (SkNSec)(time.tv_sec * 1000000000 + time.tv_nsec);
+}
+
+#endif
diff --git a/src/ports/SkTime_win.cpp b/src/ports/SkTime_win.cpp
index 37af9f2..a48a69e 100644
--- a/src/ports/SkTime_win.cpp
+++ b/src/ports/SkTime_win.cpp
@@ -9,8 +9,7 @@
 
 #include "SkTime.h"
 
-void SkTime::GetDateTime(DateTime* dt)
-{
+void SkTime::GetDateTime(DateTime* dt) {
     if (dt)
     {
         SYSTEMTIME      st;
@@ -26,13 +25,12 @@
     }
 }
 
-SkMSec SkTime::GetMSecs()
-{
+SkNSec SkTime::GetNSecs() {
     FILETIME        ft;
     LARGE_INTEGER   li;
     GetSystemTimeAsFileTime(&ft);
     li.LowPart  = ft.dwLowDateTime;
     li.HighPart = ft.dwHighDateTime;
     __int64 t  = li.QuadPart;       /* In 100-nanosecond intervals */
-    return (SkMSec)(t / 10000);               /* In milliseconds */
+    return (SkMSec)(t * 100);
 }
diff --git a/tools/bench_playback.cpp b/tools/bench_playback.cpp
index a5dfe50..534ad96 100644
--- a/tools/bench_playback.cpp
+++ b/tools/bench_playback.cpp
@@ -40,7 +40,7 @@
                                                                 src.width() * sizeof(SkPMColor)));
     canvas->clipRect(SkRect::MakeWH(SkIntToScalar(FLAGS_tile), SkIntToScalar(FLAGS_tile)));
 
-    const SkMSec start = SkTime::GetMSecs();
+    const SkNSec start = SkTime::GetNSecs();
     for (int i = 0; i < FLAGS_loops; i++) {
         if (FLAGS_skr) {
             SkRecordDraw(record, canvas.get());
@@ -49,9 +49,9 @@
         }
     }
 
-    const SkMSec elapsed = SkTime::GetMSecs() - start;
-    const double msPerLoop = elapsed / (double)FLAGS_loops;
-    printf("%6.2f\t%s\n", msPerLoop, name);
+    const SkNSec elapsed = SkTime::GetNSecs() - start;
+    const double nsPerLoop = elapsed / (double)FLAGS_loops;
+    printf("%u\t%s\n", SkToUInt(nsPerLoop), name);
 }
 
 int tool_main(int argc, char** argv);
diff --git a/tools/bench_record.cpp b/tools/bench_record.cpp
index 63139d6..712f63a 100644
--- a/tools/bench_record.cpp
+++ b/tools/bench_record.cpp
@@ -56,7 +56,7 @@
 }
 
 static void bench_record(SkPicture* src, const char* name, SkBBHFactory* bbhFactory) {
-    const SkMSec start = SkTime::GetMSecs();
+    const SkNSec start = SkTime::GetNSecs();
     const int width  = src ? src->width()  : FLAGS_nullSize;
     const int height = src ? src->height() : FLAGS_nullSize;
 
@@ -80,9 +80,9 @@
         }
     }
 
-    const SkMSec elapsed = SkTime::GetMSecs() - start;
-    const double msPerLoop = elapsed / (double)FLAGS_loops;
-    printf("%.2g\t%s\n", msPerLoop, name);
+    const SkNSec elapsed = SkTime::GetNSecs() - start;
+    const double nsPerLoop = elapsed / (double)FLAGS_loops;
+    printf("%u\t%s\n", SkToUInt(nsPerLoop), name);
 }
 
 int tool_main(int argc, char** argv);