diff options
| author | Tejun Heo <tj@kernel.org> | 2013-01-24 14:39:44 -0500 |
|---|---|---|
| committer | Tejun Heo <tj@kernel.org> | 2013-02-07 16:14:20 -0500 |
| commit | e19e397a85f33100bfa4210e256bec82fe22e167 (patch) | |
| tree | 18b9b0f883561584027a0085586d4f31abcba213 | |
| parent | 1606283622689bdc460052b4a1281c36de13fe49 (diff) | |
workqueue: move nr_running into worker_pool
As nr_running is likely to be accessed from other CPUs during
try_to_wake_up(), it was kept outside worker_pool; however, while less
frequent, other fields in worker_pool are accessed from other CPUs
for, e.g., non-reentrancy check. Also, with recent pool related
changes, accessing nr_running matching the worker_pool isn't as simple
as it used to be.
Move nr_running inside worker_pool. Keep it aligned to cacheline and
define CPU pools using DEFINE_PER_CPU_SHARED_ALIGNED(). This should
give at least the same cacheline behavior.
get_pool_nr_running() is replaced with direct pool->nr_running
accesses.
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Joonsoo Kim <js1304@gmail.com>
| -rw-r--r-- | kernel/workqueue.c | 63 |
1 files changed, 22 insertions, 41 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index e2dd61861fbd..91ce7a984c22 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c | |||
| @@ -144,6 +144,13 @@ struct worker_pool { | |||
| 144 | 144 | ||
| 145 | struct mutex assoc_mutex; /* protect POOL_DISASSOCIATED */ | 145 | struct mutex assoc_mutex; /* protect POOL_DISASSOCIATED */ |
| 146 | struct ida worker_ida; /* L: for worker IDs */ | 146 | struct ida worker_ida; /* L: for worker IDs */ |
| 147 | |||
| 148 | /* | ||
| 149 | * The current concurrency level. As it's likely to be accessed | ||
| 150 | * from other CPUs during try_to_wake_up(), put it in a separate | ||
| 151 | * cacheline. | ||
| 152 | */ | ||
| 153 | atomic_t nr_running ____cacheline_aligned_in_smp; | ||
| 147 | } ____cacheline_aligned_in_smp; | 154 | } ____cacheline_aligned_in_smp; |
| 148 | 155 | ||
| 149 | /* | 156 | /* |
| @@ -417,23 +424,12 @@ static LIST_HEAD(workqueues); | |||
| 417 | static bool workqueue_freezing; /* W: have wqs started freezing? */ | 424 | static bool workqueue_freezing; /* W: have wqs started freezing? */ |
| 418 | 425 | ||
| 419 | /* | 426 | /* |
| 420 | * The CPU standard worker pools. nr_running is the only field which is | 427 | * The CPU and unbound standard worker pools. The unbound ones have |
| 421 | * expected to be used frequently by other cpus via try_to_wake_up(). Put | 428 | * POOL_DISASSOCIATED set, and their workers have WORKER_UNBOUND set. |
| 422 | * it in a separate cacheline. | ||
| 423 | */ | ||
| 424 | static DEFINE_PER_CPU(struct worker_pool [NR_STD_WORKER_POOLS], | ||
| 425 | cpu_std_worker_pools); | ||
| 426 | static DEFINE_PER_CPU_SHARED_ALIGNED(atomic_t [NR_STD_WORKER_POOLS], | ||
| 427 | cpu_std_pool_nr_running); | ||
| 428 | |||
| 429 | /* | ||
| 430 | * Standard worker pools and nr_running counter for unbound CPU. The pools | ||
| 431 | * have POOL_DISASSOCIATED set, and all workers have WORKER_UNBOUND set. | ||
| 432 | */ | 429 | */ |
| 430 | static DEFINE_PER_CPU_SHARED_ALIGNED(struct worker_pool [NR_STD_WORKER_POOLS], | ||
| 431 | cpu_std_worker_pools); | ||
| 433 | static struct worker_pool unbound_std_worker_pools[NR_STD_WORKER_POOLS]; | 432 | static struct worker_pool unbound_std_worker_pools[NR_STD_WORKER_POOLS]; |
| 434 | static atomic_t unbound_std_pool_nr_running[NR_STD_WORKER_POOLS] = { | ||
| 435 | [0 ... NR_STD_WORKER_POOLS - 1] = ATOMIC_INIT(0), /* always 0 */ | ||
| 436 | }; | ||
| 437 | 433 | ||
| 438 | /* idr of all pools */ | 434 | /* idr of all pools */ |
| 439 | static DEFINE_MUTEX(worker_pool_idr_mutex); | 435 | static DEFINE_MUTEX(worker_pool_idr_mutex); |
| @@ -483,17 +479,6 @@ static struct worker_pool *get_std_worker_pool(int cpu, bool highpri) | |||
| 483 | return &pools[highpri]; | 479 | return &pools[highpri]; |
| 484 | } | 480 | } |
| 485 | 481 | ||
| 486 | static atomic_t *get_pool_nr_running(struct worker_pool *pool) | ||
| 487 | { | ||
| 488 | int cpu = pool->cpu; | ||
| 489 | int idx = std_worker_pool_pri(pool); | ||
| 490 | |||
| 491 | if (cpu != WORK_CPU_UNBOUND) | ||
| 492 | return &per_cpu(cpu_std_pool_nr_running, cpu)[idx]; | ||
| 493 | else | ||
| 494 | return &unbound_std_pool_nr_running[idx]; | ||
| 495 | } | ||
| 496 | |||
| 497 | static struct cpu_workqueue_struct *get_cwq(unsigned int cpu, | 482 | static struct cpu_workqueue_struct *get_cwq(unsigned int cpu, |
| 498 | struct workqueue_struct *wq) | 483 | struct workqueue_struct *wq) |
| 499 | { | 484 | { |
| @@ -654,7 +639,7 @@ static bool work_is_canceling(struct work_struct *work) | |||
| 654 | 639 | ||
| 655 | static bool __need_more_worker(struct worker_pool *pool) | 640 | static bool __need_more_worker(struct worker_pool *pool) |
| 656 | { | 641 | { |
| 657 | return !atomic_read(get_pool_nr_running(pool)); | 642 | return !atomic_read(&pool->nr_running); |
| 658 | } | 643 | } |
| 659 | 644 | ||
| 660 | /* | 645 | /* |
| @@ -679,9 +664,8 @@ static bool may_start_working(struct worker_pool *pool) | |||
| 679 | /* Do I need to keep working? Called from currently running workers. */ | 664 | /* Do I need to keep working? Called from currently running workers. */ |
| 680 | static bool keep_working(struct worker_pool *pool) | 665 | static bool keep_working(struct worker_pool *pool) |
| 681 | { | 666 | { |
| 682 | atomic_t *nr_running = get_pool_nr_running(pool); | 667 | return !list_empty(&pool->worklist) && |
| 683 | 668 | atomic_read(&pool->nr_running) <= 1; | |
| 684 | return !list_empty(&pool->worklist) && atomic_read(nr_running) <= 1; | ||
| 685 | } | 669 | } |
| 686 | 670 | ||
| 687 | /* Do we need a new worker? Called from manager. */ | 671 | /* Do we need a new worker? Called from manager. */ |
| @@ -761,7 +745,7 @@ void wq_worker_waking_up(struct task_struct *task, unsigned int cpu) | |||
| 761 | 745 | ||
| 762 | if (!(worker->flags & WORKER_NOT_RUNNING)) { | 746 | if (!(worker->flags & WORKER_NOT_RUNNING)) { |
| 763 | WARN_ON_ONCE(worker->pool->cpu != cpu); | 747 | WARN_ON_ONCE(worker->pool->cpu != cpu); |
| 764 | atomic_inc(get_pool_nr_running(worker->pool)); | 748 | atomic_inc(&worker->pool->nr_running); |
| 765 | } | 749 | } |
| 766 | } | 750 | } |
| 767 | 751 | ||
| @@ -785,7 +769,6 @@ struct task_struct *wq_worker_sleeping(struct task_struct *task, | |||
| 785 | { | 769 | { |
| 786 | struct worker *worker = kthread_data(task), *to_wakeup = NULL; | 770 | struct worker *worker = kthread_data(task), *to_wakeup = NULL; |
| 787 | struct worker_pool *pool; | 771 | struct worker_pool *pool; |
| 788 | atomic_t *nr_running; | ||
| 789 | 772 | ||
| 790 | /* | 773 | /* |
| 791 | * Rescuers, which may not have all the fields set up like normal | 774 | * Rescuers, which may not have all the fields set up like normal |
| @@ -796,7 +779,6 @@ struct task_struct *wq_worker_sleeping(struct task_struct *task, | |||
| 796 | return NULL; | 779 | return NULL; |
| 797 | 780 | ||
| 798 | pool = worker->pool; | 781 | pool = worker->pool; |
| 799 | nr_running = get_pool_nr_running(pool); | ||
| 800 | 782 | ||
| 801 | /* this can only happen on the local cpu */ | 783 | /* this can only happen on the local cpu */ |
| 802 | BUG_ON(cpu != raw_smp_processor_id()); | 784 | BUG_ON(cpu != raw_smp_processor_id()); |
| @@ -812,7 +794,8 @@ struct task_struct *wq_worker_sleeping(struct task_struct *task, | |||
| 812 | * manipulating idle_list, so dereferencing idle_list without pool | 794 | * manipulating idle_list, so dereferencing idle_list without pool |
| 813 | * lock is safe. | 795 | * lock is safe. |
| 814 | */ | 796 | */ |
| 815 | if (atomic_dec_and_test(nr_running) && !list_empty(&pool->worklist)) | 797 | if (atomic_dec_and_test(&pool->nr_running) && |
| 798 | !list_empty(&pool->worklist)) | ||
| 816 | to_wakeup = first_worker(pool); | 799 | to_wakeup = first_worker(pool); |
| 817 | return to_wakeup ? to_wakeup->task : NULL; | 800 | return to_wakeup ? to_wakeup->task : NULL; |
| 818 | } | 801 | } |
| @@ -844,14 +827,12 @@ static inline void worker_set_flags(struct worker *worker, unsigned int flags, | |||
| 844 | */ | 827 | */ |
| 845 | if ((flags & WORKER_NOT_RUNNING) && | 828 | if ((flags & WORKER_NOT_RUNNING) && |
| 846 | !(worker->flags & WORKER_NOT_RUNNING)) { | 829 | !(worker->flags & WORKER_NOT_RUNNING)) { |
| 847 | atomic_t *nr_running = get_pool_nr_running(pool); | ||
| 848 | |||
| 849 | if (wakeup) { | 830 | if (wakeup) { |
| 850 | if (atomic_dec_and_test(nr_running) && | 831 | if (atomic_dec_and_test(&pool->nr_running) && |
| 851 | !list_empty(&pool->worklist)) | 832 | !list_empty(&pool->worklist)) |
| 852 | wake_up_worker(pool); | 833 | wake_up_worker(pool); |
| 853 | } else | 834 | } else |
| 854 | atomic_dec(nr_running); | 835 | atomic_dec(&pool->nr_running); |
| 855 | } | 836 | } |
| 856 | 837 | ||
| 857 | worker->flags |= flags; | 838 | worker->flags |= flags; |
| @@ -883,7 +864,7 @@ static inline void worker_clr_flags(struct worker *worker, unsigned int flags) | |||
| 883 | */ | 864 | */ |
| 884 | if ((flags & WORKER_NOT_RUNNING) && (oflags & WORKER_NOT_RUNNING)) | 865 | if ((flags & WORKER_NOT_RUNNING) && (oflags & WORKER_NOT_RUNNING)) |
| 885 | if (!(worker->flags & WORKER_NOT_RUNNING)) | 866 | if (!(worker->flags & WORKER_NOT_RUNNING)) |
| 886 | atomic_inc(get_pool_nr_running(pool)); | 867 | atomic_inc(&pool->nr_running); |
| 887 | } | 868 | } |
| 888 | 869 | ||
| 889 | /** | 870 | /** |
| @@ -1518,7 +1499,7 @@ static void worker_enter_idle(struct worker *worker) | |||
| 1518 | */ | 1499 | */ |
| 1519 | WARN_ON_ONCE(!(pool->flags & POOL_DISASSOCIATED) && | 1500 | WARN_ON_ONCE(!(pool->flags & POOL_DISASSOCIATED) && |
| 1520 | pool->nr_workers == pool->nr_idle && | 1501 | pool->nr_workers == pool->nr_idle && |
| 1521 | atomic_read(get_pool_nr_running(pool))); | 1502 | atomic_read(&pool->nr_running)); |
| 1522 | } | 1503 | } |
| 1523 | 1504 | ||
| 1524 | /** | 1505 | /** |
| @@ -3506,7 +3487,7 @@ static void wq_unbind_fn(struct work_struct *work) | |||
| 3506 | * didn't already. | 3487 | * didn't already. |
| 3507 | */ | 3488 | */ |
| 3508 | for_each_std_worker_pool(pool, cpu) | 3489 | for_each_std_worker_pool(pool, cpu) |
| 3509 | atomic_set(get_pool_nr_running(pool), 0); | 3490 | atomic_set(&pool->nr_running, 0); |
| 3510 | } | 3491 | } |
| 3511 | 3492 | ||
| 3512 | /* | 3493 | /* |
