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