Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1362893 > unrolled thread

[PATCHSET][RFC] Make background writeback not suck

Started byJens Axboe <axboe@fb.com>
First post2016-03-22 19:00 +0100
Last post2016-03-23 00:00 +0100
Articles 8 — 3 participants

Back to article view | Back to linux.kernel


Contents

  [PATCHSET][RFC] Make background writeback not suck Jens Axboe <axboe@fb.com> - 2016-03-22 19:00 +0100
    [PATCH 3/6] block: add ability to flag write back caching on a device Jens Axboe <axboe@fb.com> - 2016-03-22 19:00 +0100
      Re: [PATCH 3/6] block: add ability to flag write back caching on a  device Christoph Hellwig <hch@infradead.org> - 2016-03-22 20:00 +0100
        Re: [PATCH 3/6] block: add ability to flag write back caching on a  device Jens Axboe <axboe@fb.com> - 2016-03-22 20:10 +0100
    Re: [PATCHSET][RFC] Make background writeback not suck Dave Chinner <david@fromorbit.com> - 2016-03-22 23:00 +0100
      Re: [PATCHSET][RFC] Make background writeback not suck Jens Axboe <axboe@fb.com> - 2016-03-22 23:10 +0100
        Re: [PATCHSET][RFC] Make background writeback not suck Dave Chinner <david@fromorbit.com> - 2016-03-22 23:40 +0100
          Re: [PATCHSET][RFC] Make background writeback not suck Jens Axboe <axboe@fb.com> - 2016-03-23 00:00 +0100

#1362893 — [PATCHSET][RFC] Make background writeback not suck

FromJens Axboe <axboe@fb.com>
Date2016-03-22 19:00 +0100
Subject[PATCHSET][RFC] Make background writeback not suck
Message-ID<rfyKZ-88A-3@gated-at.bofh.it>
This patchset isn't as much a final solution, as it's demonstration
of what I believe is a huge issue. Since the dawn of time, our
background buffered writeback has sucked. When we do background
buffered writeback, it should have little impact on foreground
activity. That's the definition of background activity... But for as
long as I can remember, heavy buffered writers has not behaved like
that. For instance, if I do something like this:

$ dd if=/dev/zero of=foo bs=1M count=10k

on my laptop, and then try and start chrome, it basically won't start
before the buffered writeback is done. Or for server oriented workloads
where installation of a big RPM (or similar) adversely impacts data
base reads. When that happens, I get people yelling at me.

A quick demonstration - a fio job that reads a a file, while someone
else issues the above 'dd'. Run on a flash device, using XFS. The
vmstat output looks something like this:

--io---- -system-- ------cpu-----
bi    bo   in   cs us sy id wa st
   156  4648   58  151  0  1 98  1  0
     0     0   64   83  0  0 100  0  0
     0    32   76  119  0  0 100  0  0
 26616     0 7574 13907  7  0 91  2  0
 41992     0 10811 21395  0  2 95  3  0
 46040     0 11836 23395  0  3 94  3  0
 19376 1310736 5894 10080  0  4 93  3  0
   116 1974296 1858  455  0  4 93  3  0
   124 2020372 1964  545  0  4 92  4  0
   112 1678356 1955  620  0  3 93  3  0
  8560 405508 3759 4756  0  1 96  3  0
 42496     0 10798 21566  0  0 97  3  0
 42476     0 10788 21524  0  0 97  3  0

The read starts out fine, but goes to shit when we start bacckground
flushing. The reader experiences latency spikes in the seconds range.
On flash.

With this set of patches applies, the situation looks like this instead:

--io---- -system-- ------cpu-----
bi    bo   in   cs us sy id wa st
 33544     0 8650 17204  0  1 97  2  0
 42488     0 10856 21756  0  0 97  3  0
 42032     0 10719 21384  0  0 97  3  0
 42544    12 10838 21631  0  0 97  3  0
 42620     0 10982 21727  0  3 95  3  0
 46392     0 11923 23597  0  3 94  3  0
 36268 512000 9907 20044  0  3 91  5  0
 31572 696324 8840 18248  0  1 91  7  0
 30748 626692 8617 17636  0  2 91  6  0
 31016 618504 8679 17736  0  3 91  6  0
 30612 648196 8625 17624  0  3 91  6  0
 30992 650296 8738 17859  0  3 91  6  0
 30680 604075 8614 17605  0  3 92  6  0
 30592 595040 8572 17564  0  2 92  6  0
 31836 539656 8819 17962  0  2 92  5  0

and the reader never sees latency spikes above a few miliseconds.

The above was the why. The how is basically throttling background
writeback. We still want to issue big writes from the vm side of things,
so we get nice and big extents on the file system end. But we don't need
to flood the device with THOUSANDS of requests for background writeback.
For most devices, we don't need a whole lot to get decent throughput.

This adds some simple blk-wb code that keeps limits how much buffered
writeback we keep in flight on the device end. The default is pretty
low. If we end up switching to WB_SYNC_ALL, we up the limits. If the
dirtying task ends up being throttled in balance_dirty_pages(), we up
the limit. Currently there are tunables associated with this, see the
last patch for descriptions of those.

