Commit | Line | Data |
---|---|---|
3c39a379 JA |
1 | #include <time.h> |
2 | #include <sys/time.h> | |
3 | ||
4 | #include "fio.h" | |
5 | ||
263e529f | 6 | static struct timeval genesis; |
fd841467 | 7 | static unsigned long ns_granularity; |
c223da83 | 8 | unsigned long long genesis_cycles; |
263e529f | 9 | |
10927316 | 10 | unsigned long long utime_since(struct timeval *s, struct timeval *e) |
3c39a379 | 11 | { |
10927316 SL |
12 | long sec, usec; |
13 | unsigned long long ret; | |
5ec10eaa | 14 | |
3c39a379 JA |
15 | sec = e->tv_sec - s->tv_sec; |
16 | usec = e->tv_usec - s->tv_usec; | |
17 | if (sec > 0 && usec < 0) { | |
18 | sec--; | |
19 | usec += 1000000; | |
20 | } | |
21 | ||
2bfe24bd JA |
22 | /* |
23 | * time warp bug on some kernels? | |
24 | */ | |
10927316 SL |
25 | if (sec < 0 || (sec == 0 && usec < 0)) |
26 | return 0; | |
5ec10eaa | 27 | |
10927316 | 28 | ret = sec * 1000000ULL + usec; |
5ec10eaa | 29 | |
2bfe24bd | 30 | return ret; |
3c39a379 JA |
31 | } |
32 | ||
10927316 | 33 | unsigned long long utime_since_now(struct timeval *s) |
3c39a379 JA |
34 | { |
35 | struct timeval t; | |
36 | ||
02bcaa8c | 37 | fio_gettime(&t, NULL); |
3c39a379 JA |
38 | return utime_since(s, &t); |
39 | } | |
40 | ||
41 | unsigned long mtime_since(struct timeval *s, struct timeval *e) | |
42 | { | |
2bfe24bd | 43 | long sec, usec, ret; |
3c39a379 JA |
44 | |
45 | sec = e->tv_sec - s->tv_sec; | |
46 | usec = e->tv_usec - s->tv_usec; | |
47 | if (sec > 0 && usec < 0) { | |
48 | sec--; | |
49 | usec += 1000000; | |
50 | } | |
51 | ||
64b18e12 JA |
52 | sec *= 1000UL; |
53 | usec /= 1000UL; | |
2bfe24bd JA |
54 | ret = sec + usec; |
55 | ||
56 | /* | |
57 | * time warp bug on some kernels? | |
58 | */ | |
59 | if (ret < 0) | |
60 | ret = 0; | |
3c39a379 | 61 | |
2bfe24bd | 62 | return ret; |
3c39a379 JA |
63 | } |
64 | ||
65 | unsigned long mtime_since_now(struct timeval *s) | |
66 | { | |
67 | struct timeval t; | |
02bcaa8c | 68 | void *p = __builtin_return_address(0); |
3c39a379 | 69 | |
02bcaa8c | 70 | fio_gettime(&t, p); |
3c39a379 JA |
71 | return mtime_since(s, &t); |
72 | } | |
73 | ||
74 | unsigned long time_since_now(struct timeval *s) | |
75 | { | |
76 | return mtime_since_now(s) / 1000; | |
77 | } | |
78 | ||
79 | /* | |
80 | * busy looping version for the last few usec | |
81 | */ | |
6dd6f2cd | 82 | void usec_spin(unsigned int usec) |
3c39a379 JA |
83 | { |
84 | struct timeval start; | |
85 | ||
02bcaa8c | 86 | fio_gettime(&start, NULL); |
3c39a379 JA |
87 | while (utime_since_now(&start) < usec) |
88 | nop; | |
89 | } | |
90 | ||
91 | void usec_sleep(struct thread_data *td, unsigned long usec) | |
92 | { | |
fd841467 JA |
93 | struct timespec req; |
94 | struct timeval tv; | |
3c39a379 JA |
95 | |
96 | do { | |
fd841467 JA |
97 | unsigned long ts = usec; |
98 | ||
99 | if (usec < ns_granularity) { | |
6dd6f2cd | 100 | usec_spin(usec); |
3c39a379 JA |
101 | break; |
102 | } | |
103 | ||
fd841467 | 104 | ts = usec - ns_granularity; |
3c39a379 | 105 | |
fd841467 JA |
106 | if (ts >= 1000000) { |
107 | req.tv_sec = ts / 1000000; | |
108 | ts -= 1000000 * req.tv_sec; | |
109 | } else | |
110 | req.tv_sec = 0; | |
111 | ||
112 | req.tv_nsec = ts * 1000; | |
113 | fio_gettime(&tv, NULL); | |
114 | ||
115 | if (nanosleep(&req, NULL) < 0) | |
3c39a379 JA |
116 | break; |
117 | ||
fd841467 JA |
118 | ts = utime_since_now(&tv); |
119 | if (ts >= usec) | |
120 | break; | |
3c39a379 | 121 | |
fd841467 | 122 | usec -= ts; |
3c39a379 JA |
123 | } while (!td->terminate); |
124 | } | |
125 | ||
263e529f JA |
126 | unsigned long mtime_since_genesis(void) |
127 | { | |
128 | return mtime_since_now(&genesis); | |
129 | } | |
130 | ||
b29ee5b3 JA |
131 | int in_ramp_time(struct thread_data *td) |
132 | { | |
133 | return td->o.ramp_time && !td->ramp_time_over; | |
134 | } | |
135 | ||
721938ae JA |
136 | int ramp_time_over(struct thread_data *td) |
137 | { | |
138 | struct timeval tv; | |
139 | ||
140 | if (!td->o.ramp_time || td->ramp_time_over) | |
141 | return 1; | |
142 | ||
143 | fio_gettime(&tv, NULL); | |
144 | if (mtime_since(&td->epoch, &tv) >= td->o.ramp_time * 1000) { | |
145 | td->ramp_time_over = 1; | |
b29ee5b3 JA |
146 | reset_all_stats(td); |
147 | td_set_runstate(td, TD_RAMP); | |
721938ae JA |
148 | return 1; |
149 | } | |
150 | ||
151 | return 0; | |
152 | } | |
153 | ||
c223da83 | 154 | void fio_init fio_time_init(void) |
263e529f | 155 | { |
fd841467 JA |
156 | int i; |
157 | ||
c223da83 JA |
158 | fio_clock_init(); |
159 | ||
fd841467 JA |
160 | /* |
161 | * Check the granularity of the nanosleep function | |
162 | */ | |
163 | for (i = 0; i < 10; i++) { | |
164 | struct timeval tv; | |
165 | struct timespec ts; | |
166 | unsigned long elapsed; | |
167 | ||
168 | fio_gettime(&tv, NULL); | |
169 | ts.tv_sec = 0; | |
170 | ts.tv_nsec = 1000; | |
171 | ||
172 | nanosleep(&ts, NULL); | |
173 | elapsed = utime_since_now(&tv); | |
174 | ||
175 | if (elapsed > ns_granularity) | |
176 | ns_granularity = elapsed; | |
177 | } | |
263e529f | 178 | } |
6043c579 | 179 | |
a2f77c9f JA |
180 | void set_genesis_time(void) |
181 | { | |
182 | fio_gettime(&genesis, NULL); | |
c223da83 | 183 | genesis_cycles = get_cpu_clock(); |
a2f77c9f JA |
184 | } |
185 | ||
6043c579 JA |
186 | void fill_start_time(struct timeval *t) |
187 | { | |
188 | memcpy(t, &genesis, sizeof(genesis)); | |
189 | } |