gem5  v21.0.0.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/intmath.hh"
36 #include "base/logging.hh"
37 #include "debug/CacheComp.hh"
39 #include "params/FrequentValuesCompressor.hh"
40 
41 namespace Compressor {
42 
44  : Base(p), useHuffmanEncoding(p.max_code_length != 0),
45  encoder(p.max_code_length), counterBits(p.counter_bits),
46  codeGenerationTicks(p.code_generation_ticks),
47  checkSaturation(p.check_saturation), numVFTEntries(p.vft_entries),
48  numSamples(p.num_samples), takenSamples(0), phase(SAMPLING),
49  VFT(p.vft_assoc, p.vft_entries, p.vft_indexing_policy,
50  p.vft_replacement_policy, VFTEntry(counterBits)),
51  codeGenerationEvent([this]{ phase = COMPRESSING; }, name())
52 {
53  fatal_if((numVFTEntries - 1) > mask(chunkSizeBits),
54  "There are more VFT entries than possible values.");
55 }
56 
57 std::unique_ptr<Base::CompressionData>
59  Cycles& decomp_lat)
60 {
61  std::unique_ptr<CompData> comp_data =
62  std::unique_ptr<CompData>(new CompData());
63 
64  // Compression size
65  std::size_t size = 0;
66 
67  // Compress every value sequentially. The compressed values are then
68  // added to the final compressed data.
69  for (const auto& chunk : chunks) {
70  Encoder::Code code;
71  int length = 0;
72  if (phase == COMPRESSING) {
73  VFTEntry* entry = VFT.findEntry(chunk, false);
74 
75  // Theoretically, the code would be the index of the entry;
76  // however, there is no practical need to do so, and we simply
77  // use the value instead
78  const unsigned uncompressed_index = uncompressedValue;
79  const unsigned index = entry ? chunk : uncompressed_index;
80 
81  // If using an index encoder, apply it
82  if (useHuffmanEncoding) {
83  code = encoder.encode(index);
84 
85  if (index == uncompressed_index) {
86  code.length += chunkSizeBits;
87  } else if (code.length > 64) {
88  // If, for some reason, we could not generate an encoding
89  // for the value, generate the uncompressed encoding
90  code = encoder.encode(uncompressed_index);
91  assert(code.length <= 64);
92  code.length += chunkSizeBits;
93  }
94  } else {
95  const unsigned code_size = std::log2(numVFTEntries);
96  if (entry) {
97  code = {index, code_size};
98  } else {
99  code = {uncompressed_index, code_size + chunkSizeBits};
100  }
101  }
102  } else {
103  // Not compressing yet; simply copy the value over
104  code = {chunk, chunkSizeBits};
105  }
106  length += code.length;
107 
108  DPRINTF(CacheComp, "Compressed %016x to %016x (Size = %d) "
109  "(Phase: %d)\n", chunk, code.code, length, phase);
110 
111  comp_data->compressedValues.emplace_back(code, chunk);
112 
113  size += length;
114  }
115 
116  // Set final compression size
117  comp_data->setSizeBits(size);
118 
119  // Set latencies based on the degree of parallelization, and any extra
120  // latencies due to shifting or packaging
121  comp_lat = Cycles(compExtraLatency +
122  (chunks.size() / compChunksPerCycle));
123  decomp_lat = Cycles(decompExtraLatency +
124  (chunks.size() / decompChunksPerCycle));
125 
126  // Return compressed line
127  return comp_data;
128 }
129 
130 void
131 FrequentValues::decompress(const CompressionData* comp_data, uint64_t* data)
132 {
133  const CompData* casted_comp_data = static_cast<const CompData*>(comp_data);
134 
135  // Decompress every entry sequentially
136  std::vector<Chunk> decomp_chunks;
137  for (const auto& comp_chunk : casted_comp_data->compressedValues) {
138  if (phase == COMPRESSING) {
139  if (useHuffmanEncoding) {
140  // Although in theory we have the codeword and have to find
141  // its corresponding value, in order to make life easier we
142  // search for the value and verify that the stored code
143  // matches the table's
144  M5_VAR_USED const Encoder::Code code =
145  encoder.encode(comp_chunk.value);
146 
147  // Either the value will be found and the codes match, or the
148  // value will not be found because it is an uncompressed entry
149  assert(((code.length <= 64) &&
150  (code.code == comp_chunk.code.code)) ||
151  (comp_chunk.code.code ==
153  } else {
154  // The value at the given VFT entry must match the one stored,
155  // if it is not the uncompressed value
156  assert((comp_chunk.code.code == uncompressedValue) ||
157  VFT.findEntry(comp_chunk.value, false));
158  }
159  }
160 
161  decomp_chunks.push_back(comp_chunk.value);
162  DPRINTF(CacheComp, "Decompressed %016x to %016x\n",
163  comp_chunk.code.code, comp_chunk.value);
164  }
165 
166  // Concatenate the decompressed words to generate the cache lines
167  fromChunks(decomp_chunks, data);
168 }
169 
170 void
172  bool is_invalidation)
173 {
174  const std::vector<Chunk> chunks = toChunks(data.data());
175  for (const Chunk& chunk : chunks) {
176  VFTEntry* entry = VFT.findEntry(chunk, false);
177  bool saturated = false;
178  if (!is_invalidation) {
179  // If a VFT hit, increase new value's counter; otherwise, insert
180  // new value
181  if (!entry) {
182  entry = VFT.findVictim(chunk);
183  assert(entry != nullptr);
184  entry->value = chunk;
185  VFT.insertEntry(chunk, false, entry);
186  } else {
187  VFT.accessEntry(entry);
188  }
189  entry->counter++;
190  saturated = entry->counter.isSaturated();
191  } else {
192  // If a VFT hit, decrease value's counter
193  if (entry) {
194  VFT.accessEntry(entry);
195  entry->counter--;
196  }
197  }
198 
199  // If any counter saturates, all counters are shifted right,
200  // resulting in precision loss
201  if (checkSaturation && saturated) {
202  for (auto& entry : VFT) {
203  entry.counter >>= 1;
204  }
205  }
206  }
207 
208  takenSamples += chunks.size();
209 }
210 
211 void
213 {
214  // We need to find a pseudo value to store uncompressed values as
215  // For that we generate all possible values from 0 to 1 size larger
216  // than the number of real values.
217  std::set<uint64_t> uncompressed_values;
218  for (int i = 0; i < numVFTEntries+1; ++i) {
219  uncompressed_values.insert(uncompressed_values.end(), i);
220  }
221 
222  for (const auto& entry : VFT) {
223  // Remove the respective real value from the list of possible
224  // pseudo values for the uncompressed value
225  uncompressed_values.erase(entry.value);
226  }
227 
228  // Select the first remaining possible value as the value
229  // representing uncompressed values
230  assert(uncompressed_values.size() >= 1);
231  uncompressedValue = *uncompressed_values.begin();
232  assert(VFT.findEntry(uncompressedValue, false) == nullptr);
233 
234  if (useHuffmanEncoding) {
235  // Populate the queue, adding each entry as a tree with one node.
236  // They are sorted such that the value with highest frequency is
237  // the queue's top
238  for (const auto& entry : VFT) {
239  encoder.sample(entry.value, entry.counter);
240  }
241 
242  // Insert the uncompressed value in the tree assuming it has the
243  // highest frequency, since it is in fact a group of all the values
244  // not present in the VFT
245  encoder.sample(uncompressedValue, ULLONG_MAX);
246 
248  }
249 
250  // Generate the code map and mark the current phase as code generation
252 
253  // Let us know when to change from the code generation phase to the
254  // effective compression phase
256 }
257 
258 void
260 {
261  // Do not update VFT if not sampling
262  if (phase == SAMPLING) {
263  // If the new data is not present, the notification is due to a
264  // fill; otherwise, sample the old block's contents
265  if (data_update.oldData.size() > 0) {
266  sampleValues(data_update.oldData, true);
267  }
268  // If the new data is not present, the notification is due to an
269  // invalidation; otherwise, sample the new block's contents
270  if (data_update.newData.size() > 0) {
271  sampleValues(data_update.newData, false);
272  }
273 
274  // Check if it is done with the sampling phase. If so, generate the
275  // codes that will be used for the compression phase
276  if (takenSamples >= numSamples) {
277  generateCodes();
278  }
279  }
280 }
281 
282 void
284 {
285  assert(listeners.empty());
286  assert(cache != nullptr);
287  listeners.push_back(new FrequentValuesListener(
288  *this, cache->getProbeManager(), "Data Update"));
289 }
290 
291 void
293 {
294  parent.probeNotify(data_update);
295 }
296 
297 } // namespace Compressor
associative_set_impl.hh
BaseCache::DataUpdate::oldData
std::vector< uint64_t > oldData
The stale data contents.
Definition: base.hh:123
Compressor::Base::decompExtraLatency
const Cycles decompExtraLatency
Extra latency added to decompression due to packaging, shifting or other operations.
Definition: base.hh:121
Compressor::FrequentValues::decompress
void decompress(const CompressionData *comp_data, uint64_t *data) override
Apply the decompression process to the compressed data.
Definition: frequent_values.cc:131
Compressor::FrequentValues::FrequentValuesListener
Definition: frequent_values.hh:64
Compressor::FrequentValues::takenSamples
unsigned takenSamples
Number of samples taken so far.
Definition: frequent_values.hh:101
data
const char data[]
Definition: circlebuf.test.cc:47
Compressor::Base::chunkSizeBits
const unsigned chunkSizeBits
Chunk size, in number of bits.
Definition: base.hh:91
MipsISA::index
Bitfield< 30, 0 > index
Definition: pra_constants.hh:44
Compressor::FrequentValues::regProbeListeners
void regProbeListeners() override
Register probe listeners for this object.
Definition: frequent_values.cc:283
ArmISA::i
Bitfield< 7 > i
Definition: miscregs_types.hh:63
Compressor
Definition: base.cc:47
Compressor::FrequentValues::SAMPLING
@ SAMPLING
Definition: frequent_values.hh:107
frequent_values.hh
Compressor::Encoder::Huffman::generateCodeMaps
void generateCodeMaps()
Generation of the code maps.
Definition: huffman.cc:77
Compressor::Encoder::Code::code
uint64_t code
Only the LSB of the code are relevant.
Definition: base.hh:40
Compressor::FrequentValues::listeners
std::vector< FrequentValuesListener * > listeners
Definition: frequent_values.hh:77
Compressor::FrequentValues::useHuffmanEncoding
const bool useHuffmanEncoding
Whether Huffman encoding is applied to the VFT indices.
Definition: frequent_values.hh:80
Compressor::FrequentValues::FrequentValuesListener::notify
void notify(const DataUpdate &data_update) override
Definition: frequent_values.cc:292
Compressor::Encoder::Huffman::sample
void sample(uint64_t value, uint64_t frequency)
Inserts the value-frequency pair in the tree.
Definition: huffman.cc:46
Compressor::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:58
std::vector< Chunk >
Compressor::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:128
Compressor::Base
Base cache compressor interface.
Definition: base.hh:59
BaseCache::DataUpdate::newData
std::vector< uint64_t > newData
The new data contents.
Definition: base.hh:125
Compressor::FrequentValues::generateCodes
void generateCodes()
End sampling phase and start the code generation.
Definition: frequent_values.cc:212
Compressor::FrequentValues::codeGenerationTicks
const Tick codeGenerationTicks
Ticks needed to perform the CODE_GENERATION phase.
Definition: frequent_values.hh:89
Compressor::FrequentValues::VFTEntry
Definition: frequent_values.hh:110
EventManager::schedule
void schedule(Event &event, Tick when)
Definition: eventq.hh:1016
Compressor::Base::CompressionData
Definition: base.hh:240
bitfield.hh
Compressor::FrequentValues::encoder
Encoder::Huffman encoder
The encoder applied to the VFT indices.
Definition: frequent_values.hh:83
Compressor::Encoder::Code
Definition: base.hh:37
DPRINTF
#define DPRINTF(x,...)
Definition: trace.hh:237
Compressor::Base::Params
BaseCacheCompressorParams Params
Definition: base.hh:196
Compressor::FrequentValues::codeGenerationEvent
EventFunctionWrapper codeGenerationEvent
Event to handle finishing code generation and starting compression.
Definition: frequent_values.hh:155
Compressor::FrequentValues::numVFTEntries
const unsigned numVFTEntries
Maximum number of VFT entries, and thus of codewords too.
Definition: frequent_values.hh:95
Compressor::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:117
Compressor::FrequentValues::probeNotify
void probeNotify(const DataUpdate &data_update)
Process a notification event from the ProbeListener.
Definition: frequent_values.cc:259
Compressor::FrequentValues::CompData::compressedValues
std::vector< CompressedValue > compressedValues
The values contained in the original data, after being compressed sequentially.
Definition: frequent_values.hh:218
Compressor::FrequentValues::FrequentValuesListener::parent
FrequentValues & parent
Definition: frequent_values.hh:67
Compressor::Base::compChunksPerCycle
const Cycles compChunksPerCycle
Degree of parallelization of the compression process.
Definition: base.hh:103
name
const std::string & name()
Definition: trace.cc:48
SimObject::getProbeManager
ProbeManager * getProbeManager()
Get the probe manager for this object.
Definition: sim_object.cc:114
Compressor::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:125
Compressor::FrequentValues::CODE_GENERATION
@ CODE_GENERATION
Definition: frequent_values.hh:107
Compressor::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:145
Compressor::Base::compExtraLatency
const Cycles compExtraLatency
Extra latency added to compression due to packaging, shifting or other operations.
Definition: base.hh:109
Compressor::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:109
Compressor::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:171
BaseCache::DataUpdate
A data contents update is composed of the updated block's address, the old contents,...
Definition: base.hh:116
Compressor::FrequentValues::CompData
Definition: frequent_values.hh:190
Compressor::FrequentValues::uncompressedValue
uint64_t uncompressedValue
A pseudo value is used as the representation of uncompressed values.
Definition: frequent_values.hh:152
Compressor::Encoder::Code::length
unsigned length
Number of bits in the code.
Definition: base.hh:42
Compressor::FrequentValues::FrequentValues
FrequentValues(const Params &p)
Definition: frequent_values.cc:43
Compressor::FrequentValues::COMPRESSING
@ COMPRESSING
Definition: frequent_values.hh:107
logging.hh
Cycles
Cycles is a wrapper class for representing cycle counts, i.e.
Definition: types.hh:79
curTick
Tick curTick()
The universal simulation clock.
Definition: cur_tick.hh:43
MipsISA::p
Bitfield< 0 > p
Definition: pra_constants.hh:323
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:219
Compressor::Base::decompChunksPerCycle
const Cycles decompChunksPerCycle
Degree of parallelization of the decompression process.
Definition: base.hh:115
Compressor::Base::Chunk
uint64_t Chunk
A chunk is a basic lexical unit.
Definition: base.hh:66
Compressor::FrequentValues::phase
Phase phase
Definition: frequent_values.hh:108
Compressor::Encoder::Huffman::encode
Code encode(const uint64_t val) const override
The function responsible for the generation of the alternative value.
Definition: huffman.cc:109
Compressor::FrequentValues::numSamples
const unsigned numSamples
Number of samples in the sampling phase.
Definition: frequent_values.hh:98
GenericSatCounter::isSaturated
bool isSaturated() const
Whether the counter has achieved its maximum value or not.
Definition: sat_counter.hh:309
Compressor::FrequentValues::checkSaturation
const bool checkSaturation
Whether an action must be performed when counters saturate.
Definition: frequent_values.hh:92
ArmISA::mask
Bitfield< 28, 24 > mask
Definition: miscregs_types.hh:711
Compressor::Base::cache
BaseCache * cache
Pointer to the parent cache.
Definition: base.hh:124

Generated on Tue Mar 23 2021 19:41:27 for gem5 by doxygen 1.8.17