Commit | Line | Data |
---|---|---|
02bcaa8c | 1 | /* |
f5cc024a | 2 | * Clock functions |
02bcaa8c | 3 | */ |
f5cc024a | 4 | |
02bcaa8c JA |
5 | #include <unistd.h> |
6 | #include <sys/time.h> | |
7 | ||
8 | #include "fio.h" | |
02bcaa8c JA |
9 | |
10 | #include "hash.h" | |
11 | ||
5ec10eaa | 12 | static int clock_gettime_works; |
3e488920 JA |
13 | static struct timeval last_tv; |
14 | static int last_tv_valid; | |
02bcaa8c JA |
15 | |
16 | #ifdef FIO_DEBUG_TIME | |
17 | ||
18 | #define HASH_BITS 8 | |
19 | #define HASH_SIZE (1 << HASH_BITS) | |
20 | ||
01743ee1 | 21 | static struct flist_head hash[HASH_SIZE]; |
02bcaa8c JA |
22 | static int gtod_inited; |
23 | ||
24 | struct gtod_log { | |
01743ee1 | 25 | struct flist_head list; |
02bcaa8c JA |
26 | void *caller; |
27 | unsigned long calls; | |
28 | }; | |
29 | ||
30 | static struct gtod_log *find_hash(void *caller) | |
31 | { | |
32 | unsigned long h = hash_ptr(caller, HASH_BITS); | |
01743ee1 | 33 | struct flist_head *entry; |
02bcaa8c | 34 | |
01743ee1 JA |
35 | flist_for_each(entry, &hash[h]) { |
36 | struct gtod_log *log = flist_entry(entry, struct gtod_log, | |
37 | list); | |
02bcaa8c JA |
38 | |
39 | if (log->caller == caller) | |
40 | return log; | |
41 | } | |
42 | ||
43 | return NULL; | |
44 | } | |
45 | ||
46 | static struct gtod_log *find_log(void *caller) | |
47 | { | |
48 | struct gtod_log *log = find_hash(caller); | |
49 | ||
50 | if (!log) { | |
51 | unsigned long h; | |
52 | ||
53 | log = malloc(sizeof(*log)); | |
01743ee1 | 54 | INIT_FLIST_HEAD(&log->list); |
02bcaa8c JA |
55 | log->caller = caller; |
56 | log->calls = 0; | |
57 | ||
58 | h = hash_ptr(caller, HASH_BITS); | |
01743ee1 | 59 | flist_add_tail(&log->list, &hash[h]); |
02bcaa8c JA |
60 | } |
61 | ||
62 | return log; | |
63 | } | |
64 | ||
65 | static void gtod_log_caller(void *caller) | |
66 | { | |
67 | if (gtod_inited) { | |
68 | struct gtod_log *log = find_log(caller); | |
69 | ||
70 | log->calls++; | |
71 | } | |
72 | } | |
73 | ||
74 | static void fio_exit fio_dump_gtod(void) | |
75 | { | |
76 | unsigned long total_calls = 0; | |
77 | int i; | |
78 | ||
79 | for (i = 0; i < HASH_SIZE; i++) { | |
01743ee1 | 80 | struct flist_head *entry; |
02bcaa8c JA |
81 | struct gtod_log *log; |
82 | ||
01743ee1 JA |
83 | flist_for_each(entry, &hash[i]) { |
84 | log = flist_entry(entry, struct gtod_log, list); | |
02bcaa8c | 85 | |
5ec10eaa JA |
86 | printf("function %p, calls %lu\n", log->caller, |
87 | log->calls); | |
02bcaa8c JA |
88 | total_calls += log->calls; |
89 | } | |
90 | } | |
91 | ||
92 | printf("Total %lu gettimeofday\n", total_calls); | |
93 | } | |
94 | ||
95 | static void fio_init gtod_init(void) | |
96 | { | |
97 | int i; | |
98 | ||
99 | for (i = 0; i < HASH_SIZE; i++) | |
01743ee1 | 100 | INIT_FLIST_HEAD(&hash[i]); |
02bcaa8c JA |
101 | |
102 | gtod_inited = 1; | |
103 | } | |
104 | ||
105 | #endif /* FIO_DEBUG_TIME */ | |
106 | ||
1e97cce9 | 107 | #ifdef FIO_DEBUG_TIME |
02bcaa8c | 108 | void fio_gettime(struct timeval *tp, void *caller) |
1e97cce9 JA |
109 | #else |
110 | void fio_gettime(struct timeval *tp, void fio_unused *caller) | |
111 | #endif | |
02bcaa8c JA |
112 | { |
113 | #ifdef FIO_DEBUG_TIME | |
114 | if (!caller) | |
115 | caller = __builtin_return_address(0); | |
116 | ||
117 | gtod_log_caller(caller); | |
02bcaa8c | 118 | #endif |
7e326f3b JA |
119 | if (!clock_gettime_works) { |
120 | gtod: | |
02bcaa8c | 121 | gettimeofday(tp, NULL); |
7e326f3b | 122 | } else { |
02bcaa8c JA |
123 | struct timespec ts; |
124 | ||
125 | if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) { | |
126 | clock_gettime_works = 0; | |
7e326f3b | 127 | goto gtod; |
02bcaa8c JA |
128 | } |
129 | ||
130 | tp->tv_sec = ts.tv_sec; | |
131 | tp->tv_usec = ts.tv_nsec / 1000; | |
132 | } | |
3e488920 JA |
133 | |
134 | /* | |
135 | * If Linux is using the tsc clock on non-synced processors, | |
136 | * sometimes time can appear to drift backwards. Fix that up. | |
137 | */ | |
138 | if (last_tv_valid) { | |
139 | if (tp->tv_sec < last_tv.tv_sec) | |
140 | tp->tv_sec = last_tv.tv_sec; | |
141 | else if (last_tv.tv_sec == tp->tv_sec && | |
142 | tp->tv_usec < last_tv.tv_usec) | |
143 | tp->tv_usec = last_tv.tv_usec; | |
144 | } | |
145 | last_tv_valid = 1; | |
146 | memcpy(&last_tv, tp, sizeof(*tp)); | |
02bcaa8c | 147 | } |