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