I welcome testing. The end goal here would be having much of this
auto-tuned, so that we don't lose substantial bandwidth for background
writes, while still maintaining decent non-wb performance and latencies.

You can also find this in a branch in the block git repo:

git://git.kernel.dk/linux-block.git wb-buf-throttle

Note that I rebase this branch when I collapse patches. Patches are
against current Linus' git, 4.5.0+.

 block/Makefile                   |    2 
 block/blk-core.c                 |   21 +++
 block/blk-lib.c                  |    1 
 block/blk-mq.c                   |   32 +++++
 block/blk-settings.c             |   11 +
 block/blk-sysfs.c                |  123 +++++++++++++++++++++
 block/blk-wb.c                   |  219 +++++++++++++++++++++++++++++++++++++++
 block/blk-wb.h                   |   24 ++++
 block/cfq-iosched.c              |    2 
 block/elevator.c                 |    6 -
 drivers/nvme/host/core.c         |    1 
 drivers/scsi/sd.c                |    5 
 fs/fs-writeback.c                |    5 
 include/linux/backing-dev-defs.h |    2 
 include/linux/blk_types.h        |    2 
 include/linux/blkdev.h           |    9 +
 include/linux/elevator.h         |    4 
 mm/page-writeback.c              |    2 
 18 files changed, 456 insertions(+), 15 deletions(-)


-- 
Jens Axboe

[toc] | [next] | [standalone]


#1362895 — [PATCH 3/6] block: add ability to flag write back caching on a device

FromJens Axboe <axboe@fb.com>
Date2016-03-22 19:00 +0100
Subject[PATCH 3/6] block: add ability to flag write back caching on a device
Message-ID<rfyL0-88A-33@gated-at.bofh.it>
In reply to#1362893
Add an internal helper and flag for setting whether a queue has
write back caching, or write through (or none). Add a sysfs file
to show this as well, and make it changeable from user space.

Signed-off-by: Jens Axboe <axboe@fb.com>
---
 block/blk-settings.c   | 11 +++++++++++
 block/blk-sysfs.c      | 40 ++++++++++++++++++++++++++++++++++++++++
 include/linux/blkdev.h |  4 ++++
 3 files changed, 55 insertions(+)

diff --git a/block/blk-settings.c b/block/blk-settings.c
index c7bb666aafd1..4dbd511a9889 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -846,6 +846,17 @@ void blk_queue_flush_queueable(struct request_queue *q, bool queueable)
 }
 EXPORT_SYMBOL_GPL(blk_queue_flush_queueable);
 
