Add verify trim support
[fio.git] / gettime.c
CommitLineData
02bcaa8c 1/*
f5cc024a 2 * Clock functions
02bcaa8c 3 */
f5cc024a 4
02bcaa8c 5#include <unistd.h>
c223da83 6#include <math.h>
02bcaa8c
JA
7#include <sys/time.h>
8
9#include "fio.h"
be4ecfdf 10#include "smalloc.h"
02bcaa8c
JA
11
12#include "hash.h"
13
09a32402 14#ifdef ARCH_HAVE_CPU_CLOCK
c223da83 15static unsigned long cycles_per_usec;
c223da83 16static unsigned long last_cycles;
09a32402
JA
17#endif
18static struct timeval last_tv;
3e488920 19static int last_tv_valid;
02bcaa8c 20
be4ecfdf
JA
21static struct timeval *fio_tv;
22int fio_gtod_offload = 0;
23int fio_gtod_cpu = -1;
24
c223da83
JA
25enum fio_cs fio_clock_source = CS_GTOD;
26
02bcaa8c
JA
27#ifdef FIO_DEBUG_TIME
28
29#define HASH_BITS 8
30#define HASH_SIZE (1 << HASH_BITS)
31
01743ee1 32static struct flist_head hash[HASH_SIZE];
02bcaa8c
JA
33static int gtod_inited;
34
35struct gtod_log {
01743ee1 36 struct flist_head list;
02bcaa8c
JA
37 void *caller;
38 unsigned long calls;
39};
40
41static struct gtod_log *find_hash(void *caller)
42{
43 unsigned long h = hash_ptr(caller, HASH_BITS);
01743ee1 44 struct flist_head *entry;
02bcaa8c 45
01743ee1
JA
46 flist_for_each(entry, &hash[h]) {
47 struct gtod_log *log = flist_entry(entry, struct gtod_log,
48 list);
02bcaa8c
JA
49
50 if (log->caller == caller)
51 return log;
52 }
53
54 return NULL;
55}
56
57static struct gtod_log *find_log(void *caller)
58{
59 struct gtod_log *log = find_hash(caller);
60
61 if (!log) {
62 unsigned long h;
63
64 log = malloc(sizeof(*log));
01743ee1 65 INIT_FLIST_HEAD(&log->list);
02bcaa8c
JA
66 log->caller = caller;
67 log->calls = 0;
68
69 h = hash_ptr(caller, HASH_BITS);
01743ee1 70 flist_add_tail(&log->list, &hash[h]);
02bcaa8c
JA
71 }
72
73 return log;
74}
75
76static void gtod_log_caller(void *caller)
77{
78 if (gtod_inited) {
79 struct gtod_log *log = find_log(caller);
80
81 log->calls++;
82 }
83}
84
85static void fio_exit fio_dump_gtod(void)
86{
87 unsigned long total_calls = 0;
88 int i;
89
90 for (i = 0; i < HASH_SIZE; i++) {
01743ee1 91 struct flist_head *entry;
02bcaa8c
JA
92 struct gtod_log *log;
93
01743ee1
JA
94 flist_for_each(entry, &hash[i]) {
95 log = flist_entry(entry, struct gtod_log, list);
02bcaa8c 96
5ec10eaa
JA
97 printf("function %p, calls %lu\n", log->caller,
98 log->calls);
02bcaa8c
JA
99 total_calls += log->calls;
100 }
101 }
102
103 printf("Total %lu gettimeofday\n", total_calls);
104}
105
106static void fio_init gtod_init(void)
107{
108 int i;
109
110 for (i = 0; i < HASH_SIZE; i++)
01743ee1 111 INIT_FLIST_HEAD(&hash[i]);
02bcaa8c
JA
112
113 gtod_inited = 1;
114}
115
116#endif /* FIO_DEBUG_TIME */
117
1e97cce9 118#ifdef FIO_DEBUG_TIME
02bcaa8c 119void fio_gettime(struct timeval *tp, void *caller)
1e97cce9
JA
120#else
121void fio_gettime(struct timeval *tp, void fio_unused *caller)
122#endif
02bcaa8c
JA
123{
124#ifdef FIO_DEBUG_TIME
125 if (!caller)
126 caller = __builtin_return_address(0);
127
128 gtod_log_caller(caller);
02bcaa8c 129#endif
be4ecfdf
JA
130 if (fio_tv) {
131 memcpy(tp, fio_tv, sizeof(*tp));
132 return;
c223da83
JA
133 }
134
135 switch (fio_clock_source) {
136 case CS_GTOD:
02bcaa8c 137 gettimeofday(tp, NULL);
c223da83
JA
138 break;
139 case CS_CGETTIME: {
02bcaa8c
JA
140 struct timespec ts;
141
d481e006 142 if (clock_gettime(CLOCK_REALTIME, &ts) < 0) {
c223da83
JA
143 log_err("fio: clock_gettime fails\n");
144 assert(0);
02bcaa8c
JA
145 }
146
147 tp->tv_sec = ts.tv_sec;
148 tp->tv_usec = ts.tv_nsec / 1000;
c223da83
JA
149 break;
150 }
151#ifdef ARCH_HAVE_CPU_CLOCK
152 case CS_CPUCLOCK: {
153 unsigned long long usecs, t;
154
155 t = get_cpu_clock();
156 if (t < last_cycles) {
157 dprint(FD_TIME, "CPU clock going back in time\n");
158 t = last_cycles;
159 }
160
161 usecs = t / cycles_per_usec;
162 tp->tv_sec = usecs / 1000000;
163 tp->tv_usec = usecs % 1000000;
164 last_cycles = t;
165 break;
166 }
167#endif
168 default:
169 log_err("fio: invalid clock source %d\n", fio_clock_source);
170 break;
02bcaa8c 171 }
3e488920
JA
172
173 /*
174 * If Linux is using the tsc clock on non-synced processors,
175 * sometimes time can appear to drift backwards. Fix that up.
176 */
177 if (last_tv_valid) {
178 if (tp->tv_sec < last_tv.tv_sec)
179 tp->tv_sec = last_tv.tv_sec;
180 else if (last_tv.tv_sec == tp->tv_sec &&
181 tp->tv_usec < last_tv.tv_usec)
182 tp->tv_usec = last_tv.tv_usec;
183 }
184 last_tv_valid = 1;
185 memcpy(&last_tv, tp, sizeof(*tp));
02bcaa8c 186}
be4ecfdf 187
09a32402 188#ifdef ARCH_HAVE_CPU_CLOCK
c223da83
JA
189static unsigned long get_cycles_per_usec(void)
190{
191 struct timeval s, e;
192 unsigned long long c_s, c_e;
193
194 gettimeofday(&s, NULL);
195 c_s = get_cpu_clock();
196 do {
197 unsigned long long elapsed;
198
199 gettimeofday(&e, NULL);
200 elapsed = utime_since(&s, &e);
201 if (elapsed >= 10) {
202 c_e = get_cpu_clock();
203 break;
204 }
205 } while (1);
206
207 return c_e - c_s;
208}
209
09a32402 210static void calibrate_cpu_clock(void)
c223da83
JA
211{
212 double delta, mean, S;
213 unsigned long avg, cycles[10];
214 int i, samples;
215
c223da83
JA
216 cycles[0] = get_cycles_per_usec();
217 S = delta = mean = 0.0;
218 for (i = 0; i < 10; i++) {
219 cycles[i] = get_cycles_per_usec();
220 delta = cycles[i] - mean;
221 if (delta) {
222 mean += delta / (i + 1.0);
223 S += delta * (cycles[i] - mean);
224 }
225 }
226
227 S = sqrt(S / (10 - 1.0));
228
229 samples = avg = 0;
230 for (i = 0; i < 10; i++) {
231 double this = cycles[i];
232
233 if ((max(this, mean) - min(this, mean)) > S)
234 continue;
235 samples++;
236 avg += this;
237 }
238
239 S /= 10.0;
240 mean /= 10.0;
241
242 for (i = 0; i < 10; i++)
243 dprint(FD_TIME, "cycles[%d]=%lu\n", i, cycles[i] / 10);
244
245 avg /= (samples * 10);
246 dprint(FD_TIME, "avg: %lu\n", avg);
247 dprint(FD_TIME, "mean=%f, S=%f\n", mean, S);
248
249 cycles_per_usec = avg;
09a32402
JA
250
251}
252#else
253static void calibrate_cpu_clock(void)
254{
255}
256#endif
257
258void fio_clock_init(void)
259{
260 last_tv_valid = 0;
261 calibrate_cpu_clock();
c223da83
JA
262}
263
be4ecfdf
JA
264void fio_gtod_init(void)
265{
266 fio_tv = smalloc(sizeof(struct timeval));
267 assert(fio_tv);
268}
269
270void fio_gtod_update(void)
271{
272 gettimeofday(fio_tv, NULL);
273}