1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2013 Couchbase, Inc
4  *
5  *   Licensed under the Apache License, Version 2.0 (the "License");
6  *   you may not use this file except in compliance with the License.
7  *   You may obtain a copy of the License at
8  *
9  *       http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *   Unless required by applicable law or agreed to in writing, software
12  *   distributed under the License is distributed on an "AS IS" BASIS,
13  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *   See the License for the specific language governing permissions and
15  *   limitations under the License.
16  */
17 #include "config.h"
18 #include <assert.h>
19 
20 #ifdef __APPLE__
21 #include <mach/mach_time.h>
22 
23 /*
24  * OS X doesn't have clock_gettime, but for monotonic, we can build
25  * one with mach_absolute_time as shown below.
26  *
27  * Most of the idea came from
28  * http://www.wand.net.nz/~smr26/wordpress/2009/01/19/monotonic-time-in-mac-os-x/
29  */
30 #define CLOCK_MONOTONIC 192996728
31 
mach_absolute_difference(uint64_t start, uint64_t end, struct timespec *tp)32 static void mach_absolute_difference(uint64_t start, uint64_t end,
33                                      struct timespec *tp)
34 {
35     uint64_t elapsednano;
36     uint64_t difference = end - start;
37     static mach_timebase_info_data_t info = {0, 0};
38 
39     if (info.denom == 0) {
40         mach_timebase_info(&info);
41     }
42 
43     elapsednano = difference * (info.numer / info.denom);
44 
45     tp->tv_sec = elapsednano * 1e-9;
46     tp->tv_nsec = elapsednano - (tp->tv_sec * 1e9);
47 }
48 
clock_gettime(int which, struct timespec *tp)49 static int clock_gettime(int which, struct timespec *tp)
50 {
51     uint64_t now;
52     static uint64_t epoch = 0;
53 
54     assert(which == CLOCK_MONOTONIC);
55 
56     if (epoch == 0) {
57         epoch = mach_absolute_time();
58     }
59 
60     now = mach_absolute_time();
61 
62     mach_absolute_difference(epoch, now, tp);
63 
64     return 0;
65 }
66 #endif
67 
68 #if defined(linux) || defined(__APPLE__)
gethrtime(void)69 hrtime_t gethrtime(void)
70 {
71     struct timespec tm;
72     if (clock_gettime(CLOCK_MONOTONIC, &tm) == -1) {
73         abort();
74     }
75     return (((hrtime_t)tm.tv_sec) * 1000000000) + tm.tv_nsec;
76 }
77 #elif defined(WIN32)
gethrtime(void)78 hrtime_t gethrtime(void)
79 {
80     double ret;
81     /*
82     ** To fix the potential race condition for the local static variable,
83     ** gethrtime should be called in a global static variable first.
84     ** It will guarantee the local static variable will be initialized
85     ** before any thread calls the function.
86     */
87     static int initialized;
88     static LARGE_INTEGER pf;
89     static double freq;
90     LARGE_INTEGER currtime;
91 
92     if (initialized == 0) {
93         memset(&pf, 0, sizeof(pf));
94         if (!QueryPerformanceFrequency(&pf)) {
95             /* @todo trond figure this one out! */
96             abort();
97         } else {
98             assert(pf.QuadPart != 0);
99             freq = 1.0e9 / (double)pf.QuadPart;
100         }
101     }
102 
103     if (!QueryPerformanceCounter(&currtime)) {
104         abort();
105     }
106 
107     ret = (double)currtime.QuadPart * freq ;
108     return (hrtime_t)ret;
109 }
110 
111 #if 0
112 __attribute__((constructor))
113 static void init_clock_win32(void)
114 {
115     gethrtime();
116 }
117 #endif
118 
119 #elif !defined(CB_DONT_NEED_GETHRTIME)
120 #error "I don't know how to build a highres clock..."
121 #endif
122