xgboost
context.h
Go to the documentation of this file.
1 
5 #ifndef XGBOOST_CONTEXT_H_
6 #define XGBOOST_CONTEXT_H_
7 
8 #include <xgboost/base.h> // for bst_d_ordinal_t
9 #include <xgboost/logging.h> // for CHECK_GE
10 #include <xgboost/parameter.h> // for XGBoostParameter
11 
12 #include <cstdint> // for int16_t, int32_t, int64_t
13 #include <memory> // for shared_ptr
14 #include <random> // for mt19937
15 #include <string> // for string, to_string
16 #include <type_traits> // for invoke_result_t, is_same_v, underlying_type_t
17 
18 namespace xgboost {
19 
20 class Json;
21 struct CUDAContext;
25 using RandomEngine = std::mt19937;
26 
27 // symbolic names
28 struct DeviceSym {
29  static auto constexpr CPU() { return "cpu"; }
30  static auto constexpr CUDA() { return "cuda"; }
31  static auto constexpr SyclDefault() { return "sycl"; }
32  static auto constexpr SyclCPU() { return "sycl:cpu"; }
33  static auto constexpr SyclGPU() { return "sycl:gpu"; }
34 };
35 
40 struct DeviceOrd {
41  // Constant representing the device ID of CPU.
42  static bst_d_ordinal_t constexpr CPUOrdinal() { return -1; }
43  static bst_d_ordinal_t constexpr InvalidOrdinal() { return -2; }
44 
45  enum Type : std::int16_t {
46  kCPU = 0,
47  kCUDA = 1,
49  kSyclCPU = 3,
50  kSyclGPU = 4
51  } device{kCPU};
52  // CUDA or Sycl device ordinal.
54 
55  [[nodiscard]] bool IsCUDA() const { return device == kCUDA; }
56  [[nodiscard]] bool IsCPU() const { return device == kCPU; }
57  [[nodiscard]] bool IsSyclDefault() const { return device == kSyclDefault; }
58  [[nodiscard]] bool IsSyclCPU() const { return device == kSyclCPU; }
59  [[nodiscard]] bool IsSyclGPU() const { return device == kSyclGPU; }
60  [[nodiscard]] bool IsSycl() const { return (IsSyclDefault() || IsSyclCPU() || IsSyclGPU()); }
61 
62  constexpr DeviceOrd() = default;
63  constexpr DeviceOrd(Type type, bst_d_ordinal_t ord) : device{type}, ordinal{ord} {}
64 
65  constexpr DeviceOrd(DeviceOrd const& that) = default;
66  constexpr DeviceOrd& operator=(DeviceOrd const& that) = default;
67  constexpr DeviceOrd(DeviceOrd&& that) = default;
68  constexpr DeviceOrd& operator=(DeviceOrd&& that) = default;
69 
73  [[nodiscard]] constexpr static auto CPU() { return DeviceOrd{kCPU, CPUOrdinal()}; }
79  [[nodiscard]] static constexpr auto CUDA(bst_d_ordinal_t ordinal) {
80  return DeviceOrd{kCUDA, ordinal};
81  }
87  [[nodiscard]] constexpr static auto SyclDefault(bst_d_ordinal_t ordinal = -1) {
89  }
95  [[nodiscard]] constexpr static auto SyclCPU(bst_d_ordinal_t ordinal = -1) {
96  return DeviceOrd{kSyclCPU, ordinal};
97  }
98 
104  [[nodiscard]] constexpr static auto SyclGPU(bst_d_ordinal_t ordinal = -1) {
105  return DeviceOrd{kSyclGPU, ordinal};
106  }
107 
108  [[nodiscard]] bool operator==(DeviceOrd const& that) const {
109  return device == that.device && ordinal == that.ordinal;
110  }
111  [[nodiscard]] bool operator!=(DeviceOrd const& that) const { return !(*this == that); }
115  [[nodiscard]] std::string Name() const {
116  switch (device) {
117  case DeviceOrd::kCPU:
118  return DeviceSym::CPU();
119  case DeviceOrd::kCUDA:
120  return DeviceSym::CUDA() + (':' + std::to_string(ordinal));
122  return DeviceSym::SyclDefault() + (':' + std::to_string(ordinal));
123  case DeviceOrd::kSyclCPU:
124  return DeviceSym::SyclCPU() + (':' + std::to_string(ordinal));
125  case DeviceOrd::kSyclGPU:
126  return DeviceSym::SyclGPU() + (':' + std::to_string(ordinal));
127  default: {
128  LOG(FATAL) << "Unknown device.";
129  return "";
130  }
131  }
132  }
133 };
134 
135 static_assert(sizeof(DeviceOrd) == sizeof(std::int32_t));
136 
137 std::ostream& operator<<(std::ostream& os, DeviceOrd ord);
138 
142 struct Context : public XGBoostParameter<Context> {
143  private:
144  // User interfacing parameter for device ordinal
145  std::string device{DeviceSym::CPU()}; // NOLINT
146  // The device ordinal set by user
147  DeviceOrd device_{DeviceOrd::CPU()};
148 
149  public:
150  static std::int64_t constexpr kDefaultSeed = 0;
151 
152  public:
154 
155  void Init(Args const& kwargs);
156 
157  template <typename Container>
158  Args UpdateAllowUnknown(Container const& kwargs) {
160  this->SetDeviceOrdinal(kwargs);
161  return args;
162  }
163 
164  // The number of threads to use if OpenMP is enabled. If equals 0, use the system default.
165  std::int32_t nthread{0}; // NOLINT
166  // stored random seed
167  std::int64_t seed{kDefaultSeed};
168  // whether seed the PRNG each iteration
169  bool seed_per_iteration{false};
170  // fail when gpu_id is invalid
172  bool validate_parameters{false};
173 
178  [[nodiscard]] std::int32_t Threads() const;
182  [[nodiscard]] bool IsCPU() const { return Device().IsCPU(); }
186  [[nodiscard]] bool IsCUDA() const { return Device().IsCUDA(); }
190  [[nodiscard]] bool IsSyclDefault() const { return Device().IsSyclDefault(); }
194  [[nodiscard]] bool IsSyclCPU() const { return Device().IsSyclCPU(); }
198  [[nodiscard]] bool IsSyclGPU() const { return Device().IsSyclGPU(); }
202  [[nodiscard]] bool IsSycl() const { return IsSyclDefault() || IsSyclCPU() || IsSyclGPU(); }
203 
207  [[nodiscard]] DeviceOrd Device() const { return device_; }
208 
213  [[nodiscard]] DeviceOrd DeviceFP64() const;
214 
218  [[nodiscard]] bst_d_ordinal_t Ordinal() const { return Device().ordinal; }
222  [[nodiscard]] std::string DeviceName() const { return Device().Name(); }
226  [[nodiscard]] CUDAContext const* CUDACtx() const;
230  [[nodiscard]] RandomEngine& Rng() const { return rng_; }
231 
232  [[nodiscard]] Json ToJson() const;
233  void FromJson(Json const& in);
234 
240  [[nodiscard]] Context MakeCUDA(bst_d_ordinal_t ordinal = 0) const {
241  Context ctx = *this;
242  return ctx.SetDevice(DeviceOrd::CUDA(ordinal));
243  }
247  [[nodiscard]] Context MakeCPU() const {
248  Context ctx = *this;
249  return ctx.SetDevice(DeviceOrd::CPU());
250  }
251 
255  template <typename CPUFn, typename CUDAFn>
256  decltype(auto) DispatchDevice(CPUFn&& cpu_fn, CUDAFn&& cuda_fn) const {
257  static_assert(std::is_same_v<std::invoke_result_t<CPUFn>, std::invoke_result_t<CUDAFn>>);
258  switch (this->Device().device) {
259  case DeviceOrd::kCPU:
260  return cpu_fn();
261  case DeviceOrd::kCUDA:
262  return cuda_fn();
263  default:
264  // Do not use the device name as this is likely an internal error, the name
265  // wouldn't be valid.
266  if (this->Device().IsSycl()) {
267  LOG(WARNING) << "The requested feature doesn't have SYCL specific implementation yet. "
268  << "CPU implementation is used";
269  return cpu_fn();
270  } else {
271  LOG(FATAL) << "Unknown device type:"
272  << static_cast<std::underlying_type_t<DeviceOrd::Type>>(this->Device().device);
273  break;
274  }
275  }
276  return std::invoke_result_t<CPUFn>();
277  }
278 
282  template <typename CPUFn, typename CUDAFn, typename SYCLFn>
283  decltype(auto) DispatchDevice(CPUFn&& cpu_fn, CUDAFn&& cuda_fn, SYCLFn&& sycl_fn) const {
284  static_assert(std::is_same_v<std::invoke_result_t<CPUFn>, std::invoke_result_t<SYCLFn>>);
285  if (this->Device().IsSycl()) {
286  return sycl_fn();
287  } else {
288  return DispatchDevice(cpu_fn, cuda_fn);
289  }
290  }
291 
292  // declare parameters
294  DMLC_DECLARE_FIELD(seed)
295  .set_default(kDefaultSeed)
296  .describe("Random number seed during training.");
297  DMLC_DECLARE_ALIAS(seed, random_state);
298  DMLC_DECLARE_FIELD(seed_per_iteration)
299  .set_default(false)
300  .describe("Seed PRNG determnisticly via iterator number.");
301  DMLC_DECLARE_FIELD(device).set_default(DeviceSym::CPU()).describe("Device ordinal.");
302  DMLC_DECLARE_FIELD(nthread).set_default(0).describe("Number of threads to use.");
303  DMLC_DECLARE_ALIAS(nthread, n_jobs);
304  DMLC_DECLARE_FIELD(fail_on_invalid_gpu_id)
305  .set_default(false)
306  .describe("Fail with error when gpu_id is invalid.");
307  DMLC_DECLARE_FIELD(validate_parameters)
308  .set_default(false)
309  .describe("Enable checking whether parameters are used or not.");
310  }
311 
312  private:
313  void SetDeviceOrdinal(Args const& kwargs);
314  Context& SetDevice(DeviceOrd d) {
315  this->device = (this->device_ = d).Name();
316  return *this;
317  }
318 
319  // mutable for lazy cuda context initialization. This avoids initializing CUDA at load.
320  // shared_ptr is used instead of unique_ptr as with unique_ptr it's difficult to define
321  // p_impl while trying to hide CUDA code from the host compiler.
322  mutable std::shared_ptr<CUDAContext> cuctx_;
323  mutable RandomEngine rng_;
324  // cached value for CFS CPU limit. (used in containerized env)
325  std::int32_t cfs_cpu_count_; // NOLINT
326 };
327 } // namespace xgboost
328 
329 #endif // XGBOOST_CONTEXT_H_
Defines configuration macros and basic types for xgboost.
Data structure representing JSON format.
Definition: json.h:396
Learner interface that integrates objective, gbm and evaluation together. This is the user facing XGB...
Definition: base.h:89
std::vector< std::pair< std::string, std::string > > Args
Definition: base.h:306
std::ostream & operator<<(std::ostream &os, DeviceOrd ord)
std::int16_t bst_d_ordinal_t
Ordinal of a CUDA device.
Definition: base.h:131
std::mt19937 RandomEngine
Define mt19937 as default type Random Engine.
Definition: context.h:25
macro for using C++11 enum class as DMLC parameter
Runtime context for XGBoost. Contains information like threads and device.
Definition: context.h:142
decltype(auto) DispatchDevice(CPUFn &&cpu_fn, CUDAFn &&cuda_fn) const
Call function based on the current device.
Definition: context.h:256
bool fail_on_invalid_gpu_id
Definition: context.h:171
DeviceOrd Device() const
Get the current device and ordinal.
Definition: context.h:207
void FromJson(Json const &in)
bool IsSycl() const
Is XGBoost running on any SYCL device?
Definition: context.h:202
std::string DeviceName() const
Name of the current device.
Definition: context.h:222
DeviceOrd DeviceFP64() const
Get the current device and ordinal, if it supports fp64, otherwise returns default CPU.
Json ToJson() const
bool seed_per_iteration
Definition: context.h:169
std::int32_t Threads() const
Returns the automatically chosen number of threads based on the nthread parameter and the system sett...
bool validate_parameters
Definition: context.h:172
std::int64_t seed
Definition: context.h:167
Context MakeCUDA(bst_d_ordinal_t ordinal=0) const
Make a CUDA context based on the current context.
Definition: context.h:240
RandomEngine & Rng() const
Get the random engine.
Definition: context.h:230
bool IsCPU() const
Is XGBoost running on CPU?
Definition: context.h:182
CUDAContext const * CUDACtx() const
Get a CUDA device context for allocator and stream.
static constexpr std::int64_t kDefaultSeed
Definition: context.h:150
bool IsCUDA() const
Is XGBoost running on a CUDA device?
Definition: context.h:186
bool IsSyclCPU() const
Is XGBoost running on a SYCL CPU?
Definition: context.h:194
std::int32_t nthread
Definition: context.h:165
Context MakeCPU() const
Make a CPU context based on the current context.
Definition: context.h:247
bool IsSyclGPU() const
Is XGBoost running on a SYCL GPU?
Definition: context.h:198
bool IsSyclDefault() const
Is XGBoost running on the default SYCL device?
Definition: context.h:190
DMLC_DECLARE_PARAMETER(Context)
Definition: context.h:293
bst_d_ordinal_t Ordinal() const
Get the CUDA device ordinal. -1 if XGBoost is running on CPU.
Definition: context.h:218
void Init(Args const &kwargs)
Args UpdateAllowUnknown(Container const &kwargs)
Definition: context.h:158
A type for device ordinal. The type is packed into 32-bit for efficient use in viewing types like lin...
Definition: context.h:40
constexpr static auto SyclGPU(bst_d_ordinal_t ordinal=-1)
Constructor for SYCL GPU.
Definition: context.h:104
bool operator==(DeviceOrd const &that) const
Definition: context.h:108
bool IsCUDA() const
Definition: context.h:55
bool operator!=(DeviceOrd const &that) const
Definition: context.h:111
bool IsSyclCPU() const
Definition: context.h:58
std::string Name() const
Get a string representation of the device and the ordinal.
Definition: context.h:115
enum xgboost::DeviceOrd::Type kCPU
bool IsSyclDefault() const
Definition: context.h:57
constexpr DeviceOrd & operator=(DeviceOrd &&that)=default
constexpr DeviceOrd(DeviceOrd &&that)=default
constexpr DeviceOrd & operator=(DeviceOrd const &that)=default
Type
Definition: context.h:45
@ kSyclGPU
Definition: context.h:50
@ kSyclDefault
Definition: context.h:48
@ kCUDA
Definition: context.h:47
@ kSyclCPU
Definition: context.h:49
bool IsSyclGPU() const
Definition: context.h:59
bool IsCPU() const
Definition: context.h:56
static constexpr bst_d_ordinal_t InvalidOrdinal()
Definition: context.h:43
static constexpr bst_d_ordinal_t CPUOrdinal()
Definition: context.h:42
constexpr DeviceOrd(Type type, bst_d_ordinal_t ord)
Definition: context.h:63
constexpr static auto SyclCPU(bst_d_ordinal_t ordinal=-1)
Constructor for SYCL CPU.
Definition: context.h:95
constexpr DeviceOrd()=default
bool IsSycl() const
Definition: context.h:60
static constexpr auto CUDA(bst_d_ordinal_t ordinal)
Constructor for CUDA device.
Definition: context.h:79
constexpr DeviceOrd(DeviceOrd const &that)=default
constexpr static auto CPU()
Constructor for CPU.
Definition: context.h:73
constexpr static auto SyclDefault(bst_d_ordinal_t ordinal=-1)
Constructor for SYCL.
Definition: context.h:87
bst_d_ordinal_t ordinal
Definition: context.h:53
Definition: context.h:28
static constexpr auto CUDA()
Definition: context.h:30
static constexpr auto CPU()
Definition: context.h:29
static constexpr auto SyclDefault()
Definition: context.h:31
static constexpr auto SyclGPU()
Definition: context.h:33
static constexpr auto SyclCPU()
Definition: context.h:32
Definition: parameter.h:84
Args UpdateAllowUnknown(Container const &kwargs)
Definition: parameter.h:90