Arcane  4.1.12.0
Developer documentation
Loading...
Searching...
No Matches
HWLocProcessorAffinity.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* HWLocProcessorAffinity.cc (C) 2000-2025 */
9/* */
10/* Management of processor affinity via the HWLOC library. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/IProcessorAffinityService.h"
15#include "arcane/utils/ITraceMng.h"
16#include "arcane/utils/OStringStream.h"
17
18#include "arcane/core/FactoryService.h"
19#include "arcane/core/AbstractService.h"
20
21#include "arccore/base/internal/DependencyInjection.h"
22
23#include <hwloc.h>
24
25#include <cstdio>
26
27/*---------------------------------------------------------------------------*/
28/*---------------------------------------------------------------------------*/
29
30namespace Arcane
31{
32
33/*---------------------------------------------------------------------------*/
34/*---------------------------------------------------------------------------*/
35
36class HWLocProcessorAffinityService
37: public TraceAccessor
39{
40 public:
41
42 explicit HWLocProcessorAffinityService(const ServiceBuildInfo& sbi)
44 {
45 }
46 explicit HWLocProcessorAffinityService(ITraceMng* tm)
47 : TraceAccessor(tm)
48 {
49 }
50
51 //<! Frees resources
52 ~HWLocProcessorAffinityService() override
53 {
54 if (m_topology)
55 hwloc_topology_destroy(m_topology);
56 }
57
58 public:
59
60 void build() override {}
61
62 public:
63
64 void printInfos() override;
65 String cpuSetString() override;
66 void bindThread(Int32 cpu) override;
67
68 Int32 numberOfCore() override;
69 Int32 numberOfSocket() override;
71
72 private:
73 private:
74
75 bool m_is_init = false;
76 hwloc_topology_t m_topology = nullptr;
77
78 private:
79
80 void _checkInit();
81 void _outputTopology(hwloc_obj_t l, hwloc_obj_t parent, int i, OStringStream& ostr);
82 int _numberOf(const hwloc_obj_type_t);
83};
84
85/*---------------------------------------------------------------------------*/
86/*---------------------------------------------------------------------------*/
87
88// Temporary copy of 'hwloc_obj_snprintf' which no longer exists
89// starting from hwloc version 2.0
90static int
91_internal_hwloc_obj_snprintf(char* string, size_t size,
92 hwloc_obj* l, const char* _indexprefix, int verbose)
93{
94 const char* indexprefix = _indexprefix ? _indexprefix : "#";
95 char os_index[12] = "";
96 char type[64];
97 char attr[128];
98 int attrlen;
99
100 if (l->os_index != (unsigned)-1) {
101 std::snprintf(os_index, 12, "%s%u", indexprefix, l->os_index);
102 }
103
104 hwloc_obj_type_snprintf(type, sizeof(type), l, verbose);
105 attrlen = hwloc_obj_attr_snprintf(attr, sizeof(attr), l, " ", verbose);
106
107 if (attrlen > 0)
108 return std::snprintf(string, size, "%s%s(%s)", type, os_index, attr);
109 else
110 return std::snprintf(string, size, "%s%s", type, os_index);
111}
112
113/*---------------------------------------------------------------------------*/
114/*---------------------------------------------------------------------------*/
115
116/* Recursively output topology in a console fashion */
117void HWLocProcessorAffinityService::
118_outputTopology(hwloc_obj_t l, hwloc_obj_t parent, int i, OStringStream& ostr)
119{
120 const char* indexprefix = "#";
121 char line[512];
122 if (parent && parent->arity == 1 && hwloc_bitmap_isequal(l->cpuset, parent->cpuset)) {
123 ostr() << " + ";
124 }
125 else {
126 if (parent) {
127 info() << ostr.str();
128 ostr.reset();
129 }
130 for (int z = 0; z < 2 * i; ++z)
131 ostr() << ' ';
132 i++;
133 }
134 _internal_hwloc_obj_snprintf(line, sizeof(line) - 1, l, indexprefix, 0);
135 ostr() << line;
136 unsigned int arity = l->arity;
137 if (arity != 0 || (!i && !arity)) {
138 for (unsigned int x = 0; x < arity; ++x) {
139 _outputTopology(l->children[x], l, i, ostr);
140 }
141 }
142}
143
144/*---------------------------------------------------------------------------*/
145/*---------------------------------------------------------------------------*/
146
147void HWLocProcessorAffinityService::
148_checkInit()
149{
150 if (m_is_init)
151 return;
152 m_is_init = true;
153
154 info() << "Getting hardware architecture hwloc_version=" << HWLOC_VERSION;
155 int err = hwloc_topology_init(&m_topology);
156 if (err != 0) {
157 info() << "Error in hwloc_topology_init r=" << err;
158 return;
159 }
160 unsigned long flags = 0;
161 hwloc_topology_set_flags(m_topology, flags);
162
163 err = hwloc_topology_load(m_topology);
164 if (err != 0) {
165 info() << "Error in hwloc_topology_load r=" << err;
166 return;
167 }
168}
169
170/*---------------------------------------------------------------------------*/
171/*---------------------------------------------------------------------------*/
172
175{
176 hwloc_bitmap_t new_cpuset = hwloc_bitmap_alloc();
177 hwloc_get_cpubind(m_topology, new_cpuset, 0 | HWLOC_CPUBIND_THREAD);
178 char result_s[1024];
179 hwloc_bitmap_snprintf(result_s, sizeof(result_s) - 1, new_cpuset);
180 String s{ StringView(result_s) };
181 //ostr() << "R=" << result_s << '\n';
182 hwloc_bitmap_free(new_cpuset);
183 return s;
184}
185
186/*---------------------------------------------------------------------------*/
187/*---------------------------------------------------------------------------*/
188
191{
192 _checkInit();
193 OStringStream ostrf;
194 _outputTopology(hwloc_get_root_obj(m_topology), nullptr, 0, ostrf);
195 info() << ostrf.str();
196 info() << "Cpuset: " << cpuSetString();
197}
198
199/*---------------------------------------------------------------------------*/
200/*---------------------------------------------------------------------------*/
201
203bindThread(Int32 cpu)
204{
205 int flags = 0;
206 hwloc_bitmap_t new_cpuset = hwloc_bitmap_alloc();
207 hwloc_get_cpubind(m_topology, new_cpuset, 0 | HWLOC_CPUBIND_THREAD);
208
209 {
210 Integer cpu_index = 0;
211 unsigned int cpu_iter = 0;
212 hwloc_bitmap_foreach_begin(cpu_iter, new_cpuset)
213 {
214 //info() << "CPUSET ITER =" << cpu_iter << " wanted=" << cpu
215 // << " is_set?=" << hwloc_cpuset_isset(new_cpuset, cpu_iter);
216 if (cpu_index == cpu)
217 hwloc_bitmap_only(new_cpuset, cpu_iter);
218 ++cpu_index;
219 }
220 hwloc_bitmap_foreach_end();
221 }
222
223 hwloc_set_cpubind(m_topology, new_cpuset, flags | HWLOC_CPUBIND_THREAD);
224
225 // Check if bind is ok
226 hwloc_get_cpubind(m_topology, new_cpuset, 0 | HWLOC_CPUBIND_THREAD);
227 char result_s[1024];
228 hwloc_bitmap_snprintf(result_s, sizeof(result_s) - 1, new_cpuset);
229 //info() << "CPUSET V2=" << result_s;
230 hwloc_bitmap_free(new_cpuset);
231}
232
233/*---------------------------------------------------------------------------*/
234/*---------------------------------------------------------------------------*/
235
236Int32 HWLocProcessorAffinityService::
237_numberOf(const hwloc_obj_type_t that)
238{
239 _checkInit();
240 int depth = hwloc_get_type_depth(m_topology, that);
241 if (depth == HWLOC_TYPE_DEPTH_UNKNOWN)
242 return -1;
243 int width = hwloc_get_nbobjs_by_depth(m_topology, depth);
244 return width;
245}
246
247/*---------------------------------------------------------------------------*/
248/*---------------------------------------------------------------------------*/
249
251numberOfCore(void)
252{
253 return _numberOf(HWLOC_OBJ_CORE);
254}
255
256/*---------------------------------------------------------------------------*/
257/*---------------------------------------------------------------------------*/
258
261{
262 return _numberOf(HWLOC_OBJ_SOCKET);
263}
264
265/*---------------------------------------------------------------------------*/
266/*---------------------------------------------------------------------------*/
267
270{
271 return _numberOf(HWLOC_OBJ_PU);
272}
273
274/*---------------------------------------------------------------------------*/
275/*---------------------------------------------------------------------------*/
276
279 HWLoc);
280
281/*---------------------------------------------------------------------------*/
282/*---------------------------------------------------------------------------*/
283
284ARCANE_DI_REGISTER_PROVIDER(HWLocProcessorAffinityService,
285 DependencyInjection::ProviderProperty("HWLoc"),
286 ARCANE_DI_INTERFACES(IProcessorAffinityService),
287 ARCANE_DI_CONSTRUCTOR(ITraceMng*));
288
289/*---------------------------------------------------------------------------*/
290/*---------------------------------------------------------------------------*/
291
292} // namespace Arcane
293
294/*---------------------------------------------------------------------------*/
295/*---------------------------------------------------------------------------*/
#define ARCANE_REGISTER_APPLICATION_FACTORY(aclass, ainterface, aname)
Registers a factory service for the class aclass.
Int32 numberOfProcessingUnit() override
Number of logical cores (-1 if unknown).
void bindThread(Int32 cpu) override
Constrains the current thread to stay on the core with index cpu.
void printInfos() override
Displays complete topology information via info().
Int32 numberOfCore() override
Number of CPU cores (-1 if unknown).
String cpuSetString() override
Returns the cpuset for the current thread.
Int32 numberOfSocket() override
Number of sockets (-1 if unknown).
virtual ITraceMng * traceMng() const =0
Trace manager.
Interface of a CPU core affinity management service.
Output stream linked to a String.
IApplication * application() const
Access to the associated IApplication.
Structure containing the information to create a service.
View of a UTF-8 character string.
Definition StringView.h:44
TraceAccessor(ITraceMng *m)
Constructs an accessor via the trace manager m.
TraceMessage info() const
Flow for an information message.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Int32 Integer
Type representing an integer.
std::int32_t Int32
Signed integer type of 32 bits.