+void blk_queue_write_cache(struct request_queue *q, bool enabled)
+{
+	spin_lock_irq(q->queue_lock);
+	if (enabled)
+		queue_flag_set(QUEUE_FLAG_WC, q);
+	else
+		queue_flag_clear(QUEUE_FLAG_WC, q);
+	spin_unlock_irq(q->queue_lock);
+}
+EXPORT_SYMBOL_GPL(blk_queue_write_cache);
+
 static int __init blk_settings_init(void)
 {
 	blk_max_low_pfn = max_low_pfn - 1;
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index dd93763057ce..deb2270bf1f3 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -347,6 +347,39 @@ static ssize_t queue_poll_store(struct request_queue *q, const char *page,
 	return ret;
 }
 
+static ssize_t queue_wc_show(struct request_queue *q, char *page)
+{
+	if (test_bit(QUEUE_FLAG_WC, &q->queue_flags))
+		return sprintf(page, "write back\n");
+
+	return sprintf(page, "write through\n");
+}
+
+static ssize_t queue_wc_store(struct request_queue *q, const char *page,
+			      size_t count)
+{
+	ssize_t ret;
+	int set = -1;
+
+	if (!strncmp(page, "write back", 10))
+		set = 1;
+	else if (!strncmp(page, "write through", 13) ||
+		 !strncmp(page, "none", 4))
+		set = 0;
+
+	if (set == -1)
+		return -EINVAL;
+		
+	spin_lock_irq(q->queue_lock);
+	if (set)
+		queue_flag_set(QUEUE_FLAG_WC, q);
+	else
+		queue_flag_clear(QUEUE_FLAG_WC, q);
+	spin_unlock_irq(q->queue_lock);
+
+	return ret;
+}
+
 static struct queue_sysfs_entry queue_requests_entry = {
 	.attr = {.name = "nr_requests", .mode = S_IRUGO | S_IWUSR },
 	.show = queue_requests_show,
@@ -478,6 +511,12 @@ static struct queue_sysfs_entry queue_poll_entry = {
 	.store = queue_poll_store,
 };
 
+static struct queue_sysfs_entry queue_wc_entry = {
+	.attr = {.name = "write_cache", .mode = S_IRUGO | S_IWUSR },
+	.show = queue_wc_show,
+	.store = queue_wc_store,
+};
+
 static struct attribute *default_attrs[] = {
 	&queue_requests_entry.attr,
 	&queue_ra_entry.attr,
@@ -503,6 +542,7 @@ static struct attribute *default_attrs[] = {
 	&queue_iostats_entry.attr,
 	&queue_random_entry.attr,
 	&queue_poll_entry.attr,
+	&queue_wc_entry.attr,
 	NULL,
 };
 
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 930bd4c5b7ff..da5e85c35318 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -491,15 +491,18 @@ struct request_queue {
 #define QUEUE_FLAG_INIT_DONE   20	/* queue is initialized */
 #define QUEUE_FLAG_NO_SG_MERGE 21	/* don't attempt to merge SG segments*/
 #define QUEUE_FLAG_POLL	       22	/* IO polling enabled if set */
+#define QUEUE_FLAG_WC	       23	/* Write back caching */
 
 #define QUEUE_FLAG_DEFAULT	((1 << QUEUE_FLAG_IO_STAT) |		\
 				 (1 << QUEUE_FLAG_STACKABLE)	|	\
 				 (1 << QUEUE_FLAG_SAME_COMP)	|	\
+				 (1 << QUEUE_FLAG_WC)		|	\
 				 (1 << QUEUE_FLAG_ADD_RANDOM))
 
 #define QUEUE_FLAG_MQ_DEFAULT	((1 << QUEUE_FLAG_IO_STAT) |		\
 				 (1 << QUEUE_FLAG_STACKABLE)	|	\
 				 (1 << QUEUE_FLAG_SAME_COMP)	|	\
+				 (1 << QUEUE_FLAG_WC)		|	\
 				 (1 << QUEUE_FLAG_POLL))
 
 static inline void queue_lockdep_assert_held(struct request_queue *q)
@@ -1009,6 +1012,7 @@ extern void blk_queue_rq_timed_out(struct request_queue *, rq_timed_out_fn *);
 extern void blk_queue_rq_timeout(struct request_queue *, unsigned int);
 extern void blk_queue_flush(struct request_queue *q, unsigned int flush);
 extern void blk_queue_flush_queueable(struct request_queue *q, bool queueable);
+extern void blk_queue_write_cache(struct request_queue *q, bool enabled);
 extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
 
 extern int blk_rq_map_sg(struct request_queue *, struct request *, struct scatterlist *);
-- 
2.4.1.168.g1ea28e1

[toc] | [prev] | [next] | [standalone]


#1362913 — Re: [PATCH 3/6] block: add ability to flag write back caching on a device

FromChristoph Hellwig <hch@infradead.org>
Date2016-03-22 20:00 +0100
SubjectRe: [PATCH 3/6] block: add ability to flag write back caching on a device
Message-ID<rfzH4-h4-5@gated-at.bofh.it>
In reply to#1362895
On Tue, Mar 22, 2016 at 11:55:17AM -0600, Jens Axboe wrote:
> Add an internal helper and flag for setting whether a queue has
> write back caching, or write through (or none). Add a sysfs file
> to show this as well, and make it changeable from user space.

We do this by passing the REQ_FLUSH flag to blk_queue_flush today.
While that's not a great interface, adding a second one doesn't make it
any better :)

[toc] | [prev] | [next] | [standalone]


#1362919 — Re: [PATCH 3/6] block: add ability to flag write back caching on a device

FromJens Axboe <axboe@fb.com>
Date2016-03-22 20:10 +0100
SubjectRe: [PATCH 3/6] block: add ability to flag write back caching on a device
Message-ID<rfzQK-Ab-11@gated-at.bofh.it>
In reply to#1362913
On 03/22/2016 12:57 PM, Christoph Hellwig wrote:
> On Tue, Mar 22, 2016 at 11:55:17AM -0600, Jens Axboe wrote:
>> Add an internal helper and flag for setting whether a queue has
>> write back caching, or write through (or none). Add a sysfs file
>> to show this as well, and make it changeable from user space.
>
> We do this by passing the REQ_FLUSH flag to blk_queue_flush today.
> While that's not a great interface, adding a second one doesn't make it
> any better :)

I think the newer one is cleaner, so would make more sense to put the 
flush part on top.


-- 
Jens Axboe

[toc] | [prev] | [next] | [standalone]


#1363034

FromDave Chinner <david@fromorbit.com>
Date2016-03-22 23:00 +0100
Message-ID<rfCvg-276-5@gated-at.bofh.it>
In reply to#1362893
On Tue, Mar 22, 2016 at 11:55:14AM -0600, Jens Axboe wrote:
> This patchset isn't as much a final solution, as it's demonstration
> of what I believe is a huge issue. Since the dawn of time, our
> background buffered writeback has sucked. When we do background
> buffered writeback, it should have little impact on foreground
> activity. That's the definition of background activity... But for as
> long as I can remember, heavy buffered writers has not behaved like
> that.

Of course not. The IO scheduler is supposed to determine how we
meter out bulk vs latency sensitive IO that is queued. That's what
all the things like anticipatory scheduling for read requests was
supposed to address....

