* If nohz_full is enabled, set power efficient workqueue as unbound. * This allows workqueue items to be moved to HK CPUs. */ if (housekeeping_enabled(HK_TYPE_TICK)) wq_power_efficient = true; /* initialize WQ_AFFN_SYSTEM pods */ pt->pod_cpus = kzalloc_objs(pt->pod_cpus[0], 1); pt->pod_node = kzalloc_objs(pt->pod_node[0], 1); pt->cpu_pod = kzalloc_objs(pt->cpu_pod[0], nr_cpu_ids); BUG_ON(!pt->pod_cpus || !pt->pod_node || !pt->cpu_pod); BUG_ON(!zalloc_cpumask_var_node(&pt->pod_cpus[0], GFP_KERNEL, NUMA_NO_NODE)); pt->nr_pods = 1; cpumask_copy(pt->pod_cpus[0], cpu_possible_mask); pt->pod_node[0] = NUMA_NO_NODE; pt->cpu_pod[0] = 0; /* initialize BH and CPU pools */ for_each_possible_cpu(cpu) { struct worker_pool *pool; i = 0; for_each_bh_worker_pool(pool, cpu) { init_cpu_worker_pool(pool, cpu, std_nice[i]); pool->flags |= POOL_BH; init_irq_work(bh_pool_irq_work(pool), irq_work_fns[i]); i++; } i = 0; for_each_cpu_worker_pool(pool, cpu) init_cpu_worker_pool(pool, cpu, std_nice[i++]); } /* create default unbound and ordered wq attrs */ for (i = 0; i < NR_STD_WORKER_POOLS; i++) { struct workqueue_attrs *attrs; BUG_ON(!(attrs = alloc_workqueue_attrs())); attrs->nice = std_nice[i]; unbound_std_wq_attrs[i] = attrs; /* * An ordered wq should have only one pwq as ordering is * guaranteed by max_active which is enforced by pwqs. */ BUG_ON(!(attrs = alloc_workqueue_attrs())); attrs->nice = std_nice[i]; attrs->ordered = true; ordered_wq_attrs[i] = attrs; } system_wq = alloc_workqueue("events", WQ_PERCPU | __WQ_DEPRECATED, 0); system_percpu_wq = alloc_workqueue("events", WQ_PERCPU, 0); system_highpri_wq = alloc_workqueue("events_highpri", WQ_HIGHPRI | WQ_PERCPU, 0); system_long_wq = alloc_workqueue("events_long", WQ_PERCPU, 0); system_unbound_wq = alloc_workqueue("events_unbound", WQ_UNBOUND | __WQ_DEPRECATED, WQ_MAX_ACTIVE); system_dfl_wq = alloc_workqueue("events_unbound", WQ_UNBOUND, WQ_MAX_ACTIVE); system_freezable_wq = alloc_workqueue("events_freezable", WQ_FREEZABLE | WQ_PERCPU, 0); system_power_efficient_wq = alloc_workqueue("events_power_efficient", WQ_POWER_EFFICIENT | WQ_PERCPU, 0); system_freezable_power_efficient_wq = alloc_workqueue("events_freezable_pwr_efficient", WQ_FREEZABLE | WQ_POWER_EFFICIENT | WQ_PERCPU, 0); system_bh_wq = alloc_workqueue("events_bh", WQ_BH | WQ_PERCPU, 0); system_bh_highpri_wq = alloc_workqueue("events_bh_highpri", WQ_BH | WQ_HIGHPRI | WQ_PERCPU, 0); system_dfl_long_wq = alloc_workqueue("events_dfl_long", WQ_UNBOUND, WQ_MAX_ACTIVE); BUG_ON(!system_wq || !system_percpu_wq|| !system_highpri_wq || !system_long_wq || !system_unbound_wq || !system_freezable_wq || !system_dfl_wq || !system_power_efficient_wq || !system_freezable_power_efficient_wq || !system_bh_wq || !system_bh_highpri_wq || !system_dfl_long_wq);} static void __init wq_cpu_intensive_thresh_init(void){ unsigned long thresh; unsigned long bogo; pwq_release_worker = kthread_run_worker(0, "pool_workqueue_release"); BUG_ON(IS_ERR(pwq_release_worker)); /* if the user set it to a specific value, keep it */ if (wq_cpu_intensive_thresh_us != ULONG_MAX) return; /* * The default of 10ms is derived from the fact that most modern (as of * 2023) processors can do a lot in 10ms and that it's just below what * most consider human-perceivable. However, the kernel also runs on a * lot slower CPUs including microcontrollers where the threshold is way * too low. * * Let's scale up the threshold upto 1 second if BogoMips is below 4000. * This is by no means accurate but it doesn't have to be. The mechanism * is still useful even when the threshold is fully scaled up. Also, as * the reports would usually be applicable to everyone, some machines * operating on longer thresholds won't significantly diminish their * usefulness. */ thresh = 10 * USEC_PER_MSEC; /* see init/calibrate.c for lpj -> BogoMIPS calculation */ bogo = max_t(unsigned long, loops_per_jiffy / 500000 * HZ, 1); if (bogo < 4000) thresh = min_t(unsigned long, thresh * 4000 / bogo, USEC_PER_SEC); pr_debug("wq_cpu_intensive_thresh: lpj=%lu BogoMIPS=%lu thresh_us=%lu\n", loops_per_jiffy, bogo, thresh); wq_cpu_intensive_thresh_us = thresh;} /** * workqueue_init - bring workqueue subsystem fully online * * This is the second step of three-staged workqueue subsystem initialization * and invoked as soon as kthreads can be created and scheduled. Workqueues have * been created and work items queued on them, but there are no kworkers * executing the work items yet. Populate the worker pools with the initial * workers and enable future kworker creations. */void __init workqueue_init(void){ struct workqueue_struct *wq; struct worker_pool *pool; int cpu, bkt; wq_cpu_intensive_thresh_init(); mutex_lock(&wq_pool_mutex); /* * Per-cpu pools created earlier could be missing node hint. Fix them * up. Also, create a rescuer for workqueues that requested it. */ for_each_possible_cpu(cpu) { for_each_bh_worker_pool(pool, cpu) pool->node = cpu_to_node(cpu); for_each_cpu_worker_pool(pool, cpu) pool->node = cpu_to_node(cpu); } list_for_each_entry(wq, &workqueues, list) { WARN(init_rescuer(wq), "workqueue: failed to create early rescuer for %s", wq->name); } mutex_unlock(&wq_pool_mutex); /* * Create the initial workers. A BH pool has one pseudo worker that * represents the shared BH execution context and thus doesn't get * affected by hotplug events. Create the BH pseudo workers for all * possible CPUs here. */ for_each_possible_cpu(cpu) for_each_bh_worker_pool(pool, cpu) BUG_ON(!create_worker(pool)); for_each_online_cpu(cpu) { for_each_cpu_worker_pool(pool, cpu) { pool->flags &= ~POOL_DISASSOCIATED; BUG_ON(!create_worker(pool)); } } hash_for_each(unbound_pool_hash, bkt, pool, hash_node) BUG_ON(!create_worker(pool)); wq_online = true; wq_watchdog_init();} /* * Initialize @pt by first initializing @pt->cpu_pod[] with pod IDs according to * @cpu_shares_pod(). Each subset of CPUs that share a pod is assigned a unique * and consecutive pod ID. The rest of @pt is initialized accordingly. */static void __init init_pod_type(struct wq_pod_type *pt, bool (*cpus_share_pod)(int, int)){ int cur, pre, cpu, pod; pt->nr_pods = 0; /* init @pt->cpu_pod[] according to @cpus_share_pod() */ pt->cpu_pod = kzalloc_objs(pt->cpu_pod[0], nr_cpu_ids); BUG_ON(!pt->cpu_pod); for_each_possible_cpu(cur) { for_each_possible_cpu(pre) { if (pre >= cur) { pt->cpu_pod[cur] = pt->nr_pods++; break; } if (cpus_share_pod(cur, pre)) { pt->cpu_pod[cur] = pt->cpu_pod[pre]; break; } } } /* init the rest to match @pt->cpu_pod[] */ pt->pod_cpus = kzalloc_objs(pt->pod_cpus[0], pt->nr_pods); pt->pod_node = kzalloc_objs(pt->pod_node[0], pt->nr_pods); BUG_ON(!pt->pod_cpus || !pt->pod_node); for (pod = 0; pod < pt->nr_pods; pod++) BUG_ON(!zalloc_cpumask_var(&pt->pod_cpus[pod], GFP_KERNEL)); for_each_possible_cpu(cpu) { cpumask_set_cpu(cpu, pt->pod_cpus[pt->cpu_pod[cpu]]); pt->pod_node[pt->cpu_pod[cpu]] = cpu_to_node(cpu); }} static bool __init cpus_dont_share(int cpu0, int cpu1){ return false;} static bool __init cpus_share_smt(int cpu0, int cpu1){ return cpumask_test_cpu(cpu0, cpu_smt_mask(cpu1));} static bool __init cpus_share_numa(int cpu0, int cpu1){ return cpu_to_node(cpu0) == cpu_to_node(cpu1);} /* Maps each CPU to its shard index within the LLC pod it belongs to */static int cpu_shard_id[NR_CPUS] __initdata; /** * llc_count_cores - count distinct cores (SMT groups) within an LLC pod * @pod_cpus: the cpumask of CPUs in the LLC pod * @smt_pods: the SMT pod type, used to identify sibling groups * * A core is represented by the lowest-numbered CPU in its SMT group. Returns * the number of distinct cores found in @pod_cpus. */static int __init llc_count_cores(const struct cpumask *pod_cpus, struct wq_pod_type *smt_pods){ const struct cpumask *sibling_cpus; int nr_cores = 0, c; /* * Count distinct cores by only counting the first CPU in each * SMT sibling group. */ for_each_cpu(c, pod_cpus) { sibling_cpus = smt_pods->pod_cpus[smt_pods->cpu_pod[c]]; if (cpumask_first(sibling_cpus) == c) nr_cores++; } return nr_cores;} /* * llc_shard_size - number of cores in a given shard * * Cores are spread as evenly as possible. The first @nr_large_shards shards are * "large shards" with (cores_per_shard + 1) cores; the rest are "default * shards" with cores_per_shard cores. */static int __init llc_shard_size(int shard_id, int cores_per_shard, int nr_large_shards){ /* The first @nr_large_shards shards are large shards */ if (shard_id < nr_large_shards) return cores_per_shard + 1; /* The remaining shards are default shards */ return cores_per_shard;} /* * llc_calc_shard_layout - compute the shard layout for an LLC pod * @nr_cores: number of distinct cores in the LLC pod * * Chooses the number of shards that keeps average shard size closest to * wq_cache_shard_size. Returns a struct describing the total number of shards, * the base size of each, and how many are large shards. */static struct llc_shard_layout __init llc_calc_shard_layout(int nr_cores){ struct llc_shard_layout layout; /* Ensure at least one shard; pick the count closest to the target size */ layout.nr_shards = max(1, DIV_ROUND_CLOSEST(nr_cores, wq_cache_shard_size)); layout.cores_per_shard = nr_cores / layout.nr_shards; layout.nr_large_shards = nr_cores % layout.nr_shards; return layout;} /* * llc_shard_is_full - check whether a shard has reached its core capacity * @cores_in_shard: number of cores already assigned to this shard * @shard_id: index of the shard being checked * @layout: the shard layout computed by llc_calc_shard_layout() * * Returns true if @cores_in_shard equals the expected size for @shard_id. */static bool __init llc_shard_is_full(int cores_in_shard, int shard_id, const struct llc_shard_layout *layout){ return cores_in_shard == llc_shard_size(shard_id, layout->cores_per_shard, layout->nr_large_shards);} /** * llc_populate_cpu_shard_id - populate cpu_shard_id[] for each CPU in an LLC pod * @pod_cpus: the cpumask of CPUs in the LLC pod * @smt_pods: the SMT pod type, used to identify sibling groups * @nr_cores: number of distinct cores in @pod_cpus (from llc_count_cores()) * * Walks @pod_cpus in order. At each SMT group leader, advances to the next * shard once the current shard is full. Results are written to cpu_shard_id[]. */static void __init llc_populate_cpu_shard_id(const struct cpumask *pod_cpus, struct wq_pod_type *smt_pods, int nr_cores){ struct llc_shard_layout layout = llc_calc_shard_layout(nr_cores); const struct cpumask *sibling_cpus; /* Count the number of cores in the current shard_id */ int cores_in_shard = 0; unsigned int leader; /* This is a cursor for the shards. Go from zero to nr_shards - 1*/ int shard_id = 0; int c; /* Iterate at every CPU for a given LLC pod, and assign it a shard */ for_each_cpu(c, pod_cpus) { sibling_cpus = smt_pods->pod_cpus[smt_pods->cpu_pod[c]]; if (cpumask_first(sibling_cpus) == c) { /* This is the CPU leader for the siblings */ if (llc_shard_is_full(cores_in_shard, shard_id, &layout)) { shard_id++; cores_in_shard = 0; } cores_in_shard++; cpu_shard_id[c] = shard_id; } else { /* * The siblings' shard MUST be the same as the leader. * never split threads in the same core. */ leader = cpumask_first(sibling_cpus); /* * This check silences a Warray-bounds warning on UP * configs where NR_CPUS=1 makes cpu_shard_id[] * a single-element array, and the compiler can't * prove the index is always 0. */ if (WARN_ON_ONCE(leader >= nr_cpu_ids)) continue; cpu_shard_id[c] = cpu_shard_id[leader]; } } WARN_ON_ONCE(shard_id != (layout.nr_shards - 1));} /** * precompute_cache_shard_ids - assign each CPU its shard index within its LLC * * Iterates over all LLC pods. For each pod, counts distinct cores then assigns * shard indices to all CPUs in the pod. Must be called after WQ_AFFN_CACHE and * WQ_AFFN_SMT have been initialized. */static void __init precompute_cache_shard_ids(void){ struct wq_pod_type *llc_pods = &wq_pod_types[WQ_AFFN_CACHE]; struct wq_pod_type *smt_pods = &wq_pod_types[WQ_AFFN_SMT]; const struct cpumask *cpus_sharing_llc; int nr_cores; int pod; if (!wq_cache_shard_size) { pr_warn("workqueue: cache_shard_size must be > 0, setting to 1\n"); wq_cache_shard_size = 1; } for (pod = 0; pod < llc_pods->nr_pods; pod++) { cpus_sharing_llc = llc_pods->pod_cpus[pod]; /* Number of cores in this given LLC */ nr_cores = llc_count_cores(cpus_sharing_llc, smt_pods); llc_populate_cpu_shard_id(cpus_sharing_llc, smt_pods, nr_cores); }} /* * cpus_share_cache_shard - test whether two CPUs belong to the same cache shard * * Two CPUs share a cache shard if they are in the same LLC and have the same * shard index. Used as the pod affinity callback for WQ_AFFN_CACHE_SHARD. */static bool __init cpus_share_cache_shard(int cpu0, int cpu1){ if (!cpus_share_cache(cpu0, cpu1)) return false; return cpu_shard_id[cpu0] == cpu_shard_id[cpu1];} /** * workqueue_init_topology - initialize CPU pods for unbound workqueues * * This is the third step of three-staged workqueue subsystem initialization and * invoked after SMP and topology information are fully initialized. It * initializes the unbound CPU pods accordingly. */void __init workqueue_init_topology(void){ struct workqueue_struct *wq; int cpu; init_pod_type(&wq_pod_types[WQ_AFFN_CPU], cpus_dont_share); init_pod_type(&wq_pod_types[WQ_AFFN_SMT], cpus_share_smt); init_pod_type(&wq_pod_types[WQ_AFFN_CACHE], cpus_share_cache); precompute_cache_shard_ids(); init_pod_type(&wq_pod_types[WQ_AFFN_CACHE_SHARD], cpus_share_cache_shard); init_pod_type(&wq_pod_types[WQ_AFFN_NUMA], cpus_share_numa); wq_topo_initialized = true; mutex_lock(&wq_pool_mutex); /* * Workqueues allocated earlier would have all CPUs sharing the default * worker pool. Explicitly call unbound_wq_update_pwq() on all workqueue * and CPU combinations to apply per-pod sharing. */ list_for_each_entry(wq, &workqueues, list) { for_each_online_cpu(cpu) unbound_wq_update_pwq(wq, cpu); if (wq->flags & WQ_UNBOUND) { mutex_lock(&wq->mutex); wq_update_node_max_active(wq, -1); mutex_unlock(&wq->mutex); } } mutex_unlock(&wq_pool_mutex);} void __warn_flushing_systemwide_wq(void){ pr_warn("WARNING: Flushing system-wide workqueues will be prohibited in near future.\n"); dump_stack();}EXPORT_SYMBOL(__warn_flushing_systemwide_wq); static int __init workqueue_unbound_cpus_setup(char *str){ if (cpulist_parse(str, &wq_cmdline_cpumask) < 0) { cpumask_clear(&wq_cmdline_cpumask); pr_warn("workqueue.unbound_cpus: incorrect CPU range, using default\n"); } return 1;}__setup("workqueue.unbound_cpus=", workqueue_unbound_cpus_setup);Lines 8001–8475 of 8475. Previous lines
* If nohz_full is enabled, set power efficient workqueue as unbound. * This allows workqueue items to be moved to HK CPUs. */ if (housekeeping_enabled(HK_TYPE_TICK)) wq_power_efficient = true; /* initialize WQ_AFFN_SYSTEM pods */ pt->pod_cpus = kzalloc_objs(pt->pod_cpus[0], 1); pt->pod_node = kzalloc_objs(pt->pod_node[0], 1); pt->cpu_pod = kzalloc_objs(pt->cpu_pod[0], nr_cpu_ids); BUG_ON(!pt->pod_cpus || !pt->pod_node || !pt->cpu_pod); BUG_ON(!zalloc_cpumask_var_node(&pt->pod_cpus[0], GFP_KERNEL, NUMA_NO_NODE)); pt->nr_pods = 1; cpumask_copy(pt->pod_cpus[0], cpu_possible_mask); pt->pod_node[0] = NUMA_NO_NODE; pt->cpu_pod[0] = 0; /* initialize BH and CPU pools */ for_each_possible_cpu(cpu) { struct worker_pool *pool; i = 0; for_each_bh_worker_pool(pool, cpu) { init_cpu_worker_pool(pool, cpu, std_nice[i]); pool->flags |= POOL_BH; init_irq_work(bh_pool_irq_work(pool), irq_work_fns[i]); i++; } i = 0; for_each_cpu_worker_pool(pool, cpu) init_cpu_worker_pool(pool, cpu, std_nice[i++]); } /* create default unbound and ordered wq attrs */ for (i = 0; i < NR_STD_WORKER_POOLS; i++) { struct workqueue_attrs *attrs; BUG_ON(!(attrs = alloc_workqueue_attrs())); attrs->nice = std_nice[i]; unbound_std_wq_attrs[i] = attrs; /* * An ordered wq should have only one pwq as ordering is * guaranteed by max_active which is enforced by pwqs. */ BUG_ON(!(attrs = alloc_workqueue_attrs())); attrs->nice = std_nice[i]; attrs->ordered = true; ordered_wq_attrs[i] = attrs; } system_wq = alloc_workqueue("events", WQ_PERCPU | __WQ_DEPRECATED, 0); system_percpu_wq = alloc_workqueue("events", WQ_PERCPU, 0); system_highpri_wq = alloc_workqueue("events_highpri", WQ_HIGHPRI | WQ_PERCPU, 0); system_long_wq = alloc_workqueue("events_long", WQ_PERCPU, 0); system_unbound_wq = alloc_workqueue("events_unbound", WQ_UNBOUND | __WQ_DEPRECATED, WQ_MAX_ACTIVE); system_dfl_wq = alloc_workqueue("events_unbound", WQ_UNBOUND, WQ_MAX_ACTIVE); system_freezable_wq = alloc_workqueue("events_freezable", WQ_FREEZABLE | WQ_PERCPU, 0); system_power_efficient_wq = alloc_workqueue("events_power_efficient", WQ_POWER_EFFICIENT | WQ_PERCPU, 0); system_freezable_power_efficient_wq = alloc_workqueue("events_freezable_pwr_efficient", WQ_FREEZABLE | WQ_POWER_EFFICIENT | WQ_PERCPU, 0); system_bh_wq = alloc_workqueue("events_bh", WQ_BH | WQ_PERCPU, 0); system_bh_highpri_wq = alloc_workqueue("events_bh_highpri", WQ_BH | WQ_HIGHPRI | WQ_PERCPU, 0); system_dfl_long_wq = alloc_workqueue("events_dfl_long", WQ_UNBOUND, WQ_MAX_ACTIVE); BUG_ON(!system_wq || !system_percpu_wq|| !system_highpri_wq || !system_long_wq || !system_unbound_wq || !system_freezable_wq || !system_dfl_wq || !system_power_efficient_wq || !system_freezable_power_efficient_wq || !system_bh_wq || !system_bh_highpri_wq || !system_dfl_long_wq); } static void __init wq_cpu_intensive_thresh_init(void) { unsigned long thresh; unsigned long bogo; pwq_release_worker = kthread_run_worker(0, "pool_workqueue_release"); BUG_ON(IS_ERR(pwq_release_worker)); /* if the user set it to a specific value, keep it */ if (wq_cpu_intensive_thresh_us != ULONG_MAX) return; /* * The default of 10ms is derived from the fact that most modern (as of * 2023) processors can do a lot in 10ms and that it's just below what * most consider human-perceivable. However, the kernel also runs on a * lot slower CPUs including microcontrollers where the threshold is way * too low. * * Let's scale up the threshold upto 1 second if BogoMips is below 4000. * This is by no means accurate but it doesn't have to be. The mechanism * is still useful even when the threshold is fully scaled up. Also, as * the reports would usually be applicable to everyone, some machines * operating on longer thresholds won't significantly diminish their * usefulness. */ thresh = 10 * USEC_PER_MSEC; /* see init/calibrate.c for lpj -> BogoMIPS calculation */ bogo = max_t(unsigned long, loops_per_jiffy / 500000 * HZ, 1); if (bogo < 4000) thresh = min_t(unsigned long, thresh * 4000 / bogo, USEC_PER_SEC); pr_debug("wq_cpu_intensive_thresh: lpj=%lu BogoMIPS=%lu thresh_us=%lu\n", loops_per_jiffy, bogo, thresh); wq_cpu_intensive_thresh_us = thresh; } /** * workqueue_init - bring workqueue subsystem fully online * * This is the second step of three-staged workqueue subsystem initialization * and invoked as soon as kthreads can be created and scheduled. Workqueues have * been created and work items queued on them, but there are no kworkers * executing the work items yet. Populate the worker pools with the initial * workers and enable future kworker creations. */ void __init workqueue_init(void) { struct workqueue_struct *wq; struct worker_pool *pool; int cpu, bkt; wq_cpu_intensive_thresh_init(); mutex_lock(&wq_pool_mutex); /* * Per-cpu pools created earlier could be missing node hint. Fix them * up. Also, create a rescuer for workqueues that requested it. */ for_each_possible_cpu(cpu) { for_each_bh_worker_pool(pool, cpu) pool->node = cpu_to_node(cpu); for_each_cpu_worker_pool(pool, cpu) pool->node = cpu_to_node(cpu); } list_for_each_entry(wq, &workqueues, list) { WARN(init_rescuer(wq), "workqueue: failed to create early rescuer for %s", wq->name); } mutex_unlock(&wq_pool_mutex); /* * Create the initial workers. A BH pool has one pseudo worker that * represents the shared BH execution context and thus doesn't get * affected by hotplug events. Create the BH pseudo workers for all * possible CPUs here. */ for_each_possible_cpu(cpu) for_each_bh_worker_pool(pool, cpu) BUG_ON(!create_worker(pool)); for_each_online_cpu(cpu) { for_each_cpu_worker_pool(pool, cpu) { pool->flags &= ~POOL_DISASSOCIATED; BUG_ON(!create_worker(pool)); } } hash_for_each(unbound_pool_hash, bkt, pool, hash_node) BUG_ON(!create_worker(pool)); wq_online = true; wq_watchdog_init(); } /* * Initialize @pt by first initializing @pt->cpu_pod[] with pod IDs according to * @cpu_shares_pod(). Each subset of CPUs that share a pod is assigned a unique * and consecutive pod ID. The rest of @pt is initialized accordingly. */ static void __init init_pod_type(struct wq_pod_type *pt, bool (*cpus_share_pod)(int, int)) { int cur, pre, cpu, pod; pt->nr_pods = 0; /* init @pt->cpu_pod[] according to @cpus_share_pod() */ pt->cpu_pod = kzalloc_objs(pt->cpu_pod[0], nr_cpu_ids); BUG_ON(!pt->cpu_pod); for_each_possible_cpu(cur) { for_each_possible_cpu(pre) { if (pre >= cur) { pt->cpu_pod[cur] = pt->nr_pods++; break; } if (cpus_share_pod(cur, pre)) { pt->cpu_pod[cur] = pt->cpu_pod[pre]; break; } } } /* init the rest to match @pt->cpu_pod[] */ pt->pod_cpus = kzalloc_objs(pt->pod_cpus[0], pt->nr_pods); pt->pod_node = kzalloc_objs(pt->pod_node[0], pt->nr_pods); BUG_ON(!pt->pod_cpus || !pt->pod_node); for (pod = 0; pod < pt->nr_pods; pod++) BUG_ON(!zalloc_cpumask_var(&pt->pod_cpus[pod], GFP_KERNEL)); for_each_possible_cpu(cpu) { cpumask_set_cpu(cpu, pt->pod_cpus[pt->cpu_pod[cpu]]); pt->pod_node[pt->cpu_pod[cpu]] = cpu_to_node(cpu); } } static bool __init cpus_dont_share(int cpu0, int cpu1) { return false; } static bool __init cpus_share_smt(int cpu0, int cpu1) { return cpumask_test_cpu(cpu0, cpu_smt_mask(cpu1)); } static bool __init cpus_share_numa(int cpu0, int cpu1) { return cpu_to_node(cpu0) == cpu_to_node(cpu1); } /* Maps each CPU to its shard index within the LLC pod it belongs to */ static int cpu_shard_id[NR_CPUS] __initdata; /** * llc_count_cores - count distinct cores (SMT groups) within an LLC pod * @pod_cpus: the cpumask of CPUs in the LLC pod * @smt_pods: the SMT pod type, used to identify sibling groups * * A core is represented by the lowest-numbered CPU in its SMT group. Returns * the number of distinct cores found in @pod_cpus. */ static int __init llc_count_cores(const struct cpumask *pod_cpus, struct wq_pod_type *smt_pods) { const struct cpumask *sibling_cpus; int nr_cores = 0, c; /* * Count distinct cores by only counting the first CPU in each * SMT sibling group. */ for_each_cpu(c, pod_cpus) { sibling_cpus = smt_pods->pod_cpus[smt_pods->cpu_pod[c]]; if (cpumask_first(sibling_cpus) == c) nr_cores++; } return nr_cores; } /* * llc_shard_size - number of cores in a given shard * * Cores are spread as evenly as possible. The first @nr_large_shards shards are * "large shards" with (cores_per_shard + 1) cores; the rest are "default * shards" with cores_per_shard cores. */ static int __init llc_shard_size(int shard_id, int cores_per_shard, int nr_large_shards) { /* The first @nr_large_shards shards are large shards */ if (shard_id < nr_large_shards) return cores_per_shard + 1; /* The remaining shards are default shards */ return cores_per_shard; } /* * llc_calc_shard_layout - compute the shard layout for an LLC pod * @nr_cores: number of distinct cores in the LLC pod * * Chooses the number of shards that keeps average shard size closest to * wq_cache_shard_size. Returns a struct describing the total number of shards, * the base size of each, and how many are large shards. */ static struct llc_shard_layout __init llc_calc_shard_layout(int nr_cores) { struct llc_shard_layout layout; /* Ensure at least one shard; pick the count closest to the target size */ layout.nr_shards = max(1, DIV_ROUND_CLOSEST(nr_cores, wq_cache_shard_size)); layout.cores_per_shard = nr_cores / layout.nr_shards; layout.nr_large_shards = nr_cores % layout.nr_shards; return layout; } /* * llc_shard_is_full - check whether a shard has reached its core capacity * @cores_in_shard: number of cores already assigned to this shard * @shard_id: index of the shard being checked * @layout: the shard layout computed by llc_calc_shard_layout() * * Returns true if @cores_in_shard equals the expected size for @shard_id. */ static bool __init llc_shard_is_full(int cores_in_shard, int shard_id, const struct llc_shard_layout *layout) { return cores_in_shard == llc_shard_size(shard_id, layout->cores_per_shard, layout->nr_large_shards); } /** * llc_populate_cpu_shard_id - populate cpu_shard_id[] for each CPU in an LLC pod * @pod_cpus: the cpumask of CPUs in the LLC pod * @smt_pods: the SMT pod type, used to identify sibling groups * @nr_cores: number of distinct cores in @pod_cpus (from llc_count_cores()) * * Walks @pod_cpus in order. At each SMT group leader, advances to the next * shard once the current shard is full. Results are written to cpu_shard_id[]. */ static void __init llc_populate_cpu_shard_id(const struct cpumask *pod_cpus, struct wq_pod_type *smt_pods, int nr_cores) { struct llc_shard_layout layout = llc_calc_shard_layout(nr_cores); const struct cpumask *sibling_cpus; /* Count the number of cores in the current shard_id */ int cores_in_shard = 0; unsigned int leader; /* This is a cursor for the shards. Go from zero to nr_shards - 1*/ int shard_id = 0; int c; /* Iterate at every CPU for a given LLC pod, and assign it a shard */ for_each_cpu(c, pod_cpus) { sibling_cpus = smt_pods->pod_cpus[smt_pods->cpu_pod[c]]; if (cpumask_first(sibling_cpus) == c) { /* This is the CPU leader for the siblings */ if (llc_shard_is_full(cores_in_shard, shard_id, &layout)) { shard_id++; cores_in_shard = 0; } cores_in_shard++; cpu_shard_id[c] = shard_id; } else { /* * The siblings' shard MUST be the same as the leader. * never split threads in the same core. */ leader = cpumask_first(sibling_cpus); /* * This check silences a Warray-bounds warning on UP * configs where NR_CPUS=1 makes cpu_shard_id[] * a single-element array, and the compiler can't * prove the index is always 0. */ if (WARN_ON_ONCE(leader >= nr_cpu_ids)) continue; cpu_shard_id[c] = cpu_shard_id[leader]; } } WARN_ON_ONCE(shard_id != (layout.nr_shards - 1)); } /** * precompute_cache_shard_ids - assign each CPU its shard index within its LLC * * Iterates over all LLC pods. For each pod, counts distinct cores then assigns * shard indices to all CPUs in the pod. Must be called after WQ_AFFN_CACHE and * WQ_AFFN_SMT have been initialized. */ static void __init precompute_cache_shard_ids(void) { struct wq_pod_type *llc_pods = &wq_pod_types[WQ_AFFN_CACHE]; struct wq_pod_type *smt_pods = &wq_pod_types[WQ_AFFN_SMT]; const struct cpumask *cpus_sharing_llc; int nr_cores; int pod; if (!wq_cache_shard_size) { pr_warn("workqueue: cache_shard_size must be > 0, setting to 1\n"); wq_cache_shard_size = 1; } for (pod = 0; pod < llc_pods->nr_pods; pod++) { cpus_sharing_llc = llc_pods->pod_cpus[pod]; /* Number of cores in this given LLC */ nr_cores = llc_count_cores(cpus_sharing_llc, smt_pods); llc_populate_cpu_shard_id(cpus_sharing_llc, smt_pods, nr_cores); } } /* * cpus_share_cache_shard - test whether two CPUs belong to the same cache shard * * Two CPUs share a cache shard if they are in the same LLC and have the same * shard index. Used as the pod affinity callback for WQ_AFFN_CACHE_SHARD. */ static bool __init cpus_share_cache_shard(int cpu0, int cpu1) { if (!cpus_share_cache(cpu0, cpu1)) return false; return cpu_shard_id[cpu0] == cpu_shard_id[cpu1]; } /** * workqueue_init_topology - initialize CPU pods for unbound workqueues * * This is the third step of three-staged workqueue subsystem initialization and * invoked after SMP and topology information are fully initialized. It * initializes the unbound CPU pods accordingly. */ void __init workqueue_init_topology(void) { struct workqueue_struct *wq; int cpu; init_pod_type(&wq_pod_types[WQ_AFFN_CPU], cpus_dont_share); init_pod_type(&wq_pod_types[WQ_AFFN_SMT], cpus_share_smt); init_pod_type(&wq_pod_types[WQ_AFFN_CACHE], cpus_share_cache); precompute_cache_shard_ids(); init_pod_type(&wq_pod_types[WQ_AFFN_CACHE_SHARD], cpus_share_cache_shard); init_pod_type(&wq_pod_types[WQ_AFFN_NUMA], cpus_share_numa); wq_topo_initialized = true; mutex_lock(&wq_pool_mutex); /* * Workqueues allocated earlier would have all CPUs sharing the default * worker pool. Explicitly call unbound_wq_update_pwq() on all workqueue * and CPU combinations to apply per-pod sharing. */ list_for_each_entry(wq, &workqueues, list) { for_each_online_cpu(cpu) unbound_wq_update_pwq(wq, cpu); if (wq->flags & WQ_UNBOUND) { mutex_lock(&wq->mutex); wq_update_node_max_active(wq, -1); mutex_unlock(&wq->mutex); } } mutex_unlock(&wq_pool_mutex); } void __warn_flushing_systemwide_wq(void) { pr_warn("WARNING: Flushing system-wide workqueues will be prohibited in near future.\n"); dump_stack(); } EXPORT_SYMBOL(__warn_flushing_systemwide_wq); static int __init workqueue_unbound_cpus_setup(char *str) { if (cpulist_parse(str, &wq_cmdline_cpumask) < 0) { cpumask_clear(&wq_cmdline_cpumask); pr_warn("workqueue.unbound_cpus: incorrect CPU range, using default\n"); } return 1; } __setup("workqueue.unbound_cpus=", workqueue_unbound_cpus_setup);