gem5 v23.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/compiler.hh"
36#include "base/intmath.hh"
37#include "base/logging.hh"
38#include "debug/CacheComp.hh"
40#include "params/FrequentValuesCompressor.hh"
41
42namespace gem5
43{
44
45namespace 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
62std::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
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
135void
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
175void
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
216void
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
263void
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) {
283 }
284 }
285}
286
287void
289{
290 assert(listeners.empty());
291 assert(cache != nullptr);
292 listeners.push_back(new FrequentValuesListener(
293 *this, cache->getProbeManager(), "Data Update"));
294}
295
296void
298{
299 parent.probeNotify(data_update);
300}
301
302} // namespace compression
303} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:210
const char data[]
Cycles is a wrapper class for representing cycle counts, i.e.
Definition types.hh:79
Base cache compressor interface.
Definition base.hh:65
const Cycles compExtraLatency
Extra latency added to compression due to packaging, shifting or other operations.
Definition base.hh:114
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
BaseCache * cache
Pointer to the parent cache.
Definition base.hh:129
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
const Cycles decompExtraLatency
Extra latency added to decompression due to packaging, shifting or other operations.
Definition base.hh:126
const Cycles compChunksPerCycle
Degree of parallelization of the compression process.
Definition base.hh:108
uint64_t Chunk
A chunk is a basic lexical unit.
Definition base.hh:82
const unsigned chunkSizeBits
Chunk size, in number of bits.
Definition base.hh:96
const Cycles decompChunksPerCycle
Degree of parallelization of the decompression process.
Definition base.hh:120
std::vector< CompressedValue > compressedValues
The values contained in the original data, after being compressed sequentially.
void notify(const DataUpdate &data_update) override
SatCounter32 counter
The ideal counter width (in bits) is determined by the maximum number of times a given value appears ...
uint64_t value
The value is stored as a 64 bit entry to accomodate for the uncompressed value.
std::vector< FrequentValuesListener * > listeners
FrequentValuesCompressorParams Params
void decompress(const CompressionData *comp_data, uint64_t *data) override
Apply the decompression process to the compressed data.
void regProbeListeners() override
Register probe listeners for this object.
void sampleValues(const std::vector< uint64_t > &data, bool is_invalidation)
Sample values from a packet, adding them to the VFT.
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.
unsigned takenSamples
Number of samples taken so far.
void probeNotify(const DataUpdate &data_update)
Process a notification event from the ProbeListener.
const unsigned numVFTEntries
Maximum number of VFT entries, and thus of codewords too.
const Tick codeGenerationTicks
Ticks needed to perform the CODE_GENERATION phase.
const bool checkSaturation
Whether an action must be performed when counters saturate.
void generateCodes()
End sampling phase and start the code generation.
const unsigned numSamples
Number of samples in the sampling phase.
encoder::Huffman indexEncoder
The encoder applied to the VFT indices.
const bool useHuffmanEncoding
Whether Huffman encoding is applied to the VFT indices.
uint64_t uncompressedValue
A pseudo value is used as the representation of uncompressed values.
AssociativeSet< VFTEntry > VFT
The Value Frequency Table, a small cache that keeps track and estimates the frequency distribution of...
EventFunctionWrapper codeGenerationEvent
Event to handle finishing code generation and starting compression.
void sample(uint64_t value, uint64_t frequency)
Inserts the value-frequency pair in the tree.
Definition huffman.cc:51
Code encode(const uint64_t val) const override
The function responsible for the generation of the alternative value.
Definition huffman.cc:114
void generateCodeMaps()
Generation of the code maps.
Definition huffman.cc:82
STL vector class.
Definition stl.hh:37
void schedule(Event &event, Tick when)
Definition eventq.hh:1012
#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
bool isSaturated() const
Whether the counter has achieved its maximum value or not.
ProbeManager * getProbeManager()
Get the probe manager for this object.
Bitfield< 3, 0 > mask
Definition pcstate.hh:63
Bitfield< 7 > i
Definition misc_types.hh:67
Bitfield< 30, 0 > index
Bitfield< 0 > p
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
Tick curTick()
The universal simulation clock.
Definition cur_tick.hh:46
A data contents update is composed of the updated block's address, the old contents,...
Definition base.hh:124
std::vector< uint64_t > newData
The new data contents.
Definition base.hh:132
std::vector< uint64_t > oldData
The stale data contents.
Definition base.hh:130
unsigned length
Number of bits in the code.
Definition base.hh:49
uint64_t code
Only the LSB of the code are relevant.
Definition base.hh:47
const std::string & name()
Definition trace.cc:48

Generated on Mon Jul 10 2023 14:24:32 for gem5 by doxygen 1.9.7