bdev: count down for qos tracking

This will simplify some future patches which will
account for missed timeslice timers by allowing
additional IO/BW in the following timeslice.

Signed-off-by: Jim Harris <james.r.harris@intel.com>
Change-Id: I9dd46a768c98ce267c733a9f9719a2d3d2c3c915

Reviewed-on: https://review.gerrithub.io/423579
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Chandler-Test-Pool: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: GangCao <gang.cao@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
This commit is contained in:
Jim Harris 2018-08-27 11:55:59 -07:00 committed by Ben Walker
parent 5595a7cad7
commit 5443e0aed3

View File

@ -140,11 +140,15 @@ struct spdk_bdev_qos {
* only valid for the master channel which manages the outstanding IOs. */
uint64_t max_byte_per_timeslice;
/** Submitted IO in one timeslice (e.g., 1ms) */
uint64_t io_submitted_this_timeslice;
/** Remaining IO allowed in current timeslice (e.g., 1ms) */
uint64_t io_remaining_this_timeslice;
/** Submitted byte in one timeslice (e.g., 1ms) */
uint64_t byte_submitted_this_timeslice;
/** Remaining bytes allowed in current timeslice (e.g., 1ms).
* Allowed to run negative if an I/O is submitted when some bytes are remaining,
* but the I/O is bigger than that amount. The excess will be deducted from the
* next timeslice.
*/
int64_t byte_remaining_this_timeslice;
/** Poller that processes queued I/O commands each time slice. */
struct spdk_poller *poller;
@ -1026,20 +1030,18 @@ _spdk_bdev_qos_io_submit(struct spdk_bdev_channel *ch)
struct spdk_bdev_shared_resource *shared_resource = ch->shared_resource;
while (!TAILQ_EMPTY(&qos->queued)) {
if (qos->max_ios_per_timeslice > 0 &&
qos->io_submitted_this_timeslice >= qos->max_ios_per_timeslice) {
if (qos->max_ios_per_timeslice > 0 && qos->io_remaining_this_timeslice == 0) {
break;
}
if (qos->max_byte_per_timeslice > 0 &&
qos->byte_submitted_this_timeslice >= qos->max_byte_per_timeslice) {
if (qos->max_byte_per_timeslice > 0 && qos->byte_remaining_this_timeslice <= 0) {
break;
}
bdev_io = TAILQ_FIRST(&qos->queued);
TAILQ_REMOVE(&qos->queued, bdev_io, internal.link);
qos->io_submitted_this_timeslice++;
qos->byte_submitted_this_timeslice += _spdk_bdev_get_io_size_in_byte(bdev_io);
qos->io_remaining_this_timeslice--;
qos->byte_remaining_this_timeslice -= _spdk_bdev_get_io_size_in_byte(bdev_io);
ch->io_outstanding++;
shared_resource->io_outstanding++;
bdev->fn_table->submit_request(ch->channel, bdev_io);
@ -1434,14 +1436,17 @@ spdk_bdev_channel_poll_qos(void *arg)
struct spdk_bdev_qos *qos = arg;
/* Reset for next round of rate limiting */
qos->io_submitted_this_timeslice = 0;
qos->io_remaining_this_timeslice = qos->max_ios_per_timeslice;
/* More bytes sent in the last timeslice, allow less in this timeslice */
if (qos->byte_submitted_this_timeslice > qos->max_byte_per_timeslice) {
qos->byte_submitted_this_timeslice -= qos->max_byte_per_timeslice;
} else {
qos->byte_submitted_this_timeslice = 0;
/* We may have allowed the bytes to slightly overrun in the last timeslice.
* byte_remaining_this_timeslice is signed, so if it's negative here, we'll
* account for the overrun so that the next timeslice will be appropriately
* reduced.
*/
if (qos->byte_remaining_this_timeslice > 0) {
qos->byte_remaining_this_timeslice = 0;
}
qos->byte_remaining_this_timeslice += qos->max_byte_per_timeslice;
_spdk_bdev_qos_io_submit(qos->ch);
@ -1501,8 +1506,8 @@ _spdk_bdev_enable_qos(struct spdk_bdev *bdev, struct spdk_bdev_channel *ch)
TAILQ_INIT(&qos->queued);
spdk_bdev_qos_update_max_quota_per_timeslice(qos);
qos->io_submitted_this_timeslice = 0;
qos->byte_submitted_this_timeslice = 0;
qos->io_remaining_this_timeslice = qos->max_ios_per_timeslice;
qos->byte_remaining_this_timeslice = qos->max_byte_per_timeslice;
qos->poller = spdk_poller_register(spdk_bdev_channel_poll_qos,
qos,
@ -1685,8 +1690,8 @@ spdk_bdev_qos_destroy(struct spdk_bdev *bdev)
new_qos->thread = NULL;
new_qos->max_ios_per_timeslice = 0;
new_qos->max_byte_per_timeslice = 0;
new_qos->io_submitted_this_timeslice = 0;
new_qos->byte_submitted_this_timeslice = 0;
new_qos->io_remaining_this_timeslice = 0;
new_qos->byte_remaining_this_timeslice = 0;
new_qos->poller = NULL;
TAILQ_INIT(&new_qos->queued);