Loading [MathJax]/extensions/tex2jax.js
ATLAS Offline Software
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
DeviceMgmtSvc.cxx
Go to the documentation of this file.
1 //
2 // Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 //
4 
5 // Local include(s).
6 #include "DeviceMgmtSvc.h"
7 
8 // System include(s).
9 #include <filesystem>
10 #include <fstream>
11 #include <CL/cl_ext_xilinx.h>
12 
13 namespace AthXRT {
14 
20 
21  std::vector<cl::Platform> platforms;
22 
23  ATH_CHECK(cl::Platform::get(&platforms) == CL_SUCCESS);
24  si.device_count = 0;
25  for (const cl::Platform &platform : platforms) {
26 
27  // Filter platforms by name. Currently AMD FPGA platform is
28  // still referenced as "Xilinx".
29  std::string platform_name;
30  ATH_CHECK(platform.getInfo(CL_PLATFORM_NAME, &platform_name) == CL_SUCCESS);
31  if (platform_name != "Xilinx") {
32  ATH_MSG_WARNING("Skipping unsuported platform " << platform_name);
33  continue;
34  }
35 
36  // Get devices list for the platform and count total devices.
37  std::vector<cl::Device> devices;
38  ATH_CHECK(platform.getDevices(CL_DEVICE_TYPE_ACCELERATOR, &devices) ==
39  CL_SUCCESS);
40  ATH_MSG_DEBUG("Found XRT/OpenCL platform '" << platform_name << "' with "
41  << devices.size()
42  << " devices");
43  si.device_count += devices.size();
44 
45  // Group devices by type, using the name property.
46  // All similar devices should have the same name,
47  // I.E: "xilinx_u250_gen3x16_xdma_shell_4_1"
48  for (const cl::Device &device : devices) {
49  const std::string device_name = get_device_name(device);
50 
51  // Check if we already have a device with the same name.
52  bool found = false;
53  for (std::vector<cl::Device> &list : si.device_types) {
54  std::string list_device_name;
55  ATH_CHECK(list[0].getInfo(CL_DEVICE_NAME, &list_device_name) ==
56  CL_SUCCESS);
57  if (device_name == list_device_name) {
58  found = true;
59  list.push_back(device);
60  break;
61  }
62  }
63  if (!found) {
64  std::vector<cl::Device> new_list = {device};
65  si.device_types.push_back(new_list);
66  }
67  }
68  }
69 
70  // We expect to have at least one device to program.
71  if (si.device_count < 1) {
72  // This should not be this catastrophic and we could fallback to
73  // software implementation, but for now we will consider that an
74  // accelerator have to be present if this service is configured.
75  ATH_MSG_ERROR("No XRT device found");
76  return StatusCode::FAILURE;
77  } else {
78  ATH_MSG_INFO("Found a total of "
79  << si.device_count << " AMD FPGA device(s) ("
80  << si.device_types.size() << " device type(s))");
81  }
82 
83  return StatusCode::SUCCESS;
84 
85 } // DeviceMgmtSvc::inspect_devices()
86 
92 
93  // We expect at least one XCLBIN file to be specified.
94  if (m_xclbin_path_list.empty()) {
95  ATH_MSG_ERROR("No XCLBIN list specified");
96  return StatusCode::FAILURE;
97  }
98 
99  // If there is more XCLBIN files to program than device(s), this
100  // is probably an error (the opposite is ok).
101  if (m_xclbin_path_list.size() > si.device_count) {
103  "More XCLBIN file(s) specified than "
104  "devices type available ("
105  << si.device_count << "): ");
106  for (const std::string &xclbin_path : m_xclbin_path_list) {
107  ATH_MSG_ERROR(xclbin_path);
108  }
109  return StatusCode::FAILURE;
110  }
111 
112  // Inspect XCLBIN files.
113  for (const std::string &xclbin_path : m_xclbin_path_list) {
114 
115  if (!std::filesystem::exists(xclbin_path)) {
116  ATH_MSG_ERROR("XCLBIN file does not exist: " << xclbin_path);
117  return StatusCode::FAILURE;
118  }
119 
120  // Create a temporary XRT API XCLBIN object to use introspection
121  // to gather some information. With this approach, we are loading
122  // them twice from disk which is not optimal.
123  DeviceMgmtSvc::XclbinInfo xclbin_info;
124  try {
125  xrt::xclbin xrt_xclbin(xclbin_path);
126  xclbin_info.path = xclbin_path;
127  xclbin_info.xsa_name = xrt_xclbin.get_xsa_name();
128  xclbin_info.fpga_device_name = xrt_xclbin.get_fpga_device_name();
129  xclbin_info.uuid = xrt_xclbin.get_uuid().to_string();
130  for (const xrt::xclbin::kernel &kernel : xrt_xclbin.get_kernels()) {
131  // Ensure that the kernel have a least one compute unit.
132  // Having a kernel without compute unit is not a common use case,
133  // but it is possible if a .xo with a kernel is linked in the
134  // .xclbin, but the number of said kernel is set to 0.
135  if (!kernel.get_cus().empty()) {
136  xclbin_info.kernel_names.push_back(kernel.get_name());
137  }
138  }
139  } catch (...) {
140  ATH_MSG_ERROR("Could not create xrt::xclbin from " << xclbin_path);
141  return StatusCode::FAILURE;
142  }
143  m_xclbin_infos.push_back(xclbin_info);
144  }
145 
146  // Extract some more information from the XCLBIN collection:
147  // The number of different XCLBIN files and the number of different
148  // FPGA device names targeted by the XCLBIN files.
149  std::set<std::string> uuids;
150  std::set<std::string> fpga_device_names;
151  for (const XclbinInfo &info : m_xclbin_infos) {
152  uuids.insert(info.uuid);
153  fpga_device_names.insert(info.fpga_device_name);
154  }
155  si.different_xclbin_count = uuids.size();
156  si.different_xclbin_fpga_device_name = fpga_device_names.size();
157 
158  return StatusCode::SUCCESS;
159 
160 } // DeviceMgmtSvc::inspect_xclbin()
161 
165 std::string DeviceMgmtSvc::get_device_name(const cl::Device &device) const {
166 
167  cl_int err = CL_SUCCESS;
168  std::string device_name;
169  err = device.getInfo(CL_DEVICE_NAME, &device_name);
170  if (err != CL_SUCCESS) {
171  ATH_MSG_ERROR("Failed to get device name");
172  return std::string("error");
173  }
174  return device_name;
175 }
176 
180 std::string DeviceMgmtSvc::get_device_bdf(const cl::Device &device) const {
181 
182  cl_int err = CL_SUCCESS;
183  std::string device_bdf;
184  err = device.getInfo(CL_DEVICE_PCIE_BDF, &device_bdf);
185  if (err != CL_SUCCESS) {
186  ATH_MSG_ERROR("Failed to get device BDF");
187  return std::string("error");
188  }
189  return device_bdf;
190 }
191 
198 static std::string getPrefixUpToNthOccurrence(const std::string &str,
199  char token, int n) {
200 
201  std::size_t pos = 0;
202  int count = 0;
203 
204  // Iterate through the string to find the nth occurrence of the token
205  while (count < n && pos != std::string::npos) {
206  pos = str.find(token, pos + 1);
207  count++;
208  }
209 
210  // If the token isn't found n times, return the whole string
211  if (pos == std::string::npos) {
212  return str;
213  }
214 
215  // Return the substring up to and including the nth occurrence
216  return str.substr(0, pos + 1);
217 }
218 
228  const DeviceMgmtSvc::XclbinInfo &xclbin_info,
229  const cl::Device &device) const {
230 
231  const std::string device_prefix =
232  getPrefixUpToNthOccurrence(get_device_name(device), '_', 2);
233  const std::string xsa_prefix =
234  getPrefixUpToNthOccurrence(xclbin_info.xsa_name, '_', 2);
235  if (device_prefix == xsa_prefix) {
236  return true;
237  } else {
238  return false;
239  }
240 }
241 
263 
264  // Do we have only one FPGA type?
265  if (si.device_types.size() == 1) {
266 
267  if (m_xclbin_infos.size() == 1) {
268 
269  // We have one or multiple device(s) of the same type and only have one
270  // XCLBIN: Program all device(s) with the same XCLBIN and create one
271  // context.
272  ATH_MSG_DEBUG("Case 1: One or multiple identical device(s), one xclbin");
273  DeviceMgmtSvc::AthClContext ath_cl_context;
274  for (const cl::Device &device : si.device_types[0]) {
275  ath_cl_context.devices.push_back(device);
276  }
277  ath_cl_context.xclbin_info = m_xclbin_infos[0];
278  m_ath_cl_contexts.push_back(ath_cl_context);
279 
280  } else {
281 
283 
284  // This is an error: we only have one FPGA type but
285  // XCLBIN files targeting multiple fpga.
287  "Specified XCLBINs target multiple device types, but only one "
288  "device type is present");
289  return StatusCode::FAILURE;
290  }
291 
292  if (si.different_xclbin_count == 1) {
293  // We have multiple device of the same type and multiple identical
294  // xclbin: Program the same number of devices that we have XCLBIN files,
295  // but put them in only one context as the XCLBIN will be identical for
296  // all programmed devices. Some devices might be left un-programmed.
298  "Case 2: Multiple identical devices, multiple identical xclbins");
299  DeviceMgmtSvc::AthClContext ath_cl_context;
300  for (std::size_t i = 0; i < m_xclbin_infos.size(); ++i) {
301  ath_cl_context.devices.push_back(si.device_types[0][i]);
302  }
303  ath_cl_context.xclbin_info = m_xclbin_infos[0];
304  m_ath_cl_contexts.push_back(ath_cl_context);
305 
306  } else {
307 
308  // We have multiple device of the same type and multiple different
309  // XCLBIN, but all targeting the same device: Program all devices with a
310  // differnt XCLBIN and create one context per device/XCLBIN. Some
311  // devices might be left un-programmed.
313  "Case 3: Multiple identical devices, multiple different XCLBIN "
314  "files, but targeting the same device type");
315  for (std::size_t i = 0; i < m_xclbin_infos.size(); ++i) {
316  DeviceMgmtSvc::AthClContext ath_cl_context;
317  ath_cl_context.xclbin_info = m_xclbin_infos[i];
318  ath_cl_context.devices.push_back(si.device_types[0][i]);
319  m_ath_cl_contexts.push_back(ath_cl_context);
320  }
321  }
322  }
323  } else {
324 
325  // More tricky (and probably an edge case): we have different
326  // devices types. We will try to pair each device them with a
327  // XCLBIN files based on the device name and XCLBIN XSA name,
328  // and load them in separate contexts.
329  ATH_MSG_DEBUG("Case 4: Multiple different devices, multiple xclbins");
330  std::vector<XclbinInfo> unaffected_xclbin_infos(m_xclbin_infos);
331  for (const std::vector<cl::Device> &device_type : si.device_types) {
332  for (const cl::Device &device : device_type) {
333  DeviceMgmtSvc::AthClContext ath_cl_context;
334  ath_cl_context.devices.push_back(device);
335 
336  // Try to find a matching XCLBIN for this device.
338  bool found = false;
339  for (iter = unaffected_xclbin_infos.begin();
340  iter != unaffected_xclbin_infos.end();) {
341  if (is_xclbin_compatible_with_device(*iter, device)) {
342  ath_cl_context.xclbin_info = *iter;
343  iter = unaffected_xclbin_infos.erase(iter);
344  found = true;
345  break;
346  } else {
347  ++iter;
348  }
349  }
350 
351  // Only keep this combination if we found a matching XCLBIN.
352  if (found) {
353  m_ath_cl_contexts.push_back(ath_cl_context);
354  } else {
355  // If we did not find a matching XCLBIN, we will not program the
356  // device. This is not an error, but we will report it.
357  ATH_MSG_WARNING("No compatible XCLBIN found for device "
358  << get_device_name(device) << " ("
359  << get_device_bdf(device) << ")");
360  }
361  }
362  }
363 
364  for (const XclbinInfo &xclbin_info : unaffected_xclbin_infos) {
365  // Report XCLBIN files that were not affected to a device.
366  // (This could happen for XCLBIN not compatible with any device.)
368  "No compatible device found for XCLBIN: " << xclbin_info.path);
369  }
370  }
371 
372  return StatusCode::SUCCESS;
373 
374 } // DeviceMgmtSvc::pair_devices_and_xclbins()
375 
383 
384  cl_int err = CL_SUCCESS;
385 
386  for (AthClContext &ath_cl_context : m_ath_cl_contexts) {
387 
388  // Create an OpenCL context for the device(s).
389  ath_cl_context.context = std::make_shared<cl::Context>(
390  ath_cl_context.devices, nullptr, nullptr, nullptr, &err);
391  if (err != CL_SUCCESS) {
392  ATH_MSG_ERROR("Failed to create cl::Context");
393  return StatusCode::FAILURE;
394  }
395 
396  // Load XCLBIN file from disk.
397  std::ifstream file;
398  try {
399  file.open(ath_cl_context.xclbin_info.path.c_str(), std::ios::binary);
400  } catch (...) {
401  ATH_MSG_ERROR("Could not open " << ath_cl_context.xclbin_info.path
402  << " for reading");
403  return StatusCode::FAILURE;
404  }
405  std::vector<char> xclbin_buffer((std::istreambuf_iterator<char>(file)),
406  std::istreambuf_iterator<char>());
407 
408  // Wrap XCLBIN data and size in a vector of cl::Program::Binaries.
409  // If we program multiple devices, we need to provide the same
410  // binary for each device.
411  cl::Program::Binaries binary;
412  for (std::size_t i = 0; i < ath_cl_context.devices.size(); ++i) {
413  binary.push_back({xclbin_buffer.data(), xclbin_buffer.size()});
414  }
415 
416  // Create a program from the XCLBIN binary.
417  // Effectively loading the XCLBIN on the device(s).
418  ath_cl_context.program = std::make_shared<cl::Program>(
419  *ath_cl_context.context, ath_cl_context.devices, binary, nullptr, &err);
420  if (err != CL_SUCCESS) {
421  ATH_MSG_ERROR("Failed to create cl::Program");
422  return StatusCode::FAILURE;
423  }
424 
425  // Report what have been done.
426  std::string bdfs = "";
427  for (const cl::Device &device : ath_cl_context.devices) {
428  bdfs += get_device_bdf(device);
429  bdfs += " ";
430  }
431  ATH_MSG_INFO("Loaded " << ath_cl_context.xclbin_info.path << " on "
432  << ath_cl_context.devices.size() << " "
433  << get_device_name(ath_cl_context.devices[0])
434  << " device(s): " << bdfs);
435  }
436 
437  return StatusCode::SUCCESS;
438 
439 } // DeviceMgmtSvc::program_devices
440 
448 
449  SystemInfo sys_info;
450 
451  // Inspect available device(s) and fill sys_info.
452  ATH_CHECK(inspect_devices(sys_info));
453 
454  // Inspect provided XCLBINs to gather information about kernel(s)
455  // into sys_info and a list of XclbinInfo.
456  ATH_CHECK(inspect_xclbins(sys_info));
457 
458  // Now we can make a decision about the pairing of device(s)
459  // and xclbin(s), and the number of required context(s) by
460  // filling m_ath_cl_contexts.
462 
463  // Program the devices with the XCLBINs and create contexts,
464  // and programs based on m_ath_cl_contexts.
466 
467  // Return gracefully.
468  return StatusCode::SUCCESS;
469 }
470 
472 
473  // Finalise the base class.
475 
476  // Return gracefully.
477  return StatusCode::SUCCESS;
478 }
479 
480 const std::vector<std::shared_ptr<xrt::device>>
482 
483  std::vector<std::shared_ptr<xrt::device>> devices;
484 
485  // Iterate over all contexts and check if the kernel name is in the list.
486  // If so, add the device(s) to the list of devices to return.
487  for (const AthClContext &ath_cl_context : m_ath_cl_contexts) {
488  if (std::find(ath_cl_context.xclbin_info.kernel_names.begin(),
489  ath_cl_context.xclbin_info.kernel_names.end(),
490  name) != ath_cl_context.xclbin_info.kernel_names.end()) {
491  for (const cl::Device &device : ath_cl_context.devices) {
492  devices.push_back(std::make_shared<xrt::device>(
493  xrt::opencl::get_xrt_device(device())));
494  }
495  }
496  }
497 
498  return devices;
499 }
500 
501 const std::vector<IDeviceMgmtSvc::OpenCLHandle>
503  const std::string &name) const {
504 
505  std::vector<IDeviceMgmtSvc::OpenCLHandle> handles;
506 
507  // Iterate over all contexts and check if the kernel name is in the list.
508  // If so, add the context and program to the list of handles to return.
509  for (const AthClContext &ath_cl_context : m_ath_cl_contexts) {
510  if (std::find(ath_cl_context.xclbin_info.kernel_names.begin(),
511  ath_cl_context.xclbin_info.kernel_names.end(),
512  name) != ath_cl_context.xclbin_info.kernel_names.end()) {
513  IDeviceMgmtSvc::OpenCLHandle handle = {ath_cl_context.context,
514  ath_cl_context.program};
515  handles.push_back(handle);
516  }
517  }
518 
519  return handles;
520 }
521 
522 } // namespace AthXRT
grepfile.info
info
Definition: grepfile.py:38
xAOD::iterator
JetConstituentVector::iterator iterator
Definition: JetConstituentVector.cxx:68
AthXRT::DeviceMgmtSvc::get_opencl_handles_by_kernel_name
virtual const std::vector< IDeviceMgmtSvc::OpenCLHandle > get_opencl_handles_by_kernel_name(const std::string &name) const override
Get a list of OpenCL handles providing the specified kernel.
Definition: DeviceMgmtSvc.cxx:502
AthXRT::DeviceMgmtSvc::finalize
virtual StatusCode finalize() override
Finalise the service.
Definition: DeviceMgmtSvc.cxx:471
AthXRT::DeviceMgmtSvc::SystemInfo::different_xclbin_count
std::size_t different_xclbin_count
Definition: DeviceMgmtSvc.h:93
createLinkingScheme.iter
iter
Definition: createLinkingScheme.py:56
AthXRT::DeviceMgmtSvc::XclbinInfo::kernel_names
std::vector< std::string > kernel_names
Definition: DeviceMgmtSvc.h:116
python.tests.PyTestsLib.finalize
def finalize(self)
_info( "content of StoreGate..." ) self.sg.dump()
Definition: PyTestsLib.py:50
AthXRT::DeviceMgmtSvc::AthClContext
Struct to hold information about a context, as well as the devices, the program and XCLBIN file assoc...
Definition: DeviceMgmtSvc.h:129
AthXRT::DeviceMgmtSvc::m_xclbin_infos
std::vector< XclbinInfo > m_xclbin_infos
List of XCLBIN files info configured for the service.
Definition: DeviceMgmtSvc.h:125
AthXRT::DeviceMgmtSvc::SystemInfo::different_xclbin_fpga_device_name
std::size_t different_xclbin_fpga_device_name
Definition: DeviceMgmtSvc.h:94
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
find
std::string find(const std::string &s)
return a remapped string
Definition: hcg.cxx:135
AthXRT::DeviceMgmtSvc::get_xrt_devices_by_kernel_name
virtual const std::vector< std::shared_ptr< xrt::device > > get_xrt_devices_by_kernel_name(const std::string &name) const override
Get a list of XRT devices providing the specified kernel.
Definition: DeviceMgmtSvc.cxx:481
AthXRT::IDeviceMgmtSvc::OpenCLHandle::context
std::shared_ptr< cl::Context > context
Definition: IDeviceMgmtSvc.h:49
AthXRT::DeviceMgmtSvc::SystemInfo
Definition: DeviceMgmtSvc.h:86
AthXRT::DeviceMgmtSvc::get_device_bdf
std::string get_device_bdf(const cl::Device &device) const
Get the BDF (bus:device:function) string of a cl::device.
Definition: DeviceMgmtSvc.cxx:180
AthXRT::DeviceMgmtSvc::XclbinInfo::path
std::string path
Definition: DeviceMgmtSvc.h:112
AthXRT::DeviceMgmtSvc::inspect_xclbins
StatusCode inspect_xclbins(SystemInfo &si)
Inspect the provided XCLBIN files and fill the SystemInfo structure.
Definition: DeviceMgmtSvc.cxx:91
AthXRT::DeviceMgmtSvc::XclbinInfo::fpga_device_name
std::string fpga_device_name
Definition: DeviceMgmtSvc.h:114
AthXRT::DeviceMgmtSvc::AthClContext::xclbin_info
XclbinInfo xclbin_info
Definition: DeviceMgmtSvc.h:132
AthXRT::DeviceMgmtSvc::XclbinInfo::uuid
std::string uuid
Definition: DeviceMgmtSvc.h:115
XMLtoHeader.count
count
Definition: XMLtoHeader.py:85
AthXRT::DeviceMgmtSvc::XclbinInfo
Struct to hold information about an XCLBIN file, as well as the kernels it contains.
Definition: DeviceMgmtSvc.h:111
AthXRT::DeviceMgmtSvc::initialize
virtual StatusCode initialize() override
Initialise the service.
Definition: DeviceMgmtSvc.cxx:447
AthXRT::DeviceMgmtSvc::SystemInfo::device_count
std::size_t device_count
Definition: DeviceMgmtSvc.h:92
AthXRT::DeviceMgmtSvc::is_xclbin_compatible_with_device
bool is_xclbin_compatible_with_device(const DeviceMgmtSvc::XclbinInfo &xclbin_info, const cl::Device &device) const
Helper function to check if an XCLBIN file is compatible with a device.
Definition: DeviceMgmtSvc.cxx:227
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
dqt_zlumi_pandas.err
err
Definition: dqt_zlumi_pandas.py:182
lumiFormat.i
int i
Definition: lumiFormat.py:85
AthXRT::DeviceMgmtSvc::m_xclbin_path_list
Gaudi::Property< std::vector< std::string > > m_xclbin_path_list
The list of xclbin files to use.
Definition: DeviceMgmtSvc.h:72
AthXRT::DeviceMgmtSvc::XclbinInfo::xsa_name
std::string xsa_name
Definition: DeviceMgmtSvc.h:113
beamspotman.n
n
Definition: beamspotman.py:731
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
AthXRT::DeviceMgmtSvc::SystemInfo::device_types
std::vector< std::vector< cl::Device > > device_types
Definition: DeviceMgmtSvc.h:90
python.CaloAddPedShiftConfig.str
str
Definition: CaloAddPedShiftConfig.py:42
file
TFile * file
Definition: tile_monitor.h:29
AthXRT::DeviceMgmtSvc::AthClContext::devices
std::vector< cl::Device > devices
Definition: DeviceMgmtSvc.h:131
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
AthXRT::DeviceMgmtSvc::get_device_name
std::string get_device_name(const cl::Device &device) const
Get the name of a cl::device.
Definition: DeviceMgmtSvc.cxx:165
histSizes.list
def list(name, path='/')
Definition: histSizes.py:38
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
DeviceMgmtSvc.h
checkTriggerxAOD.found
found
Definition: checkTriggerxAOD.py:328
AthXRT::DeviceMgmtSvc::m_ath_cl_contexts
std::vector< AthClContext > m_ath_cl_contexts
List of contexts configured for the service.
Definition: DeviceMgmtSvc.h:137
python.LumiBlobConversion.pos
pos
Definition: LumiBlobConversion.py:18
make_hlt_rep.platform
platform
Definition: make_hlt_rep.py:46
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
AthXRT::IDeviceMgmtSvc::OpenCLHandle
Struct holding OpenCL handles for a kernel.
Definition: IDeviceMgmtSvc.h:48
AthXRT::DeviceMgmtSvc::pair_devices_and_xclbins
StatusCode pair_devices_and_xclbins(const SystemInfo &si)
Pair devices and XCLBINs and create contexts.
Definition: DeviceMgmtSvc.cxx:262
get
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition: hcg.cxx:127
AthXRT::DeviceMgmtSvc::inspect_devices
StatusCode inspect_devices(SystemInfo &si)
Inspect the available devices and fill the SystemInfo structure.
Definition: DeviceMgmtSvc.cxx:19
AthXRT::DeviceMgmtSvc::program_devices
StatusCode program_devices()
Program the devices with the XCLBIN files and create contexts.
Definition: DeviceMgmtSvc.cxx:382
str
Definition: BTagTrackIpAccessor.cxx:11
python.dummyaccess.exists
def exists(filename)
Definition: dummyaccess.py:9
AthXRT
Definition: IDeviceMgmtSvc.h:30