I'm guessing you're seeing problems like this because blk-mq has no
IO scheduler infrastructure and so no way of prioritising,
scheduling and/or throttling different types of IO? Would that be
accurate?

> For instance, if I do something like this:
> 
> $ dd if=/dev/zero of=foo bs=1M count=10k
> 
> on my laptop, and then try and start chrome, it basically won't start
> before the buffered writeback is done. Or for server oriented workloads
> where installation of a big RPM (or similar) adversely impacts data
> base reads. When that happens, I get people yelling at me.
> 
> A quick demonstration - a fio job that reads a a file, while someone
> else issues the above 'dd'. Run on a flash device, using XFS. The
> vmstat output looks something like this:
> 
> --io---- -system-- ------cpu-----
> bi    bo   in   cs us sy id wa st
>    156  4648   58  151  0  1 98  1  0
>      0     0   64   83  0  0 100  0  0
>      0    32   76  119  0  0 100  0  0
>  26616     0 7574 13907  7  0 91  2  0
>  41992     0 10811 21395  0  2 95  3  0
>  46040     0 11836 23395  0  3 94  3  0
>  19376 1310736 5894 10080  0  4 93  3  0
>    116 1974296 1858  455  0  4 93  3  0
>    124 2020372 1964  545  0  4 92  4  0
>    112 1678356 1955  620  0  3 93  3  0
>   8560 405508 3759 4756  0  1 96  3  0
>  42496     0 10798 21566  0  0 97  3  0
>  42476     0 10788 21524  0  0 97  3  0

So writeback is running at about 2GB/s, meaning the memory is
cleaned in about 5s.

> The read starts out fine, but goes to shit when we start bacckground
> flushing. The reader experiences latency spikes in the seconds range.
> On flash.
> 
> With this set of patches applies, the situation looks like this instead:
> 
> --io---- -system-- ------cpu-----
> bi    bo   in   cs us sy id wa st
>  33544     0 8650 17204  0  1 97  2  0
>  42488     0 10856 21756  0  0 97  3  0
>  42032     0 10719 21384  0  0 97  3  0
>  42544    12 10838 21631  0  0 97  3  0
>  42620     0 10982 21727  0  3 95  3  0
>  46392     0 11923 23597  0  3 94  3  0
>  36268 512000 9907 20044  0  3 91  5  0
>  31572 696324 8840 18248  0  1 91  7  0
>  30748 626692 8617 17636  0  2 91  6  0
>  31016 618504 8679 17736  0  3 91  6  0
>  30612 648196 8625 17624  0  3 91  6  0
>  30992 650296 8738 17859  0  3 91  6  0
>  30680 604075 8614 17605  0  3 92  6  0
>  30592 595040 8572 17564  0  2 92  6  0
>  31836 539656 8819 17962  0  2 92  5  0

And now it runs at ~600MB/s, slowing down the rate at which memory
is cleaned by 60%.

Given that background writeback is relied on by memory reclaim to
clean memory faster than the LRUs are cycled, I suspect this is
going to have a big impact on low memory behaviour and balance,
which will then feed into IO breakdown problems caused by writeback
being driven from the LRUs rather than the flusher threads.....

> The above was the why. The how is basically throttling background
> writeback. We still want to issue big writes from the vm side of things,
> so we get nice and big extents on the file system end. But we don't need
> to flood the device with THOUSANDS of requests for background writeback.
> For most devices, we don't need a whole lot to get decent throughput.

Except, when the system is busy (e.g. CPU busy) and the writeback
threads can be starved of CPU by other operations, the writeback
queue depth needs to go way up so that we don't end up with idle
devices because the flusher threads are starved of CPU....

> This adds some simple blk-wb code that keeps limits how much buffered
> writeback we keep in flight on the device end. The default is pretty
> low. If we end up switching to WB_SYNC_ALL, we up the limits. If the
> dirtying task ends up being throttled in balance_dirty_pages(), we up
> the limit. Currently there are tunables associated with this, see the
> last patch for descriptions of those.
>
> I welcome testing. The end goal here would be having much of this
> auto-tuned, so that we don't lose substantial bandwidth for
> background writes, while still maintaining decent non-wb
> performance and latencies.

Right, another layer of "writeback tunables" is not really a
desirable outcome. We spent a lot of time making the dirty page
cache flushing not need tunables (i.e. via careful design of closed
loop feedback systems), so I think that if we're going to add a new
layer of throttling, we need to do the same thing. i.e. it needs to
adapt automatically and correctly to changing loads and workloads.

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

[toc] | [prev] | [next] | [standalone]


#1363044

