1 | /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ |
2 | // vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4: |
3 | #ident "$Id$" |
4 | /*====== |
5 | This file is part of PerconaFT. |
6 | |
7 | |
8 | Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved. |
9 | |
10 | PerconaFT is free software: you can redistribute it and/or modify |
11 | it under the terms of the GNU General Public License, version 2, |
12 | as published by the Free Software Foundation. |
13 | |
14 | PerconaFT is distributed in the hope that it will be useful, |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | GNU General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU General Public License |
20 | along with PerconaFT. If not, see <http://www.gnu.org/licenses/>. |
21 | |
22 | ---------------------------------------- |
23 | |
24 | PerconaFT is free software: you can redistribute it and/or modify |
25 | it under the terms of the GNU Affero General Public License, version 3, |
26 | as published by the Free Software Foundation. |
27 | |
28 | PerconaFT is distributed in the hope that it will be useful, |
29 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
30 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
31 | GNU Affero General Public License for more details. |
32 | |
33 | You should have received a copy of the GNU Affero General Public License |
34 | along with PerconaFT. If not, see <http://www.gnu.org/licenses/>. |
35 | ======= */ |
36 | |
37 | #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved." |
38 | |
39 | #pragma once |
40 | |
41 | #include "toku_config.h" |
42 | |
43 | #include <time.h> |
44 | #include <sys/time.h> |
45 | #include <stdint.h> |
46 | #if defined(__powerpc__) |
47 | # include <sys/platform/ppc.h> |
48 | #endif |
49 | |
50 | static inline float toku_tdiff (struct timeval *a, struct timeval *b) { |
51 | return (float)((a->tv_sec - b->tv_sec) + 1e-6 * (a->tv_usec - b->tv_usec)); |
52 | } |
53 | |
54 | #if !defined(HAVE_CLOCK_REALTIME) |
55 | // OS X does not have clock_gettime, we fake clockid_t for the interface, and we'll implement it with clock_get_time. |
56 | typedef int clockid_t; |
57 | // just something bogus, it doesn't matter, we just want to make sure we're |
58 | // only supporting this mode because we're not sure we can support other modes |
59 | // without a real clock_gettime() |
60 | #define CLOCK_REALTIME 0x01867234 |
61 | #endif |
62 | int toku_clock_gettime(clockid_t clk_id, struct timespec *ts) __attribute__((__visibility__("default" ))); |
63 | |
64 | // *************** Performance timers ************************ |
65 | // What do you really want from a performance timer: |
66 | // (1) Can determine actual time of day from the performance time. |
67 | // (2) Time goes forward, never backward. |
68 | // (3) Same time on different processors (or even different machines). |
69 | // (4) Time goes forward at a constant rate (doesn't get faster and slower) |
70 | // (5) Portable. |
71 | // (6) Getting the time is cheap. |
72 | // Unfortuately it seems tough to get Properties 1-5. So we go for Property 6,, but we abstract it. |
73 | // We offer a type tokutime_t which can hold the time. |
74 | // This type can be subtracted to get a time difference. |
75 | // We can get the present time cheaply. |
76 | // We can convert this type to seconds (but that can be expensive). |
77 | // The implementation is to use RDTSC (hence we lose property 3: not portable). |
78 | // Recent machines have constant_tsc in which case we get property (4). |
79 | // Recent OSs on recent machines (that have RDTSCP) fix the per-processor clock skew, so we get property (3). |
80 | // We get property 2 with RDTSC (as long as there's not any skew). |
81 | // We don't even try to get propety 1, since we don't need it. |
82 | // The decision here is that these times are really accurate only on modern machines with modern OSs. |
83 | typedef uint64_t tokutime_t; // Time type used in by tokutek timers. |
84 | |
85 | // The value of tokutime_t is not specified here. |
86 | // It might be microseconds since 1/1/1970 (if gettimeofday() is |
87 | // used), or clock cycles since boot (if rdtsc is used). Or something |
88 | // else. |
89 | // Two tokutime_t values can be subtracted to get a time difference. |
90 | // Use tokutime_to_seconds to that convert difference to seconds. |
91 | // We want get_tokutime() to be fast, but don't care so much about tokutime_to_seconds(); |
92 | // |
93 | // For accurate time calculations do the subtraction in the right order: |
94 | // Right: tokutime_to_seconds(t1-t2); |
95 | // Wrong tokutime_to_seconds(t1)-toku_time_to_seconds(t2); |
96 | // Doing it the wrong way is likely to result in loss of precision. |
97 | // A double can hold numbers up to about 53 bits. RDTSC which uses about 33 bits every second, so that leaves |
98 | // 2^20 seconds from booting (about 2 weeks) before the RDTSC value cannot be represented accurately as a double. |
99 | // |
100 | double tokutime_to_seconds(tokutime_t) __attribute__((__visibility__("default" ))); // Convert tokutime to seconds. |
101 | |
102 | // Get the value of tokutime for right now. We want this to be fast, so we expose the implementation as RDTSC. |
103 | static inline tokutime_t toku_time_now(void) { |
104 | #if defined(__x86_64__) || defined(__i386__) |
105 | uint32_t lo, hi; |
106 | __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); |
107 | return (uint64_t)hi << 32 | lo; |
108 | #elif defined (__aarch64__) |
109 | uint64_t result; |
110 | __asm __volatile__ ("mrs %[rt], cntvct_el0" : [rt] "=r" (result)); |
111 | return result; |
112 | #elif defined(__powerpc__) |
113 | return __ppc_get_timebase(); |
114 | #else |
115 | #error No timer implementation for this platform |
116 | #endif |
117 | } |
118 | |
119 | static inline uint64_t toku_current_time_microsec(void) { |
120 | struct timeval t; |
121 | gettimeofday(&t, NULL); |
122 | return t.tv_sec * (1UL * 1000 * 1000) + t.tv_usec; |
123 | } |
124 | |
125 | // sleep microseconds |
126 | static inline void toku_sleep_microsec(uint64_t ms) { |
127 | struct timeval t; |
128 | |
129 | t.tv_sec = ms / 1000000; |
130 | t.tv_usec = ms % 1000000; |
131 | |
132 | select(0, NULL, NULL, NULL, &t); |
133 | } |
134 | |