datasource.hpp
前往此文件的文档。
1 /*
2  * 版权所有 (c) 2020-2025, NVIDIA CORPORATION.
3  *
4  * 根据 Apache 许可,版本 2.0 (以下简称“许可”) 获得许可;
5  * 除非遵守许可,否则不得使用此文件。
6  * 您可以获取一份许可的副本,地址如下:
7  *
8  * https://apache.ac.cn/licenses/LICENSE-2.0
9  *
10  * 除非适用法律要求或书面同意,否则根据许可分发
11  * 的软件是按“原样”分发的,
12  * 不附带任何明示或默示的担保或条件。
13  * 请参阅许可了解特定语言的管理权限和
14  * 限制。
15  */
16 
17 #pragma once
18 
19 #include <cudf/io/types.hpp>
20 #include <cudf/utilities/error.hpp>
21 #include <cudf/utilities/export.hpp>
22 #include <cudf/utilities/span.hpp>
23 
24 #include <rmm/cuda_stream_view.hpp>
25 
26 #include <future>
27 #include <memory>
28 
29 namespace CUDF_EXPORT cudf {
31 namespace io {
32 
42 /**
43  * @brief 为读取器提供输入数据的接口类。
44  */
45  template <typename Container>
46  class owning_buffer; // 前向声明
51  class buffer {
52  public
58  /**
59  * @brief 返回缓冲区的字节大小。
65  */ [[nodiscard]] virtual size_t size() const = 0;
66 
70  /**
71  * @brief 返回缓冲区中数据的地址。
79  */ [[nodiscard]] virtual uint8_t const* data() const = 0;
80  virtual ~buffer() = default;
81 
82  /**
83  * @brief 从容器构造 datasource 缓冲区对象的工厂函数。
101  template <typename Container>
102  static std::unique_ptr<buffer> create(Container&& data_owner)
103  {
104  return std::make_unique<owning_buffer<Container>>(std::forward<Container>(data_owner));
105  }
113  static std::unique_ptr<datasource> create(std::string const& filepath,
114  size_t offset = 0,
121  size_t max_size_estimate = 0);
122 
129  /**
130  * @brief 从主机内存缓冲区创建 source。
137  static std::unique_ptr<datasource> create(host_buffer const& buffer);
138 
145  /**
146  * @brief 从主机内存缓冲区创建 source。
147  */ static std::unique_ptr<datasource> create(cudf::host_span<std::byte const> buffer);
148 
149  /**
150  * @brief 从设备内存缓冲区创建 source。
151  */ static std::unique_ptr<datasource> create(cudf::device_span<std::byte const> buffer);
152 
153  /**
154  * @brief 从用户实现的 datasource 对象创建 source。
155  */ static std::unique_ptr<datasource> create(datasource* source);
159  template <typename T>
160  /**
169  * @brief 创建 datasource 向量,输入向量中的每个元素对应一个 datasource。
170  */ static std::vector<std::unique_ptr<datasource>> create(std::vector<T> const& args)
171  {
172  std::vector<std::unique_ptr<datasource>> sources;
173  sources.reserve(args.size());
174  std::transform(args.cbegin(), args.cend(), std::back_inserter(sources), [](auto const& arg) {
175  return datasource::create(arg);
176  });
183  return sources;
184  }
195  /**
211  * @brief 返回包含 source 部分数据的缓冲区。
225  */ virtual ~datasource() = default;
226 
233  /**
237  * @brief 从 datasource 读取指定部分的数据。
254  */ virtual std::unique_ptr<datasource::buffer> host_read(size_t offset, size_t size) = 0;
255 
256  /**
257  * @brief 从 datasource 异步读取指定部分的数据。
278  */ virtual std::future<std::unique_ptr<datasource::buffer>> host_read_async(size_t offset,
279  size_t size);
280 
303  /**
304  * @brief 将选定范围的数据读取到预分配的缓冲区中。
316  */ virtual size_t host_read(size_t offset, size_t size, uint8_t* dst) = 0;
317 
323  /**
328  * @brief 将数据从 source 异步读取到提供的主机内存缓冲区中。
329  */ virtual std::future<size_t> host_read_async(size_t offset, size_t size, uint8_t* dst);
330 
331  /**
338  * @brief 此 source 是否支持直接读取到设备内存中。
339  */ [[nodiscard]] virtual bool supports_device_read() const { return false; }
345  /**
352  * @brief 估计对于给定大小,直接设备读取是否更优。
353  */ [[nodiscard]] virtual bool is_device_read_preferred(size_t size) const
354  {
366  return supports_device_read();
367  }
368 
369  /**
370  * @brief 返回包含 source 部分数据的设备缓冲区。
371  */ virtual std::unique_ptr<datasource::buffer> device_read(size_t offset,
372  size_t size,
373  rmm::cuda_stream_view stream)
374  {
375  CUDF_FAIL("datasource classes that support device_read must override it.");
376  }
377 
380  /**
381  * @brief 将选定范围的数据读取到预分配的设备缓冲区中。
382  */ virtual size_t device_read(size_t offset, size_t size, uint8_t* dst, rmm::cuda_stream_view stream)
383  {
384  CUDF_FAIL("datasource classes that support device_read must override it.");
385  }
394  /**
404  * @brief 将选定范围的数据异步读取到预分配的设备缓冲区中。
405  */ virtual std::future<size_t> device_read_async(size_t offset,
406  size_t size,
407  uint8_t* dst,
412  {
413  CUDF_FAIL("datasource classes that support device_read_async must override it.");
414  }
415 
416  /**
417  * @brief 返回 source 中数据的大小。
418  */ [[nodiscard]] virtual size_t size() const = 0;
419 
420  /**
421  * @brief 返回 source 是否包含任何数据。
422  */ [[nodiscard]] virtual bool is_empty() const { return size() == 0; }
423 
424  /**
425  * @brief 非拥有缓冲区的实现,datasource 在销毁前持有该缓冲区。
426  */ class non_owning_buffer : public buffer {
427  public
428  non_owning_buffer() = default;
429 
430  /**
438  * @brief 构造一个新的非拥有缓冲区对象。
439  */ non_owning_buffer(uint8_t const* data, size_t size) : _data(data), _size(size) {}
440 
445  /**
452  * @brief 返回缓冲区的大小。
453  */ [[nodiscard]] size_t size() const override { return _size; }
454 
466  /**
467  * @brief 返回缓冲区的指针。
468  */ [[nodiscard]] uint8_t const* data() const override { return _data; }
469 
470  private
471  uint8_t const* _data{nullptr};
472  size_t _size{0};
473  };
474 
475  /**
476  * @brief 拥有数据的缓冲区的派生实现。
477  */
478  template <typename Container>
479  class owning_buffer : public buffer {
480  public
481  // 要求传递给构造函数的参数是右值 (Container&& 是右值引用)。
482  static_assert(std::is_rvalue_reference_v<Container&&>,
483  "传递给构造函数的容器参数必须是右值。");
484 
494  /**
495  * @brief 将输入容器移动到新创建的对象中。
496  */ owning_buffer(Container&& moved_data_owner)
497  : _data(std::move(moved_data_owner)), _data_ptr(_data.data()), _size(_data.size())
498  {
499  }
500 
501  /**
504  * @brief 将输入容器移动到新创建的对象中,并暴露缓冲区的子跨度。
505  */ owning_buffer(Container&& moved_data_owner, uint8_t const* data_ptr, size_t size)
506  : _data(std::move(moved_data_owner)), _data_ptr(data_ptr), _size(size)
507  {
508  }
509 
511  /**
517  * @brief 返回缓冲区的大小。
518  */ [[nodiscard]] size_t size() const override { return _size; }
519 
520  /**
521  * @brief 返回缓冲区中数据的指针。
518  */ [[nodiscard]] size_t size() const override { return _size; }
522  */ [[nodiscard]] uint8_t const* data() const override
523  {
524  return static_cast<uint8_t const*>(_data_ptr);
525  }
496  */ owning_buffer(Container&& moved_data_owner)
497  : _data(std::move(moved_data_owner)), _data_ptr(_data.data()), _size(_data.size())
526 
527  private
500 
528  Container _data;
529  void const* _data_ptr;
530  size_t _size;
531  };
532 };
533  // 组结束
535 } // namespace io
472  size_t _size{0};
536 } // namespace CUDF_EXPORT cudf
cudf::io::datasource::buffer
datasource 返回给调用者的缓冲区的接口类。
virtual ~buffer()=default
基类析构函数。
cudf::io::datasource::buffer::create
536 } // namespace CUDF_EXPORT cudf
static std::unique_ptr< buffer > create(Container &&data_owner)
从容器构造 datasource 缓冲区对象的工厂函数。
cudf::io::datasource::buffer::size
virtual size_t size() const =0
cudf::io::datasource::buffer::data
virtual uint8_t const * data() const =0
返回缓冲区中数据的地址。
非拥有缓冲区的实现,datasource 在销毁前持有该缓冲区。
cudf::io::datasource::non_owning_buffer::size
536 } // namespace CUDF_EXPORT cudf
size_t size() const override
返回缓冲区的大小。
cudf::io::datasource::non_owning_buffer::data
uint8_t const * data() const override
返回缓冲区的指针。
cudf::io::datasource::non_owning_buffer::non_owning_buffer
non_owning_buffer(uint8_t const *data, size_t size)
构造一个新的非拥有缓冲区对象。
cudf::io::datasource::owning_buffer
cudf::io::datasource::owning_buffer::owning_buffer
536 } // namespace CUDF_EXPORT cudf
owning_buffer(Container &&moved_data_owner)
将输入容器移动到新创建的对象中。
owning_buffer(Container &&moved_data_owner, uint8_t const *data_ptr, size_t size)
将输入容器移动到新创建的对象中,并暴露缓冲区的子跨度。
478  template <typename Container>
cudf::io::datasource::owning_buffer::size
cudf::io::datasource::owning_buffer::data
536 } // namespace CUDF_EXPORT cudf
返回缓冲区中数据的指针。
将输入容器移动到新创建的对象中。
536 } // namespace CUDF_EXPORT cudf
cudf::io::datasource
cudf::io::datasource::create
static std::vector< std::unique_ptr< datasource > > create(std::vector< T > const &args)
cudf::io::datasource::supports_device_read
virtual bool supports_device_read() const
static std::unique_ptr< datasource > create(datasource *source)
从用户实现的 datasource 对象创建 source。
virtual std::future< std::unique_ptr< datasource::buffer > > host_read_async(size_t offset, size_t size)
cudf::io::datasource::device_read
virtual size_t device_read(size_t offset, size_t size, uint8_t *dst, rmm::cuda_stream_view stream)
估计对于给定大小,直接设备读取是否更优。