FromJens Axboe <axboe@fb.com>
Date2016-03-22 23:10 +0100
Message-ID<rfCEX-2qy-29@gated-at.bofh.it>
In reply to#1363034
On 03/22/2016 03:51 PM, Dave Chinner wrote:
> On Tue, Mar 22, 2016 at 11:55:14AM -0600, Jens Axboe wrote:
>> This patchset isn't as much a final solution, as it's demonstration
>> of what I believe is a huge issue. Since the dawn of time, our
>> background buffered writeback has sucked. When we do background
>> buffered writeback, it should have little impact on foreground
>> activity. That's the definition of background activity... But for as
>> long as I can remember, heavy buffered writers has not behaved like
>> that.
>
> Of course not. The IO scheduler is supposed to determine how we
> meter out bulk vs latency sensitive IO that is queued. That's what
> all the things like anticipatory scheduling for read requests was
> supposed to address....
>
> I'm guessing you're seeing problems like this because blk-mq has no
> IO scheduler infrastructure and so no way of prioritising,
> scheduling and/or throttling different types of IO? Would that be
> accurate?

It's not just that, but obviously the IO scheduler would be one place to 
throttle it. This, in a way, is a way of scheduling the writeback writes 
better. But most of the reports I get on writeback sucking is not using 
scsi/blk-mq, they end up being "classic" on things like deadline.

>> For instance, if I do something like this:
>>
>> $ dd if=/dev/zero of=foo bs=1M count=10k
>>
>> on my laptop, and then try and start chrome, it basically won't start
>> before the buffered writeback is done. Or for server oriented workloads
>> where installation of a big RPM (or similar) adversely impacts data
>> base reads. When that happens, I get people yelling at me.
>>
>> A quick demonstration - a fio job that reads a a file, while someone
>> else issues the above 'dd'. Run on a flash device, using XFS. The
>> vmstat output looks something like this:
>>
>> --io---- -system-- ------cpu-----
>> bi    bo   in   cs us sy id wa st
>>     156  4648   58  151  0  1 98  1  0
>>       0     0   64   83  0  0 100  0  0
>>       0    32   76  119  0  0 100  0  0
>>   26616     0 7574 13907  7  0 91  2  0
>>   41992     0 10811 21395  0  2 95  3  0
>>   46040     0 11836 23395  0  3 94  3  0
>>   19376 1310736 5894 10080  0  4 93  3  0
>>     116 1974296 1858  455  0  4 93  3  0
>>     124 2020372 1964  545  0  4 92  4  0
>>     112 1678356 1955  620  0  3 93  3  0
>>    8560 405508 3759 4756  0  1 96  3  0
>>   42496     0 10798 21566  0  0 97  3  0
>>   42476     0 10788 21524  0  0 97  3  0
>
> So writeback is running at about 2GB/s, meaning the memory is
> cleaned in about 5s.

Correct, and at the same time destroying anything else that runs on the 
disk. For most use cases, not ideal. If we get in a tighter spot on 
memory or someone waits on it, yes, we should ramp up. But not for 
background cleaning.

>> The read starts out fine, but goes to shit when we start bacckground
>> flushing. The reader experiences latency spikes in the seconds range.
>> On flash.
>>
>> With this set of patches applies, the situation looks like this instead:
>>
>> --io---- -system-- ------cpu-----
>> bi    bo   in   cs us sy id wa st
>>   33544     0 8650 17204  0  1 97  2  0
>>   42488     0 10856 21756  0  0 97  3  0
>>   42032     0 10719 21384  0  0 97  3  0
>>   42544    12 10838 21631  0  0 97  3  0
>>   42620     0 10982 21727  0  3 95  3  0
>>   46392     0 11923 23597  0  3 94  3  0
>>   36268 512000 9907 20044  0  3 91  5  0
>>   31572 696324 8840 18248  0  1 91  7  0
>>   30748 626692 8617 17636  0  2 91  6  0
>>   31016 618504 8679 17736  0  3 91  6  0
>>   30612 648196 8625 17624  0  3 91  6  0
>>   30992 650296 8738 17859  0  3 91  6  0
>>   30680 604075 8614 17605  0  3 92  6  0
>>   30592 595040 8572 17564  0  2 92  6  0
>>   31836 539656 8819 17962  0  2 92  5  0
>
> And now it runs at ~600MB/s, slowing down the rate at which memory
> is cleaned by 60%.

Which is the point, correct... If we're not anywhere near being tight on 
memory AND nobody is waiting for this IO, then by definition, the 
foreground activity is the important one. For the case used here, that's 
the application doing reads.

> Given that background writeback is relied on by memory reclaim to
> clean memory faster than the LRUs are cycled, I suspect this is
> going to have a big impact on low memory behaviour and balance,
> which will then feed into IO breakdown problems caused by writeback
> being driven from the LRUs rather than the flusher threads.....

You're missing the part where the intent is to only throttle it heavily 
when it's pure background writeback. Of course, if we are low on memory 
and doing reclaim, we should get much closer to device bandwidth.

If I run the above dd without the reader running, I'm already at 90% of 
the device bandwidth - not quite all the way there, since I still want 
to quickly be able to inject reads (or other IO) without having to wait 
for the queues to purge thousands of requests.

