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 <string> // for string, to_string
15 #include <type_traits> // for invoke_result_t, is_same_v, underlying_type_t
16 
17 namespace xgboost {
18 
19 struct CUDAContext;
20 
21 // symbolic names
22 struct DeviceSym {
23  static auto constexpr CPU() { return "cpu"; }
24  static auto constexpr CUDA() { return "cuda"; }
25 };
26 
31 struct DeviceOrd {
32  enum Type : std::int16_t { kCPU = 0, kCUDA = 1 } device{kCPU};
33  // CUDA device ordinal.
35 
36  [[nodiscard]] bool IsCUDA() const { return device == kCUDA; }
37  [[nodiscard]] bool IsCPU() const { return device == kCPU; }
38 
39  DeviceOrd() = default;
40  constexpr DeviceOrd(Type type, bst_d_ordinal_t ord) : device{type}, ordinal{ord} {}
41 
42  DeviceOrd(DeviceOrd const& that) = default;
43  DeviceOrd& operator=(DeviceOrd const& that) = default;
44  DeviceOrd(DeviceOrd&& that) = default;
45  DeviceOrd& operator=(DeviceOrd&& that) = default;
46 
50  [[nodiscard]] constexpr static auto CPU() { return DeviceOrd{kCPU, -1}; }
56  [[nodiscard]] static auto CUDA(bst_d_ordinal_t ordinal) { return DeviceOrd{kCUDA, ordinal}; }
57 
58  [[nodiscard]] bool operator==(DeviceOrd const& that) const {
59  return device == that.device && ordinal == that.ordinal;
60  }
61  [[nodiscard]] bool operator!=(DeviceOrd const& that) const { return !(*this == that); }
65  [[nodiscard]] std::string Name() const {
66  switch (device) {
67  case DeviceOrd::kCPU:
68  return DeviceSym::CPU();
69  case DeviceOrd::kCUDA:
70  return DeviceSym::CUDA() + (':' + std::to_string(ordinal));
71  default: {
72  LOG(FATAL) << "Unknown device.";
73  return "";
74  }
75  }
76  }
77 };
78 
79 static_assert(sizeof(DeviceOrd) == sizeof(std::int32_t));
80 
84 struct Context : public XGBoostParameter<Context> {
85  private:
86  std::string device{DeviceSym::CPU()}; // NOLINT
87  // The device object for the current context. We are in the middle of replacing the
88  // `gpu_id` with this device field.
89  DeviceOrd device_{DeviceOrd::CPU()};
90 
91  public:
92  // Constant representing the device ID of CPU.
93  static bst_d_ordinal_t constexpr kCpuId = -1;
94  static bst_d_ordinal_t constexpr InvalidOrdinal() { return -2; }
95  static std::int64_t constexpr kDefaultSeed = 0;
96 
97  public:
99 
100  template <typename Container>
101  Args UpdateAllowUnknown(Container const& kwargs) {
103  this->SetDeviceOrdinal(kwargs);
104  return args;
105  }
106 
107  std::int32_t gpu_id{kCpuId};
108  // The number of threads to use if OpenMP is enabled. If equals 0, use the system default.
109  std::int32_t nthread{0}; // NOLINT
110  // stored random seed
111  std::int64_t seed{kDefaultSeed};
112  // whether seed the PRNG each iteration
113  bool seed_per_iteration{false};
114  // fail when gpu_id is invalid
116  bool validate_parameters{false};
117 
124  void ConfigureGpuId(bool require_gpu);
129  [[nodiscard]] std::int32_t Threads() const;
133  [[nodiscard]] bool IsCPU() const { return Device().IsCPU(); }
137  [[nodiscard]] bool IsCUDA() const { return Device().IsCUDA(); }
141  [[nodiscard]] DeviceOrd Device() const { return device_; }
145  [[nodiscard]] bst_d_ordinal_t Ordinal() const { return Device().ordinal; }
149  [[nodiscard]] std::string DeviceName() const { return Device().Name(); }
153  [[nodiscard]] CUDAContext const* CUDACtx() const;
154 
160  [[nodiscard]] Context MakeCUDA(bst_d_ordinal_t ordinal = 0) const {
161  Context ctx = *this;
162  return ctx.SetDevice(DeviceOrd::CUDA(ordinal));
163  }
167  [[nodiscard]] Context MakeCPU() const {
168  Context ctx = *this;
169  return ctx.SetDevice(DeviceOrd::CPU());
170  }
174  template <typename CPUFn, typename CUDAFn>
175  decltype(auto) DispatchDevice(CPUFn&& cpu_fn, CUDAFn&& cuda_fn) const {
176  static_assert(std::is_same_v<std::invoke_result_t<CPUFn>, std::invoke_result_t<CUDAFn>>);
177  switch (this->Device().device) {
178  case DeviceOrd::kCPU:
179  return cpu_fn();
180  case DeviceOrd::kCUDA:
181  return cuda_fn();
182  default:
183  // Do not use the device name as this is likely an internal error, the name
184  // wouldn't be valid.
185  LOG(FATAL) << "Unknown device type:"
186  << static_cast<std::underlying_type_t<DeviceOrd::Type>>(this->Device().device);
187  break;
188  }
189  return std::invoke_result_t<CPUFn>();
190  }
191 
192  // declare parameters
194  DMLC_DECLARE_FIELD(seed)
195  .set_default(kDefaultSeed)
196  .describe("Random number seed during training.");
197  DMLC_DECLARE_ALIAS(seed, random_state);
198  DMLC_DECLARE_FIELD(seed_per_iteration)
199  .set_default(false)
200  .describe("Seed PRNG determnisticly via iterator number.");
201  DMLC_DECLARE_FIELD(device).set_default(DeviceSym::CPU()).describe("Device ordinal.");
202  DMLC_DECLARE_FIELD(nthread).set_default(0).describe("Number of threads to use.");
203  DMLC_DECLARE_ALIAS(nthread, n_jobs);
204  DMLC_DECLARE_FIELD(fail_on_invalid_gpu_id)
205  .set_default(false)
206  .describe("Fail with error when gpu_id is invalid.");
207  DMLC_DECLARE_FIELD(validate_parameters)
208  .set_default(false)
209  .describe("Enable checking whether parameters are used or not.");
210  }
211 
212  private:
213  void SetDeviceOrdinal(Args const& kwargs);
214  Context& SetDevice(DeviceOrd d) {
215  this->device_ = d;
216  this->gpu_id = d.ordinal; // this can be removed once we move away from `gpu_id`.
217  this->device = d.Name();
218  return *this;
219  }
220 
221  // mutable for lazy cuda context initialization. This avoids initializing CUDA at load.
222  // shared_ptr is used instead of unique_ptr as with unique_ptr it's difficult to define
223  // p_impl while trying to hide CUDA code from the host compiler.
224  mutable std::shared_ptr<CUDAContext> cuctx_;
225  // cached value for CFS CPU limit. (used in containerized env)
226  std::int32_t cfs_cpu_count_; // NOLINT
227 };
228 } // namespace xgboost
229 
230 #endif // XGBOOST_CONTEXT_H_
Defines configuration macros and basic types for xgboost.
namespace of xgboost
Definition: base.h:90
std::vector< std::pair< std::string, std::string > > Args
Definition: base.h:316
std::int16_t bst_d_ordinal_t
Ordinal of a CUDA device.
Definition: base.h:130
macro for using C++11 enum class as DMLC parameter
Runtime context for XGBoost. Contains information like threads and device.
Definition: context.h:84
decltype(auto) DispatchDevice(CPUFn &&cpu_fn, CUDAFn &&cuda_fn) const
Call function based on the current device.
Definition: context.h:175
bool fail_on_invalid_gpu_id
Definition: context.h:115
DeviceOrd Device() const
Get the current device and ordinal.
Definition: context.h:141
std::string DeviceName() const
Name of the current device.
Definition: context.h:149
void ConfigureGpuId(bool require_gpu)
Configure the parameter ‘gpu_id’.
bool seed_per_iteration
Definition: context.h:113
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:116
std::int64_t seed
Definition: context.h:111
Context MakeCUDA(bst_d_ordinal_t ordinal=0) const
Make a CUDA context based on the current context.
Definition: context.h:160
static constexpr bst_d_ordinal_t InvalidOrdinal()
Definition: context.h:94
bool IsCPU() const
Is XGBoost running on CPU?
Definition: context.h:133
static constexpr bst_d_ordinal_t kCpuId
Definition: context.h:93
CUDAContext const * CUDACtx() const
Get a CUDA device context for allocator and stream.
std::int32_t gpu_id
Definition: context.h:107
static constexpr std::int64_t kDefaultSeed
Definition: context.h:95
bool IsCUDA() const
Is XGBoost running on a CUDA device?
Definition: context.h:137
std::int32_t nthread
Definition: context.h:109
Context MakeCPU() const
Make a CPU context based on the current context.
Definition: context.h:167
DMLC_DECLARE_PARAMETER(Context)
Definition: context.h:193
bst_d_ordinal_t Ordinal() const
Get the CUDA device ordinal. -1 if XGBoost is running on CPU.
Definition: context.h:145
Args UpdateAllowUnknown(Container const &kwargs)
Definition: context.h:101
A type for device ordinal. The type is packed into 32-bit for efficient use in viewing types like lin...
Definition: context.h:31
bool operator==(DeviceOrd const &that) const
Definition: context.h:58
bool IsCUDA() const
Definition: context.h:36
bool operator!=(DeviceOrd const &that) const
Definition: context.h:61
std::string Name() const
Get a string representation of the device and the ordinal.
Definition: context.h:65
DeviceOrd(DeviceOrd const &that)=default
enum xgboost::DeviceOrd::Type kCPU
DeviceOrd(DeviceOrd &&that)=default
DeviceOrd & operator=(DeviceOrd const &that)=default
Type
Definition: context.h:32
@ kCUDA
Definition: context.h:32
static auto CUDA(bst_d_ordinal_t ordinal)
Constructor for CUDA device.
Definition: context.h:56
bool IsCPU() const
Definition: context.h:37
DeviceOrd & operator=(DeviceOrd &&that)=default
constexpr DeviceOrd(Type type, bst_d_ordinal_t ord)
Definition: context.h:40
constexpr static auto CPU()
Constructor for CPU.
Definition: context.h:50
bst_d_ordinal_t ordinal
Definition: context.h:34
Definition: context.h:22
static constexpr auto CUDA()
Definition: context.h:24
static constexpr auto CPU()
Definition: context.h:23
Definition: parameter.h:84
Args UpdateAllowUnknown(Container const &kwargs)
Definition: parameter.h:90