iterative-solver 0.0
BufferManager.h
1#ifndef ITERATIVE_SOLVER_BUFFERMANAGER_H
2#define ITERATIVE_SOLVER_BUFFERMANAGER_H
3
4#include <future>
5#include <molpro/linalg/array/DistrArray.h>
6#include <molpro/linalg/array/util/Distribution.h>
7#include <vector>
8
10
19template <class T>
21 using VecRef = std::vector<std::reference_wrapper<T>>;
22 using CVecRef = std::vector<std::reference_wrapper<const T>>;
23 auto cwrap(const std::vector<T>& arrays) {
24 CVecRef w;
25 for (auto it = arrays.begin(); it != arrays.end(); ++it)
26 w.emplace_back(std::cref(*it));
27 return w;
28 }
29
30public:
39 BufferManager(const CVecRef& arrays, size_t buffer_size = 8192, int number_of_buffers = 2)
40 : m_arrays(arrays), m_buffer_size(buffer_size), m_number_of_buffers(number_of_buffers),
41 m_range(arrays.empty() ? std::pair<typename T::index_type, typename T::index_type>{0, 0}
42 : arrays.front().get().distribution().range(molpro::mpi::rank_global())),
43 m_buffer(arrays.size() * number_of_buffers * buffer_size) {
44 assert(number_of_buffers > 0 && number_of_buffers < 3);
45 }
46
47 BufferManager(const std::vector<T>& arrays, size_t buffer_size = 8192, int number_of_buffers = 2)
48 : BufferManager(cwrap(arrays), buffer_size, number_of_buffers) {}
49 BufferManager(const T& array, size_t buffer_size = 8192, int number_of_buffers = 2)
50 : BufferManager(CVecRef{std::cref(array)}, buffer_size, number_of_buffers) {}
51
56 size_t buffer_size() const { return m_current_buffer_size; }
61 size_t buffer_stride() const { return m_buffer_size; }
66 size_t buffer_offset() const { return m_current_segment * m_buffer_size; }
67
68protected:
69 using value_type = typename T::value_type;
70 const CVecRef& m_arrays; // reference to the DistrArray objects data is being accessed from
71 const size_t m_buffer_size = 8192;
72 const int m_number_of_buffers = 2;
74
75public:
80 struct Iterator {
81 // iterator properties
82 using iterator_category = std::forward_iterator_tag;
83 using difference_type = std::ptrdiff_t;
87
95 Iterator(BufferManager& manager, bool begin = false, bool end = false)
96 : m_manager(manager), m_value(end ? value_type(nullptr, 0) : manager.next(begin)) {}
97
98 // iterator operators
99 reference operator*() const { return m_value; }
100
101 pointer operator->() { return &m_value; }
102
104 m_value = m_manager.next();
105 return *this;
106 }
107
109 Iterator tmp = *this;
110 ++(*this);
111 return tmp;
112 }
113
114 friend bool operator==(const Iterator& a, const Iterator& b) {
115 return (a.m_value.size() == b.m_value.size() and b.m_value.size() == 0) // special for end of file
116 or a.m_value.data() == b.m_value.data();
117 };
118
119 friend bool operator!=(const Iterator& a, const Iterator& b) { return not(a == b); };
120
121 private:
122 BufferManager& m_manager; // BufferManager object containing buffers
123 value_type m_value; // iterator value
124 };
125
126 [[nodiscard]] Iterator begin() { return Iterator(*this, true); }
127
128 [[nodiscard]] Iterator end() { return Iterator(*this, false, true); }
129
130protected:
136 [[nodiscard]] Span<value_type> next(bool initial = false) {
137 if (initial)
139 else
141 const auto buffer_id = m_current_segment % m_number_of_buffers;
142 const auto lo = m_range.first + m_current_segment * this->m_buffer_size;
143 if (lo >= m_range.second)
144 return Span<BufferManager::value_type>(nullptr, 0);
145 const auto hi = std::min(lo + this->m_buffer_size, m_range.second);
146 m_current_buffer_size = hi - lo;
147 {
148 if (m_number_of_buffers == 1 or lo == m_range.first) {
149 for (size_t iarray = 0; iarray < m_arrays.size(); ++iarray) {
150 assert(hi > lo);
151 assert(buffer_id * m_buffer_size * m_arrays.size() + iarray * m_buffer_size + hi - lo <= m_buffer.size());
152 m_arrays[iarray].get().get(
153 lo, hi, &m_buffer.at(buffer_id * m_buffer_size * m_arrays.size() + iarray * m_buffer_size));
154 }
155 } else {
156 m_read_future.wait();
157 }
158 }
159
160 const auto next_buffer_id = (m_current_segment + 1) % m_number_of_buffers;
161 const auto next_lo = m_range.first + (m_current_segment + 1) * this->m_buffer_size;
162 const auto next_hi = std::min(next_lo + this->m_buffer_size, m_range.second);
163 if (m_number_of_buffers > 1 and next_lo < m_range.second) {
164 m_read_future = std::async(std::launch::async, [this, next_lo, next_hi, next_buffer_id]() {
165 for (size_t iarray = 0; iarray < m_arrays.size(); ++iarray)
166 m_arrays[iarray].get().get(
167 next_lo, next_hi,
168 &m_buffer.at(next_buffer_id * m_buffer_size * m_arrays.size() + iarray * m_buffer_size));
169 });
170 }
171
172 return Span<value_type>(&m_buffer.at(buffer_id * m_buffer_size * m_arrays.size()), m_buffer_size * m_arrays.size());
173 }
174
175 size_t m_current_segment = 0; // current chunk
176 const std::pair<size_t, size_t>
177 m_range; // memory offsets for MPI found via distr_array_disk.distribution().range(...)
178 std::vector<typename T::value_type> m_buffer;
179 std::future<void> m_read_future;
180};
181
182} // namespace molpro::linalg::array::util
183
184#endif // ITERATIVE_SOLVER_BUFFERMANAGER_H
Non-owning container taking a pointer to the data buffer and its size and exposing routines for itera...
Definition: Span.h:28
size_type size() const
Definition: Span.h:74
iterator data()
Definition: Span.h:63
BufferManager provides single-buffered or asynchronous double-buffered read access to the data in a c...
Definition: BufferManager.h:20
size_t buffer_offset() const
Definition: BufferManager.h:66
const CVecRef & m_arrays
Definition: BufferManager.h:70
typename T::value_type value_type
Definition: BufferManager.h:69
size_t m_current_segment
Definition: BufferManager.h:175
const std::pair< size_t, size_t > m_range
Definition: BufferManager.h:177
size_t buffer_size() const
Definition: BufferManager.h:56
size_t buffer_stride() const
Definition: BufferManager.h:61
Iterator end()
Definition: BufferManager.h:128
BufferManager(const std::vector< T > &arrays, size_t buffer_size=8192, int number_of_buffers=2)
Definition: BufferManager.h:47
Span< value_type > next(bool initial=false)
Move to the next segment of the arrays and complete loading of the buffer.
Definition: BufferManager.h:136
size_t m_current_buffer_size
Definition: BufferManager.h:73
const size_t m_buffer_size
Definition: BufferManager.h:71
BufferManager(const CVecRef &arrays, size_t buffer_size=8192, int number_of_buffers=2)
Construct a new Buffer Manager object and allocate memory for the chunks.
Definition: BufferManager.h:39
BufferManager(const T &array, size_t buffer_size=8192, int number_of_buffers=2)
Definition: BufferManager.h:49
Iterator begin()
Definition: BufferManager.h:126
std::future< void > m_read_future
Definition: BufferManager.h:179
const int m_number_of_buffers
Definition: BufferManager.h:72
std::vector< typename T::value_type > m_buffer
Definition: BufferManager.h:178
Definition: ArrayHandler.h:23
Custom iterator for the BufferManager. This iterator is responsible for loading data into the buffers...
Definition: BufferManager.h:80
std::forward_iterator_tag iterator_category
Definition: BufferManager.h:82
pointer operator->()
Definition: BufferManager.h:101
friend bool operator!=(const Iterator &a, const Iterator &b)
Definition: BufferManager.h:119
std::ptrdiff_t difference_type
Definition: BufferManager.h:83
Iterator & operator++()
Definition: BufferManager.h:103
Iterator(BufferManager &manager, bool begin=false, bool end=false)
Construct a new Iterator object.
Definition: BufferManager.h:95
Iterator operator++(int)
Definition: BufferManager.h:108
reference operator*() const
Definition: BufferManager.h:99
friend bool operator==(const Iterator &a, const Iterator &b)
Definition: BufferManager.h:114