From 96a3dfa63e0d3ba69d26dba86ba2208573973bd3 Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Tue, 25 Jul 2017 13:06:48 +0200 Subject: [PATCH 213/325] # This is a combination of 2 commits. 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 845ea73a21c5..e58a79df73c3 100644 --- a/sys/cam/cam_iosched.c +++ b/sys/cam/cam_iosched.c @@ -283,6 +283,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; @@ -735,6 +736,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); @@ -1080,6 +1085,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); @@ -1158,6 +1164,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, &isc->quanta, 0, cam_iosched_quanta_sysctl, "I", @@ -1233,10 +1244,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.32.0