From: Alexander Fomichev <a.fomichev@xxxxxxxxx> Introduce "on_cpu" module parameter for dmatest. By default, its value is -1 which means no binding implies. Positive values or zero cause the next "channel" assignment(s) to bind channel's thread to certain CPU. Thus, it is possible to bind different DMA channels' threads to different CPUs. This is useful for the cases when cold cache (because of task migrating between CPUs) significantly impacts DMA Engine performance. Such situation was analyzed in [1]. [1] Scheduler: DMA Engine regression because of sched/fair changes https://lore.kernel.org/all/20220128165058.zxyrnd7nzr4hlks2@xxxxxxxxx/ Signed-off-by: Alexander Fomichev <a.fomichev@xxxxxxxxx> --- drivers/dma/dmatest.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index f696246f57fd..c91cbc9e5d1a 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -89,6 +89,10 @@ static bool polled; module_param(polled, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(polled, "Use polling for completion instead of interrupts"); +static int on_cpu = -1; +module_param(on_cpu, int, 0644); +MODULE_PARM_DESC(on_cpu, "Bind CPU to run threads on (default: auto scheduled (-1))"); + /** * struct dmatest_params - test parameters. * @buf_size: size of the memcpy test buffer @@ -237,6 +241,7 @@ struct dmatest_thread { struct dmatest_chan { struct list_head node; struct dma_chan *chan; + int cpu; struct list_head threads; }; @@ -602,6 +607,7 @@ static int dmatest_func(void *data) ret = -ENOMEM; smp_rmb(); + thread->pending = false; info = thread->info; params = &info->params; @@ -1010,6 +1016,7 @@ static int dmatest_add_channel(struct dmatest_info *info, struct dmatest_chan *dtc; struct dma_device *dma_dev = chan->device; unsigned int thread_count = 0; + char cpu_str[20]; int cnt; dtc = kmalloc(sizeof(struct dmatest_chan), GFP_KERNEL); @@ -1018,6 +1025,13 @@ static int dmatest_add_channel(struct dmatest_info *info, return -ENOMEM; } + memset(cpu_str, 0, sizeof(cpu_str)); + if (on_cpu >= nr_cpu_ids || on_cpu < -1) + on_cpu = -1; + dtc->cpu = on_cpu; + if (dtc->cpu != -1) + snprintf(cpu_str, sizeof(cpu_str) - 1, " on CPU #%d", dtc->cpu); + dtc->chan = chan; INIT_LIST_HEAD(&dtc->threads); @@ -1050,8 +1064,8 @@ static int dmatest_add_channel(struct dmatest_info *info, thread_count += cnt > 0 ? cnt : 0; } - pr_info("Added %u threads using %s\n", - thread_count, dma_chan_name(chan)); + pr_info("Added %u threads using %s%s\n", + thread_count, dma_chan_name(chan), cpu_str); list_add_tail(&dtc->node, &info->channels); info->nr_channels++; @@ -1125,6 +1139,11 @@ static void run_pending_tests(struct dmatest_info *info) thread_count = 0; list_for_each_entry(thread, &dtc->threads, node) { + if (dtc->cpu != -1) { + if (!thread->pending) + continue; + kthread_bind(thread->task, dtc->cpu); + } wake_up_process(thread->task); thread_count++; } -- 2.37.1