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