| /* |
| * Copyright (c) 2019-2020 Inria |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer; |
| * redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution; |
| * neither the name of the copyright holders nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #ifndef __MEM_CACHE_COMPRESSORS_FREQUENT_VALUES_HH__ |
| #define __MEM_CACHE_COMPRESSORS_FREQUENT_VALUES_HH__ |
| |
| #include <climits> |
| #include <cstdint> |
| #include <memory> |
| #include <vector> |
| |
| #include "base/sat_counter.hh" |
| #include "base/types.hh" |
| #include "mem/cache/base.hh" |
| #include "mem/cache/compressors/base.hh" |
| #include "mem/cache/compressors/encoders/huffman.hh" |
| #include "mem/cache/prefetch/associative_set.hh" |
| #include "sim/eventq.hh" |
| #include "sim/probe/probe.hh" |
| |
| struct FrequentValuesCompressorParams; |
| |
| namespace Compressor { |
| |
| /** |
| * This compressor samples the cache for a while, trying to define the |
| * most frequently used values. When these values are determined, they are |
| * associated to shorter representations (codes). Then the compressor can |
| * start its effective compression phase, in which occurrences of these |
| * values are substituted by their codes. |
| */ |
| class FrequentValues : public Base |
| { |
| private: |
| class CompData; |
| |
| using DataUpdate = BaseCache::DataUpdate; |
| |
| class FrequentValuesListener : public ProbeListenerArgBase<DataUpdate> |
| { |
| protected: |
| FrequentValues &parent; |
| |
| public: |
| FrequentValuesListener(FrequentValues &_parent, ProbeManager *pm, |
| const std::string &name) |
| : ProbeListenerArgBase(pm, name), parent(_parent) |
| { |
| } |
| void notify(const DataUpdate &data_update) override; |
| }; |
| std::vector<FrequentValuesListener*> listeners; |
| |
| /** Whether Huffman encoding is applied to the VFT indices. */ |
| const bool useHuffmanEncoding; |
| |
| /** The encoder applied to the VFT indices. */ |
| Encoder::Huffman encoder; |
| |
| /** Number of bits in the saturating counters. */ |
| const int counterBits; |
| |
| /** Ticks needed to perform the CODE_GENERATION phase. */ |
| const Tick codeGenerationTicks; |
| |
| /** Whether an action must be performed when counters saturate. */ |
| const bool checkSaturation; |
| |
| /** Maximum number of VFT entries, and thus of codewords too. */ |
| const unsigned numVFTEntries; |
| |
| /** Number of samples in the sampling phase. */ |
| const unsigned numSamples; |
| |
| /** Number of samples taken so far. */ |
| unsigned takenSamples; |
| |
| /** |
| * The phase that the compressor is at. It assumes that sampling and |
| * code generation are done only once. |
| */ |
| enum Phase {SAMPLING, CODE_GENERATION, COMPRESSING}; |
| Phase phase; |
| |
| class VFTEntry : public TaggedEntry |
| { |
| public: |
| /** |
| * The value is stored as a 64 bit entry to accomodate for the |
| * uncompressed value. All real values must be 32 bits. |
| */ |
| uint64_t value; |
| |
| /** |
| * The ideal counter width (in bits) is determined by the maximum |
| * number of times a given value appears in the cache |
| * (log2(cache_size / chunkSizeBits)). If smaller counters are used |
| * their values should be rescaled when saturated. |
| */ |
| SatCounter32 counter; |
| |
| VFTEntry(std::size_t num_bits) |
| : TaggedEntry(), value(0), counter(num_bits) |
| { |
| } |
| |
| void |
| invalidate() override |
| { |
| TaggedEntry::invalidate(); |
| value = 0; |
| counter.reset(); |
| } |
| }; |
| |
| /** |
| * The Value Frequency Table, a small cache that keeps track and estimates |
| * the frequency distribution of values in the cache. |
| */ |
| AssociativeSet<VFTEntry> VFT; |
| |
| /** |
| * A pseudo value is used as the representation of uncompressed values. |
| * This value is a random value that is not present in the VFT. It is |
| * selected at the end of the sampling phase. |
| */ |
| uint64_t uncompressedValue; |
| |
| /** Event to handle finishing code generation and starting compression. */ |
| EventFunctionWrapper codeGenerationEvent; |
| |
| /** |
| * Sample values from a packet, adding them to the VFT. |
| * |
| * @param data The line being sampled. |
| * @param is_invalidation whether this event comes from an invalidation. |
| */ |
| void sampleValues(const std::vector<uint64_t> &data, |
| bool is_invalidation); |
| |
| /** End sampling phase and start the code generation. */ |
| void generateCodes(); |
| |
| std::unique_ptr<Base::CompressionData> compress( |
| const std::vector<Chunk>& chunks, Cycles& comp_lat, |
| Cycles& decomp_lat) override; |
| |
| void decompress(const CompressionData* comp_data, uint64_t* data) override; |
| |
| public: |
| typedef FrequentValuesCompressorParams Params; |
| FrequentValues(const Params &p); |
| ~FrequentValues() = default; |
| |
| /** |
| * Process a notification event from the ProbeListener. |
| * |
| * @param data_update The data regarding the entry's contents update. |
| */ |
| void probeNotify(const DataUpdate &data_update); |
| |
| void regProbeListeners() override; |
| }; |
| |
| class FrequentValues::CompData : public CompressionData |
| { |
| public: |
| /** |
| * A compressed value contains its encoding, and the compressed data |
| * itself. |
| */ |
| struct CompressedValue |
| { |
| /** The codeword.*/ |
| Encoder::Code code; |
| |
| /** |
| * Original value, stored both for when the codeword marks an |
| * uncompressed entry, and to verify correctness. |
| */ |
| uint64_t value; |
| |
| CompressedValue(Encoder::Code _code, uint64_t _value) |
| : code(_code), value(_value) |
| { |
| } |
| }; |
| |
| /** |
| * The values contained in the original data, after being compressed |
| * sequentially. |
| */ |
| std::vector<CompressedValue> compressedValues; |
| }; |
| |
| } // namespace Compressor |
| |
| #endif //__MEM_CACHE_COMPRESSORS_FREQUENT_VALUES_HH__ |