2015-06-08 19:17:42 +03:00
|
|
|
/*
|
|
|
|
* QEMU block throttling group infrastructure
|
|
|
|
*
|
|
|
|
* Copyright (C) Nodalink, EURL. 2014
|
|
|
|
* Copyright (C) Igalia, S.L. 2015
|
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Benoît Canet <benoit.canet@nodalink.com>
|
|
|
|
* Alberto Garcia <berto@igalia.com>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License as
|
|
|
|
* published by the Free Software Foundation; either version 2 or
|
|
|
|
* (at your option) version 3 of the License.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef THROTTLE_GROUPS_H
|
|
|
|
#define THROTTLE_GROUPS_H
|
|
|
|
|
2022-12-21 16:35:49 +03:00
|
|
|
#include "qemu/coroutine.h"
|
2015-06-08 19:17:42 +03:00
|
|
|
#include "qemu/throttle.h"
|
2020-09-03 23:43:22 +03:00
|
|
|
#include "qom/object.h"
|
2015-06-08 19:17:42 +03:00
|
|
|
|
2017-08-25 16:20:23 +03:00
|
|
|
/* The ThrottleGroupMember structure indicates membership in a ThrottleGroup
|
|
|
|
* and holds related data.
|
|
|
|
*/
|
|
|
|
|
|
|
|
typedef struct ThrottleGroupMember {
|
2017-08-25 16:20:24 +03:00
|
|
|
AioContext *aio_context;
|
2017-08-25 16:20:23 +03:00
|
|
|
/* throttled_reqs_lock protects the CoQueues for throttled requests. */
|
|
|
|
CoMutex throttled_reqs_lock;
|
block/throttle-groups: Use ThrottleDirection instread of bool is_write
'bool is_write' style is obsolete from throttle framework, adapt
block throttle groups to the new style:
- use ThrottleDirection instead of 'bool is_write'. Ex,
schedule_next_request(ThrottleGroupMember *tgm, bool is_write)
-> schedule_next_request(ThrottleGroupMember *tgm, ThrottleDirection direction)
- use THROTTLE_MAX instead of hard code. Ex, ThrottleGroupMember *tokens[2]
-> ThrottleGroupMember *tokens[THROTTLE_MAX]
- use ThrottleDirection instead of hard code on iteration. Ex, (i = 0; i < 2; i++)
-> for (dir = THROTTLE_READ; dir < THROTTLE_MAX; dir++)
Use a simple python script to test the new style:
#!/usr/bin/python3
import subprocess
import random
import time
commands = ['virsh blkdeviotune jammy vda --write-bytes-sec ', \
'virsh blkdeviotune jammy vda --write-iops-sec ', \
'virsh blkdeviotune jammy vda --read-bytes-sec ', \
'virsh blkdeviotune jammy vda --read-iops-sec ']
for loop in range(1, 1000):
time.sleep(random.randrange(3, 5))
command = commands[random.randrange(0, 3)] + str(random.randrange(0, 1000000))
subprocess.run(command, shell=True, check=True)
This works fine.
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
Message-Id: <20230728022006.1098509-10-pizhenwei@bytedance.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
2023-07-28 05:20:06 +03:00
|
|
|
CoQueue throttled_reqs[THROTTLE_MAX];
|
2017-08-25 16:20:23 +03:00
|
|
|
|
|
|
|
/* Nonzero if the I/O limits are currently being ignored; generally
|
|
|
|
* it is zero. Accessed with atomic operations.
|
|
|
|
*/
|
|
|
|
unsigned int io_limits_disabled;
|
|
|
|
|
2019-01-14 16:32:56 +03:00
|
|
|
/* Number of pending throttle_group_restart_queue_entry() coroutines.
|
|
|
|
* Accessed with atomic operations.
|
|
|
|
*/
|
|
|
|
unsigned int restart_pending;
|
|
|
|
|
2017-08-25 16:20:23 +03:00
|
|
|
/* The following fields are protected by the ThrottleGroup lock.
|
|
|
|
* See the ThrottleGroup documentation for details.
|
|
|
|
* throttle_state tells us if I/O limits are configured. */
|
|
|
|
ThrottleState *throttle_state;
|
|
|
|
ThrottleTimers throttle_timers;
|
block/throttle-groups: Use ThrottleDirection instread of bool is_write
'bool is_write' style is obsolete from throttle framework, adapt
block throttle groups to the new style:
- use ThrottleDirection instead of 'bool is_write'. Ex,
schedule_next_request(ThrottleGroupMember *tgm, bool is_write)
-> schedule_next_request(ThrottleGroupMember *tgm, ThrottleDirection direction)
- use THROTTLE_MAX instead of hard code. Ex, ThrottleGroupMember *tokens[2]
-> ThrottleGroupMember *tokens[THROTTLE_MAX]
- use ThrottleDirection instead of hard code on iteration. Ex, (i = 0; i < 2; i++)
-> for (dir = THROTTLE_READ; dir < THROTTLE_MAX; dir++)
Use a simple python script to test the new style:
#!/usr/bin/python3
import subprocess
import random
import time
commands = ['virsh blkdeviotune jammy vda --write-bytes-sec ', \
'virsh blkdeviotune jammy vda --write-iops-sec ', \
'virsh blkdeviotune jammy vda --read-bytes-sec ', \
'virsh blkdeviotune jammy vda --read-iops-sec ']
for loop in range(1, 1000):
time.sleep(random.randrange(3, 5))
command = commands[random.randrange(0, 3)] + str(random.randrange(0, 1000000))
subprocess.run(command, shell=True, check=True)
This works fine.
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
Message-Id: <20230728022006.1098509-10-pizhenwei@bytedance.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
2023-07-28 05:20:06 +03:00
|
|
|
unsigned pending_reqs[THROTTLE_MAX];
|
2017-08-25 16:20:23 +03:00
|
|
|
QLIST_ENTRY(ThrottleGroupMember) round_robin;
|
|
|
|
|
|
|
|
} ThrottleGroupMember;
|
|
|
|
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 16:20:26 +03:00
|
|
|
#define TYPE_THROTTLE_GROUP "throttle-group"
|
2020-09-16 21:25:19 +03:00
|
|
|
OBJECT_DECLARE_SIMPLE_TYPE(ThrottleGroup, THROTTLE_GROUP)
|
block: convert ThrottleGroup to object with QOM
ThrottleGroup is converted to an object. This will allow the future
throttle block filter drive easy creation and configuration of throttle
groups in QMP and cli.
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
struct for all throttle configuration needs in QMP.
ThrottleGroups can be created via CLI as
-object throttle-group,id=foo,x-iops-total=100,x-..
where x-* are individual limit properties. Since we can't add non-scalar
properties in -object this interface must be used instead. However,
setting these properties must be disabled after initialization because
certain combinations of limits are forbidden and thus configuration
changes should be done in one transaction. The individual properties
will go away when support for non-scalar values in CLI is implemented
and thus are marked as experimental.
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
struct. It can be used to create ThrottleGroups or set the
configuration in existing groups as follows:
{ "execute": "object-add",
"arguments": {
"qom-type": "throttle-group",
"id": "foo",
"props" : {
"limits": {
"iops-total": 100
}
}
}
}
{ "execute" : "qom-set",
"arguments" : {
"path" : "foo",
"property" : "limits",
"value" : {
"iops-total" : 99
}
}
}
This also means a group's configuration can be fetched with qom-get.
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2017-08-25 16:20:26 +03:00
|
|
|
|
2017-08-25 16:20:23 +03:00
|
|
|
const char *throttle_group_get_name(ThrottleGroupMember *tgm);
|
2015-06-08 19:17:42 +03:00
|
|
|
|
2015-10-19 18:53:23 +03:00
|
|
|
ThrottleState *throttle_group_incref(const char *name);
|
|
|
|
void throttle_group_unref(ThrottleState *ts);
|
|
|
|
|
2017-08-25 16:20:23 +03:00
|
|
|
void throttle_group_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
|
|
|
|
void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
|
2015-06-08 19:17:42 +03:00
|
|
|
|
2017-08-25 16:20:23 +03:00
|
|
|
void throttle_group_register_tgm(ThrottleGroupMember *tgm,
|
2017-08-25 16:20:24 +03:00
|
|
|
const char *groupname,
|
|
|
|
AioContext *ctx);
|
2017-08-25 16:20:23 +03:00
|
|
|
void throttle_group_unregister_tgm(ThrottleGroupMember *tgm);
|
|
|
|
void throttle_group_restart_tgm(ThrottleGroupMember *tgm);
|
2015-06-08 19:17:42 +03:00
|
|
|
|
2017-08-25 16:20:23 +03:00
|
|
|
void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm,
|
block/throttle-groups: throttle_group_co_io_limits_intercept(): 64bit bytes
The function is called from 64bit io handlers, and bytes is just passed
to throttle_account() which is 64bit too (unsigned though). So, let's
convert intermediate argument to 64bit too.
This patch is a first in the 64-bit-blocklayer series, so we are
generally moving to int64_t for both offset and bytes parameters on all
io paths. Main motivation is realization of 64-bit write_zeroes
operation for fast zeroing large disk chunks, up to the whole disk.
We chose signed type, to be consistent with off_t (which is signed) and
with possibility for signed return type (where negative value means
error).
Patch-correctness audit by Eric Blake:
Caller has 32-bit, this patch now causes widening which is safe:
block/block-backend.c: blk_do_preadv() passes 'unsigned int'
block/block-backend.c: blk_do_pwritev_part() passes 'unsigned int'
block/throttle.c: throttle_co_pwrite_zeroes() passes 'int'
block/throttle.c: throttle_co_pdiscard() passes 'int'
Caller has 64-bit, this patch fixes potential bug where pre-patch
could narrow, except it's easy enough to trace that callers are still
capped at 2G actions:
block/throttle.c: throttle_co_preadv() passes 'uint64_t'
block/throttle.c: throttle_co_pwritev() passes 'uint64_t'
Implementation in question: block/throttle-groups.c
throttle_group_co_io_limits_intercept() takes 'unsigned int bytes'
and uses it: argument to util/throttle.c throttle_account(uint64_t)
All safe: it patches a latent bug, and does not introduce any 64-bit
gotchas once throttle_co_p{read,write}v are relaxed, and assuming
throttle_account() is not buggy.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Message-Id: <20201211183934.169161-7-vsementsov@virtuozzo.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
2020-12-11 21:39:24 +03:00
|
|
|
int64_t bytes,
|
block/throttle-groups: Use ThrottleDirection instread of bool is_write
'bool is_write' style is obsolete from throttle framework, adapt
block throttle groups to the new style:
- use ThrottleDirection instead of 'bool is_write'. Ex,
schedule_next_request(ThrottleGroupMember *tgm, bool is_write)
-> schedule_next_request(ThrottleGroupMember *tgm, ThrottleDirection direction)
- use THROTTLE_MAX instead of hard code. Ex, ThrottleGroupMember *tokens[2]
-> ThrottleGroupMember *tokens[THROTTLE_MAX]
- use ThrottleDirection instead of hard code on iteration. Ex, (i = 0; i < 2; i++)
-> for (dir = THROTTLE_READ; dir < THROTTLE_MAX; dir++)
Use a simple python script to test the new style:
#!/usr/bin/python3
import subprocess
import random
import time
commands = ['virsh blkdeviotune jammy vda --write-bytes-sec ', \
'virsh blkdeviotune jammy vda --write-iops-sec ', \
'virsh blkdeviotune jammy vda --read-bytes-sec ', \
'virsh blkdeviotune jammy vda --read-iops-sec ']
for loop in range(1, 1000):
time.sleep(random.randrange(3, 5))
command = commands[random.randrange(0, 3)] + str(random.randrange(0, 1000000))
subprocess.run(command, shell=True, check=True)
This works fine.
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
Message-Id: <20230728022006.1098509-10-pizhenwei@bytedance.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
2023-07-28 05:20:06 +03:00
|
|
|
ThrottleDirection direction);
|
2017-08-25 16:20:24 +03:00
|
|
|
void throttle_group_attach_aio_context(ThrottleGroupMember *tgm,
|
|
|
|
AioContext *new_context);
|
|
|
|
void throttle_group_detach_aio_context(ThrottleGroupMember *tgm);
|
2017-08-25 16:20:27 +03:00
|
|
|
/*
|
|
|
|
* throttle_group_exists() must be called under the global
|
|
|
|
* mutex.
|
|
|
|
*/
|
|
|
|
bool throttle_group_exists(const char *name);
|
2015-06-08 19:17:44 +03:00
|
|
|
|
2015-06-08 19:17:42 +03:00
|
|
|
#endif
|