mem-cache: Templatize DictionaryCompressor

Templatize DictionaryCompressor so that the dictionary entries' sizes
can be changed.

Change-Id: I3d89e3c692a721cefcd7e3c55d2ccdefa425f614
Signed-off-by: Daniel R. Carvalho <odanrc@yahoo.com.br>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/21148
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Bobby R. Bruce <bbruce@ucdavis.edu>
Maintainer: Nikos Nikoleris <nikos.nikoleris@arm.com>
This commit is contained in:
Daniel R. Carvalho
2019-09-05 17:39:38 +02:00
committed by Daniel Carvalho
parent 7ce9fe0af9
commit 7a8debf0fa
7 changed files with 311 additions and 220 deletions

View File

@@ -40,6 +40,14 @@ class BaseCacheCompressor(SimObject):
"in bytes, in which a block must be compressed to. Otherwise it is "
"stored in its uncompressed state")
class BaseDictionaryCompressor(BaseCacheCompressor):
type = 'BaseDictionaryCompressor'
abstract = True
cxx_header = "mem/cache/compressors/dictionary_compressor.hh"
dictionary_size = Param.Int(Parent.cache_line_size,
"Number of dictionary entries")
class BDI(BaseCacheCompressor):
type = 'BDI'
cxx_class = 'BDI'
@@ -49,15 +57,7 @@ class BDI(BaseCacheCompressor):
"combinations of base and delta for the compressors. False if using" \
"only the lowest possible delta size for each base size.");
class DictionaryCompressor(BaseCacheCompressor):
type = 'DictionaryCompressor'
abstract = True
cxx_header = "mem/cache/compressors/dictionary_compressor.hh"
dictionary_size = Param.Int(Parent.cache_line_size,
"Number of dictionary entries")
class CPack(DictionaryCompressor):
class CPack(BaseDictionaryCompressor):
type = 'CPack'
cxx_class = 'CPack'
cxx_header = "mem/cache/compressors/cpack.hh"

View File

@@ -33,6 +33,6 @@ Import('*')
SimObject('Compressors.py')
Source('base.cc')
Source('base_dictionary_compressor.cc')
Source('bdi.cc')
Source('cpack.cc')
Source('dictionary_compressor.cc')

View File

@@ -0,0 +1,61 @@
/*
* Copyright (c) 2018-2019 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.
*
* Authors: Daniel Carvalho
*/
/** @file
* Implementation of a base sim object for the templated dictionary-based
* cache compressor.
*/
#include "mem/cache/compressors/dictionary_compressor.hh"
#include "params/BaseDictionaryCompressor.hh"
BaseDictionaryCompressor::BaseDictionaryCompressor(const Params *p)
: BaseCacheCompressor(p), dictionarySize(p->dictionary_size), numEntries(0)
{
}
void
BaseDictionaryCompressor::regStats()
{
BaseCacheCompressor::regStats();
// We store the frequency of each pattern
patternStats
.init(getNumPatterns())
.name(name() + ".pattern")
.desc("Number of data entries that were compressed to this pattern.")
;
for (unsigned i = 0; i < getNumPatterns(); ++i) {
patternStats.subname(i, getName(i));
patternStats.subdesc(i, "Number of data entries that match pattern " +
getName(i));
}
}

View File

