1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (C) 2022. Huawei Technologies Co., Ltd */
3 #define _GNU_SOURCE
4 #include <sched.h>
5 #include <unistd.h>
6 #include <stdlib.h>
7 #include <stdbool.h>
8 #include <errno.h>
9 #include <string.h>
10 #include <pthread.h>
11
12 #include <bpf/bpf.h>
13 #include <bpf/libbpf.h>
14
15 #include "bpf_util.h"
16 #include "test_maps.h"
17 #include "task_local_storage_helpers.h"
18 #include "read_bpf_task_storage_busy.skel.h"
19
20 struct lookup_ctx {
21 bool start;
22 bool stop;
23 int pid_fd;
24 int map_fd;
25 int loop;
26 };
27
lookup_fn(void * arg)28 static void *lookup_fn(void *arg)
29 {
30 struct lookup_ctx *ctx = arg;
31 long value;
32 int i = 0;
33
34 while (!ctx->start)
35 usleep(1);
36
37 while (!ctx->stop && i++ < ctx->loop)
38 bpf_map_lookup_elem(ctx->map_fd, &ctx->pid_fd, &value);
39 return NULL;
40 }
41
abort_lookup(struct lookup_ctx * ctx,pthread_t * tids,unsigned int nr)42 static void abort_lookup(struct lookup_ctx *ctx, pthread_t *tids, unsigned int nr)
43 {
44 unsigned int i;
45
46 ctx->stop = true;
47 ctx->start = true;
48 for (i = 0; i < nr; i++)
49 pthread_join(tids[i], NULL);
50 }
51
test_task_storage_map_stress_lookup(void)52 void test_task_storage_map_stress_lookup(void)
53 {
54 #define MAX_NR_THREAD 4096
55 unsigned int i, nr = 256, loop = 8192, cpu = 0;
56 struct read_bpf_task_storage_busy *skel;
57 pthread_t tids[MAX_NR_THREAD];
58 struct lookup_ctx ctx;
59 cpu_set_t old, new;
60 const char *cfg;
61 int err;
62
63 cfg = getenv("TASK_STORAGE_MAP_NR_THREAD");
64 if (cfg) {
65 nr = atoi(cfg);
66 if (nr > MAX_NR_THREAD)
67 nr = MAX_NR_THREAD;
68 }
69 cfg = getenv("TASK_STORAGE_MAP_NR_LOOP");
70 if (cfg)
71 loop = atoi(cfg);
72 cfg = getenv("TASK_STORAGE_MAP_PIN_CPU");
73 if (cfg)
74 cpu = atoi(cfg);
75
76 skel = read_bpf_task_storage_busy__open_and_load();
77 err = libbpf_get_error(skel);
78 CHECK(err, "open_and_load", "error %d\n", err);
79
80 /* Only for a fully preemptible kernel */
81 if (!skel->kconfig->CONFIG_PREEMPTION) {
82 printf("%s SKIP (no CONFIG_PREEMPTION)\n", __func__);
83 read_bpf_task_storage_busy__destroy(skel);
84 skips++;
85 return;
86 }
87
88 /* Save the old affinity setting */
89 sched_getaffinity(getpid(), sizeof(old), &old);
90
91 /* Pinned on a specific CPU */
92 CPU_ZERO(&new);
93 CPU_SET(cpu, &new);
94 sched_setaffinity(getpid(), sizeof(new), &new);
95
96 ctx.start = false;
97 ctx.stop = false;
98 ctx.pid_fd = sys_pidfd_open(getpid(), 0);
99 ctx.map_fd = bpf_map__fd(skel->maps.task);
100 ctx.loop = loop;
101 for (i = 0; i < nr; i++) {
102 err = pthread_create(&tids[i], NULL, lookup_fn, &ctx);
103 if (err) {
104 abort_lookup(&ctx, tids, i);
105 CHECK(err, "pthread_create", "error %d\n", err);
106 goto out;
107 }
108 }
109
110 ctx.start = true;
111 for (i = 0; i < nr; i++)
112 pthread_join(tids[i], NULL);
113
114 skel->bss->pid = getpid();
115 err = read_bpf_task_storage_busy__attach(skel);
116 CHECK(err, "attach", "error %d\n", err);
117
118 /* Trigger program */
119 sys_gettid();
120 skel->bss->pid = 0;
121
122 CHECK(skel->bss->busy != 0, "bad bpf_task_storage_busy", "got %d\n", skel->bss->busy);
123 out:
124 read_bpf_task_storage_busy__destroy(skel);
125 /* Restore affinity setting */
126 sched_setaffinity(getpid(), sizeof(old), &old);
127 printf("%s:PASS\n", __func__);
128 }
129