diff options
author | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2010-12-14 20:36:02 -0500 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2010-12-17 15:34:49 -0500 |
commit | b52573d2796274f7f31cfeff7185c320adcd4f12 (patch) | |
tree | 61580632fa8fbf80225ba7339274ada0c013a01b /kernel/rcutree.c | |
parent | 0209f6490b030f35349a2bb71294f3fd75b0f36d (diff) |
rcu: reduce __call_rcu()-induced contention on rcu_node structures
When the current __call_rcu() function was written, the expedited
APIs did not exist. The __call_rcu() implementation therefore went
to great lengths to detect the end of old grace periods and to start
new ones, all in the name of reducing grace-period latency. Now the
expedited APIs do exist, and the usage of __call_rcu() has increased
considerably. This commit therefore causes __call_rcu() to avoid
worrying about grace periods unless there are a large number of
RCU callbacks stacked up on the current CPU.
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Diffstat (limited to 'kernel/rcutree.c')
-rw-r--r-- | kernel/rcutree.c | 38 |
1 files changed, 21 insertions, 17 deletions
diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 01c8ad33c510..d0ddfea6579d 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c | |||
@@ -1435,22 +1435,11 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu), | |||
1435 | */ | 1435 | */ |
1436 | local_irq_save(flags); | 1436 | local_irq_save(flags); |
1437 | rdp = this_cpu_ptr(rsp->rda); | 1437 | rdp = this_cpu_ptr(rsp->rda); |
1438 | rcu_process_gp_end(rsp, rdp); | ||
1439 | check_for_new_grace_period(rsp, rdp); | ||
1440 | 1438 | ||
1441 | /* Add the callback to our list. */ | 1439 | /* Add the callback to our list. */ |
1442 | *rdp->nxttail[RCU_NEXT_TAIL] = head; | 1440 | *rdp->nxttail[RCU_NEXT_TAIL] = head; |
1443 | rdp->nxttail[RCU_NEXT_TAIL] = &head->next; | 1441 | rdp->nxttail[RCU_NEXT_TAIL] = &head->next; |
1444 | 1442 | ||
1445 | /* Start a new grace period if one not already started. */ | ||
1446 | if (!rcu_gp_in_progress(rsp)) { | ||
1447 | unsigned long nestflag; | ||
1448 | struct rcu_node *rnp_root = rcu_get_root(rsp); | ||
1449 | |||
1450 | raw_spin_lock_irqsave(&rnp_root->lock, nestflag); | ||
1451 | rcu_start_gp(rsp, nestflag); /* releases rnp_root->lock. */ | ||
1452 | } | ||
1453 | |||
1454 | /* | 1443 | /* |
1455 | * Force the grace period if too many callbacks or too long waiting. | 1444 | * Force the grace period if too many callbacks or too long waiting. |
1456 | * Enforce hysteresis, and don't invoke force_quiescent_state() | 1445 | * Enforce hysteresis, and don't invoke force_quiescent_state() |
@@ -1459,12 +1448,27 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu), | |||
1459 | * is the only one waiting for a grace period to complete. | 1448 | * is the only one waiting for a grace period to complete. |
1460 | */ | 1449 | */ |
1461 | if (unlikely(++rdp->qlen > rdp->qlen_last_fqs_check + qhimark)) { | 1450 | if (unlikely(++rdp->qlen > rdp->qlen_last_fqs_check + qhimark)) { |
1462 | rdp->blimit = LONG_MAX; | 1451 | |
1463 | if (rsp->n_force_qs == rdp->n_force_qs_snap && | 1452 | /* Are we ignoring a completed grace period? */ |
1464 | *rdp->nxttail[RCU_DONE_TAIL] != head) | 1453 | rcu_process_gp_end(rsp, rdp); |
1465 | force_quiescent_state(rsp, 0); | 1454 | check_for_new_grace_period(rsp, rdp); |
1466 | rdp->n_force_qs_snap = rsp->n_force_qs; | 1455 | |
1467 | rdp->qlen_last_fqs_check = rdp->qlen; | 1456 | /* Start a new grace period if one not already started. */ |
1457 | if (!rcu_gp_in_progress(rsp)) { | ||
1458 | unsigned long nestflag; | ||
1459 | struct rcu_node *rnp_root = rcu_get_root(rsp); | ||
1460 | |||
1461 | raw_spin_lock_irqsave(&rnp_root->lock, nestflag); | ||
1462 | rcu_start_gp(rsp, nestflag); /* rlses rnp_root->lock */ | ||
1463 | } else { | ||
1464 | /* Give the grace period a kick. */ | ||
1465 | rdp->blimit = LONG_MAX; | ||
1466 | if (rsp->n_force_qs == rdp->n_force_qs_snap && | ||
1467 | *rdp->nxttail[RCU_DONE_TAIL] != head) | ||
1468 | force_quiescent_state(rsp, 0); | ||
1469 | rdp->n_force_qs_snap = rsp->n_force_qs; | ||
1470 | rdp->qlen_last_fqs_check = rdp->qlen; | ||
1471 | } | ||
1468 | } else if (ULONG_CMP_LT(ACCESS_ONCE(rsp->jiffies_force_qs), jiffies)) | 1472 | } else if (ULONG_CMP_LT(ACCESS_ONCE(rsp->jiffies_force_qs), jiffies)) |
1469 | force_quiescent_state(rsp, 1); | 1473 | force_quiescent_state(rsp, 1); |
1470 | local_irq_restore(flags); | 1474 | local_irq_restore(flags); |