1 | /* |
---|---|
2 | This file is part of Mtproto-proxy Library. |
3 | |
4 | Mtproto-proxy Library is free software: you can redistribute it and/or modify |
5 | it under the terms of the GNU Lesser General Public License as published by |
6 | the Free Software Foundation, either version 2 of the License, or |
7 | (at your option) any later version. |
8 | |
9 | Mtproto-proxy Library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | GNU Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public License |
15 | along with Mtproto-proxy Library. If not, see <http://www.gnu.org/licenses/>. |
16 | |
17 | Copyright 2014 Telegram Messenger Inc |
18 | 2014 Anton Maydell |
19 | */ |
20 | #include <assert.h> |
21 | #include <sys/time.h> |
22 | #include <time.h> |
23 | /* unistd.h defines _POSIX_TIMERS */ |
24 | #include <unistd.h> |
25 | |
26 | #include "precise-time.h" |
27 | |
28 | __thread int now; |
29 | __thread double precise_now; |
30 | __thread long long precise_now_rdtsc; |
31 | long long precise_time; |
32 | long long precise_time_rdtsc; |
33 | |
34 | double get_utime_monotonic (void) __attribute__ ((weak)); |
35 | double get_utime_monotonic (void) { |
36 | struct timespec T; |
37 | #if _POSIX_TIMERS |
38 | assert (clock_gettime (CLOCK_MONOTONIC, &T) >= 0); |
39 | precise_now_rdtsc = rdtsc (); |
40 | return precise_now = T.tv_sec + (double) T.tv_nsec * 1e-9; |
41 | #else |
42 | #error "No high-precision clock" |
43 | return precise_now = time (); |
44 | #endif |
45 | } |
46 | |
47 | double get_double_time (void) { |
48 | static double last_double_time = -1; |
49 | static long long next_rdtsc; |
50 | long long cur_rdtsc = rdtsc (); |
51 | if (cur_rdtsc > next_rdtsc) { |
52 | struct timeval tv; |
53 | gettimeofday (&tv, NULL); |
54 | next_rdtsc = cur_rdtsc + 1000000; |
55 | return (last_double_time = tv.tv_sec + 1e-6 * tv.tv_usec); |
56 | } else { |
57 | return last_double_time; |
58 | } |
59 | } |
60 | |
61 | double get_utime (int clock_id) { |
62 | struct timespec T; |
63 | #if _POSIX_TIMERS |
64 | assert (clock_gettime (clock_id, &T) >= 0); |
65 | double res = T.tv_sec + (double) T.tv_nsec * 1e-9; |
66 | #else |
67 | #error "No high-precision clock" |
68 | double res = time (); |
69 | #endif |
70 | if (clock_id == CLOCK_REALTIME) { |
71 | precise_time = (long long) (res * (1LL << 32)); |
72 | precise_time_rdtsc = rdtsc (); |
73 | } |
74 | return res; |
75 | } |
76 | |
77 | long long get_precise_time (unsigned precision) { |
78 | unsigned long long diff = rdtsc() - precise_time_rdtsc; |
79 | if (diff > precision) { |
80 | get_utime (CLOCK_REALTIME); |
81 | } |
82 | return precise_time; |
83 | } |
84 |