The Sparta Modeling Framework
Loading...
Searching...
No Matches
SIValuesBuffer.hpp
1// <SIValuesBuffer> -*- C++ -*-
2
3#pragma once
4
6#include "simdb/schema/Schema.hpp"
7#include "sparta/report/db/Schema.hpp"
8
9namespace sparta {
10namespace statistics {
11
13inline void refillWithNaNs(std::vector<double> & vec)
14{
15 vec = std::vector<double>(vec.size(), NAN);
16}
17
48{
49public:
52 SIValuesBuffer(const std::vector<const StatisticInstance*> & stats,
53 const Clock & root_clk) :
54 stats_(stats),
55 scheduler_(*root_clk.getScheduler()),
56 root_clk_(root_clk)
57 {
58 //We are going to be asking the SI's for their values
59 //ourselves. Don't take the performance hit of having
60 //them writing their values into SnapshotLogger's that
61 //nobody is listening to.
62 for (const auto si : stats_) {
63 si->disableSnapshotLogging();
64 }
65 }
66
72 if (!buffersAreEmpty()) {
73 throw SpartaException(
74 "Cannot change row/column-major ordering when "
75 "SIValuesBuffer contains buffered data");
76 }
77 is_row_major_ = true;
78 }
79
84 if (!buffersAreEmpty()) {
85 throw SpartaException(
86 "Cannot change row/column-major ordering when "
87 "SIValuesBuffer contains buffered data");
88 }
89 is_row_major_ = false;
90 }
91
94 db::MajorOrdering getMajorOrdering() const {
95 return is_row_major_ ?
96 db::MajorOrdering::ROW_MAJOR :
97 db::MajorOrdering::COLUMN_MAJOR;
98 }
99
108 void initializeNumSIBuffers(const size_t num_si_buffers) {
109 si_values_buffer_.resize(num_si_buffers * stats_.size());
110 max_num_si_buffers_ = num_si_buffers;
111 }
112
135 void updateNumSIBuffers(const size_t num_si_buffers) {
136 sparta_assert(num_si_buffers > 0, "You cannot have an "
137 "SIValuesBuffer with zero SI capacity");
138 updated_num_si_buffers_ = num_si_buffers;
139 }
140
146 bool buffersAreFilled() const {
147 return (current_buffer_write_idx_ == max_num_si_buffers_);
148 }
149
151 bool buffersAreEmpty() const {
152 return (current_buffer_write_idx_ == 0);
153 }
154
157 size_t getNumBufferedSIBlocks() const {
158 return current_buffer_write_idx_;
159 }
160
167 void resetSIBuffers(const bool fill_with_nans = true) {
168 current_buffer_write_idx_ = 0;
169 if (updated_num_si_buffers_.isValid()) {
170 initializeNumSIBuffers(updated_num_si_buffers_);
171 updated_num_si_buffers_.clearValid();
172 }
173
174 if (fill_with_nans) {
175 refillWithNaNs(si_values_buffer_);
176 }
177
178 si_buffer_beginning_picoseconds_.clearValid();
179 si_buffer_ending_picoseconds_.clearValid();
180 si_buffer_beginning_clock_cycles_.clearValid();
181 si_buffer_ending_clock_cycles_.clearValid();
182 }
183
216 //Ensure that we have the space in our buffer to append the
217 //current SI values
218 sparta_assert(current_buffer_write_idx_ < max_num_si_buffers_);
219
220 //Capture the current simulated picoseconds & root clock cycle
221 //if this is the first write into a fresh buffer
222 if (buffersAreEmpty()) {
223 si_buffer_beginning_picoseconds_ = scheduler_.getSimulatedPicoSeconds();
224 si_buffer_beginning_clock_cycles_ = root_clk_.currentCycle();
225 }
226
227 //For row-major ordering, we start the write index at the Nth SI
228 //position, where N equals the current buffer index. For column-
229 //major ordering, we start the write index at the 0th position
230 //of the Mth buffer, where M equals the current buffer index.
231 size_t buffer_idx =
232 is_row_major_ ?
233 current_buffer_write_idx_ * stats_.size() :
234 current_buffer_write_idx_;
235 for (const auto si : stats_) {
236 si_values_buffer_[buffer_idx] = si->getValue();
237 //Row-major ordering jumps the write index ahead by 1.
238 //Column-major ordering jumps this index to the next
239 //available buffer.
240 buffer_idx += is_row_major_ ? 1 : max_num_si_buffers_;
241 }
242 ++current_buffer_write_idx_;
243
244 //Capture the ending simulated picoseconds & root clock cycle
245 //in this buffer
246 si_buffer_ending_picoseconds_ = scheduler_.getSimulatedPicoSeconds();
247 si_buffer_ending_clock_cycles_ = root_clk_.currentCycle();
248 }
249
268 const std::vector<double> & getBufferedSIValues() {
269 if (buffersAreFilled()) {
270 return si_values_buffer_;
271 }
272
273 if (buffersAreEmpty()) {
274 refillWithNaNs(si_values_buffer_);
275 return si_values_buffer_;
276 }
277
278 const size_t num_filled_buffers = current_buffer_write_idx_;
279 squeezed_si_values_.resize(num_filled_buffers * stats_.size());
280 auto read_iter = si_values_buffer_.begin();
281
282 //When using row-major ordering, simply copy the SI values
283 //buffer as-is into the squeezed SI values vector.
284 if (is_row_major_) {
285 memcpy(&squeezed_si_values_[0],
286 &si_values_buffer_[0],
287 squeezed_si_values_.size() * sizeof(double));
288 } else {
289 //Column-major ordering is a little bit different.
290 //For each "block" of buffers, whether filled or unfilled...
291 for (size_t si_idx = 0; si_idx < stats_.size(); ++si_idx) {
292 //...copy over the SI values from the filled buffer slots...
293 std::copy(read_iter,
294 read_iter + num_filled_buffers,
295 squeezed_si_values_.begin() + (si_idx * num_filled_buffers));
296
297 //...and jump over the unfilled buffer slots to the start
298 //of the next filled buffer.
299 std::advance(read_iter, max_num_si_buffers_);
300 }
301 }
302
303 return squeezed_si_values_;
304 }
305
313 uint64_t & starting_picoseconds,
314 uint64_t & ending_picoseconds,
315 uint64_t & starting_cycles,
316 uint64_t & ending_cycles) const
317 {
318 starting_picoseconds = si_buffer_beginning_picoseconds_;
319 ending_picoseconds = si_buffer_ending_picoseconds_;
320 starting_cycles = si_buffer_beginning_clock_cycles_;
321 ending_cycles = si_buffer_ending_clock_cycles_;
322 }
323
324private:
325 const std::vector<const StatisticInstance*> stats_;
326 std::vector<double> si_values_buffer_;
327 std::vector<double> squeezed_si_values_;
328 size_t current_buffer_write_idx_ = 0;
329 size_t max_num_si_buffers_ = 0;
330 utils::ValidValue<size_t> updated_num_si_buffers_;
331 bool is_row_major_ = true;
332
333 utils::ValidValue<uint64_t> si_buffer_beginning_picoseconds_;
334 utils::ValidValue<uint64_t> si_buffer_ending_picoseconds_;
335 utils::ValidValue<uint64_t> si_buffer_beginning_clock_cycles_;
336 utils::ValidValue<uint64_t> si_buffer_ending_clock_cycles_;
337
341 const Scheduler & scheduler_;
342 const Clock & root_clk_;
343
344};
345
346} // namespace statistics
347} // namespace sparta
348
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
Contains a StatisticInstance which refers to a StatisticDef or Counter and some local state to comput...
A representation of simulated time.
Definition Clock.hpp:51
Cycle currentCycle() const
Get the current cycle (uses current tick from the Scheduler)
Definition Clock.hpp:176
A class that lets you schedule events now and in the future.
Tick getSimulatedPicoSeconds() const noexcept
Used to construct and throw a standard C++ exception. Inherits from std::exception.
This class helps organize contiguous blocks of SI values. These values are buffered at each report up...
db::MajorOrdering getMajorOrdering() const
void resetSIBuffers(const bool fill_with_nans=true)
void getBeginningAndEndingTimestampsForBufferedSIs(uint64_t &starting_picoseconds, uint64_t &ending_picoseconds, uint64_t &starting_cycles, uint64_t &ending_cycles) const
void updateNumSIBuffers(const size_t num_si_buffers)
const std::vector< double > & getBufferedSIValues()
bool buffersAreEmpty() const
Ask if this buffer is completely empty.
SIValuesBuffer(const std::vector< const StatisticInstance * > &stats, const Clock &root_clk)
void initializeNumSIBuffers(const size_t num_si_buffers)
Provides a wrapper around a value to ensure that the value is assigned.
void clearValid()
Clear the validity of this object.
bool isValid() const
Is this value valid.
void refillWithNaNs(std::vector< double > &vec)
Utility to set all elements of a vector to NaN.
Macros for handling exponential backoff.