]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/numa.cc
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / common / numa.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include "numa.h"
5
6 #include <cstring>
7 #include <errno.h>
8 #include <iostream>
9
10 #include "include/stringify.h"
11 #include "common/safe_io.h"
12
13
14 // list
15 #if defined(__linux__)
16 int parse_cpu_set_list(const char *s,
17 size_t *cpu_set_size,
18 cpu_set_t *cpu_set)
19 {
20 CPU_ZERO(cpu_set);
21 while (*s) {
22 char *end;
23 int a = strtol(s, &end, 10);
24 if (end == s) {
25 return -EINVAL;
26 }
27 if (*end == '-') {
28 s = end + 1;
29 int b = strtol(s, &end, 10);
30 if (end == s) {
31 return -EINVAL;
32 }
33 for (; a <= b; ++a) {
34 CPU_SET(a, cpu_set);
35 }
36 *cpu_set_size = a;
37 } else {
38 CPU_SET(a, cpu_set);
39 *cpu_set_size = a + 1;
40 }
41 if (*end == 0) {
42 break;
43 }
44 if (*end != ',') {
45 return -EINVAL;
46 }
47 s = end + 1;
48 }
49 return 0;
50 }
51
52 std::string cpu_set_to_str_list(size_t cpu_set_size,
53 const cpu_set_t *cpu_set)
54 {
55 std::string r;
56 unsigned a = 0;
57 while (true) {
58 while (a < cpu_set_size && !CPU_ISSET(a, cpu_set)) {
59 ++a;
60 }
61 if (a >= cpu_set_size) {
62 break;
63 }
64 unsigned b = a + 1;
65 while (b < cpu_set_size && CPU_ISSET(b, cpu_set)) {
66 ++b;
67 }
68 if (r.size()) {
69 r += ",";
70 }
71 if (b > a + 1) {
72 r += stringify(a) + "-" + stringify(b - 1);
73 } else {
74 r += stringify(a);
75 }
76 a = b;
77 }
78 return r;
79 }
80
81 std::set<int> cpu_set_to_set(size_t cpu_set_size,
82 const cpu_set_t *cpu_set)
83 {
84 set<int> r;
85 unsigned a = 0;
86 while (true) {
87 while (a < cpu_set_size && !CPU_ISSET(a, cpu_set)) {
88 ++a;
89 }
90 if (a >= cpu_set_size) {
91 break;
92 }
93 unsigned b = a + 1;
94 while (b < cpu_set_size && CPU_ISSET(b, cpu_set)) {
95 ++b;
96 }
97 while (a < b) {
98 r.insert(a);
99 ++a;
100 }
101 }
102 return r;
103 }
104
105
106 int get_numa_node_cpu_set(
107 int node,
108 size_t *cpu_set_size,
109 cpu_set_t *cpu_set)
110 {
111 std::string fn = "/sys/devices/system/node/node";
112 fn += stringify(node);
113 fn += "/cpulist";
114 int fd = ::open(fn.c_str(), O_RDONLY);
115 if (fd < 0) {
116 return -errno;
117 }
118 char buf[1024];
119 int r = safe_read(fd, &buf, sizeof(buf));
120 if (r < 0) {
121 goto out;
122 }
123 buf[r] = 0;
124 while (r > 0 && ::isspace(buf[--r])) {
125 buf[r] = 0;
126 }
127 r = parse_cpu_set_list(buf, cpu_set_size, cpu_set);
128 if (r < 0) {
129 goto out;
130 }
131 r = 0;
132 out:
133 ::close(fd);
134 return r;
135 }
136
137 static int easy_readdir(const std::string& dir, std::set<std::string> *out)
138 {
139 DIR *h = ::opendir(dir.c_str());
140 if (!h) {
141 return -errno;
142 }
143 struct dirent *de = nullptr;
144 while ((de = ::readdir(h))) {
145 if (strcmp(de->d_name, ".") == 0 ||
146 strcmp(de->d_name, "..") == 0) {
147 continue;
148 }
149 out->insert(de->d_name);
150 }
151 closedir(h);
152 return 0;
153 }
154
155 int set_cpu_affinity_all_threads(size_t cpu_set_size, cpu_set_t *cpu_set)
156 {
157 // first set my affinity
158 int r = sched_setaffinity(getpid(), cpu_set_size, cpu_set);
159 if (r < 0) {
160 return -errno;
161 }
162
163 // make 2 passes here so that we (hopefully) catch racing threads creating
164 // threads.
165 for (unsigned pass = 0; pass < 2; ++pass) {
166 // enumerate all child threads from /proc
167 std::set<std::string> ls;
168 std::string path = "/proc/"s + stringify(getpid()) + "/task";
169 r = easy_readdir(path, &ls);
170 if (r < 0) {
171 return r;
172 }
173 for (auto& i : ls) {
174 pid_t tid = atoll(i.c_str());
175 if (!tid) {
176 continue; // wtf
177 }
178 r = sched_setaffinity(tid, cpu_set_size, cpu_set);
179 if (r < 0) {
180 return -errno;
181 }
182 }
183 }
184 return 0;
185 }
186
187 #elif defined(__FreeBSD__)
188
189 int parse_cpu_set_list(const char *s,
190 size_t *cpu_set_size,
191 cpu_set_t *cpu_set)
192 {
193 return -ENOTSUP;
194 }
195
196 std::string cpu_set_to_str_list(size_t cpu_set_size,
197 const cpu_set_t *cpu_set)
198 {
199 return {};
200 }
201
202 std::set<int> cpu_set_to_set(size_t cpu_set_size,
203 const cpu_set_t *cpu_set)
204 {
205 return {};
206 }
207
208 int get_numa_node_cpu_set(int node,
209 size_t *cpu_set_size,
210 cpu_set_t *cpu_set)
211 {
212 return -ENOTSUP;
213 }
214
215 int set_cpu_affinity_all_threads(size_t cpu_set_size,
216 cpu_set_t *cpu_set)
217 {
218 return -ENOTSUP;
219 }
220
221 #endif