gem5  [DEVELOP-FOR-23.0]
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
frequent_values.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019-2020 Inria
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met: redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer;
9  * redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution;
12  * neither the name of the copyright holders nor the names of its
13  * contributors may be used to endorse or promote products derived from
14  * this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
30 
31 #include <algorithm>
32 #include <limits>
33 
34 #include "base/bitfield.hh"
35 #include "base/compiler.hh"
36 #include "base/intmath.hh"
37 #include "base/logging.hh"
38 #include "debug/CacheComp.hh"
40 #include "params/FrequentValuesCompressor.hh"
41 
42 namespace gem5
43 {
44 
45 namespace compression
46 {
47 
49  : Base(p), useHuffmanEncoding(p.max_code_length != 0),
50  indexEncoder(p.max_code_length), counterBits(p.counter_bits),
51  codeGenerationTicks(p.code_generation_ticks),
52  checkSaturation(p.check_saturation), numVFTEntries(p.vft_entries),
53  numSamples(p.num_samples), takenSamples(0), phase(SAMPLING),
54  VFT(p.vft_assoc, p.vft_entries, p.vft_indexing_policy,
55  p.vft_replacement_policy, VFTEntry(counterBits)),
56  codeGenerationEvent([this]{ phase = COMPRESSING; }, name())
57 {
58  fatal_if((numVFTEntries - 1) > mask(chunkSizeBits),
59  "There are more VFT entries than possible values.");
60 }
61 
62 std::unique_ptr<Base::CompressionData>
64  Cycles& decomp_lat)
65 {
66  std::unique_ptr<CompData> comp_data =
67  std::unique_ptr<CompData>(new CompData());
68 
69  // Compression size
70  std::size_t size = 0;
71 
72  // Compress every value sequentially. The compressed values are then
73  // added to the final compressed data.
74  for (const auto& chunk : chunks) {
75  encoder::Code code;
76  int length = 0;
77  if (phase == COMPRESSING) {
78  VFTEntry* entry = VFT.findEntry(chunk, false);
79 
80  // Theoretically, the code would be the index of the entry;
81  // however, there is no practical need to do so, and we simply
82  // use the value instead
83  const unsigned uncompressed_index = uncompressedValue;
84  const unsigned index = entry ? chunk : uncompressed_index;
85 
86  // If using an index encoder, apply it
87  if (useHuffmanEncoding) {
88  code = indexEncoder.encode(index);
89 
90  if (index == uncompressed_index) {
91  code.length += chunkSizeBits;
92  } else if (code.length > 64) {
93  // If, for some reason, we could not generate an encoding
94  // for the value, generate the uncompressed encoding
95  code = indexEncoder.encode(uncompressed_index);
96  assert(code.length <= 64);
97  code.length += chunkSizeBits;
98  }
99  } else {
100  const unsigned code_size = std::log2(numVFTEntries);
101  if (entry) {
102  code = {index, code_size};
103  } else {
104  code = {uncompressed_index, code_size + chunkSizeBits};
105  }
106  }
107  } else {
108  // Not compressing yet; simply copy the value over
109  code = {chunk, chunkSizeBits};
110  }
111  length += code.length;
112 
113  DPRINTF(CacheComp, "Compressed %016x to %016x (Size = %d) "
114  "(Phase: %d)\n", chunk, code.code, length, phase);
115 
116  comp_data->compressedValues.emplace_back(code, chunk);
117 
118  size += length;
119  }
120 
121  // Set final compression size
122  comp_data->setSizeBits(size);
123 
124  // Set latencies based on the degree of parallelization, and any extra
125  // latencies due to shifting or packaging
126  comp_lat = Cycles(compExtraLatency +
127  (chunks.size() / compChunksPerCycle));
128  decomp_lat = Cycles(decompExtraLatency +
129  (chunks.size() / decompChunksPerCycle));
130 
131  // Return compressed line
132  return comp_data;
133 }
134 
135 void
136 FrequentValues::decompress(const CompressionData* comp_data, uint64_t* data)
137 {
138  const CompData* casted_comp_data = static_cast<const CompData*>(comp_data);
139 
140  // Decompress every entry sequentially
141  std::vector<Chunk> decomp_chunks;
142  for (const auto& comp_chunk : casted_comp_data->compressedValues) {
143  if (phase == COMPRESSING) {
144  if (useHuffmanEncoding) {
145  // Although in theory we have the codeword and have to find
146  // its corresponding value, in order to make life easier we
147  // search for the value and verify that the stored code
148  // matches the table's
149  [[maybe_unused]] const encoder::Code code =
150  indexEncoder.encode(comp_chunk.value);
151 
152  // Either the value will be found and the codes match, or the
153  // value will not be found because it is an uncompressed entry
154  assert(((code.length <= 64) &&
155  (code.code == comp_chunk.code.code)) ||
156  (comp_chunk.code.code ==
158  } else {
159  // The value at the given VFT entry must match the one stored,
160  // if it is not the uncompressed value
161  assert((comp_chunk.code.code == uncompressedValue) ||
162  VFT.findEntry(comp_chunk.value, false));
163  }
164  }
165 
166  decomp_chunks.push_back(comp_chunk.value);
167  DPRINTF(CacheComp, "Decompressed %016x to %016x\n",
168  comp_chunk.code.code, comp_chunk.value);
169  }
170 
171  // Concatenate the decompressed words to generate the cache lines
172  fromChunks(decomp_chunks, data);
173 }
174 
175 void
177  bool is_invalidation)
178 {
179  const std::vector<Chunk> chunks = toChunks(data.data());
180  for (const Chunk& chunk : chunks) {
181  VFTEntry* entry = VFT.findEntry(chunk, false);
182  bool saturated = false;
183  if (!is_invalidation) {
184  // If a VFT hit, increase new value's counter; otherwise, insert
185  // new value
186  if (!entry) {
187  entry = VFT.findVictim(chunk);
188  assert(entry != nullptr);
189  entry->value = chunk;
190  VFT.insertEntry(chunk, false, entry);
191  } else {
192  VFT.accessEntry(entry);
193  }
194  entry->counter++;
195  saturated = entry->counter.isSaturated();
196  } else {
197  // If a VFT hit, decrease value's counter
198  if (entry) {
199  VFT.accessEntry(entry);
200  entry->counter--;
201  }
202  }
203 
204  // If any counter saturates, all counters are shifted right,
205  // resulting in precision loss
206  if (checkSaturation && saturated) {
207  for (auto& entry : VFT) {
208  entry.counter >>= 1;
209  }
210  }
211  }
212 
213  takenSamples += chunks.size();
214 }
215 
216 void
218 {
219  // We need to find a pseudo value to store uncompressed values as
220  // For that we generate all possible values from 0 to 1 size larger
221  // than the number of real values.
222  std::set<uint64_t> uncompressed_values;
223  for (int i = 0; i < numVFTEntries+1; ++i) {
224  uncompressed_values.insert(uncompressed_values.end(), i);
225  }
226 
227  for (const auto& entry : VFT) {
228  // Remove the respective real value from the list of possible
229  // pseudo values for the uncompressed value
230  uncompressed_values.erase(entry.value);
231  }
232 
233  // Select the first remaining possible value as the value
234  // representing uncompressed values
235  assert(uncompressed_values.size() >= 1);
236  uncompressedValue = *uncompressed_values.begin();
237  assert(VFT.findEntry(uncompressedValue, false) == nullptr);
238 
239  if (useHuffmanEncoding) {
240  // Populate the queue, adding each entry as a tree with one node.
241  // They are sorted such that the value with highest frequency is
242  // the queue's top
243  for (const auto& entry : VFT) {
244  indexEncoder.sample(entry.value, entry.counter);
245  }
246 
247  // Insert the uncompressed value in the tree assuming it has the
248  // highest frequency, since it is in fact a group of all the values
249  // not present in the VFT
251 
253  }
254 
255  // Generate the code map and mark the current phase as code generation
257 
258  // Let us know when to change from the code generation phase to the
259  // effective compression phase
261 }
262 
263 void
265 {
266  // Do not update VFT if not sampling
267  if (phase == SAMPLING) {
268  // If the new data is not present, the notification is due to a
269  // fill; otherwise, sample the old block's contents
270  if (data_update.oldData.size() > 0) {
271  sampleValues(data_update.oldData, true);
272  }
273  // If the new data is not present, the notification is due to an
274  // invalidation; otherwise, sample the new block's contents
275  if (data_update.newData.size() > 0) {
276  sampleValues(data_update.newData, false);
277  }
278 
279  // Check if it is done with the sampling phase. If so, generate the
280  // codes that will be used for the compression phase
281  if (takenSamples >= numSamples) {
282  generateCodes();
283  }
284  }
285 }
286 
287 void
289 {
290  assert(listeners.empty());
291  assert(cache != nullptr);
292  listeners.push_back(new FrequentValuesListener(
293  *this, cache->getProbeManager(), "Data Update"));
294 }
295 
296 void
298 {
299  parent.probeNotify(data_update);
300 }
301 
302 } // namespace compression
303 } // namespace gem5
associative_set_impl.hh
gem5::compression::FrequentValues::compress
std::unique_ptr< Base::CompressionData > compress(const std::vector< Chunk > &chunks, Cycles &comp_lat, Cycles &decomp_lat) override
Apply the compression process to the cache line.
Definition: frequent_values.cc:63
gem5::curTick
Tick curTick()
The universal simulation clock.
Definition: cur_tick.hh:46
gem5::compression::Base::CompressionData
Definition: base.hh:245
gem5::compression::FrequentValues::uncompressedValue
uint64_t uncompressedValue
A pseudo value is used as the representation of uncompressed values.
Definition: frequent_values.hh:156
gem5::compression::Base::chunkSizeBits
const unsigned chunkSizeBits
Chunk size, in number of bits.
Definition: base.hh:96
gem5::BaseCache::DataUpdate::oldData
std::vector< uint64_t > oldData
The stale data contents.
Definition: base.hh:130
gem5::compression::FrequentValues::probeNotify
void probeNotify(const DataUpdate &data_update)
Process a notification event from the ProbeListener.
Definition: frequent_values.cc:264
data
const char data[]
Definition: circlebuf.test.cc:48
gem5::compression::Base::decompChunksPerCycle
const Cycles decompChunksPerCycle
Degree of parallelization of the decompression process.
Definition: base.hh:120
gem5::compression::FrequentValues::checkSaturation
const bool checkSaturation
Whether an action must be performed when counters saturate.
Definition: frequent_values.hh:96
gem5::MipsISA::index
Bitfield< 30, 0 > index
Definition: pra_constants.hh:47
gem5::compression::FrequentValues::FrequentValuesListener::notify
void notify(const DataUpdate &data_update) override
Definition: frequent_values.cc:297
gem5::compression::FrequentValues::useHuffmanEncoding
const bool useHuffmanEncoding
Whether Huffman encoding is applied to the VFT indices.
Definition: frequent_values.hh:84
gem5::compression::FrequentValues::decompress
void decompress(const CompressionData *comp_data, uint64_t *data) override
Apply the decompression process to the compressed data.
Definition: frequent_values.cc:136
gem5::compression::FrequentValues::VFTEntry::value
uint64_t value
The value is stored as a 64 bit entry to accomodate for the uncompressed value.
Definition: frequent_values.hh:121
gem5::compression::FrequentValues::listeners
std::vector< FrequentValuesListener * > listeners
Definition: frequent_values.hh:81
frequent_values.hh
gem5::compression::Base::Chunk
uint64_t Chunk
A chunk is a basic lexical unit.
Definition: base.hh:71
gem5::compression::Base::Params
BaseCacheCompressorParams Params
Definition: base.hh:201
gem5::GenericSatCounter::isSaturated
bool isSaturated() const
Whether the counter has achieved its maximum value or not.
Definition: sat_counter.hh:312
gem5::EventManager::schedule
void schedule(Event &event, Tick when)
Definition: eventq.hh:1012
std::vector< Chunk >
gem5::compression::FrequentValues::sampleValues
void sampleValues(const std::vector< uint64_t > &data, bool is_invalidation)
Sample values from a packet, adding them to the VFT.
Definition: frequent_values.cc:176
gem5::compression::Base::compExtraLatency
const Cycles compExtraLatency
Extra latency added to compression due to packaging, shifting or other operations.
Definition: base.hh:114
gem5::compression::FrequentValues::VFT
AssociativeSet< VFTEntry > VFT
The Value Frequency Table, a small cache that keeps track and estimates the frequency distribution of...
Definition: frequent_values.hh:149
gem5::compression::FrequentValues::takenSamples
unsigned takenSamples
Number of samples taken so far.
Definition: frequent_values.hh:105
gem5::ArmISA::i
Bitfield< 7 > i
Definition: misc_types.hh:67
gem5::compression::FrequentValues::codeGenerationTicks
const Tick codeGenerationTicks
Ticks needed to perform the CODE_GENERATION phase.
Definition: frequent_values.hh:93
gem5::compression::FrequentValues::CompData::compressedValues
std::vector< CompressedValue > compressedValues
The values contained in the original data, after being compressed sequentially.
Definition: frequent_values.hh:222
gem5::mask
constexpr uint64_t mask(unsigned nbits)
Generate a 64-bit mask of 'nbits' 1s, right justified.
Definition: bitfield.hh:63
gem5::compression::Base::fromChunks
void fromChunks(const std::vector< Chunk > &chunks, uint64_t *data) const
This function re-joins the chunks to recreate the original data.
Definition: base.cc:133
gem5::compression::FrequentValues::CODE_GENERATION
@ CODE_GENERATION
Definition: frequent_values.hh:111
gem5::Cycles
Cycles is a wrapper class for representing cycle counts, i.e.
Definition: types.hh:78
gem5::compression::FrequentValues::phase
Phase phase
Definition: frequent_values.hh:112
gem5::compression::Base::decompExtraLatency
const Cycles decompExtraLatency
Extra latency added to decompression due to packaging, shifting or other operations.
Definition: base.hh:126
gem5::BaseCache::DataUpdate::newData
std::vector< uint64_t > newData
The new data contents.
Definition: base.hh:132
gem5::BaseCache::DataUpdate
A data contents update is composed of the updated block's address, the old contents,...
Definition: base.hh:123
gem5::compression::Base::cache
BaseCache * cache
Pointer to the parent cache.
Definition: base.hh:129
gem5::compression::Base::toChunks
std::vector< Chunk > toChunks(const uint64_t *data) const
This function splits the raw data into chunks, so that it can be parsed by the compressor.
Definition: base.cc:114
gem5::compression::encoder::Code::code
uint64_t code
Only the LSB of the code are relevant.
Definition: base.hh:47
gem5::compression::encoder::Code
Definition: base.hh:44
gem5::compression::FrequentValues::indexEncoder
encoder::Huffman indexEncoder
The encoder applied to the VFT indices.
Definition: frequent_values.hh:87
bitfield.hh
gem5::VegaISA::p
Bitfield< 54 > p
Definition: pagetable.hh:70
gem5::compression::encoder::Huffman::encode
Code encode(const uint64_t val) const override
The function responsible for the generation of the alternative value.
Definition: huffman.cc:114
DPRINTF
#define DPRINTF(x,...)
Definition: trace.hh:210
gem5::compression::FrequentValues::numSamples
const unsigned numSamples
Number of samples in the sampling phase.
Definition: frequent_values.hh:102
gem5::compression::Base
Base cache compressor interface.
Definition: base.hh:64
gem5::compression::FrequentValues::VFTEntry::counter
SatCounter32 counter
The ideal counter width (in bits) is determined by the maximum number of times a given value appears ...
Definition: frequent_values.hh:129
compiler.hh
gem5::compression::FrequentValues::numVFTEntries
const unsigned numVFTEntries
Maximum number of VFT entries, and thus of codewords too.
Definition: frequent_values.hh:99
name
const std::string & name()
Definition: trace.cc:48
gem5::compression::FrequentValues::FrequentValuesListener::parent
FrequentValues & parent
Definition: frequent_values.hh:71
gem5::SimObject::getProbeManager
ProbeManager * getProbeManager()
Get the probe manager for this object.
Definition: sim_object.cc:117
gem5::compression::encoder::Huffman::sample
void sample(uint64_t value, uint64_t frequency)
Inserts the value-frequency pair in the tree.
Definition: huffman.cc:51
gem5::compression::encoder::Code::length
unsigned length
Number of bits in the code.
Definition: base.hh:49
gem5::compression::FrequentValues::COMPRESSING
@ COMPRESSING
Definition: frequent_values.hh:111
gem5::compression::FrequentValues::FrequentValuesListener
Definition: frequent_values.hh:68
logging.hh
gem5::compression::Base::compChunksPerCycle
const Cycles compChunksPerCycle
Degree of parallelization of the compression process.
Definition: base.hh:108
gem5::compression::FrequentValues::CompData
Definition: frequent_values.hh:194
gem5::compression::FrequentValues::codeGenerationEvent
EventFunctionWrapper codeGenerationEvent
Event to handle finishing code generation and starting compression.
Definition: frequent_values.hh:159
gem5::compression::FrequentValues::SAMPLING
@ SAMPLING
Definition: frequent_values.hh:111
gem5::compression::FrequentValues::VFTEntry
Definition: frequent_values.hh:114
intmath.hh
fatal_if
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
Definition: logging.hh:236
gem5
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
Definition: gpu_translation_state.hh:37
gem5::compression::FrequentValues::regProbeListeners
void regProbeListeners() override
Register probe listeners for this object.
Definition: frequent_values.cc:288
gem5::compression::FrequentValues::generateCodes
void generateCodes()
End sampling phase and start the code generation.
Definition: frequent_values.cc:217
gem5::compression::encoder::Huffman::generateCodeMaps
void generateCodeMaps()
Generation of the code maps.
Definition: huffman.cc:82
gem5::compression::FrequentValues::FrequentValues
FrequentValues(const Params &p)
Definition: frequent_values.cc:48

Generated on Sun Jul 30 2023 01:56:57 for gem5 by doxygen 1.8.17