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