From 621fe1b03b7cfdfb5609d12921bcdb2d0f8f9cbd Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Tue, 25 Jul 2017 13:06:48 +0200 Subject: [PATCH 190/310] cam iosched: Optionally only enforce write limits if there are other requests pending ... or reads queued. This reduces write latency for many workloads without impacting read latency (too much). An example workload that profits a lot from this is watching a DVD rip from an USB disk while adding DVD rips using rsync. In this case the writes only have to be throttled when VLC is reading which only happens every couple of seconds. Obtained from: ElectroBSD --- sys/cam/cam_iosched.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/sys/cam/cam_iosched.c b/sys/cam/cam_iosched.c index a8c3bd180032..97bd44a925e3 100644 --- a/sys/cam/cam_iosched.c +++ b/sys/cam/cam_iosched.c @@ -286,6 +286,7 @@ struct cam_iosched_softc { int current_read_bias; /* Current read bias state */ int total_ticks; int load; /* EMA of 'load average' of disk / 2^16 */ + int ignore_write_limiter_if_no_ops_are_pending; struct bio_queue_head write_queue; struct iop_stats read_stats, write_stats, trim_stats; @@ -738,6 +739,10 @@ cam_iosched_has_io(struct cam_iosched_softc *isc) cam_iosched_limiter_caniop(&isc->write_stats, wbp) == 0; bool can_read = rbp != NULL && cam_iosched_limiter_caniop(&isc->read_stats, rbp) == 0; + if (isc->ignore_write_limiter_if_no_ops_are_pending && + !can_read && wbp != NULL && !can_write) { + can_write = 1; + } if (iosched_debug > 2) { printf("can write %d: pending_writes %d max_writes %d\n", can_write, isc->write_stats.pending, isc->write_stats.max); printf("can read %d: read_stats.pending %d max_reads %d\n", can_read, isc->read_stats.pending, isc->read_stats.max); @@ -1117,6 +1122,7 @@ cam_iosched_init(struct cam_iosched_softc **iscp, struct cam_periph *periph) (*iscp)->read_bias = 100; (*iscp)->current_read_bias = 100; (*iscp)->quanta = min(hz, 200); + (*iscp)->ignore_write_limiter_if_no_ops_are_pending = 0; cam_iosched_iop_stats_init(*iscp, &(*iscp)->read_stats); cam_iosched_iop_stats_init(*iscp, &(*iscp)->write_stats); cam_iosched_iop_stats_init(*iscp, &(*iscp)->trim_stats); @@ -1202,6 +1208,11 @@ void cam_iosched_sysctl_init(struct cam_iosched_softc *isc, &isc->read_bias, 100, "How biased towards read should we be independent of limits"); + SYSCTL_ADD_INT(ctx, n, + OID_AUTO, "ignore_write_limiter_if_no_ops_are_pending", CTLFLAG_RW, + &isc->ignore_write_limiter_if_no_ops_are_pending, 0, + "Only enforce write limits when there are ops pending"); + SYSCTL_ADD_PROC(ctx, n, OID_AUTO, "quanta", CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, &isc->quanta, 0, cam_iosched_quanta_sysctl, "I", @@ -1327,10 +1338,20 @@ cam_iosched_get_write(struct cam_iosched_softc *isc) * See if our current limiter allows this I/O. */ if (cam_iosched_limiter_iop(&isc->write_stats, bp) != 0) { - if (iosched_debug) - printf("Can't write because limiter says no.\n"); - isc->write_stats.state_flags |= IOP_RATE_LIMITED; - return NULL; + if (isc->ignore_write_limiter_if_no_ops_are_pending && + !bioq_first(&isc->bio_queue) && + isc->read_stats.pending == 0 && + isc->write_stats.pending == 0 && + isc->trim_stats.pending == 0) { + if (iosched_debug) + printf("Write limiter says no but no ops " + "are pending. Allowing write.\n"); + } else { + if (iosched_debug) + printf("Can't write because limiter says no.\n"); + isc->write_stats.state_flags |= IOP_RATE_LIMITED; + return NULL; + } } /* -- 2.37.1