>> The above was the why. The how is basically throttling background
>> writeback. We still want to issue big writes from the vm side of things,
>> so we get nice and big extents on the file system end. But we don't need
>> to flood the device with THOUSANDS of requests for background writeback.
>> For most devices, we don't need a whole lot to get decent throughput.
>
> Except, when the system is busy (e.g. CPU busy) and the writeback
> threads can be starved of CPU by other operations, the writeback
> queue depth needs to go way up so that we don't end up with idle
> devices because the flusher threads are starved of CPU....

Sure, writeback always needs to make stable progress.

>> This adds some simple blk-wb code that keeps limits how much buffered
>> writeback we keep in flight on the device end. The default is pretty
>> low. If we end up switching to WB_SYNC_ALL, we up the limits. If the
>> dirtying task ends up being throttled in balance_dirty_pages(), we up
>> the limit. Currently there are tunables associated with this, see the
>> last patch for descriptions of those.
>>
>> I welcome testing. The end goal here would be having much of this
>> auto-tuned, so that we don't lose substantial bandwidth for
>> background writes, while still maintaining decent non-wb
>> performance and latencies.
>
> Right, another layer of "writeback tunables" is not really a
> desirable outcome. We spent a lot of time making the dirty page
> cache flushing not need tunables (i.e. via careful design of closed
> loop feedback systems), so I think that if we're going to add a new
> layer of throttling, we need to do the same thing. i.e. it needs to
> adapt automatically and correctly to changing loads and workloads.

Fully agree, and that's what I stated as well. The current patchset is a 
way to experiment with improving background writeback, that's both in 
the very first paragraph of this email, and in the blk-wb.c file as 
well. I'm not a huge fan of tunables, nobody touches them, and we need 
to get it right out of the box.

I've already removed one set of tunables from this posting compared to 
what I had a week ago, it's moving in that direction.

-- 
Jens Axboe

[toc] | [prev] | [next] | [standalone]


#1363056

FromDave Chinner <david@fromorbit.com>
Date2016-03-22 23:40 +0100
Message-ID<rfD7Y-2AF-7@gated-at.bofh.it>
In reply to#1363044
On Tue, Mar 22, 2016 at 04:03:28PM -0600, Jens Axboe wrote:
> On 03/22/2016 03:51 PM, Dave Chinner wrote:
> >On Tue, Mar 22, 2016 at 11:55:14AM -0600, Jens Axboe wrote:
> >>This patchset isn't as much a final solution, as it's demonstration
> >>of what I believe is a huge issue. Since the dawn of time, our
> >>background buffered writeback has sucked. When we do background
> >>buffered writeback, it should have little impact on foreground
> >>activity. That's the definition of background activity... But for as
> >>long as I can remember, heavy buffered writers has not behaved like
> >>that.
> >
> >Of course not. The IO scheduler is supposed to determine how we
> >meter out bulk vs latency sensitive IO that is queued. That's what
> >all the things like anticipatory scheduling for read requests was
> >supposed to address....
> >
> >I'm guessing you're seeing problems like this because blk-mq has no
> >IO scheduler infrastructure and so no way of prioritising,
> >scheduling and/or throttling different types of IO? Would that be
> >accurate?
> 
> It's not just that, but obviously the IO scheduler would be one
> place to throttle it. This, in a way, is a way of scheduling the
> writeback writes better. But most of the reports I get on writeback
> sucking is not using scsi/blk-mq, they end up being "classic" on
> things like deadline.

Deadline doesn't have anticipatory read scheduling, right?

Really, I'm just trying to understand why this isn't being added as
part of the IO scheduler infrastructure, but is instead adding
another layer of non-optional IO scheduling to the block layer...

> >>The read starts out fine, but goes to shit when we start bacckground
> >>flushing. The reader experiences latency spikes in the seconds range.
> >>On flash.
> >>
> >>With this set of patches applies, the situation looks like this instead:
> >>
> >>--io---- -system-- ------cpu-----
> >>bi    bo   in   cs us sy id wa st
> >>  33544     0 8650 17204  0  1 97  2  0
> >>  42488     0 10856 21756  0  0 97  3  0
> >>  42032     0 10719 21384  0  0 97  3  0
> >>  42544    12 10838 21631  0  0 97  3  0
> >>  42620     0 10982 21727  0  3 95  3  0
> >>  46392     0 11923 23597  0  3 94  3  0
> >>  36268 512000 9907 20044  0  3 91  5  0
> >>  31572 696324 8840 18248  0  1 91  7  0
> >>  30748 626692 8617 17636  0  2 91  6  0
> >>  31016 618504 8679 17736  0  3 91  6  0
> >>  30612 648196 8625 17624  0  3 91  6  0
> >>  30992 650296 8738 17859  0  3 91  6  0
> >>  30680 604075 8614 17605  0  3 92  6  0
> >>  30592 595040 8572 17564  0  2 92  6  0
> >>  31836 539656 8819 17962  0  2 92  5  0
> >
> >And now it runs at ~600MB/s, slowing down the rate at which memory
> >is cleaned by 60%.
> 
> Which is the point, correct... If we're not anywhere near being
> tight on memory AND nobody is waiting for this IO, then by
> definition, the foreground activity is the important one. For the
> case used here, that's the application doing reads.

