Commit 7400907c authored by Shao Denghui's avatar Shao Denghui Committed by jiangdongxu
Browse files

workqueue: add member for NUMA aware order workqueue and implement NUMA...

workqueue: add member for NUMA aware order workqueue and implement NUMA affinity for single thread workqueue

euleros inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I94XYA


CVE: NA

-------------------------------------------------

Currently, single thread workqueue only have single pwq, all of
works are queued the same workerpool. This is not optimal on
NUMA machines, will cause workers jump around across node.

This patch add a new wq flags __WQ_DYNAMIC,  this new kind of
single thread workqueue creates a separate pwq covering the
intersecting CPUS for each NUMA node which has online CPUS
in @attrs->cpumask instead of mapping all entries of numa_pwq_tbl[]
to the same pwq. After this, we can specify the @cpu of
queue_work_on, so the work can be executed on the same NUMA
node of the specified @cpu.
This kind of wq only support single work, multi works can't guarantee
the work's order.

Signed-off-by: default avatarBiaoxiang Ye <yebiaoxiang@huawei.com>
Signed-off-by: default avatarshaodenghui <shaodenghui@huawei.com>
parent f44547cb
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -29,4 +29,6 @@ source "lib/Kconfig"

source "lib/Kconfig.debug"

source "lib/Kconfig.openeuler"

source "Documentation/Kconfig"
+1 −0
Original line number Diff line number Diff line
@@ -415,6 +415,7 @@ enum {
	__WQ_ORDERED		= 1 << 17, /* internal: workqueue is ordered */
	__WQ_LEGACY		= 1 << 18, /* internal: create*_workqueue() */
	__WQ_ORDERED_EXPLICIT	= 1 << 19, /* internal: alloc_ordered_workqueue() */
	__WQ_DYNAMIC            = 1 << 25, /* internal: only support single work order WQ */

	WQ_MAX_ACTIVE		= 512,	  /* I like 512, better ideas? */
	WQ_UNBOUND_MAX_ACTIVE	= WQ_MAX_ACTIVE,
+19 −2
Original line number Diff line number Diff line
@@ -4355,6 +4355,10 @@ apply_wqattrs_prepare(struct workqueue_struct *wq,
	 * it even if we don't use it immediately.
	 */
	copy_workqueue_attrs(new_attrs, attrs);
#ifdef KWORKER_NUMA_AFFINITY
	if (wq->flags & __WQ_DYNAMIC)
		new_attrs->ordered = false;
#endif
	wqattrs_actualize_cpumask(new_attrs, unbound_cpumask);
	cpumask_copy(new_attrs->__pod_cpumask, new_attrs->cpumask);
	ctx->dfl_pwq = alloc_unbound_pwq(wq, new_attrs);
@@ -4591,10 +4595,19 @@ static int alloc_and_link_pwqs(struct workqueue_struct *wq)
	cpus_read_lock();
	if (wq->flags & __WQ_ORDERED) {
		ret = apply_workqueue_attrs(wq, ordered_wq_attrs[highpri]);
#ifdef KWORKER_NUMA_AFFINITY
		if (!(wq->flags & __WQ_DYNAMIC)) {
			/* there should only be single pwq for ordering guarantee */
			WARN(!ret && (wq->pwqs.next != &wq->dfl_pwq->pwqs_node ||
				wq->pwqs.prev != &wq->dfl_pwq->pwqs_node),
				"ordering guarantee broken for workqueue %s\n", wq->name);
		}
#else
		/* there should only be single pwq for ordering guarantee */
		WARN(!ret && (wq->pwqs.next != &wq->dfl_pwq->pwqs_node ||
				wq->pwqs.prev != &wq->dfl_pwq->pwqs_node),
				"ordering guarantee broken for workqueue %s\n", wq->name);
#endif
	} else {
		ret = apply_workqueue_attrs(wq, unbound_std_wq_attrs[highpri]);
	}
@@ -5799,7 +5812,11 @@ static int workqueue_apply_unbound_cpumask(const cpumask_var_t unbound_cpumask)

		/* creating multiple pwqs breaks ordering guarantee */
		if (!list_empty(&wq->pwqs)) {
#ifdef KWORKER_NUMA_AFFINITY
			if (wq->flags & __WQ_ORDERED_EXPLICIT && !(wq->flags & __WQ_DYNAMIC))
#else
			if (wq->flags & __WQ_ORDERED_EXPLICIT)
#endif
				continue;
			wq->flags &= ~__WQ_ORDERED;
		}

lib/Kconfig.openeuler

0 → 100644
+8 −0
Original line number Diff line number Diff line
config KWORKER_NUMA_AFFINITY
	bool "kworker NUMA affinity"
	default n
	help
	  This feature implements a set of adaptive mechanisms so that the
	  workqueue can automatically identify the CPU of the soft interrupt
	  and automatically schedule the workqueue to the corresponding NUMA
	  node.