Sleep after writing to limit I/O bandwidth usage. * * @todo Rather than sleeping after each write, it might be better to * use some kind of averaging. The current algorithm seems to always * use a bit less bandwidth than specified, because it doesn't make up * for slow periods. But arguably this is a feature. In addition, we * ought to take the time used to write the data into account. *
| 2098 | * We therefore keep track of the bytes we've written over time and only |
| 2099 | * sleep when the accumulated delay is at least 1 tenth of a second. */ |
| 2100 | static void sleep_for_bwlimit(int bytes_written) |
| 2101 | { |
| 2102 | static struct timeval prior_tv; |
| 2103 | static long total_written = 0; |
| 2104 | struct timeval tv, start_tv; |
| 2105 | long elapsed_usec, sleep_usec; |
| 2106 | |
| 2107 | #define ONE_SEC 1000000L /* # of microseconds in a second */ |
| 2108 | |
| 2109 | total_written += bytes_written; |
| 2110 | |
| 2111 | gettimeofday(&start_tv, NULL); |
| 2112 | if (prior_tv.tv_sec) { |
| 2113 | elapsed_usec = (start_tv.tv_sec - prior_tv.tv_sec) * ONE_SEC |
| 2114 | + (start_tv.tv_usec - prior_tv.tv_usec); |
| 2115 | total_written -= (int64)elapsed_usec * bwlimit / (ONE_SEC/1024); |
| 2116 | if (total_written < 0) |
| 2117 | total_written = 0; |
| 2118 | } |
| 2119 | |
| 2120 | sleep_usec = total_written * (ONE_SEC/1024) / bwlimit; |
| 2121 | if (sleep_usec < ONE_SEC / 10) { |
| 2122 | prior_tv = start_tv; |
| 2123 | return; |
| 2124 | } |
| 2125 | |
| 2126 | tv.tv_sec = sleep_usec / ONE_SEC; |
| 2127 | tv.tv_usec = sleep_usec % ONE_SEC; |
| 2128 | select(0, NULL, NULL, NULL, &tv); |
| 2129 | |
| 2130 | gettimeofday(&prior_tv, NULL); |
| 2131 | elapsed_usec = (prior_tv.tv_sec - start_tv.tv_sec) * ONE_SEC |
| 2132 | + (prior_tv.tv_usec - start_tv.tv_usec); |
| 2133 | total_written = (sleep_usec - elapsed_usec) * bwlimit / (ONE_SEC/1024); |
| 2134 | } |
| 2135 | |
| 2136 | void io_flush(int flush_type) |
| 2137 | { |