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