throttle-groups.c (6bd8ab6889f45a42d69a3a65a4d6e7fc2453c84c) throttle-groups.c (6bf77e1c2dc24da1bade16e8a9a637f3b127314d)
1/*
2 * QEMU block throttling group infrastructure
3 *
4 * Copyright (C) Nodalink, EURL. 2014
5 * Copyright (C) Igalia, S.L. 2015
6 *
7 * Authors:
8 * Benoît Canet <benoit.canet@nodalink.com>

--- 154 unchanged lines hidden (view full) ---

163
164 if (!next) {
165 next = QLIST_FIRST(&tg->head);
166 }
167
168 return blk_by_public(next);
169}
170
1/*
2 * QEMU block throttling group infrastructure
3 *
4 * Copyright (C) Nodalink, EURL. 2014
5 * Copyright (C) Igalia, S.L. 2015
6 *
7 * Authors:
8 * Benoît Canet <benoit.canet@nodalink.com>

--- 154 unchanged lines hidden (view full) ---

163
164 if (!next) {
165 next = QLIST_FIRST(&tg->head);
166 }
167
168 return blk_by_public(next);
169}
170
171/*
172 * Return whether a BlockBackend has pending requests.
173 *
174 * This assumes that tg->lock is held.
175 *
176 * @blk: the BlockBackend
177 * @is_write: the type of operation (read/write)
178 * @ret: whether the BlockBackend has pending requests.
179 */
180static inline bool blk_has_pending_reqs(BlockBackend *blk,
181 bool is_write)
182{
183 const BlockBackendPublic *blkp = blk_get_public(blk);
184 return blkp->pending_reqs[is_write];
185}
186
171/* Return the next BlockBackend in the round-robin sequence with pending I/O
172 * requests.
173 *
174 * This assumes that tg->lock is held.
175 *
176 * @blk: the current BlockBackend
177 * @is_write: the type of operation (read/write)
178 * @ret: the next BlockBackend with pending requests, or blk if there is

--- 4 unchanged lines hidden (view full) ---

183 BlockBackendPublic *blkp = blk_get_public(blk);
184 ThrottleGroup *tg = container_of(blkp->throttle_state, ThrottleGroup, ts);
185 BlockBackend *token, *start;
186
187 start = token = tg->tokens[is_write];
188
189 /* get next bs round in round robin style */
190 token = throttle_group_next_blk(token);
187/* Return the next BlockBackend in the round-robin sequence with pending I/O
188 * requests.
189 *
190 * This assumes that tg->lock is held.
191 *
192 * @blk: the current BlockBackend
193 * @is_write: the type of operation (read/write)
194 * @ret: the next BlockBackend with pending requests, or blk if there is

--- 4 unchanged lines hidden (view full) ---

199 BlockBackendPublic *blkp = blk_get_public(blk);
200 ThrottleGroup *tg = container_of(blkp->throttle_state, ThrottleGroup, ts);
201 BlockBackend *token, *start;
202
203 start = token = tg->tokens[is_write];
204
205 /* get next bs round in round robin style */
206 token = throttle_group_next_blk(token);
191 while (token != start && !blkp->pending_reqs[is_write]) {
207 while (token != start && !blk_has_pending_reqs(token, is_write)) {
192 token = throttle_group_next_blk(token);
193 }
194
195 /* If no IO are queued for scheduling on the next round robin token
196 * then decide the token is the current bs because chances are
197 * the current bs get the current request queued.
198 */
208 token = throttle_group_next_blk(token);
209 }
210
211 /* If no IO are queued for scheduling on the next round robin token
212 * then decide the token is the current bs because chances are
213 * the current bs get the current request queued.
214 */
199 if (token == start && !blkp->pending_reqs[is_write]) {
215 if (token == start && !blk_has_pending_reqs(token, is_write)) {
200 token = blk;
201 }
202
216 token = blk;
217 }
218
219 /* Either we return the original BB, or one with pending requests */
220 assert(token == blk || blk_has_pending_reqs(token, is_write));
221
203 return token;
204}
205
206/* Check if the next I/O request for a BlockBackend needs to be throttled or
207 * not. If there's no timer set in this group, set one and update the token
208 * accordingly.
209 *
210 * This assumes that tg->lock is held.

--- 41 unchanged lines hidden (view full) ---

252{
253 BlockBackendPublic *blkp = blk_get_public(blk);
254 ThrottleGroup *tg = container_of(blkp->throttle_state, ThrottleGroup, ts);
255 bool must_wait;
256 BlockBackend *token;
257
258 /* Check if there's any pending request to schedule next */
259 token = next_throttle_token(blk, is_write);
222 return token;
223}
224
225/* Check if the next I/O request for a BlockBackend needs to be throttled or
226 * not. If there's no timer set in this group, set one and update the token
227 * accordingly.
228 *
229 * This assumes that tg->lock is held.

--- 41 unchanged lines hidden (view full) ---

271{
272 BlockBackendPublic *blkp = blk_get_public(blk);
273 ThrottleGroup *tg = container_of(blkp->throttle_state, ThrottleGroup, ts);
274 bool must_wait;
275 BlockBackend *token;
276
277 /* Check if there's any pending request to schedule next */
278 token = next_throttle_token(blk, is_write);
260 if (!blkp->pending_reqs[is_write]) {
279 if (!blk_has_pending_reqs(token, is_write)) {
261 return;
262 }
263
264 /* Set a timer for the request if it needs to be throttled */
265 must_wait = throttle_group_schedule_timer(token, is_write);
266
267 /* If it doesn't have to wait, queue it for immediate execution */
268 if (!must_wait) {
269 /* Give preference to requests from the current blk */
270 if (qemu_in_coroutine() &&
271 qemu_co_queue_next(&blkp->throttled_reqs[is_write])) {
272 token = blk;
273 } else {
280 return;
281 }
282
283 /* Set a timer for the request if it needs to be throttled */
284 must_wait = throttle_group_schedule_timer(token, is_write);
285
286 /* If it doesn't have to wait, queue it for immediate execution */
287 if (!must_wait) {
288 /* Give preference to requests from the current blk */
289 if (qemu_in_coroutine() &&
290 qemu_co_queue_next(&blkp->throttled_reqs[is_write])) {
291 token = blk;
292 } else {
274 ThrottleTimers *tt = &blkp->throttle_timers;
293 ThrottleTimers *tt = &blk_get_public(token)->throttle_timers;
275 int64_t now = qemu_clock_get_ns(tt->clock_type);
276 timer_mod(tt->timers[is_write], now + 1);
277 tg->any_timer_armed[is_write] = true;
278 }
279 tg->tokens[is_write] = token;
280 }
281}
282

--- 227 unchanged lines hidden ---
294 int64_t now = qemu_clock_get_ns(tt->clock_type);
295 timer_mod(tt->timers[is_write], now + 1);
296 tg->any_timer_armed[is_write] = true;
297 }
298 tg->tokens[is_write] = token;
299 }
300}
301

--- 227 unchanged lines hidden ---