173b97bc7SHou Tao // SPDX-License-Identifier: GPL-2.0
273b97bc7SHou Tao /* Copyright (C) 2022. Huawei Technologies Co., Ltd */
373b97bc7SHou Tao #define _GNU_SOURCE
473b97bc7SHou Tao #include <sched.h>
573b97bc7SHou Tao #include <unistd.h>
673b97bc7SHou Tao #include <stdlib.h>
773b97bc7SHou Tao #include <stdbool.h>
873b97bc7SHou Tao #include <errno.h>
973b97bc7SHou Tao #include <string.h>
1073b97bc7SHou Tao #include <pthread.h>
1173b97bc7SHou Tao
1273b97bc7SHou Tao #include <bpf/bpf.h>
1373b97bc7SHou Tao #include <bpf/libbpf.h>
1473b97bc7SHou Tao
150e2fb011SKumar Kartikeya Dwivedi #include "bpf_util.h"
1673b97bc7SHou Tao #include "test_maps.h"
1773b97bc7SHou Tao #include "task_local_storage_helpers.h"
1873b97bc7SHou Tao #include "read_bpf_task_storage_busy.skel.h"
1973b97bc7SHou Tao
2073b97bc7SHou Tao struct lookup_ctx {
2173b97bc7SHou Tao bool start;
2273b97bc7SHou Tao bool stop;
2373b97bc7SHou Tao int pid_fd;
2473b97bc7SHou Tao int map_fd;
2573b97bc7SHou Tao int loop;
2673b97bc7SHou Tao };
2773b97bc7SHou Tao
lookup_fn(void * arg)2873b97bc7SHou Tao static void *lookup_fn(void *arg)
2973b97bc7SHou Tao {
3073b97bc7SHou Tao struct lookup_ctx *ctx = arg;
3173b97bc7SHou Tao long value;
3273b97bc7SHou Tao int i = 0;
3373b97bc7SHou Tao
3473b97bc7SHou Tao while (!ctx->start)
3573b97bc7SHou Tao usleep(1);
3673b97bc7SHou Tao
3773b97bc7SHou Tao while (!ctx->stop && i++ < ctx->loop)
3873b97bc7SHou Tao bpf_map_lookup_elem(ctx->map_fd, &ctx->pid_fd, &value);
3973b97bc7SHou Tao return NULL;
4073b97bc7SHou Tao }
4173b97bc7SHou Tao
abort_lookup(struct lookup_ctx * ctx,pthread_t * tids,unsigned int nr)4273b97bc7SHou Tao static void abort_lookup(struct lookup_ctx *ctx, pthread_t *tids, unsigned int nr)
4373b97bc7SHou Tao {
4473b97bc7SHou Tao unsigned int i;
4573b97bc7SHou Tao
4673b97bc7SHou Tao ctx->stop = true;
4773b97bc7SHou Tao ctx->start = true;
4873b97bc7SHou Tao for (i = 0; i < nr; i++)
4973b97bc7SHou Tao pthread_join(tids[i], NULL);
5073b97bc7SHou Tao }
5173b97bc7SHou Tao
test_task_storage_map_stress_lookup(void)5273b97bc7SHou Tao void test_task_storage_map_stress_lookup(void)
5373b97bc7SHou Tao {
5473b97bc7SHou Tao #define MAX_NR_THREAD 4096
5573b97bc7SHou Tao unsigned int i, nr = 256, loop = 8192, cpu = 0;
5673b97bc7SHou Tao struct read_bpf_task_storage_busy *skel;
5773b97bc7SHou Tao pthread_t tids[MAX_NR_THREAD];
5873b97bc7SHou Tao struct lookup_ctx ctx;
5973b97bc7SHou Tao cpu_set_t old, new;
6073b97bc7SHou Tao const char *cfg;
6173b97bc7SHou Tao int err;
6273b97bc7SHou Tao
6373b97bc7SHou Tao cfg = getenv("TASK_STORAGE_MAP_NR_THREAD");
6473b97bc7SHou Tao if (cfg) {
6573b97bc7SHou Tao nr = atoi(cfg);
6673b97bc7SHou Tao if (nr > MAX_NR_THREAD)
6773b97bc7SHou Tao nr = MAX_NR_THREAD;
6873b97bc7SHou Tao }
6973b97bc7SHou Tao cfg = getenv("TASK_STORAGE_MAP_NR_LOOP");
7073b97bc7SHou Tao if (cfg)
7173b97bc7SHou Tao loop = atoi(cfg);
7273b97bc7SHou Tao cfg = getenv("TASK_STORAGE_MAP_PIN_CPU");
7373b97bc7SHou Tao if (cfg)
7473b97bc7SHou Tao cpu = atoi(cfg);
7573b97bc7SHou Tao
7673b97bc7SHou Tao skel = read_bpf_task_storage_busy__open_and_load();
7773b97bc7SHou Tao err = libbpf_get_error(skel);
7873b97bc7SHou Tao CHECK(err, "open_and_load", "error %d\n", err);
7973b97bc7SHou Tao
8073b97bc7SHou Tao /* Only for a fully preemptible kernel */
81*6b64128aSSebastian Andrzej Siewior if (!skel->kconfig->CONFIG_PREEMPTION) {
82*6b64128aSSebastian Andrzej Siewior printf("%s SKIP (no CONFIG_PREEMPTION)\n", __func__);
83f5eb23b9SHou Tao read_bpf_task_storage_busy__destroy(skel);
84a7e85406SHou Tao skips++;
8573b97bc7SHou Tao return;
86a7e85406SHou Tao }
8773b97bc7SHou Tao
8873b97bc7SHou Tao /* Save the old affinity setting */
8973b97bc7SHou Tao sched_getaffinity(getpid(), sizeof(old), &old);
9073b97bc7SHou Tao
9173b97bc7SHou Tao /* Pinned on a specific CPU */
9273b97bc7SHou Tao CPU_ZERO(&new);
9373b97bc7SHou Tao CPU_SET(cpu, &new);
9473b97bc7SHou Tao sched_setaffinity(getpid(), sizeof(new), &new);
9573b97bc7SHou Tao
9673b97bc7SHou Tao ctx.start = false;
9773b97bc7SHou Tao ctx.stop = false;
9873b97bc7SHou Tao ctx.pid_fd = sys_pidfd_open(getpid(), 0);
9973b97bc7SHou Tao ctx.map_fd = bpf_map__fd(skel->maps.task);
10073b97bc7SHou Tao ctx.loop = loop;
10173b97bc7SHou Tao for (i = 0; i < nr; i++) {
10273b97bc7SHou Tao err = pthread_create(&tids[i], NULL, lookup_fn, &ctx);
10373b97bc7SHou Tao if (err) {
10473b97bc7SHou Tao abort_lookup(&ctx, tids, i);
10573b97bc7SHou Tao CHECK(err, "pthread_create", "error %d\n", err);
10673b97bc7SHou Tao goto out;
10773b97bc7SHou Tao }
10873b97bc7SHou Tao }
10973b97bc7SHou Tao
11073b97bc7SHou Tao ctx.start = true;
11173b97bc7SHou Tao for (i = 0; i < nr; i++)
11273b97bc7SHou Tao pthread_join(tids[i], NULL);
11373b97bc7SHou Tao
11473b97bc7SHou Tao skel->bss->pid = getpid();
11573b97bc7SHou Tao err = read_bpf_task_storage_busy__attach(skel);
11673b97bc7SHou Tao CHECK(err, "attach", "error %d\n", err);
11773b97bc7SHou Tao
11873b97bc7SHou Tao /* Trigger program */
1190e2fb011SKumar Kartikeya Dwivedi sys_gettid();
12073b97bc7SHou Tao skel->bss->pid = 0;
12173b97bc7SHou Tao
12273b97bc7SHou Tao CHECK(skel->bss->busy != 0, "bad bpf_task_storage_busy", "got %d\n", skel->bss->busy);
12373b97bc7SHou Tao out:
12473b97bc7SHou Tao read_bpf_task_storage_busy__destroy(skel);
12573b97bc7SHou Tao /* Restore affinity setting */
12673b97bc7SHou Tao sched_setaffinity(getpid(), sizeof(old), &old);
127a7e85406SHou Tao printf("%s:PASS\n", __func__);
12873b97bc7SHou Tao }
129