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 // Stored by value, not reference: the convenience constructors below
71 // delegate using temporaries (cwrap(arrays), CVecRef{std::cref(array)})
72 // that would dangle once the delegating call returns.
73 const CVecRef m_arrays; // the DistrArray objects data is being accessed from
74 const size_t m_buffer_size = 8192;
75 const int m_number_of_buffers = 2;
77
78public:
83 struct Iterator {
84 // iterator properties
85 using iterator_category = std::forward_iterator_tag;
86 using difference_type = std::ptrdiff_t;
90
98 Iterator(BufferManager& manager, bool begin = false, bool end = false)
99 : m_manager(manager), m_value(end ? value_type(nullptr, 0) : manager.next(begin)) {}
100
101 // iterator operators
102 reference operator*() const { return m_value; }
103
104 pointer operator->() { return &m_value; }
105
107 m_value = m_manager.next();
108 return *this;
109 }
110
112 Iterator tmp = *this;
113 ++(*this);
114 return tmp;
115 }
116
117 friend bool operator==(const Iterator& a, const Iterator& b) {
118 return (a.m_value.size() == b.m_value.size() and b.m_value.size() == 0) // special for end of file
119 or a.m_value.data() == b.m_value.data();
120 };
121
122 friend bool operator!=(const Iterator& a, const Iterator& b) { return not(a == b); };
123
124 private:
125 BufferManager& m_manager; // BufferManager object containing buffers
126 value_type m_value; // iterator value
127 };
128
129 [[nodiscard]] Iterator begin() { return Iterator(*this, true); }
130
131 [[nodiscard]] Iterator end() { return Iterator(*this, false, true); }
132
133protected:
139 [[nodiscard]] Span<value_type> next(bool initial = false) {
140 if (initial)
142 else
144 const auto buffer_id = m_current_segment % m_number_of_buffers;
145 const auto lo = m_range.first + m_current_segment * this->m_buffer_size;
146 if (lo >= m_range.second)
147 return Span<BufferManager::value_type>(nullptr, 0);
148 const auto hi = std::min(lo + this->m_buffer_size, m_range.second);
149 m_current_buffer_size = hi - lo;
150 {
151 if (m_number_of_buffers == 1 or lo == m_range.first) {
152 for (size_t iarray = 0; iarray < m_arrays.size(); ++iarray) {
153 assert(hi > lo);
154 assert(buffer_id * m_buffer_size * m_arrays.size() + iarray * m_buffer_size + hi - lo <= m_buffer.size());
155 m_arrays[iarray].get().get(
156 lo, hi, &m_buffer.at(buffer_id * m_buffer_size * m_arrays.size() + iarray * m_buffer_size));
157 }
158 } else {
159 m_read_future.wait();
160 }
161 }
162
163 const auto next_buffer_id = (m_current_segment + 1) % m_number_of_buffers;
164 const auto next_lo = m_range.first + (m_current_segment + 1) * this->m_buffer_size;
165 const auto next_hi = std::min(next_lo + this->m_buffer_size, m_range.second);
166 if (m_number_of_buffers > 1 and next_lo < m_range.second) {
167 m_read_future = std::async(std::launch::async, [this, next_lo, next_hi, next_buffer_id]() {
168 for (size_t iarray = 0; iarray < m_arrays.size(); ++iarray)
169 m_arrays[iarray].get().get(
170 next_lo, next_hi,
171 &m_buffer.at(next_buffer_id * m_buffer_size * m_arrays.size() + iarray * m_buffer_size));
172 });
173 }
174
175 return Span<value_type>(&m_buffer.at(buffer_id * m_buffer_size * m_arrays.size()), m_buffer_size * m_arrays.size());
176 }
177
178 size_t m_current_segment = 0; // current chunk
179 const std::pair<size_t, size_t>
180 m_range; // memory offsets for MPI found via distr_array_disk.distribution().range(...)
181 std::vector<typename T::value_type> m_buffer;
182 std::future<void> m_read_future;
183};
184
185} // namespace molpro::linalg::array::util
186
187#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:31
size_type size() const
Definition: Span.h:77
iterator data()
Definition: Span.h:66
BufferManager provides single-buffered or asynchronous double-buffered read access to the data in a c...
Definition: BufferManager.h:20
const CVecRef m_arrays
Definition: BufferManager.h:73
size_t buffer_offset() const
Definition: BufferManager.h:66
typename T::value_type value_type
Definition: BufferManager.h:69
size_t m_current_segment
Definition: BufferManager.h:178
const std::pair< size_t, size_t > m_range
Definition: BufferManager.h:180
size_t buffer_size() const
Definition: BufferManager.h:56
size_t buffer_stride() const
Definition: BufferManager.h:61
Iterator end()
Definition: BufferManager.h:131
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:139
size_t m_current_buffer_size
Definition: BufferManager.h:76
const size_t m_buffer_size
Definition: BufferManager.h:74
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:129
std::future< void > m_read_future
Definition: BufferManager.h:182
const int m_number_of_buffers
Definition: BufferManager.h:75
std::vector< typename T::value_type > m_buffer
Definition: BufferManager.h:181
Definition: ArrayHandler.h:23
Custom iterator for the BufferManager. This iterator is responsible for loading data into the buffers...
Definition: BufferManager.h:83
std::forward_iterator_tag iterator_category
Definition: BufferManager.h:85
pointer operator->()
Definition: BufferManager.h:104
friend bool operator!=(const Iterator &a, const Iterator &b)
Definition: BufferManager.h:122
std::ptrdiff_t difference_type
Definition: BufferManager.h:86
Iterator & operator++()
Definition: BufferManager.h:106
Iterator(BufferManager &manager, bool begin=false, bool end=false)
Construct a new Iterator object.
Definition: BufferManager.h:98
Iterator operator++(int)
Definition: BufferManager.h:111
reference operator*() const
Definition: BufferManager.h:102
friend bool operator==(const Iterator &a, const Iterator &b)
Definition: BufferManager.h:117