XFS: Run kernel threads on demand
cover XFS: Run kernel threads on demand
We run the xfsbufd and the xfsaild once a second even when there is no work to do. Make them demand driven so that we don't needlessly wake idle CPUs to do nothing. This should make power misers with XFS filesystems happy.
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
PATCH 1/2 XFS: Don't wake the aild once per second
Now that the AIL push algorithm is traversal safe, we don't need a watchdog function in the xfsaild to catch pushes that fail to make progress. Remove the watchdog timeout and make pushes purely driven by demand. This will remove the once-per-second wakeup that is seen when the filesystem is idle and make laptop power misers happy.
--- fs/xfs/linux-2.6/xfs_super.c | 7 +++---- fs/xfs/xfs_trans_ail.c | 17 ++++++++++------- 2 files changed, 13 insertions(+), 11 deletions(-)
fs/xfs/linux-2.6/xfs_super.c +3 -4
@@ -877,12 +877,11 @@ xfsaild( {struct xfs_ail *ailp = data;xfs_lsn_t last_pushed_lsn =0 ; -long tout =0 ; +long tout =1000 ;/* milliseconds */ while (!kthread_should_stop ()) { -if (tout) -schedule_timeout_interruptible (msecs_to_jiffies (tout)); - tout =1000 ; + tout = !tout ?MAX_SCHEDULE_TIMEOUT :msecs_to_jiffies (tout); +schedule_timeout_interruptible (tout);/* swsusp */ try_to_freeze ();
fs/xfs/xfs_trans_ail.c +10 -7
@@ -237,14 +237,15 @@ out: }/* -* Function that does the work of pushing on the AIL +* xfsaild_push does the work of pushing on the AIL. Returning a timeout of +* zero indicates that the caller should sleep until woken. */ long xfsaild_push (struct xfs_ail *ailp,xfs_lsn_t *last_lsn) { -long tout =1000 ;/* milliseconds */ +long tout =0 ;xfs_lsn_t last_pushed_lsn = *last_lsn;xfs_lsn_t target = ailp->xa_target;xfs_lsn_t lsn;
@@ -279,7 +280,6 @@ xfsaild_push(* prevents use from spinning when we can't do anything or there is * lots of contention on the AIL lists. */ - tout =10 ; lsn = lip->li_lsn; flush_log = stuck = count =0 ;while ((XFS_LSN_CMP (lip->li_lsn, target) <0 )) {
@@ -376,14 +376,14 @@ xfsaild_push(if (!count) {/* We're past our target or empty, so idle */ - tout =1000 ; + tout =0 ; }else if (XFS_LSN_CMP (lsn, target) >=0 ) {/* * We reached the target so wait a bit longer for I/O to * complete and remove pushed items from the AIL before we * start the next scan from the start of the AIL. */ - tout +=20 ; + tout =50 ; last_pushed_lsn =0 ; }else if ((stuck *100 ) / count >90 ) {/*
@@ -395,11 +395,14 @@ xfsaild_push(* Backoff a bit more to allow some I/O to complete before * continuing from where we were. */ - tout +=10 ; + tout =20 ; + }else { +/* more to do, but wait a short while before continuing */ + tout =10 ; } *last_lsn = last_pushed_lsn;return tout; -}/* xfsaild_push */ +}/*
Signature · 6 lines
1.6.5 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
Re: [PATCH 1/2] XFS: Don't wake the aild once per second
Quoted 5 lines · Dave Chinner
Now that the AIL push algorithm is traversal safe, we don't need a watchdog function in the xfsaild to catch pushes that fail to make progress. Remove the watchdog timeout and make pushes purely driven by demand. This will remove the once-per-second wakeup that is seen when the filesystem is idle and make laptop power misers happy.
Looks good, but a few nitpicks below:
fs/xfs/linux-2.6/xfs_super.c xfsaild( · line 880
Quoted 2 lines
fs/xfs/linux-2.6/xfs_super.c +1
-1-long tout =0 ; +long tout =1000 ;/* milliseconds */
Why do we use a timeout when starting up now? If there's a good reason for it the reason at least should be explained in a comment here.
fs/xfs/linux-2.6/xfs_super.c xfsaild( · line 883
Quoted 5 lines
fs/xfs/linux-2.6/xfs_super.c +1
-3while (!kthread_should_stop ()) { -if (tout) -schedule_timeout_interruptible (msecs_to_jiffies (tout)); - tout =1000 ; + tout = !tout ?MAX_SCHEDULE_TIMEOUT :msecs_to_jiffies (tout);
Why not just:
schedule_timeout_interruptible(tout ? msecs_to_jiffies(tout) : MAX_SCHEDULE_TIMEOUT);
that avoids the assignment of different units to the same variable, and also the negation.
Quoted 13 lines
fs/xfs/xfs_trans_ail.c +1
-1+long tout =0 ;xfs_lsn_t last_pushed_lsn = *last_lsn;xfs_lsn_t target = ailp->xa_target;xfs_lsn_t lsn;@@ -279,7 +280,6 @@ xfsaild_push(* prevents use from spinning when we can't do anything or there is * lots of contention on the AIL lists. */ - tout =10 ; lsn = lip->li_lsn; flush_log = stuck = count =0 ;while ((XFS_LSN_CMP (lip->li_lsn, target) <0 )) {
fs/xfs/xfs_trans_ail.c xfsaild_push( · line 379
Quoted 5 lines
fs/xfs/xfs_trans_ail.c +1
-1@@ -376,14 +376,14 @@ xfsaild_push(if (!count) {/* We're past our target or empty, so idle */ - tout =1000 ; + tout =0 ;
tout always is 0 here already.
Quoted 15 lines
fs/xfs/xfs_trans_ail.c +1
-1}else if (XFS_LSN_CMP (lsn, target) >=0 ) {/* * We reached the target so wait a bit longer for I/O to * complete and remove pushed items from the AIL before we * start the next scan from the start of the AIL. */ - tout +=20 ; + tout =50 ; last_pushed_lsn =0 ; }else if ((stuck *100 ) / count >90 ) {/* @@ -395,11 +395,14 @@ xfsaild_push(* Backoff a bit more to allow some I/O to complete before * continuing from where we were. */
fs/xfs/xfs_trans_ail.c xfsaild_push( · line 405
Quoted 10 lines
fs/xfs/xfs_trans_ail.c +5
-2- tout +=10 ; + tout =20 ; + }else { +/* more to do, but wait a short while before continuing */ + tout =10 ; } *last_lsn = last_pushed_lsn;return tout; -}/* xfsaild_push */ +}
All the += and co here is a bit confusing. We always return 0 now except for those last two cases that return 20 or 10. So I'd just change them to a tout = 10/20;
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Re: [PATCH 1/2] XFS: Don't wake the aild once per second
Quoted 7 lines · Christoph Hellwig
Quoted 5 lines · Dave Chinner
Now that the AIL push algorithm is traversal safe, we don't need a watchdog function in the xfsaild to catch pushes that fail to make progress. Remove the watchdog timeout and make pushes purely driven by demand. This will remove the once-per-second wakeup that is seen when the filesystem is idle and make laptop power misers happy.
Quoted 7 lines
Looks good, but a few nitpicks below:
Review
Quoted 2 lines
(quoted diff) +1
-1- long tout = 0; + long tout = 1000; /* milliseconds */Why do we use a timeout when starting up now? If there's a good reason for it the reason at least should be explained in a comment here.
No good reason.
Quoted 8 lines
Review
Quoted 5 lines
(quoted diff) +1
-3while (!kthread_should_stop()) { - if (tout) - schedule_timeout_interruptible(msecs_to_jiffies(tout)); - tout = 1000; + tout = !tout ? MAX_SCHEDULE_TIMEOUT : msecs_to_jiffies(tout);Why not just:
Quoted 5 lines
schedule_timeout_interruptible(tout ? msecs_to_jiffies(tout) : MAX_SCHEDULE_TIMEOUT);that avoids the assignment of different units to the same variable, and also the negation.
Much cleaner. Fixed.
Quoted 14 lines
Quoted 14 lines
(quoted diff) +1
-1+ long tout = 0; xfs_lsn_t last_pushed_lsn = *last_lsn; xfs_lsn_t target = ailp->xa_target; xfs_lsn_t lsn;@@ -279,7 +280,6 @@ xfsaild_push( * prevents use from spinning when we can't do anything or there is * lots of contention on the AIL lists. */ - tout = 10; lsn = lip->li_lsn; flush_log = stuck = count = 0; while ((XFS_LSN_CMP(lip->li_lsn, target) < 0)) {@@ -376,14 +376,14 @@ xfsaild_push(
Quoted 6 lines
Review xfsaild_push( · line 379
Quoted 4 lines
(quoted diff) +1
-1if (!count) { /* We're past our target or empty, so idle */ - tout = 1000; + tout = 0;tout always is 0 here already.
Good catch. Hmm - I just noticed that we should be resetting the last_lsn when we idle. I've fixed that now.
Quoted 21 lines
Quoted 21 lines
(quoted diff) +5
-2} else if (XFS_LSN_CMP(lsn, target) >= 0) { /* * We reached the target so wait a bit longer for I/O to * complete and remove pushed items from the AIL before we * start the next scan from the start of the AIL. */ - tout += 20; + tout = 50; last_pushed_lsn = 0; } else if ((stuck * 100) / count > 90) { /*@@ -395,11 +395,14 @@ xfsaild_push( * Backoff a bit more to allow some I/O to complete before * continuing from where we were. */ - tout += 10; + tout = 20; + } else { + /* more to do, but wait a short while before continuing */ + tout = 10; }
Quoted 8 lines
Review xfsaild_push( · line 405
Quoted 4 lines
(quoted diff) +1
-1*last_lsn = last_pushed_lsn; return tout; -} /* xfsaild_push */ +}All the += and co here is a bit confusing. We always return 0 now except for those last two cases that return 20 or 10. So I'd just change them to a tout = 10/20;
I'm not sure what you mean - isn't that what this patch does? i.e. now looks like:
if idle tout = 0 else if we reach the target tout = 50 else if stuck tout = 20 else tout = 10
Updated patch below.
Cheers,
Dave.
Signature · 16 lines
Dave Chinner [email protected] XFS: Don't wake the aild once per second Now that the AIL push algorithm is traversal safe, we don't need a watchdog function in the xfsaild to catch pushes that fail to make progress. Remove the watchdog timeout and make pushes purely driven by demand. This will remove the once-per-second wakeup that is seen when the filesystem is idle and make laptop power misers happy. Signed-off-by: Dave Chinner <[email protected]> --- fs/xfs/linux-2.6/xfs_super.c | 7 +++---- fs/xfs/xfs_trans_ail.c | 19 +++++++++++-------- 2 files changed, 14 insertions(+), 12 deletions(-)
fs/xfs/linux-2.6/xfs_super.c +3 -4
@@ -877,12 +877,11 @@ xfsaild( {struct xfs_ail *ailp = data;xfs_lsn_t last_pushed_lsn =0 ; -long tout =0 ; +long tout =0 ;/* milliseconds */ while (!kthread_should_stop ()) { -if (tout) -schedule_timeout_interruptible (msecs_to_jiffies (tout)); - tout =1000 ; +schedule_timeout_interruptible (tout ? +msecs_to_jiffies (tout) :MAX_SCHEDULE_TIMEOUT );/* swsusp */ try_to_freeze ();
fs/xfs/xfs_trans_ail.c +11 -8
@@ -237,14 +237,15 @@ out: }/* -* Function that does the work of pushing on the AIL +* xfsaild_push does the work of pushing on the AIL. Returning a timeout of +* zero indicates that the caller should sleep until woken. */ long xfsaild_push (struct xfs_ail *ailp,xfs_lsn_t *last_lsn) { -long tout =1000 ;/* milliseconds */ +long tout =0 ;xfs_lsn_t last_pushed_lsn = *last_lsn;xfs_lsn_t target = ailp->xa_target;xfs_lsn_t lsn;
@@ -262,7 +263,7 @@ xfsaild_push(*/ xfs_trans_ail_cursor_done (ailp, cur);spin_unlock (&ailp->xa_lock); - last_pushed_lsn =0 ; + *last_lsn =0 ;return tout; }
@@ -279,7 +280,6 @@ xfsaild_push(* prevents use from spinning when we can't do anything or there is * lots of contention on the AIL lists. */ - tout =10 ; lsn = lip->li_lsn; flush_log = stuck = count =0 ;while ((XFS_LSN_CMP (lip->li_lsn, target) <0 )) {
@@ -376,14 +376,14 @@ xfsaild_push(if (!count) {/* We're past our target or empty, so idle */ - tout =1000 ; + last_pushed_lsn =0 ; }else if (XFS_LSN_CMP (lsn, target) >=0 ) {/* * We reached the target so wait a bit longer for I/O to * complete and remove pushed items from the AIL before we * start the next scan from the start of the AIL. */ - tout +=20 ; + tout =50 ; last_pushed_lsn =0 ; }else if ((stuck *100 ) / count >90 ) {/*
@@ -395,11 +395,14 @@ xfsaild_push(* Backoff a bit more to allow some I/O to complete before * continuing from where we were. */ - tout +=10 ; + tout =20 ; + }else { +/* more to do, but wait a short while before continuing */ + tout =10 ; } *last_lsn = last_pushed_lsn;return tout; -}/* xfsaild_push */ +}/*
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
PATCH 2/2 XFS: Don't wake xfsbufd when idle
In reply to Dave ChinnerThe xfsbufd wakes every xfsbufd_centisecs (once per second by default) for each filesystem even when the filesystem is idle. If the xfsbufd has nothing to do, put it into a long term sleep and only wake it up when there is work pending (i.e. dirty buffers to flush soon). This will make laptop power misers happy.
--- fs/xfs/linux-2.6/xfs_buf.c | 28 +++++++++++++++++++--------- 1 files changed, 19 insertions(+), 9 deletions(-)
fs/xfs/linux-2.6/xfs_buf.c +19 -9
@@ -43,10 +43,10 @@static kmem_zone_t *xfs_buf_zone; STATIC int xfsbufd(void *); -STATIC int xfsbufd_wakeup(int, gfp_t); +STATIC int xfsbufd_wakeup_all(int, gfp_t); STATIC void xfs_buf_delwri_queue(xfs_buf_t *, int);static struct shrinker xfs_buf_shake = { - .shrink = xfsbufd_wakeup, + .shrink = xfsbufd_wakeup_all, .seeks =DEFAULT_SEEKS , };
@@ -385,7 +385,7 @@ _xfs_buf_lookup_pages( __func__, gfp_mask);XFS_STATS_INC (xb_page_retries); -xfsbufd_wakeup (0 , gfp_mask); +xfsbufd_wakeup_all (0 , gfp_mask);congestion_wait (BLK_RW_ASYNC ,HZ /50 ); goto retry; }
@@ -1595,6 +1595,11 @@ xfs_buf_delwri_queue(list_del (&bp->b_list); } +if (list_empty (dwq)) { +/* start xfsbufd as it has something to do now */ +wake_up_process (bp->b_target->bt_task); + } + bp->b_flags |= _XBF_DELWRI_Q;list_add_tail (&bp->b_list, dwq); bp->b_queuetime = jiffies;
@@ -1634,7 +1639,7 @@ xfs_buf_runall_queues( } STATIC int -xfsbufd_wakeup ( +xfsbufd_wakeup_all (int priority,gfp_t mask) {
@@ -1644,6 +1649,8 @@ xfsbufd_wakeup(list_for_each_entry (btp, &xfs_buftarg_list, bt_list) {if (test_bit (XBT_FORCE_SLEEP , &btp->bt_flags))continue ; +if (list_empty (&btp->bt_delwrite_queue)) +continue ;set_bit (XBT_FORCE_FLUSH , &btp->bt_flags);wake_up_process (btp->bt_task); }
@@ -1708,6 +1715,9 @@ xfsbufd(set_freezable (); do { + long age = xfs_buf_age_centisecs * msecs_to_jiffies(10); + long tout = age; + if (unlikely(freezing(current))) { set_bit(XBT_FORCE_SLEEP, &target->bt_flags); refrigerator();
@@ -1715,12 +1725,12 @@ xfsbufd(clear_bit (XBT_FORCE_SLEEP , &target->bt_flags); } -schedule_timeout_interruptible ( - xfs_buf_timer_centisecs *msecs_to_jiffies (10 )); - -xfs_buf_delwri_split (target, &tmp, - xfs_buf_age_centisecs *msecs_to_jiffies (10 )); +/* sleep for a long time if there is nothing to do. */ +if (list_empty (&target->bt_delwrite_queue)) + tout =MAX_SCHEDULE_TIMEOUT ; +schedule_timeout_interruptible (tout); +xfs_buf_delwri_split (target, &tmp, age); count =0 ;while (!list_empty (&tmp)) { bp =list_entry (tmp.next, xfs_buf_t, b_list);
Signature · 6 lines
1.6.5 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
Re: [PATCH 2/2] XFS: Don't wake xfsbufd when idle
Quoted 13 lines · Dave Chinner
The xfsbufd wakes every
xfsbufd_centisecs(once per second by default) for each filesystem even when the filesystem is idle. If the xfsbufd has nothing to do, put it into a long term sleep and only wake it up when there is work pending (i.e. dirty buffers to flush soon). This will make laptop power misers happy.Signed-off-by Dave Chinner <[email protected]>--- fs/xfs/linux-2.6/xfs_buf.c | 28 +++++++++++++++++++--------- 1 files changed, 19 insertions(+), 9 deletions(-)STATIC int
xfsbufd(void *);
fs/xfs/linux-2.6/xfs_buf.c line 46
Quoted 2 lines
fs/xfs/linux-2.6/xfs_buf.c +1
-1-STATIC int xfsbufd_wakeup(int, gfp_t); +STATIC int xfsbufd_wakeup_all(int, gfp_t);
this rename seems unrelated to the rest of the patch.
fs/xfs/linux-2.6/xfs_buf.c xfs_buf_delwri_queue( · line 1601
Quoted 8 lines
fs/xfs/linux-2.6/xfs_buf.c +4
-0@@ -1595,6 +1595,11 @@ xfs_buf_delwri_queue(list_del (&bp->b_list); } +if (list_empty (dwq)) { +/* start xfsbufd as it has something to do now */ +wake_up_process (bp->b_target->bt_task); + }
Does it make sense to wake xfsbufd before actually adding the item and unlocking the queue lock? Shouldn't this be defered until after the addition?
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Re: [PATCH 2/2] XFS: Don't wake xfsbufd when idle
Quoted 13 lines · Christoph Hellwig
Quoted 11 lines · Dave Chinner
The xfsbufd wakes every
xfsbufd_centisecs(once per second by default) for each filesystem even when the filesystem is idle. If the xfsbufd has nothing to do, put it into a long term sleep and only wake it up when there is work pending (i.e. dirty buffers to flush soon). This will make laptop power misers happy.Signed-off-by Dave Chinner <[email protected]>--- fs/xfs/linux-2.6/xfs_buf.c | 28 +++++++++++++++++++--------- 1 files changed, 19 insertions(+), 9 deletions(-)
Quoted 5 lines
fs/xfs/linux-2.6/xfs_buf.c line 46
Quoted 3 lines
STATIC int
xfsbufd(void *);fs/xfs/linux-2.6/xfs_buf.c +1
-1-STATIC int xfsbufd_wakeup(int, gfp_t); +STATIC int xfsbufd_wakeup_all(int, gfp_t);this rename seems unrelated to the rest of the patch.
For memory reclaim we want to wake up the xfsbufd threads on every single filesystem to free up as much memory as possible. Hence with the addition of demand flushing we have a situation now where we can wakeup either a single xfsbufd or we need to wake up all of them. It seemed right to make the distinction clear by renaming the function. I can drop it if this doesn't make sense....
Quoted 4 lines
Quoted 4 lines
fs/xfs/linux-2.6/xfs_buf.c +0
-0@@ -1595,6 +1595,11 @@ xfs_buf_delwri_queue(list_del (&bp->b_list); }
Quoted 8 lines
fs/xfs/linux-2.6/xfs_buf.c xfs_buf_delwri_queue( · line 1601
Quoted 4 lines
fs/xfs/linux-2.6/xfs_buf.c +4
-0+if (list_empty (dwq)) { +/* start xfsbufd as it has something to do now */ +wake_up_process (bp->b_target->bt_task); + }Does it make sense to wake xfsbufd before actually adding the item and unlocking the queue lock? Shouldn't this be defered until after the addition?
I did it to avoid a temp var - if the xfsbufd runs before we finish here then is will spin on the lock until we have added the buffer to the list and dropped the lock. wake_up_process() is safe to call under a spinlock, so that is not an issue here.
Also, the xfsbufd checks for an empty list before it sleeps, so on wakeup it will always see the newly added buffer because it tries unconditionally to dequeue buffers on wakeup. Hence I think this is safe and race free.
Cheers,
Dave.
Signature · 7 lines
Dave Chinner [email protected] _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs