| 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 | |