Unless, of course, we are in a situation where there is also large
memory demand, and we need to clean memory fast....

> >Given that background writeback is relied on by memory reclaim to
> >clean memory faster than the LRUs are cycled, I suspect this is
> >going to have a big impact on low memory behaviour and balance,
> >which will then feed into IO breakdown problems caused by writeback
> >being driven from the LRUs rather than the flusher threads.....
> 
> You're missing the part where the intent is to only throttle it
> heavily when it's pure background writeback. Of course, if we are
> low on memory and doing reclaim, we should get much closer to device
> bandwidth.

A demonstration, please.

I didn't see anything in the code that treated low memory conditions
differently - that just uses
wakeup_flusher_threads(WB_REASON_TRY_TO_FREE_PAGES) from
do_try_to_free_pages() to trigger background writeback to run and
clean pages, so I'm interested to see exactly how that works out...

> If I run the above dd without the reader running, I'm already at 90%
> of the device bandwidth - not quite all the way there, since I still
> want to quickly be able to inject reads (or other IO) without having
> to wait for the queues to purge thousands of requests.

So, essentially, the model is to run background write at "near
starvation" queue depths, which works fine when the system is mostly
idle and we can dispatch more IO immediately. My concern with this
model is that under heavy IO and CPU load, writeback dispatch often
has significant delays (e.g. for allocation, etc). This is when we
need deeper queue depths to maintain throughput across dispatch
latency variations.

Many production workloads don't care about read latency, but do care
about bulk page cache throughput. Such workloads are going to be
adversely affected by a fundamental block layer IO dispatch model
change like this. This is why we have the pluggable IO schedulers in
the first place - one size does not fit all.

Hence I'm thinking that this should not be applied to all block
devices as this patch does, but instead be a part of the io
scheduling infrastructure we already have (and need for blk-mq).

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

[toc] | [prev] | [next] | [standalone]


#1363074

FromJens Axboe <axboe@fb.com>
Date2016-03-23 00:00 +0100
Message-ID<rfDrk-2Hw-23@gated-at.bofh.it>
In reply to#1363056
On 03/22/2016 04:31 PM, Dave Chinner wrote:
> On Tue, Mar 22, 2016 at 04:03:28PM -0600, Jens Axboe wrote:
>> On 03/22/2016 03:51 PM, Dave Chinner wrote:
>>> On Tue, Mar 22, 2016 at 11:55:14AM -0600, Jens Axboe wrote:
>>>> This patchset isn't as much a final solution, as it's demonstration
>>>> of what I believe is a huge issue. Since the dawn of time, our
>>>> background buffered writeback has sucked. When we do background
>>>> buffered writeback, it should have little impact on foreground
>>>> activity. That's the definition of background activity... But for as
>>>> long as I can remember, heavy buffered writers has not behaved like
>>>> that.
>>>
>>> Of course not. The IO scheduler is supposed to determine how we
>>> meter out bulk vs latency sensitive IO that is queued. That's what
>>> all the things like anticipatory scheduling for read requests was
>>> supposed to address....
>>>
>>> I'm guessing you're seeing problems like this because blk-mq has no
>>> IO scheduler infrastructure and so no way of prioritising,
>>> scheduling and/or throttling different types of IO? Would that be
>>> accurate?
>>
>> It's not just that, but obviously the IO scheduler would be one
>> place to throttle it. This, in a way, is a way of scheduling the
>> writeback writes better. But most of the reports I get on writeback
>> sucking is not using scsi/blk-mq, they end up being "classic" on
>> things like deadline.
>
> Deadline doesn't have anticipatory read scheduling, right?
>
> Really, I'm just trying to understand why this isn't being added as
> part of the IO scheduler infrastructure, but is instead adding
> another layer of non-optional IO scheduling to the block layer...

This is less about IO scheduling than it is about making sure that 
background writeback isn't too intrusive. Yes, you can argue that that 
is a form of IO scheduling. But so is the rate detection, for instance, 
and some of the other limits we put in. But we don't properly limit 
depth, and I think we should.

Anticipatory read scheduling is a completely different animal, that is 
centered around avoid long seeks on rotational media, assuming that 
there's locality on disk for related (and back-to-back) reads.

This can easily be part of IO scheduling infrastructure, it already 
somewhat is, given where it's placed.

