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 111 : Thread_pinning::is_init()
30 : {
31 111 : 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 : if (g_enable_logs)
157 : {
158 : std::clog << "'pin' method do nothing as StreamPU has not been linked with the 'hwloc' library." << std::endl;
159 : }
160 : #endif
161 0 : g_mtx.unlock();
162 0 : }
163 :
164 : // Thread pinning second function using hwloc objects
165 : void
166 54 : Thread_pinning::pin(const std::string hwloc_objects)
167 : {
168 54 : g_mtx.lock();
169 :
170 : #ifdef SPU_HWLOC
171 54 : if (Thread_pinning::is_init())
172 : {
173 : // Objects parsing
174 54 : std::vector<std::string> hwloc_objects_vector = Thread_pinning_utils::thread_parser(hwloc_objects);
175 :
176 : // getting the pairs
177 54 : std::vector<std::pair<hwloc_obj_type_t, int>> object_numbers;
178 108 : for (auto obj : hwloc_objects_vector)
179 54 : object_numbers.push_back(Thread_pinning_utils::str_to_hwloc_object(obj));
180 :
181 : // getting topology depth of each object
182 54 : std::vector<int> object_depth = {};
183 108 : for (auto obj : object_numbers)
184 54 : object_depth.push_back(hwloc_get_type_or_below_depth(g_topology, obj.first));
185 :
186 : // Allocating cpu_set
187 54 : hwloc_bitmap_t all_pus = hwloc_bitmap_alloc();
188 54 : hwloc_bitmap_zero(all_pus);
189 :
190 108 : for (size_t i = 0; i < object_numbers.size(); ++i)
191 : {
192 54 : hwloc_obj_t obj = hwloc_get_obj_by_depth(g_topology, object_depth[i], object_numbers[i].second);
193 54 : if (obj == nullptr)
194 : {
195 0 : std::stringstream message;
196 0 : message << "obj is nullptr ('Type' = " << hwloc_objects_vector[i] << ").";
197 0 : throw tools::runtime_error(__FILE__, __LINE__, __func__, message.str());
198 0 : }
199 54 : hwloc_bitmap_or(all_pus, all_pus, obj->cpuset);
200 : }
201 :
202 54 : if (g_enable_logs)
203 : {
204 : char c[128];
205 0 : hwloc_bitmap_snprintf(c, 128, all_pus);
206 :
207 0 : std::clog << "Thread pinning info -- ";
208 0 : for (size_t i = 0; i < hwloc_objects_vector.size(); ++i)
209 : {
210 0 : std::clog << "Object = " << hwloc_objects_vector[i] << " | number = " << object_numbers[i].second
211 0 : << std::endl;
212 : }
213 0 : std::clog << "bitmap: " << all_pus << std::endl;
214 : }
215 :
216 : /* And try to bind ourself there. */
217 54 : if (hwloc_set_cpubind(g_topology, all_pus, HWLOC_CPUBIND_THREAD))
218 : {
219 : char* str;
220 0 : int error = errno;
221 0 : hwloc_bitmap_asprintf(&str, all_pus);
222 0 : std::clog << "Couldn't bind to cpuset " << str << ": " << strerror(error) << std::endl;
223 0 : free(str);
224 : }
225 :
226 : /* Free our cpuset copy */
227 54 : hwloc_bitmap_free(all_pus);
228 54 : }
229 : else
230 : {
231 0 : if (g_enable_logs)
232 : {
233 : std::clog << "You can't call the 'pin' method if you have not call the 'init' method before, nothing will "
234 0 : << "be done." << std::endl;
235 : }
236 : }
237 : #else
238 : if (g_enable_logs)
239 : {
240 : std::clog << "'pin' method do nothing as StreamPU has not been linked with the 'hwloc' library." << std::endl;
241 : }
242 : #endif
243 54 : g_mtx.unlock();
244 54 : }
245 :
246 : void
247 48 : Thread_pinning::unpin()
248 : {
249 48 : g_mtx.lock();
250 : #ifdef SPU_HWLOC
251 48 : if (!Thread_pinning::is_init())
252 : {
253 0 : if (g_enable_logs)
254 : {
255 : std::clog << "You can't call the 'unpin' method if you have not call the 'init' method before, nothing "
256 0 : << "will be done." << std::endl;
257 : }
258 : }
259 : else
260 : {
261 : // get cpuset of root object
262 48 : hwloc_cpuset_t unpin_set = hwloc_bitmap_dup(hwloc_get_obj_by_depth(g_topology, 0, 0)->cpuset);
263 48 : if (hwloc_set_cpubind(g_topology, unpin_set, HWLOC_CPUBIND_THREAD))
264 : {
265 : char* bitmap_str;
266 0 : int error = errno;
267 0 : hwloc_bitmap_asprintf(&bitmap_str, unpin_set);
268 0 : std::clog << "'unpin' method failed ('bitmap_str' = " << bitmap_str << ", 'error' = " << strerror(error)
269 0 : << ")" << std::endl;
270 0 : free(bitmap_str);
271 : }
272 48 : hwloc_bitmap_free(unpin_set);
273 : }
274 : #else
275 : if (g_enable_logs)
276 : {
277 : std::clog << "'unpin' method do nothing as StreamPU has not been linked with the 'hwloc' library." << std::endl;
278 : }
279 : #endif
280 48 : g_mtx.unlock();
281 48 : }
282 :
283 : std::string
284 0 : Thread_pinning::get_cur_cpuset_str()
285 : {
286 : #ifdef SPU_HWLOC
287 0 : hwloc_cpuset_t cur_cpuset = hwloc_bitmap_alloc();
288 :
289 0 : hwloc_get_cpubind(g_topology, cur_cpuset, HWLOC_CPUBIND_THREAD);
290 :
291 : char c[128];
292 0 : hwloc_bitmap_snprintf(c, 128, cur_cpuset);
293 :
294 : /* Free our cpuset copy */
295 0 : hwloc_bitmap_free(cur_cpuset);
296 :
297 0 : return std::string(c);
298 : #else
299 : std::stringstream message;
300 : message << "'get_cur_cpuset_str' method can be called only if StreamPU is linked with the 'hwloc' library.";
301 : throw tools::runtime_error(__FILE__, __LINE__, __func__, message.str());
302 : #endif
303 : }
|