Line data Source code
1 : #include <cerrno>
2 : #include <cstdio>
3 : #include <cstring>
4 : #include <functional>
5 : #include <iostream>
6 : #include <mutex>
7 : #include <sstream>
8 : #include <vector>
9 : #ifdef SPU_HWLOC
10 : #include <hwloc.h>
11 : #endif
12 :
13 : #include "Tools/Exception/exception.hpp"
14 : #include "Tools/Thread/Thread_pinning/Thread_pinning.hpp"
15 : #include "Tools/Thread/Thread_pinning/Thread_pinning_utils.hpp"
16 :
17 : using namespace spu;
18 : using namespace spu::tools;
19 :
20 : #ifdef SPU_HWLOC
21 : static hwloc_topology_t g_topology;
22 : static int g_topodepth = 0;
23 : #endif
24 : static bool g_is_init = false;
25 : static std::mutex g_mtx;
26 : static bool g_enable_logs = false;
27 :
28 : bool
29 426 : Thread_pinning::is_init()
30 : {
31 426 : return g_is_init;
32 : }
33 :
34 : void
35 2 : Thread_pinning::init()
36 : {
37 2 : if (!Thread_pinning::is_init())
38 : {
39 2 : g_mtx.lock();
40 2 : if (!Thread_pinning::is_init())
41 : {
42 2 : g_is_init = true;
43 :
44 : #ifdef SPU_HWLOC
45 : /* Allocate and initialize topology object. */
46 2 : hwloc_topology_init(&g_topology);
47 :
48 : /* ... Optionally, put detection configuration here to ignore
49 : some objects types, define a synthetic topology, etc....
50 : The default is to detect all the objects of the machine that
51 : the caller is allowed to access. See Configure Topology
52 : Detection. */
53 :
54 : /* Perform the topology detection. */
55 2 : hwloc_topology_load(g_topology);
56 :
57 : /* Optionally, get some additional topology information
58 : in case we need the topology depth later. */
59 2 : g_topodepth = hwloc_topology_get_depth(g_topology);
60 : #endif
61 : }
62 2 : g_mtx.unlock();
63 : }
64 2 : }
65 :
66 : void
67 2 : Thread_pinning::destroy()
68 : {
69 2 : if (Thread_pinning::is_init())
70 : {
71 2 : g_mtx.lock();
72 2 : if (Thread_pinning::is_init())
73 : {
74 : #ifdef SPU_HWLOC
75 : /* Destroy topology object. */
76 2 : hwloc_topology_destroy(g_topology);
77 2 : g_topodepth = 0;
78 : #endif
79 2 : g_is_init = false;
80 : }
81 2 : g_mtx.unlock();
82 : }
83 2 : }
84 :
85 : void
86 0 : Thread_pinning::set_logs(const bool enable_logs)
87 : {
88 0 : g_mtx.lock();
89 0 : g_enable_logs = enable_logs;
90 0 : g_mtx.unlock();
91 0 : }
92 :
93 : bool
94 0 : Thread_pinning::is_logs()
95 : {
96 0 : return g_enable_logs;
97 : }
98 :
99 : void
100 0 : Thread_pinning::pin(const size_t puid)
101 : {
102 0 : g_mtx.lock();
103 : #ifdef SPU_HWLOC
104 0 : if (Thread_pinning::is_init())
105 : {
106 0 : int pu_depth = hwloc_get_type_or_below_depth(g_topology, HWLOC_OBJ_PU);
107 0 : hwloc_obj_t pu_obj = hwloc_get_obj_by_depth(g_topology, pu_depth, puid);
108 :
109 0 : if (pu_obj == nullptr)
110 : {
111 0 : std::stringstream message;
112 0 : message << "'pu_obj' is nullptr ('puid' = " << puid << ").";
113 0 : throw tools::runtime_error(__FILE__, __LINE__, __func__, message.str());
114 0 : }
115 :
116 : /* Get a copy of its cpuset that we may modify. */
117 0 : hwloc_cpuset_t cpuset = hwloc_bitmap_dup(pu_obj->cpuset);
118 :
119 : /* Get only one logical processor (in case the core is
120 : SMT/hyper-threaded). */
121 0 : hwloc_bitmap_singlify(cpuset);
122 :
123 0 : if (g_enable_logs)
124 : {
125 : char c[128];
126 0 : hwloc_bitmap_snprintf(c, 128, cpuset);
127 :
128 : std::cerr << "Thread pinning info -- "
129 0 : << "PU logical index (hwloc): " << pu_obj->logical_index << " -- "
130 0 : << "P OS index: " << pu_obj->os_index << " -- "
131 0 : << "bitmap: " << c << std::endl;
132 : }
133 :
134 : /* And try to bind ourself there. */
135 0 : if (hwloc_set_cpubind(g_topology, cpuset, HWLOC_CPUBIND_THREAD))
136 : {
137 : char* str;
138 0 : int error = errno;
139 0 : hwloc_bitmap_asprintf(&str, pu_obj->cpuset);
140 0 : std::clog << "Couldn't bind to cpuset " << str << ": " << strerror(error) << std::endl;
141 0 : free(str);
142 : }
143 :
144 : /* Free our cpuset copy */
145 0 : hwloc_bitmap_free(cpuset);
146 : }
147 : else
148 : {
149 0 : if (g_enable_logs)
150 : {
151 : std::clog << "You can't call the 'pin' method if you have not call the 'init' method before, nothing will "
152 0 : << "be done." << std::endl;
153 : }
154 : }
155 : #else
156 : (void)puid;
157 : if (g_enable_logs)
158 : {
159 : std::clog << "'pin' method do nothing as StreamPU has not been linked with the 'hwloc' library." << std::endl;
160 : }
161 : #endif
162 0 : g_mtx.unlock();
163 0 : }
164 :
165 : // Thread pinning second function using hwloc objects
166 : void
167 223 : Thread_pinning::pin(const std::string hwloc_objects)
168 : {
169 223 : g_mtx.lock();
170 :
171 : #ifdef SPU_HWLOC
172 223 : if (Thread_pinning::is_init())
173 : {
174 : // Objects parsing
175 54 : std::vector<std::string> hwloc_objects_vector = Thread_pinning_utils::thread_parser(hwloc_objects);
176 :
177 : // getting the pairs
178 54 : std::vector<std::pair<hwloc_obj_type_t, int>> object_numbers;
179 108 : for (auto obj : hwloc_objects_vector)
180 54 : object_numbers.push_back(Thread_pinning_utils::str_to_hwloc_object(obj));
181 :
182 : // getting topology depth of each object
183 54 : std::vector<int> object_depth = {};
184 108 : for (auto obj : object_numbers)
185 54 : object_depth.push_back(hwloc_get_type_or_below_depth(g_topology, obj.first));
186 :
187 : // Allocating cpu_set
188 54 : hwloc_bitmap_t all_pus = hwloc_bitmap_alloc();
189 54 : hwloc_bitmap_zero(all_pus);
190 :
191 108 : for (size_t i = 0; i < object_numbers.size(); ++i)
192 : {
193 54 : hwloc_obj_t obj = hwloc_get_obj_by_depth(g_topology, object_depth[i], object_numbers[i].second);
194 54 : if (obj == nullptr)
195 : {
196 0 : std::stringstream message;
197 0 : message << "obj is nullptr ('Type' = " << hwloc_objects_vector[i] << ").";
198 0 : throw tools::runtime_error(__FILE__, __LINE__, __func__, message.str());
199 0 : }
200 54 : hwloc_bitmap_or(all_pus, all_pus, obj->cpuset);
201 : }
202 :
203 54 : if (g_enable_logs)
204 : {
205 : char c[128];
206 0 : hwloc_bitmap_snprintf(c, 128, all_pus);
207 :
208 0 : std::clog << "Thread pinning info -- ";
209 0 : for (size_t i = 0; i < hwloc_objects_vector.size(); ++i)
210 : {
211 0 : std::clog << "Object = " << hwloc_objects_vector[i] << " | number = " << object_numbers[i].second
212 0 : << std::endl;
213 : }
214 0 : std::clog << "bitmap: " << all_pus << std::endl;
215 : }
216 :
217 : /* And try to bind ourself there. */
218 54 : if (hwloc_set_cpubind(g_topology, all_pus, HWLOC_CPUBIND_THREAD))
219 : {
220 : char* str;
221 0 : int error = errno;
222 0 : hwloc_bitmap_asprintf(&str, all_pus);
223 0 : std::clog << "Couldn't bind to cpuset " << str << ": " << strerror(error) << std::endl;
224 0 : free(str);
225 : }
226 :
227 : /* Free our cpuset copy */
228 54 : hwloc_bitmap_free(all_pus);
229 54 : }
230 : else
231 : {
232 169 : if (g_enable_logs)
233 : {
234 : std::clog << "You can't call the 'pin' method if you have not call the 'init' method before, nothing will "
235 0 : << "be done." << std::endl;
236 : }
237 : }
238 : #else
239 : (void)hwloc_objects;
240 : if (g_enable_logs)
241 : {
242 : std::clog << "'pin' method do nothing as StreamPU has not been linked with the 'hwloc' library." << std::endl;
243 : }
244 : #endif
245 223 : g_mtx.unlock();
246 223 : }
247 :
248 : void
249 191 : Thread_pinning::unpin()
250 : {
251 191 : g_mtx.lock();
252 : #ifdef SPU_HWLOC
253 194 : if (!Thread_pinning::is_init())
254 : {
255 146 : if (g_enable_logs)
256 : {
257 : std::clog << "You can't call the 'unpin' method if you have not call the 'init' method before, nothing "
258 0 : << "will be done." << std::endl;
259 : }
260 : }
261 : else
262 : {
263 : // get cpuset of root object
264 48 : hwloc_cpuset_t unpin_set = hwloc_bitmap_dup(hwloc_get_obj_by_depth(g_topology, 0, 0)->cpuset);
265 48 : if (hwloc_set_cpubind(g_topology, unpin_set, HWLOC_CPUBIND_THREAD))
266 : {
267 : char* bitmap_str;
268 0 : int error = errno;
269 0 : hwloc_bitmap_asprintf(&bitmap_str, unpin_set);
270 0 : std::clog << "'unpin' method failed ('bitmap_str' = " << bitmap_str << ", 'error' = " << strerror(error)
271 0 : << ")" << std::endl;
272 0 : free(bitmap_str);
273 : }
274 48 : hwloc_bitmap_free(unpin_set);
275 : }
276 : #else
277 : if (g_enable_logs)
278 : {
279 : std::clog << "'unpin' method do nothing as StreamPU has not been linked with the 'hwloc' library." << std::endl;
280 : }
281 : #endif
282 194 : g_mtx.unlock();
283 194 : }
284 :
285 : std::string
286 0 : Thread_pinning::get_cur_cpuset_str()
287 : {
288 : #ifdef SPU_HWLOC
289 0 : hwloc_cpuset_t cur_cpuset = hwloc_bitmap_alloc();
290 :
291 0 : hwloc_get_cpubind(g_topology, cur_cpuset, HWLOC_CPUBIND_THREAD);
292 :
293 : char c[128];
294 0 : hwloc_bitmap_snprintf(c, 128, cur_cpuset);
295 :
296 : /* Free our cpuset copy */
297 0 : hwloc_bitmap_free(cur_cpuset);
298 :
299 0 : return std::string(c);
300 : #else
301 : std::stringstream message;
302 : message << "'get_cur_cpuset_str' method can be called only if StreamPU is linked with the 'hwloc' library.";
303 : throw tools::runtime_error(__FILE__, __LINE__, __func__, message.str());
304 : #endif
305 : }
|