@@ -34,15 +34,16 @@
#include "mem/cache/compressors/cpack.hh"
#include "mem/cache/compressors/dictionary_compressor_impl.hh"
#include "params/CPack.hh"
CPack::CPack(const Params *p)
: DictionaryCompressor(p)
: DictionaryCompressor<uint32_t>(p)
{
}
void
CPack::addToDictionary(std::array<uint8_t, 4> data)
CPack::addToDictionary(DictionaryEntry data)
{
assert(numEntries < dictionarySize);
dictionary[numEntries++] = data;
@@ -52,7 +53,7 @@ std::unique_ptr<BaseCacheCompressor::CompressionData>
CPack::compress(const uint64_t* data, Cycles& comp_lat, Cycles& decomp_lat)
{
std::unique_ptr<BaseCacheCompressor::CompressionData> comp_data =
DictionaryCompressor::compress(data);
DictionaryCompressor<uint32_t>::compress(data);
// Set compression latency (Accounts for pattern matching, length
// generation, packaging and shifting)

View File

@@ -36,7 +36,6 @@
#ifndef __MEM_CACHE_COMPRESSORS_CPACK_HH__
#define __MEM_CACHE_COMPRESSORS_CPACK_HH__
#include <array>
#include <cstdint>
#include <map>
#include <memory>
@@ -46,9 +45,11 @@
struct CPackParams;
class CPack : public DictionaryCompressor
class CPack : public DictionaryCompressor<uint32_t>
{
private:
using DictionaryEntry = DictionaryCompressor<uint32_t>::DictionaryEntry;
// Forward declaration of all possible patterns
class PatternZZZZ;
class PatternXXXX;
@@ -88,14 +89,14 @@ class CPack : public DictionaryCompressor
};
std::unique_ptr<Pattern> getPattern(
const std::array<uint8_t, 4>& bytes,
const std::array<uint8_t, 4>& dict_bytes,
const DictionaryEntry& bytes,
const DictionaryEntry& dict_bytes,
const int match_location) const override
{
return PatternFactory::getPattern(bytes, dict_bytes, match_location);
}
void addToDictionary(std::array<uint8_t, 4> data) override;
void addToDictionary(DictionaryEntry data) override;
/**
* Apply compression.
@@ -126,19 +127,19 @@ class CPack : public DictionaryCompressor
class CPack::PatternZZZZ : public DictionaryCompressor::Pattern
{
public:
PatternZZZZ(const std::array<uint8_t, 4> bytes, const int match_location)
PatternZZZZ(const DictionaryEntry bytes, const int match_location)
: Pattern(ZZZZ, 0x0, 2, 0, 0, false) {}
static bool isPattern(const std::array<uint8_t, 4>& bytes,
const std::array<uint8_t, 4>& dict_bytes,
const int match_location)
static bool isPattern(const DictionaryEntry& bytes,
const DictionaryEntry& dict_bytes,
const int match_location)
{
return (bytes[3] == 0) && (bytes[2] == 0) && (bytes[1] == 0) &&
(bytes[0] == 0);
}
std::array<uint8_t, 4>
decompress(const std::array<uint8_t, 4> dict_bytes) const override
DictionaryEntry
decompress(const DictionaryEntry dict_bytes) const override
{
return {0, 0, 0, 0};
}
@@ -150,23 +151,23 @@ class CPack::PatternXXXX : public DictionaryCompressor::Pattern
/**
* A copy of the word.
*/
const std::array<uint8_t, 4> bytes;
const DictionaryEntry bytes;
public:
PatternXXXX(const std::array<uint8_t, 4> bytes, const int match_location)
PatternXXXX(const DictionaryEntry bytes, const int match_location)
: Pattern(XXXX, 0x1, 2, 4, 0, true), bytes(bytes) {}
static bool isPattern(const std::array<uint8_t, 4>& bytes,
const std::array<uint8_t, 4>& dict_bytes,
const int match_location)
static bool isPattern(const DictionaryEntry& bytes,
const DictionaryEntry& dict_bytes,
const int match_location)
{
// It can always be an unmatch, as it is set to this class when other
// patterns fail
return true;
}
std::array<uint8_t, 4>
decompress(const std::array<uint8_t, 4> dict_bytes) const override
DictionaryEntry
decompress(const DictionaryEntry dict_bytes) const override
{
return bytes;
}
@@ -175,18 +176,18 @@ class CPack::PatternXXXX : public DictionaryCompressor::Pattern
class CPack::PatternMMMM : public DictionaryCompressor::Pattern
{
public:
PatternMMMM(const std::array<uint8_t, 4> bytes, const int match_location)
PatternMMMM(const DictionaryEntry bytes, const int match_location)
: Pattern(MMMM, 0x2, 6, 0, match_location, true) {}
static bool isPattern(const std::array<uint8_t, 4>& bytes,
const std::array<uint8_t, 4>& dict_bytes,
const int match_location)
static bool isPattern(const DictionaryEntry& bytes,
const DictionaryEntry& dict_bytes,
const int match_location)
{
return (bytes == dict_bytes) && (match_location >= 0);
}
std::array<uint8_t, 4>
decompress(const std::array<uint8_t, 4> dict_bytes) const override
DictionaryEntry
decompress(const DictionaryEntry dict_bytes) const override
{
return dict_bytes;
}
@@ -202,13 +203,13 @@ class CPack::PatternMMXX : public DictionaryCompressor::Pattern
const uint8_t byte1;
public:
PatternMMXX(const std::array<uint8_t, 4> bytes, const int match_location)
PatternMMXX(const DictionaryEntry bytes, const int match_location)
: Pattern(MMXX, 0xC, 8, 2, match_location, true),
byte0(bytes[0]), byte1(bytes[1]) {}
static bool isPattern(const std::array<uint8_t, 4>& bytes,
const std::array<uint8_t, 4>& dict_bytes,
const int match_location)
static bool isPattern(const DictionaryEntry& bytes,
const DictionaryEntry& dict_bytes,
const int match_location)
{
// Notice we don't compare bytes[0], as otherwise we'd be unnecessarily
// discarding MMXM. If that pattern is added this should be modified
@@ -217,8 +218,8 @@ class CPack::PatternMMXX : public DictionaryCompressor::Pattern
}
std::array<uint8_t, 4>
decompress(const std::array<uint8_t, 4> dict_bytes) const override
DictionaryEntry
decompress(const DictionaryEntry dict_bytes) const override
{
return {byte0, byte1, dict_bytes[2], dict_bytes[3]};
}
@@ -233,19 +234,19 @@ class CPack::PatternZZZX : public DictionaryCompressor::Pattern
const uint8_t byte;
public:
PatternZZZX(const std::array<uint8_t, 4> bytes, const int match_location)
PatternZZZX(const DictionaryEntry bytes, const int match_location)
: Pattern(ZZZX, 0xD, 4, 1, 0, false), byte(bytes[0]) {}
static bool isPattern(const std::array<uint8_t, 4>& bytes,
const std::array<uint8_t, 4>& dict_bytes,
const int match_location)
static bool isPattern(const DictionaryEntry& bytes,
const DictionaryEntry& dict_bytes,
const int match_location)
{
return (bytes[3] == 0) && (bytes[2] == 0) && (bytes[1] == 0) &&
(bytes[0] != 0);
}
std::array<uint8_t, 4>
decompress(const std::array<uint8_t, 4> dict_bytes) const override
DictionaryEntry
decompress(const DictionaryEntry dict_bytes) const override
{
return {byte, 0, 0, 0};
}
@@ -260,21 +261,21 @@ class CPack::PatternMMMX : public DictionaryCompressor::Pattern
const uint8_t byte;
public:
PatternMMMX(const std::array<uint8_t, 4> bytes, const int match_location)
PatternMMMX(const DictionaryEntry bytes, const int match_location)
: Pattern(MMMX, 0xE, 8, 1, match_location, true),
byte(bytes[0]) {}
static bool isPattern(const std::array<uint8_t, 4>& bytes,
const std::array<uint8_t, 4>& dict_bytes,
const int match_location)
static bool isPattern(const DictionaryEntry& bytes,
const DictionaryEntry& dict_bytes,
const int match_location)
{
return (bytes[3] == dict_bytes[3]) && (bytes[2] == dict_bytes[2]) &&
(bytes[1] == dict_bytes[1]) && (bytes[0] != dict_bytes[0]) &&
(match_location >= 0);
}
std::array<uint8_t, 4>
decompress(const std::array<uint8_t, 4> dict_bytes) const override
DictionaryEntry
decompress(const DictionaryEntry dict_bytes) const override
{
return {byte, dict_bytes[1], dict_bytes[2], dict_bytes[3]};
}

View File

@@ -55,63 +55,11 @@
#include "base/types.hh"
#include "mem/cache/compressors/base.hh"
struct DictionaryCompressorParams;
struct BaseDictionaryCompressorParams;
class DictionaryCompressor : public BaseCacheCompressor
class BaseDictionaryCompressor : public BaseCacheCompressor
{
protected:
/**
* Compression data for the dictionary compressor. It consists of a vector
* of patterns.
*/
class CompData;
// Forward declaration of a pattern
class Pattern;
/**
* Create a factory to determine if input matches a pattern. The if else
* chains are constructed by recursion. The patterns should be explored
* sorted by size for correct behaviour.
*/
template <class Head, class... Tail>
struct Factory
{
static std::unique_ptr<Pattern> getPattern(
const std::array<uint8_t, 4>& bytes,
const std::array<uint8_t, 4>& dict_bytes, const int match_location)
{
// If match this pattern, instantiate it. If a negative match
// location is used, the patterns that use the dictionary bytes
// must return false. This is used when there are no dictionary
// entries yet
if (Head::isPattern(bytes, dict_bytes, match_location)) {
return std::unique_ptr<Pattern>(
new Head(bytes, match_location));
// Otherwise, go for next pattern
} else {
return Factory<Tail...>::getPattern(bytes, dict_bytes,
match_location);
}
}
};
/** Specialization to end the recursion. */
template <class Head>
struct Factory<Head>
{
static std::unique_ptr<Pattern> getPattern(
const std::array<uint8_t, 4>& bytes,
const std::array<uint8_t, 4>& dict_bytes, const int match_location)
{
// Instantiate last pattern. Should be the XXXX pattern.
return std::unique_ptr<Pattern>(new Head(bytes, match_location));
}
};
/** The dictionary. */
std::vector<std::array<uint8_t, 4>> dictionary;
/** Dictionary size. */
const std::size_t dictionarySize;
@@ -123,9 +71,7 @@ class DictionaryCompressor : public BaseCacheCompressor
* @{
*/
/**
* Number of data entries that were compressed to each pattern.
*/
/** Number of data entries that were compressed to each pattern. */
Stats::Vector patternStats;
/**
@@ -147,14 +93,86 @@ class DictionaryCompressor : public BaseCacheCompressor
*/
virtual std::string getName(int number) const = 0;
public:
typedef BaseDictionaryCompressorParams Params;
BaseDictionaryCompressor(const Params *p);
~BaseDictionaryCompressor() = default;
void regStats() override;
};
/**
* A template version of the dictionary compressor that allows to choose the
* dictionary size.
*
* @tparam The type of a dictionary entry (e.g., uint16_t, uint32_t, etc).
*/
template <class T>
class DictionaryCompressor : public BaseDictionaryCompressor
{
protected:
/**
* Compression data for the dictionary compressor. It consists of a vector
* of patterns.
*/
class CompData;
// Forward declaration of a pattern
class Pattern;
/** Convenience typedef for a dictionary entry. */
typedef std::array<uint8_t, sizeof(T)> DictionaryEntry;
/**
* Create a factory to determine if input matches a pattern. The if else
* chains are constructed by recursion. The patterns should be explored
* sorted by size for correct behaviour.
*/
template <class Head, class... Tail>
struct Factory
{
static std::unique_ptr<Pattern> getPattern(
const DictionaryEntry& bytes, const DictionaryEntry& dict_bytes,
const int match_location)
{
// If match this pattern, instantiate it. If a negative match
// location is used, the patterns that use the dictionary bytes
// must return false. This is used when there are no dictionary
// entries yet
if (Head::isPattern(bytes, dict_bytes, match_location)) {
return std::unique_ptr<Pattern>(
new Head(bytes, match_location));
// Otherwise, go for next pattern
} else {
return Factory<Tail...>::getPattern(bytes, dict_bytes,
match_location);
}
}
};
/** Specialization to end the recursion. */
template <class Head>
struct Factory<Head>
{
static std::unique_ptr<Pattern>
getPattern(const DictionaryEntry& bytes,
const DictionaryEntry& dict_bytes, const int match_location)
{
// Instantiate last pattern. Should be the XXXX pattern.
return std::unique_ptr<Pattern>(new Head(bytes, match_location));
}
};
/** The dictionary. */
std::vector<DictionaryEntry> dictionary;
/**
* Since the factory cannot be instantiated here, classes that inherit
* from this base class have to implement the call to their factory's
* getPattern.
*/
virtual std::unique_ptr<Pattern> getPattern(
const std::array<uint8_t, 4>& bytes,
const std::array<uint8_t, 4>& dict_bytes,
virtual std::unique_ptr<Pattern>
getPattern(const DictionaryEntry& bytes, const DictionaryEntry& dict_bytes,
const int match_location) const = 0;
/**
@@ -163,15 +181,15 @@ class DictionaryCompressor : public BaseCacheCompressor
* @param data Data to be compressed.
* @return The pattern this data matches.
*/
std::unique_ptr<Pattern> compressWord(const uint32_t data);
std::unique_ptr<Pattern> compressValue(const T data);
/**
* Decompress a word.
* Decompress a pattern into a value that fits in a dictionary entry.
*
* @param pattern The pattern to be decompressed.
* @return The decompressed word.
*/
uint32_t decompressWord(const Pattern* pattern);
T decompressValue(const Pattern* pattern);
/** Clear all dictionary entries. */
void resetDictionary();
@@ -181,7 +199,7 @@ class DictionaryCompressor : public BaseCacheCompressor
*
* @param data The new entry.
*/
virtual void addToDictionary(std::array<uint8_t, 4> data) = 0;
virtual void addToDictionary(const DictionaryEntry data) = 0;
/**
* Apply compression.
@@ -200,18 +218,26 @@ class DictionaryCompressor : public BaseCacheCompressor
*/
void decompress(const CompressionData* comp_data, uint64_t* data) override;
/**
* Turn a value into a dictionary entry.
*
* @param value The value to turn.
* @return A dictionary entry containing the value.
*/
static DictionaryEntry toDictionaryEntry(T value);
/**
* Turn a dictionary entry into a value.
*
* @param The dictionary entry to turn.
* @return The value that the dictionary entry contained.
*/
static T fromDictionaryEntry(const DictionaryEntry& entry);
public:
/** Convenience typedef. */
typedef DictionaryCompressorParams Params;
/** Default constructor. */
typedef BaseDictionaryCompressorParams Params;
DictionaryCompressor(const Params *p);
/** Default destructor. */
~DictionaryCompressor() {};
/** Register local statistics. */
void regStats() override;
~DictionaryCompressor() = default;
};
/**
@@ -220,7 +246,8 @@ class DictionaryCompressor : public BaseCacheCompressor
* decompress(). Then the new pattern must be added to the PatternFactory
* declaration in crescent order of size (in the DictionaryCompressor class).
*/
class DictionaryCompressor::Pattern
template <class T>
class DictionaryCompressor<T>::Pattern
{
protected:
/** Pattern enum number. */
@@ -322,25 +349,26 @@ class DictionaryCompressor::Pattern
* @param dict_bytes The bytes in the corresponding matching entry.
* @return The decompressed pattern.
*/
virtual std::array<uint8_t, 4> decompress(
const std::array<uint8_t, 4> dict_bytes) const = 0;
virtual DictionaryEntry decompress(
const DictionaryEntry dict_bytes) const = 0;
};
class DictionaryCompressor::CompData : public CompressionData
template <class T>
class DictionaryCompressor<T>::CompData : public CompressionData
{
public:
/** The patterns matched in the original line. */
std::vector<std::unique_ptr<Pattern>> entries;
/**
* Default constructor.
*
* @param dictionary_size Number of entries in the dictionary.
*/
CompData(const std::size_t dictionary_size);
CompData();
~CompData() = default;
/** Default destructor. */
~CompData();
/**
* Add a pattern entry to the list of patterns.
*
* @param entry The new pattern entry.
*/
virtual void addEntry(std::unique_ptr<Pattern>);
};
#endif //__MEM_CACHE_COMPRESSORS_DICTIONARY_COMPRESSOR_HH__

View File

@@ -32,55 +32,63 @@
* Implementation of a dictionary based cache compressor.
*/
#include "mem/cache/compressors/dictionary_compressor.hh"
#ifndef __MEM_CACHE_COMPRESSORS_DICTIONARY_COMPRESSOR_IMPL_HH__
#define __MEM_CACHE_COMPRESSORS_DICTIONARY_COMPRESSOR_IMPL_HH__
#include <algorithm>
#include "debug/CacheComp.hh"
#include "params/DictionaryCompressor.hh"
#include "mem/cache/compressors/dictionary_compressor.hh"
#include "params/BaseDictionaryCompressor.hh"
DictionaryCompressor::CompData::CompData(const std::size_t dictionary_size)
template <class T>
DictionaryCompressor<T>::CompData::CompData()
: CompressionData()
{
}
DictionaryCompressor::CompData::~CompData()
template <class T>
void
DictionaryCompressor<T>::CompData::addEntry(std::unique_ptr<Pattern> pattern)
{
// Increase size
setSizeBits(getSizeBits() + pattern->getSizeBits());
// Push new entry to list
entries.push_back(std::move(pattern));
}
DictionaryCompressor::DictionaryCompressor(const Params *p)
: BaseCacheCompressor(p), dictionarySize(p->dictionary_size)
template <class T>
DictionaryCompressor<T>::DictionaryCompressor(const Params *p)
: BaseDictionaryCompressor(p)
{
dictionary.resize(dictionarySize);
resetDictionary();
}
template <class T>
void
DictionaryCompressor::resetDictionary()
DictionaryCompressor<T>::resetDictionary()
{
// Reset number of valid entries
numEntries = 0;
// Set all entries as 0
std::array<uint8_t, 4> zero_word = {0, 0, 0, 0};
std::fill(dictionary.begin(), dictionary.end(), zero_word);
std::fill(dictionary.begin(), dictionary.end(), toDictionaryEntry(0));
}
std::unique_ptr<DictionaryCompressor::Pattern>
DictionaryCompressor::compressWord(const uint32_t data)
template <typename T>
std::unique_ptr<typename DictionaryCompressor<T>::Pattern>
DictionaryCompressor<T>::compressValue(const T data)
{
// Split data in bytes
const std::array<uint8_t, 4> bytes = {
static_cast<uint8_t>(data & 0xFF),
static_cast<uint8_t>((data >> 8) & 0xFF),
static_cast<uint8_t>((data >> 16) & 0xFF),
static_cast<uint8_t>((data >> 24) & 0xFF)
};
const DictionaryEntry bytes = toDictionaryEntry(data);
// Start as a no-match pattern. A negative match location is used so that
// patterns that depend on the dictionary entry don't match
std::unique_ptr<Pattern> pattern = getPattern(bytes, {0, 0, 0, 0}, -1);
std::unique_ptr<Pattern> pattern =
getPattern(bytes, toDictionaryEntry(0), -1);
// Search for word on dictionary
for (std::size_t i = 0; i < numEntries; i++) {
@@ -105,69 +113,51 @@ DictionaryCompressor::compressWord(const uint32_t data)
return pattern;
}
template <class T>
std::unique_ptr<BaseCacheCompressor::CompressionData>
DictionaryCompressor::compress(const uint64_t* data)
DictionaryCompressor<T>::compress(const uint64_t* data)
{
std::unique_ptr<CompData> comp_data =
std::unique_ptr<CompData>(new CompData(dictionarySize));
// Compression size
std::size_t size = 0;
std::unique_ptr<CompData>(new CompData());
// Reset dictionary
resetDictionary();
// Compress every word sequentially
for (std::size_t i = 0; i < blkSize/8; i++) {
const uint32_t first_word = ((data[i])&0xFFFFFFFF00000000) >> 32;
const uint32_t second_word = (data[i])&0x00000000FFFFFFFF;
// Compress both words
std::unique_ptr<Pattern> first_pattern = compressWord(first_word);
std::unique_ptr<Pattern> second_pattern = compressWord(second_word);
// Update total line compression size
size += first_pattern->getSizeBits() + second_pattern->getSizeBits();
// Print debug information
DPRINTF(CacheComp, "Compressed %08x to %s\n", first_word,
first_pattern->print());
DPRINTF(CacheComp, "Compressed %08x to %s\n", second_word,
second_pattern->print());
// Append to pattern list
comp_data->entries.push_back(std::move(first_pattern));
comp_data->entries.push_back(std::move(second_pattern));
// Compress every value sequentially
const std::vector<T> values((T*)data, (T*)data + blkSize / sizeof(T));
for (const auto& value : values) {
std::unique_ptr<Pattern> pattern = compressValue(value);
DPRINTF(CacheComp, "Compressed %016x to %s\n", value,
pattern->print());
comp_data->addEntry(std::move(pattern));
}
// Set final compression size
comp_data->setSizeBits(size);
// Return compressed line
return std::move(comp_data);
}
uint32_t
DictionaryCompressor::decompressWord(const Pattern* pattern)
template <class T>
T
DictionaryCompressor<T>::decompressValue(const Pattern* pattern)
{
// Search for matching entry
std::vector<std::array<uint8_t, 4>>::iterator entry_it =
dictionary.begin();
auto entry_it = dictionary.begin();
std::advance(entry_it, pattern->getMatchLocation());
// Decompress the match. If the decompressed value must be added to
// the dictionary, do it
const std::array<uint8_t, 4> data = pattern->decompress(*entry_it);
const DictionaryEntry data = pattern->decompress(*entry_it);
if (pattern->shouldAllocate()) {
addToDictionary(data);
}
// Return word
return (((((data[3] << 8) | data[2]) << 8) | data[1]) << 8) | data[0];
// Return value
return fromDictionaryEntry(data);
}
template <class T>
void
DictionaryCompressor::decompress(const CompressionData* comp_data,
DictionaryCompressor<T>::decompress(const CompressionData* comp_data,
uint64_t* data)
{
const CompData* casted_comp_data = static_cast<const CompData*>(comp_data);
@@ -176,37 +166,47 @@ DictionaryCompressor::decompress(const CompressionData* comp_data,
resetDictionary();
// Decompress every entry sequentially
std::vector<uint32_t> decomp_words;
std::vector<T> decomp_values;
for (const auto& entry : casted_comp_data->entries) {
const uint32_t word = decompressWord(&*entry);
decomp_words.push_back(word);
// Print debug information
DPRINTF(CacheComp, "Decompressed %s to %x\n", entry->print(), word);
const T value = decompressValue(&*entry);
decomp_values.push_back(value);
DPRINTF(CacheComp, "Decompressed %s to %x\n", entry->print(), value);
}
// Concatenate the decompressed words to generate the cache lines
// Concatenate the decompressed values to generate the original data
for (std::size_t i = 0; i < blkSize/8; i++) {
data[i] = (static_cast<uint64_t>(decomp_words[2*i]) << 32) |
decomp_words[2*i+1];
data[i] = 0;
const std::size_t values_per_entry = sizeof(uint64_t)/sizeof(T);
for (int j = values_per_entry - 1; j >= 0; j--) {
data[i] |=
static_cast<uint64_t>(decomp_values[values_per_entry*i+j]) <<
(j*8*sizeof(T));
}
}
}
void
DictionaryCompressor::regStats()
template <class T>
typename DictionaryCompressor<T>::DictionaryEntry
DictionaryCompressor<T>::toDictionaryEntry(T value)
{
BaseCacheCompressor::regStats();
// We store the frequency of each pattern
patternStats
.init(getNumPatterns())
.name(name() + ".pattern")
.desc("Number of data entries that were compressed to this pattern.")
;
for (unsigned i = 0; i < getNumPatterns(); ++i) {
patternStats.subname(i, getName(i));
patternStats.subdesc(i, "Number of data entries that match pattern " +
getName(i));
DictionaryEntry entry;
for (int i = 0; i < sizeof(T); i++) {
entry[i] = value & 0xFF;
value >>= 8;
}
return entry;
}
template <class T>
T
DictionaryCompressor<T>::fromDictionaryEntry(const DictionaryEntry& entry)
{
T value = 0;
for (int i = sizeof(T) - 1; i >= 0; i--) {
value <<= 8;
value |= entry[i];
}
return value;
}
#endif //__MEM_CACHE_COMPRESSORS_DICTIONARY_COMPRESSOR_IMPL_HH__