raid5: make_request does less prepare wait
PATCH 1/1 raid5: make_request does less prepare wait
In NUMA machine, prepare_to_wait/finish_wait in make_request exposes a lot of contention for sequential workload (or big request size workload). For such workload, each bio includes several stripes. So we can just do prepare_to_wait/finish_wait once for the whold bio instead of every stripe. This reduces the lock contention completely for such workload. Random workload might have the similar lock contention too, but I didn't see it yet, maybe because my stroage is still not fast enough.
--- drivers/md/raid5.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)
drivers/md/raid5.c +14 -4
@@ -4552,6 +4552,8 @@ static void make_request(struct mddev *mstruct stripe_head *sh;const int rw =bio_data_dir (bi);int remaining; +DEFINE_WAIT (w); +bool do_prepare;if (unlikely (bi->bi_rw &REQ_FLUSH )) {md_flush_request (mddev, bi);
@@ -4575,15 +4577,19 @@ static void make_request(struct mddev *m bi->bi_next =NULL ; bi->bi_phys_segments =1 ;/* over-loaded to count active stripes */ +prepare_to_wait (&conf->wait_for_overlap, &w,TASK_UNINTERRUPTIBLE );for (;logical_sector < last_sector; logical_sector +=STRIPE_SECTORS ) {DEFINE_WAIT (w);int previous;int seq; + do_prepare = false; retry: seq =read_seqcount_begin (&conf->gen_lock); previous =0 ; -prepare_to_wait (&conf->wait_for_overlap, &w,TASK_UNINTERRUPTIBLE ); +if (do_prepare) +prepare_to_wait (&conf->wait_for_overlap, &w, +TASK_UNINTERRUPTIBLE );if (unlikely (conf->reshape_progress != MaxSector)) {/* spinlock is needed as reshape_progress may be * 64bit on a 32bit platform, and so it might be
@@ -4604,6 +4610,7 @@ static void make_request(struct mddev *m : logical_sector >= conf->reshape_safe) {spin_unlock_irq (&conf->device_lock);schedule (); + do_prepare = true; goto retry; } }
@@ -4640,6 +4647,7 @@ static void make_request(struct mddev *mif (must_retry) {release_stripe (sh);schedule (); + do_prepare = true; goto retry; } }
@@ -4663,8 +4671,10 @@ static void make_request(struct mddev *mprepare_to_wait (&conf->wait_for_overlap, &w,TASK_INTERRUPTIBLE );if (logical_sector >= mddev->suspend_lo && - logical_sector < mddev->suspend_hi) + logical_sector < mddev->suspend_hi) {schedule (); + do_prepare = true; + } goto retry; }
@@ -4677,9 +4687,9 @@ static void make_request(struct mddev *mmd_wakeup_thread (mddev->thread);release_stripe (sh);schedule (); + do_prepare = true; goto retry; } -finish_wait (&conf->wait_for_overlap, &w);set_bit (STRIPE_HANDLE , &sh->state);clear_bit (STRIPE_DELAYED , &sh->state); if ((bi->bi_rw & REQ_SYNC) &&
@@ -4689,10 +4699,10 @@ static void make_request(struct mddev *m }else {/* cannot get stripe for read-ahead, just give-up */ clear_bit (BIO_UPTODATE , &bi->bi_flags); -finish_wait (&conf->wait_for_overlap, &w);break ; } } +finish_wait (&conf->wait_for_overlap, &w); remaining =raid5_dec_bi_active_stripes (bi);if (remaining ==0 ) {
Quoted 10 lines · On Tue, 8 Apr 2014 12:05:07 +0800 Shaohua Li <[email protected]> wrote:
In NUMA machine, prepare_to_wait/finish_wait in
make_requestexposes a lot of contention for sequential workload (or big request size workload). For such workload, each bio includes several stripes. So we can just do prepare_to_wait/finish_wait once for the whold bio instead of every stripe. This reduces the lock contention completely for such workload. Random workload might have the similar lock contention too, but I didn't see it yet, maybe because my stroage is still not fast enough.Signed-off-by Shaohua Li <[email protected]>
Thanks,
this looks every sensible, except .....
Quoted 18 lines
--- drivers/md/raid5.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)Index:
linux/drivers/md/raid5.c
===================================================================drivers/md/raid5.c +2
-0@@ -4552,6 +4552,8 @@ static void make_request(struct mddev *mstruct stripe_head *sh;const int rw =bio_data_dir (bi);int remaining; +DEFINE_WAIT (w); +bool do_prepare;if (unlikely (bi->bi_rw &REQ_FLUSH )) {md_flush_request (mddev, bi);
drivers/md/raid5.c static void make_request(struct mddev *m · line 4582
Quoted 6 lines
drivers/md/raid5.c +1
-0@@ -4575,15 +4577,19 @@ static void make_request(struct mddev *m bi->bi_next =NULL ; bi->bi_phys_segments =1 ;/* over-loaded to count active stripes */ +prepare_to_wait (&conf->wait_for_overlap, &w,TASK_UNINTERRUPTIBLE );for (;logical_sector < last_sector; logical_sector +=STRIPE_SECTORS ) {DEFINE_WAIT (w);
^^^^^^^^^^^^^^^
Shouldn't this be removed? If so, please resubmit with that line deleted and I'll apply the patch.
Thanks,
NeilBrown
Quoted 65 lines
drivers/md/raid5.c +11
-4int previous;int seq; + do_prepare = false; retry: seq =read_seqcount_begin (&conf->gen_lock); previous =0 ; -prepare_to_wait (&conf->wait_for_overlap, &w,TASK_UNINTERRUPTIBLE ); +if (do_prepare) +prepare_to_wait (&conf->wait_for_overlap, &w, +TASK_UNINTERRUPTIBLE );if (unlikely (conf->reshape_progress != MaxSector)) {/* spinlock is needed as reshape_progress may be * 64bit on a 32bit platform, and so it might be @@ -4604,6 +4610,7 @@ static void make_request(struct mddev *m : logical_sector >= conf->reshape_safe) {spin_unlock_irq (&conf->device_lock);schedule (); + do_prepare = true; goto retry; } }@@ -4640,6 +4647,7 @@ static void make_request(struct mddev *mif (must_retry) {release_stripe (sh);schedule (); + do_prepare = true; goto retry; } }@@ -4663,8 +4671,10 @@ static void make_request(struct mddev *mprepare_to_wait (&conf->wait_for_overlap, &w,TASK_INTERRUPTIBLE );if (logical_sector >= mddev->suspend_lo && - logical_sector < mddev->suspend_hi) + logical_sector < mddev->suspend_hi) {schedule (); + do_prepare = true; + } goto retry; }@@ -4677,9 +4687,9 @@ static void make_request(struct mddev *mmd_wakeup_thread (mddev->thread);release_stripe (sh);schedule (); + do_prepare = true; goto retry; } -finish_wait (&conf->wait_for_overlap, &w);set_bit (STRIPE_HANDLE , &sh->state);clear_bit (STRIPE_DELAYED , &sh->state); if ((bi->bi_rw & REQ_SYNC) &&@@ -4689,10 +4699,10 @@ static void make_request(struct mddev *m }else {/* cannot get stripe for read-ahead, just give-up */ clear_bit (BIO_UPTODATE , &bi->bi_flags); -finish_wait (&conf->wait_for_overlap, &w);break ; } } +finish_wait (&conf->wait_for_overlap, &w); remaining =raid5_dec_bi_active_stripes (bi);if (remaining ==0 ) {
Quoted 38 lines · NeilBrown
Quoted 10 lines · On Tue, 8 Apr 2014 12:05:07 +0800 Shaohua Li <[email protected]> wrote:
In NUMA machine, prepare_to_wait/finish_wait in
make_requestexposes a lot of contention for sequential workload (or big request size workload). For such workload, each bio includes several stripes. So we can just do prepare_to_wait/finish_wait once for the whold bio instead of every stripe. This reduces the lock contention completely for such workload. Random workload might have the similar lock contention too, but I didn't see it yet, maybe because my stroage is still not fast enough.Signed-off-by Shaohua Li <[email protected]>Thanks,
this looks every sensible, except .....Quoted 21 lines
--- drivers/md/raid5.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)Index:
linux/drivers/md/raid5.c
===================================================================drivers/md/raid5.c +2
-0@@ -4552,6 +4552,8 @@ static void make_request(struct mddev *mstruct stripe_head *sh;const int rw =bio_data_dir (bi);int remaining; +DEFINE_WAIT (w); +bool do_prepare;if (unlikely (bi->bi_rw &REQ_FLUSH )) {md_flush_request (mddev, bi);@@ -4575,15 +4577,19 @@ static void make_request(struct mddev *m bi->bi_next =NULL ; bi->bi_phys_segments =1 ;/* over-loaded to count active stripes */
Quoted 7 lines
drivers/md/raid5.c static void make_request(struct mddev *m · line 4582
Quoted 3 lines
drivers/md/raid5.c +1
-0+prepare_to_wait (&conf->wait_for_overlap, &w,TASK_UNINTERRUPTIBLE );for (;logical_sector < last_sector; logical_sector +=STRIPE_SECTORS ) {DEFINE_WAIT (w);^^^^^^^^^^^^^^^Shouldn't this be removed? If so, please resubmit with that line deleted and I'll apply the patch.
Ah, that's silly, looks I sent wrong patch, sorry! Below is the correct one and I double checked it's the one working for me.
Subject: raid5: make_request does less prepare wait
In NUMA machine, prepare_to_wait/finish_wait in make_request exposes a lot of contention for sequential workload (or big request size workload). For such workload, each bio includes several stripes. So we can just do prepare_to_wait/finish_wait once for the whold bio instead of every stripe. This reduces the lock contention completely for such workload. Random workload might have the similar lock contention too, but I didn't see it yet, maybe because my stroage is still not fast enough.
--- drivers/md/raid5.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-)
drivers/md/raid5.c +14 -5
@@ -4552,6 +4552,8 @@ static void make_request(struct mddev *mstruct stripe_head *sh;const int rw =bio_data_dir (bi);int remaining; +DEFINE_WAIT (w); +bool do_prepare;if (unlikely (bi->bi_rw &REQ_FLUSH )) {md_flush_request (mddev, bi);
@@ -4575,15 +4577,18 @@ static void make_request(struct mddev *m bi->bi_next =NULL ; bi->bi_phys_segments =1 ;/* over-loaded to count active stripes */ +prepare_to_wait (&conf->wait_for_overlap, &w,TASK_UNINTERRUPTIBLE );for (;logical_sector < last_sector; logical_sector +=STRIPE_SECTORS ) { -DEFINE_WAIT (w);int previous;int seq; + do_prepare = false; retry: seq =read_seqcount_begin (&conf->gen_lock); previous =0 ; -prepare_to_wait (&conf->wait_for_overlap, &w,TASK_UNINTERRUPTIBLE ); +if (do_prepare) +prepare_to_wait (&conf->wait_for_overlap, &w, +TASK_UNINTERRUPTIBLE );if (unlikely (conf->reshape_progress != MaxSector)) {/* spinlock is needed as reshape_progress may be * 64bit on a 32bit platform, and so it might be
@@ -4604,6 +4609,7 @@ static void make_request(struct mddev *m : logical_sector >= conf->reshape_safe) {spin_unlock_irq (&conf->device_lock);schedule (); + do_prepare = true; goto retry; } }
@@ -4640,6 +4646,7 @@ static void make_request(struct mddev *mif (must_retry) {release_stripe (sh);schedule (); + do_prepare = true; goto retry; } }
@@ -4663,8 +4670,10 @@ static void make_request(struct mddev *mprepare_to_wait (&conf->wait_for_overlap, &w,TASK_INTERRUPTIBLE );if (logical_sector >= mddev->suspend_lo && - logical_sector < mddev->suspend_hi) + logical_sector < mddev->suspend_hi) {schedule (); + do_prepare = true; + } goto retry; }
@@ -4677,9 +4686,9 @@ static void make_request(struct mddev *mmd_wakeup_thread (mddev->thread);release_stripe (sh);schedule (); + do_prepare = true; goto retry; } -finish_wait (&conf->wait_for_overlap, &w);set_bit (STRIPE_HANDLE , &sh->state);clear_bit (STRIPE_DELAYED , &sh->state); if ((bi->bi_rw & REQ_SYNC) &&
@@ -4689,10 +4698,10 @@ static void make_request(struct mddev *m }else {/* cannot get stripe for read-ahead, just give-up */ clear_bit (BIO_UPTODATE , &bi->bi_flags); -finish_wait (&conf->wait_for_overlap, &w);break ; } } +finish_wait (&conf->wait_for_overlap, &w); remaining =raid5_dec_bi_active_stripes (bi);if (remaining ==0 ) {
NeilBrown
AppliedQuoted 141 lines · On Wed, 9 Apr 2014 11:25:47 +0800 Shaohua Li <[email protected]> wrote:
Quoted 38 lines · NeilBrown
Quoted 10 lines · On Tue, 8 Apr 2014 12:05:07 +0800 Shaohua Li <[email protected]> wrote:
In NUMA machine, prepare_to_wait/finish_wait in
make_requestexposes a lot of contention for sequential workload (or big request size workload). For such workload, each bio includes several stripes. So we can just do prepare_to_wait/finish_wait once for the whold bio instead of every stripe. This reduces the lock contention completely for such workload. Random workload might have the similar lock contention too, but I didn't see it yet, maybe because my stroage is still not fast enough.Signed-off-by Shaohua Li <[email protected]>Thanks,
this looks every sensible, except .....Quoted 21 lines
--- drivers/md/raid5.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)Index:
linux/drivers/md/raid5.c
===================================================================drivers/md/raid5.c +2
-0@@ -4552,6 +4552,8 @@ static void make_request(struct mddev *mstruct stripe_head *sh;const int rw =bio_data_dir (bi);int remaining; +DEFINE_WAIT (w); +bool do_prepare;if (unlikely (bi->bi_rw &REQ_FLUSH )) {md_flush_request (mddev, bi);@@ -4575,15 +4577,19 @@ static void make_request(struct mddev *m bi->bi_next =NULL ; bi->bi_phys_segments =1 ;/* over-loaded to count active stripes */ Quoted 7 lines
drivers/md/raid5.c static void make_request(struct mddev *m
Quoted 3 lines
drivers/md/raid5.c +1
-0+prepare_to_wait (&conf->wait_for_overlap, &w,TASK_UNINTERRUPTIBLE );for (;logical_sector < last_sector; logical_sector +=STRIPE_SECTORS ) {DEFINE_WAIT (w);^^^^^^^^^^^^^^^Shouldn't this be removed? If so, please resubmit with that line deleted and I'll apply the patch.
Ah, that's silly, looks I sent wrong patch, sorry! Below is the correct one and I double checked it's the one working for me.
Subject: raid5:
make_requestdoes less prepare waitIn NUMA machine, prepare_to_wait/finish_wait in
make_requestexposes a lot of contention for sequential workload (or big request size workload). For such workload, each bio includes several stripes. So we can just do prepare_to_wait/finish_wait once for the whold bio instead of every stripe. This reduces the lock contention completely for such workload. Random workload might have the similar lock contention too, but I didn't see it yet, maybe because my stroage is still not fast enough.Signed-off-by Shaohua Li <[email protected]>--- drivers/md/raid5.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-)Index:
linux/drivers/md/raid5.c
===================================================================drivers/md/raid5.c +13
-4@@ -4552,6 +4552,8 @@ static void make_request(struct mddev *mstruct stripe_head *sh;const int rw =bio_data_dir (bi);int remaining; +DEFINE_WAIT (w); +bool do_prepare;if (unlikely (bi->bi_rw &REQ_FLUSH )) {md_flush_request (mddev, bi);@@ -4575,15 +4577,18 @@ static void make_request(struct mddev *m bi->bi_next =NULL ; bi->bi_phys_segments =1 ;/* over-loaded to count active stripes */ +prepare_to_wait (&conf->wait_for_overlap, &w,TASK_UNINTERRUPTIBLE );for (;logical_sector < last_sector; logical_sector +=STRIPE_SECTORS ) { -DEFINE_WAIT (w);int previous;int seq; + do_prepare = false; retry: seq =read_seqcount_begin (&conf->gen_lock); previous =0 ; -prepare_to_wait (&conf->wait_for_overlap, &w,TASK_UNINTERRUPTIBLE ); +if (do_prepare) +prepare_to_wait (&conf->wait_for_overlap, &w, +TASK_UNINTERRUPTIBLE );if (unlikely (conf->reshape_progress != MaxSector)) {/* spinlock is needed as reshape_progress may be * 64bit on a 32bit platform, and so it might be @@ -4604,6 +4609,7 @@ static void make_request(struct mddev *m : logical_sector >= conf->reshape_safe) {spin_unlock_irq (&conf->device_lock);schedule (); + do_prepare = true; goto retry; } }@@ -4640,6 +4646,7 @@ static void make_request(struct mddev *mif (must_retry) {release_stripe (sh);schedule (); + do_prepare = true; goto retry; } }@@ -4663,8 +4670,10 @@ static void make_request(struct mddev *mprepare_to_wait (&conf->wait_for_overlap, &w,TASK_INTERRUPTIBLE );if (logical_sector >= mddev->suspend_lo && - logical_sector < mddev->suspend_hi) + logical_sector < mddev->suspend_hi) {schedule (); + do_prepare = true; + } goto retry; }@@ -4677,9 +4686,9 @@ static void make_request(struct mddev *mmd_wakeup_thread (mddev->thread);release_stripe (sh);schedule (); + do_prepare = true; goto retry; } -finish_wait (&conf->wait_for_overlap, &w);set_bit (STRIPE_HANDLE , &sh->state);clear_bit (STRIPE_DELAYED , &sh->state); if ((bi->bi_rw & REQ_SYNC) &&@@ -4689,10 +4698,10 @@ static void make_request(struct mddev *m }else {
drivers/md/raid5.c static void make_request(struct mddev *m · line 4707
Quoted 10 lines
drivers/md/raid5.c +1
-1/* cannot get stripe for read-ahead, just give-up */ clear_bit (BIO_UPTODATE , &bi->bi_flags); -finish_wait (&conf->wait_for_overlap, &w);break ; } } +finish_wait (&conf->wait_for_overlap, &w); remaining =raid5_dec_bi_active_stripes (bi);if (remaining ==0 ) {
Applied, thanks.
NeilBrown