>>>> The read starts out fine, but goes to shit when we start bacckground
>>>> flushing. The reader experiences latency spikes in the seconds range.
>>>> On flash.
>>>>
>>>> With this set of patches applies, the situation looks like this instead:
>>>>
>>>> --io---- -system-- ------cpu-----
>>>> bi    bo   in   cs us sy id wa st
>>>>   33544     0 8650 17204  0  1 97  2  0
>>>>   42488     0 10856 21756  0  0 97  3  0
>>>>   42032     0 10719 21384  0  0 97  3  0
>>>>   42544    12 10838 21631  0  0 97  3  0
>>>>   42620     0 10982 21727  0  3 95  3  0
>>>>   46392     0 11923 23597  0  3 94  3  0
>>>>   36268 512000 9907 20044  0  3 91  5  0
>>>>   31572 696324 8840 18248  0  1 91  7  0
>>>>   30748 626692 8617 17636  0  2 91  6  0
>>>>   31016 618504 8679 17736  0  3 91  6  0
>>>>   30612 648196 8625 17624  0  3 91  6  0
>>>>   30992 650296 8738 17859  0  3 91  6  0
>>>>   30680 604075 8614 17605  0  3 92  6  0
>>>>   30592 595040 8572 17564  0  2 92  6  0
>>>>   31836 539656 8819 17962  0  2 92  5  0
>>>
>>> And now it runs at ~600MB/s, slowing down the rate at which memory
>>> is cleaned by 60%.
>>
>> Which is the point, correct... If we're not anywhere near being
>> tight on memory AND nobody is waiting for this IO, then by
>> definition, the foreground activity is the important one. For the
>> case used here, that's the application doing reads.
>
> Unless, of course, we are in a situation where there is also large
> memory demand, and we need to clean memory fast....

If that's the case, then we should ramp up limits. The important part 
here is that we currently issue thousands of requests. Literally 
thousands. Do we need thousands to get optimal throughput? No. In fact 
it's detrimental to other system activity, without providing any 
benefits. The idea here is to throttle us within a given window of 
depth, let's call that 1..N, where N is enough to get us full write 
performance. If we're doing pure background writes, QD is well less than 
N. If the urgency increases, we'll ramp it up. But for all cases, we're 
avoiding the situation of having several thousand of requests in flight.

>>> Given that background writeback is relied on by memory reclaim to
>>> clean memory faster than the LRUs are cycled, I suspect this is
>>> going to have a big impact on low memory behaviour and balance,
>>> which will then feed into IO breakdown problems caused by writeback
>>> being driven from the LRUs rather than the flusher threads.....
>>
>> You're missing the part where the intent is to only throttle it
>> heavily when it's pure background writeback. Of course, if we are
>> low on memory and doing reclaim, we should get much closer to device
>> bandwidth.
>
> A demonstration, please.
>
> I didn't see anything in the code that treated low memory conditions
> differently - that just uses
> wakeup_flusher_threads(WB_REASON_TRY_TO_FREE_PAGES) from
> do_try_to_free_pages() to trigger background writeback to run and
> clean pages, so I'm interested to see exactly how that works out...

It's not all there yet, this is an early RFC. The case that is handled 
is the application being blocked on dirtying memory, we increase 
bandwidth for that case. I'll look into reclaim next, honestly don't see 
this as somethings that's hard to handle.

>> If I run the above dd without the reader running, I'm already at 90%
>> of the device bandwidth - not quite all the way there, since I still
>> want to quickly be able to inject reads (or other IO) without having
>> to wait for the queues to purge thousands of requests.
>
> So, essentially, the model is to run background write at "near
> starvation" queue depths, which works fine when the system is mostly
> idle and we can dispatch more IO immediately. My concern with this
> model is that under heavy IO and CPU load, writeback dispatch often
> has significant delays (e.g. for allocation, etc). This is when we
> need deeper queue depths to maintain throughput across dispatch
> latency variations.

Not near starvation. For most devices, it doesn't take a lot of writes 
to get very close to max performance. I don't want to starve the device, 
that's not the intention here. And if writeback kworkers being CPU 
starved is a concern, then yes, of course that needs to be handled 
appropriately.

If we're in or near a critical condition, then writeback must proceed 
swiftly. For the general use case of that NOT being the case, then we 
can limit writeback a bit and get much better system behavior for most 
applications and users.

> Many production workloads don't care about read latency, but do care
> about bulk page cache throughput. Such workloads are going to be
> adversely affected by a fundamental block layer IO dispatch model
> change like this. This is why we have the pluggable IO schedulers in
> the first place - one size does not fit all.

I'd counter that with most production workloads DO care about IO 
latencies, be it reads or writes. In fact it's often the single most 
important thing that people complain about. When provisioning hardware 
or setups, we're often in the situation that we have to drive things 
softer than we would otherwise want to, to get more predictable 
behavior. The current writeback is the opposite of predictable, unless 
you consider the fact that it predictably shits itself with basic 
operations like buffered writes.

On example is a user deliberately dirtying at X MB/sec, where X is well 
below what the device can handle. That user know has two choices:

1) Do nothing, and incur the wrath of periodic writeback that issues a 
ton of requests, disturbing everything else.
2) Insert periodic sync points to avoid queuing up too much. The user 
needs to be able to block to do that, so that means offloading to a thread.

Neither of those are appealing choices. Wouldn't it be great if the user 
didn't have to do anything, and have the system behave in a reasonable 
manner? I think so.

> Hence I'm thinking that this should not be applied to all block
> devices as this patch does, but instead be a part of the io
> scheduling infrastructure we already have (and need for blk-mq).

Sure, that's a placement concern, and that's something that can be 
worked on. I feel like we're arguing in circles here.

-- 
Jens Axboe

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web