deepspeed_aio_utils.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. // Copyright (c) Microsoft Corporation.
  2. // SPDX-License-Identifier: Apache-2.0
  3. // DeepSpeed Team
  4. /*
  5. Functionality for swapping optimizer tensors to/from (NVMe) storage devices.
  6. */
  7. #include <cmath>
  8. #include <iostream>
  9. #include "deepspeed_aio_utils.h"
  10. using namespace std;
  11. const int c_block_size = 128 * 1024;
  12. const int c_io_queue_depth = 8;
  13. io_xfer_ctxt::io_xfer_ctxt(const int fd,
  14. const long long int file_offset,
  15. const long long int num_bytes,
  16. const void* buffer)
  17. : _fd(fd), _base_offset(file_offset), _mem_buffer(buffer), _num_bytes(num_bytes)
  18. {
  19. }
  20. io_prep_context::io_prep_context(const bool read_op,
  21. const std::unique_ptr<io_xfer_ctxt>& xfer_ctxt,
  22. const size_t block_size,
  23. const std::vector<struct iocb*>* iocbs)
  24. : _read_op(read_op), _xfer_ctxt(xfer_ctxt), _block_size(block_size), _iocbs(iocbs)
  25. {
  26. }
  27. void io_prep_context::prep_iocbs(const int n_iocbs,
  28. const size_t num_bytes,
  29. const void* start_buffer,
  30. const long long int start_offset)
  31. {
  32. assert(static_cast<size_t>(n_iocbs) <= _iocbs->size());
  33. for (auto i = 0; i < n_iocbs; ++i) {
  34. const auto shift = i * _block_size;
  35. const auto xfer_buffer = (char*)start_buffer + _xfer_ctxt->_base_offset + shift;
  36. const auto xfer_offset = _xfer_ctxt->_base_offset + start_offset + shift;
  37. auto byte_count = _block_size;
  38. if ((shift + _block_size) > num_bytes) { byte_count = num_bytes - shift; }
  39. if (_read_op) {
  40. io_prep_pread(_iocbs->at(i), _xfer_ctxt->_fd, xfer_buffer, byte_count, xfer_offset);
  41. } else {
  42. io_prep_pwrite(_iocbs->at(i), _xfer_ctxt->_fd, xfer_buffer, byte_count, xfer_offset);
  43. }
  44. }
  45. }
  46. io_prep_generator::io_prep_generator(const bool read_op,
  47. const std::unique_ptr<io_xfer_ctxt>& xfer_ctxt,
  48. const size_t block_size)
  49. : _read_op(read_op),
  50. _xfer_ctxt(xfer_ctxt),
  51. _block_size(block_size),
  52. _remaining_bytes(xfer_ctxt->_num_bytes),
  53. _next_iocb_index(0)
  54. {
  55. _num_io_blocks =
  56. static_cast<long long int>(ceil(static_cast<double>(xfer_ctxt->_num_bytes) / block_size));
  57. _remaining_io_blocks = _num_io_blocks;
  58. }
  59. int io_prep_generator::prep_iocbs(const int n_iocbs, std::vector<struct iocb*>* iocbs)
  60. {
  61. if ((_remaining_bytes) == 0 || (_remaining_io_blocks == 0)) {
  62. assert(static_cast<long long int>(_remaining_bytes) == _remaining_io_blocks);
  63. return 0;
  64. }
  65. assert(static_cast<size_t>(n_iocbs) <= iocbs->size());
  66. auto actual_n_iocbs = min(static_cast<long long int>(n_iocbs), _remaining_io_blocks);
  67. for (auto i = 0; i < actual_n_iocbs; ++i, ++_next_iocb_index) {
  68. const auto xfer_offset = _xfer_ctxt->_base_offset + (_next_iocb_index * _block_size);
  69. const auto xfer_buffer = (char*)_xfer_ctxt->_mem_buffer + xfer_offset;
  70. const auto num_bytes = min(static_cast<long long int>(_block_size), _remaining_bytes);
  71. if (_read_op) {
  72. io_prep_pread(iocbs->at(i), _xfer_ctxt->_fd, xfer_buffer, num_bytes, xfer_offset);
  73. } else {
  74. io_prep_pwrite(iocbs->at(i), _xfer_ctxt->_fd, xfer_buffer, num_bytes, xfer_offset);
  75. }
  76. _remaining_bytes -= num_bytes;
  77. }
  78. _remaining_io_blocks -= actual_n_iocbs;
  79. return actual_n_iocbs;
  80. }
  81. int get_file_size(const char* filename, long long int& size)
  82. {
  83. struct stat st;
  84. if (stat(filename, &st) == -1) { return -1; }
  85. size = st.st_size;
  86. return 0;
  87. }
  88. void* ds_page_aligned_alloc(const size_t size, const bool lock)
  89. {
  90. void* ptr;
  91. int retval;
  92. retval = posix_memalign(&ptr, (size_t)sysconf(_SC_PAGESIZE), size);
  93. if (retval) { return nullptr; }
  94. if (lock == false) { return ptr; }
  95. auto mlock_ret = mlock(ptr, size);
  96. if (mlock_ret != 0) {
  97. auto mlock_error = errno;
  98. std::cerr << "mlock failed to allocate " << size << " bytes with error no " << mlock_error
  99. << " msg " << strerror(mlock_error) << std::endl;
  100. free(ptr);
  101. return nullptr;
  102. }
  103. return ptr;
  104. }