• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: MIT */
2 /*
3  * Description: test that io-wq affinity is correctly set for SQPOLL
4  */
5 #include <stdio.h>
6 #include <unistd.h>
7 #include <fcntl.h>
8 #include <stdlib.h>
9 #include <string.h>
10 
11 #include "liburing.h"
12 #include "helpers.h"
13 
14 #define IOWQ_CPU	0
15 #define SQPOLL_CPU	1
16 
verify_comm(pid_t pid,const char * name,int cpu)17 static int verify_comm(pid_t pid, const char *name, int cpu)
18 {
19 	char comm[64], buf[64];
20 	cpu_set_t set;
21 	int fd, ret;
22 
23 	sprintf(comm, "/proc/%d/comm", pid);
24 	fd = open(comm, O_RDONLY);
25 	if (fd < 0) {
26 		perror("open");
27 		return T_EXIT_SKIP;
28 	}
29 
30 	ret = read(fd, buf, sizeof(buf));
31 	if (ret < 0) {
32 		close(fd);
33 		return T_EXIT_SKIP;
34 	}
35 
36 	if (strncmp(buf, name, strlen(name) - 1)) {
37 		close(fd);
38 		return T_EXIT_SKIP;
39 	}
40 
41 	close(fd);
42 
43 	ret = sched_getaffinity(pid, sizeof(set), &set);
44 	if (ret < 0) {
45 		perror("sched_getaffinity");
46 		return T_EXIT_SKIP;
47 	}
48 
49 	if (CPU_COUNT(&set) != 1) {
50 		fprintf(stderr, "More than one CPU set in mask\n");
51 		return T_EXIT_FAIL;
52 	}
53 	if (!CPU_ISSET(cpu, &set)) {
54 		fprintf(stderr, "Wrong CPU set in mask\n");
55 		return T_EXIT_FAIL;
56 	}
57 
58 	return T_EXIT_PASS;
59 }
60 
verify_affinity(pid_t pid,int sqpoll)61 static int verify_affinity(pid_t pid, int sqpoll)
62 {
63 	pid_t wq_pid, sqpoll_pid = -1;
64 	char name[64];
65 	int ret;
66 
67 	wq_pid = pid + 2;
68 	if (sqpoll)
69 		sqpoll_pid = pid + 1;
70 
71 	/* verify we had the pids right */
72 	sprintf(name, "iou-wrk-%d", pid);
73 	ret = verify_comm(wq_pid, name, IOWQ_CPU);
74 	if (ret != T_EXIT_PASS)
75 		return ret;
76 
77 	if (sqpoll_pid != -1) {
78 		sprintf(name, "iou-sqp-%d", pid);
79 		ret = verify_comm(sqpoll_pid, name, SQPOLL_CPU);
80 		if (ret != T_EXIT_PASS)
81 			return ret;
82 	}
83 
84 	return T_EXIT_PASS;
85 }
86 
test(int sqpoll)87 static int test(int sqpoll)
88 {
89 	struct io_uring_params p = { };
90 	struct io_uring ring;
91 	struct io_uring_sqe *sqe;
92 	char buf[64];
93 	int fds[2], ret;
94 	cpu_set_t set;
95 
96 	if (sqpoll) {
97 		p.flags = IORING_SETUP_SQPOLL | IORING_SETUP_SQ_AFF;
98 		p.sq_thread_cpu = SQPOLL_CPU;
99 	}
100 
101 	io_uring_queue_init_params(8, &ring, &p);
102 
103 	CPU_ZERO(&set);
104 	CPU_SET(IOWQ_CPU, &set);
105 
106 	ret = io_uring_register_iowq_aff(&ring, sizeof(set), &set);
107 	if (ret) {
108 		fprintf(stderr, "register aff: %d\n", ret);
109 		return T_EXIT_FAIL;
110 	}
111 
112 	if (pipe(fds) < 0) {
113 		perror("pipe");
114 		return T_EXIT_FAIL;
115 	}
116 
117 	sqe = io_uring_get_sqe(&ring);
118 	io_uring_prep_read(sqe, fds[0], buf, sizeof(buf), 0);
119 	sqe->flags |= IOSQE_ASYNC;
120 
121 	io_uring_submit(&ring);
122 
123 	usleep(10000);
124 
125 	ret = verify_affinity(getpid(), sqpoll);
126 	io_uring_queue_exit(&ring);
127 	return ret;
128 }
129 
test_invalid_cpu(void)130 static int test_invalid_cpu(void)
131 {
132 	struct io_uring_params p = { };
133 	struct io_uring ring;
134 	int ret, nr_cpus;
135 
136 	nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
137 	if (nr_cpus < 0) {
138 		perror("sysconf(_SC_NPROCESSORS_ONLN");
139 		return T_EXIT_SKIP;
140 	}
141 
142 	p.flags = IORING_SETUP_SQPOLL | IORING_SETUP_SQ_AFF;
143 	p.sq_thread_cpu = 16 * nr_cpus;
144 
145 	ret = io_uring_queue_init_params(8, &ring, &p);
146 	if (ret == -EPERM) {
147 		return T_EXIT_SKIP;
148 	} else if (ret != -EINVAL) {
149 		fprintf(stderr, "Queue init: %d\n", ret);
150 		return T_EXIT_FAIL;
151 	}
152 
153 	io_uring_queue_exit(&ring);
154 	return T_EXIT_PASS;
155 }
156 
main(int argc,char * argv[])157 int main(int argc, char *argv[])
158 {
159 	int ret;
160 
161 	if (argc > 1)
162 		return T_EXIT_SKIP;
163 
164 	ret = test_invalid_cpu();
165 	if (ret == T_EXIT_SKIP) {
166 		return T_EXIT_SKIP;
167 	} else if (ret != T_EXIT_PASS) {
168 		fprintf(stderr, "test sqpoll cpu failed\n");
169 		return T_EXIT_FAIL;
170 	}
171 
172 	ret = test(1);
173 	if (ret == T_EXIT_SKIP) {
174 		return T_EXIT_SKIP;
175 	} else if (ret != T_EXIT_PASS) {
176 		fprintf(stderr, "test sqpoll failed\n");
177 		return T_EXIT_FAIL;
178 	}
179 
180 	return T_EXIT_PASS;
181 }
182