gem5  v22.1.0.0
dictionary_compressor.hh
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018-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 
43 #ifndef __MEM_CACHE_COMPRESSORS_DICTIONARY_COMPRESSOR_HH__
44 #define __MEM_CACHE_COMPRESSORS_DICTIONARY_COMPRESSOR_HH__
45 
46 #include <array>
47 #include <cstdint>
48 #include <map>
49 #include <memory>
50 #include <string>
51 #include <type_traits>
52 #include <vector>
53 
54 #include "base/bitfield.hh"
55 #include "base/statistics.hh"
56 #include "base/types.hh"
58 
59 namespace gem5
60 {
61 
62 struct BaseDictionaryCompressorParams;
63 
64 GEM5_DEPRECATED_NAMESPACE(Compressor, compression);
65 namespace compression
66 {
67 
69 {
70  protected:
72  const std::size_t dictionarySize;
73 
75  std::size_t numEntries;
76 
78  {
80 
81  DictionaryStats(BaseStats &base_group,
82  BaseDictionaryCompressor& _compressor);
83 
84  void regStats() override;
85 
89 
95  virtual uint64_t getNumPatterns() const = 0;
96 
103  virtual std::string getName(int number) const = 0;
104 
105  public:
106  typedef BaseDictionaryCompressorParams Params;
109 };
110 
117 template <class T>
119 {
120  protected:
122  typedef std::array<uint8_t, sizeof(T)> DictionaryEntry;
123 
128  class CompData;
129 
130  // Forward declaration of a pattern
131  class Pattern;
132  class UncompressedPattern;
133  template <T mask>
134  class MaskedPattern;
135  template <T value, T mask>
136  class MaskedValuePattern;
137  template <T mask, int location>
138  class LocatedMaskedPattern;
139  template <class RepT>
140  class RepeatedValuePattern;
141  template <std::size_t DeltaSizeBits>
142  class DeltaPattern;
143  template <unsigned N>
144  class SignExtendedPattern;
145 
151  template <class Head, class... Tail>
152  struct Factory
153  {
154  static std::unique_ptr<Pattern> getPattern(
155  const DictionaryEntry& bytes, const DictionaryEntry& dict_bytes,
156  const int match_location)
157  {
158  // If match this pattern, instantiate it. If a negative match
159  // location is used, the patterns that use the dictionary bytes
160  // must return false. This is used when there are no dictionary
161  // entries yet
162  if (Head::isPattern(bytes, dict_bytes, match_location)) {
163  return std::unique_ptr<Pattern>(
164  new Head(bytes, match_location));
165  // Otherwise, go for next pattern
166  } else {
167  return Factory<Tail...>::getPattern(bytes, dict_bytes,
168  match_location);
169  }
170  }
171  };
172 
179  template <class Head>
180  struct Factory<Head>
181  {
182  static_assert(std::is_base_of_v<UncompressedPattern, Head>,
183  "The last pattern must always be derived from the uncompressed "
184  "pattern.");
185 
186  static std::unique_ptr<Pattern>
188  const DictionaryEntry& dict_bytes, const int match_location)
189  {
190  return std::unique_ptr<Pattern>(new Head(bytes, match_location));
191  }
192  };
193 
196 
202  virtual std::unique_ptr<Pattern>
203  getPattern(const DictionaryEntry& bytes, const DictionaryEntry& dict_bytes,
204  const int match_location) const = 0;
205 
212  std::unique_ptr<Pattern> compressValue(const T data);
213 
220  T decompressValue(const Pattern* pattern);
221 
223  virtual void resetDictionary();
224 
230  virtual void addToDictionary(const DictionaryEntry data) = 0;
231 
237  virtual std::unique_ptr<DictionaryCompressor::CompData>
239 
246  std::unique_ptr<Base::CompressionData> compress(
247  const std::vector<Chunk>& chunks);
248 
249  std::unique_ptr<Base::CompressionData> compress(
250  const std::vector<Chunk>& chunks,
251  Cycles& comp_lat, Cycles& decomp_lat) override;
252 
254 
255  void decompress(const CompressionData* comp_data, uint64_t* data) override;
256 
263  static DictionaryEntry toDictionaryEntry(T value);
264 
271  static T fromDictionaryEntry(const DictionaryEntry& entry);
272 
273  public:
274  typedef BaseDictionaryCompressorParams Params;
275  DictionaryCompressor(const Params &p);
277 };
278 
285 template <class T>
287 {
288  protected:
290  const int patternNumber;
291 
293  const uint8_t code;
294 
296  const uint8_t length;
297 
299  const uint8_t numUnmatchedBits;
300 
302  const int matchLocation;
303 
305  const bool allocate;
306 
307  public:
317  Pattern(const int number, const uint64_t code,
318  const uint64_t metadata_length, const uint64_t num_unmatched_bits,
319  const int match_location, const bool allocate = true)
320  : patternNumber(number), code(code), length(metadata_length),
321  numUnmatchedBits(num_unmatched_bits),
322  matchLocation(match_location), allocate(allocate)
323  {
324  }
325 
327  virtual ~Pattern() = default;
328 
334  int getPatternNumber() const { return patternNumber; };
335 
341  uint8_t getCode() const { return code; }
342 
348  uint8_t getMatchLocation() const { return matchLocation; }
349 
356  virtual std::size_t
357  getSizeBits() const
358  {
359  return numUnmatchedBits + length;
360  }
361 
367  bool shouldAllocate() const { return allocate; }
368 
374  std::string
375  print() const
376  {
377  return csprintf("pattern %s (encoding %x, size %u bits)",
378  getPatternNumber(), getCode(), getSizeBits());
379  }
380 
389  const DictionaryEntry dict_bytes) const = 0;
390 };
391 
392 template <class T>
394 {
395  public:
398 
399  CompData();
400  ~CompData() = default;
401 
407  virtual void addEntry(std::unique_ptr<Pattern>);
408 };
409 
415 template <class T>
418 {
419  private:
422 
423  public:
424  UncompressedPattern(const int number,
425  const uint64_t code,
426  const uint64_t metadata_length,
427  const int match_location,
428  const DictionaryEntry bytes)
429  : DictionaryCompressor<T>::Pattern(number, code, metadata_length,
430  sizeof(T) * 8, match_location, true),
431  data(bytes)
432  {
433  }
434 
435  static bool
436  isPattern(const DictionaryEntry& bytes, const DictionaryEntry& dict_bytes,
437  const int match_location)
438  {
439  // An entry can always be uncompressed
440  return true;
441  }
442 
444  decompress(const DictionaryEntry dict_bytes) const override
445  {
446  return data;
447  }
448 };
449 
462 template <class T>
463 template <T mask>
466 {
467  private:
468  static_assert(mask != 0, "The pattern's value mask must not be zero. Use "
469  "the uncompressed pattern instead.");
470 
472  const T bits;
473 
474  public:
475  MaskedPattern(const int number,
476  const uint64_t code,
477  const uint64_t metadata_length,
478  const int match_location,
479  const DictionaryEntry bytes,
480  const bool allocate = true)
481  : DictionaryCompressor<T>::Pattern(number, code, metadata_length,
482  popCount(static_cast<T>(~mask)), match_location, allocate),
484  {
485  }
486 
487  static bool
488  isPattern(const DictionaryEntry& bytes, const DictionaryEntry& dict_bytes,
489  const int match_location)
490  {
491  const T masked_bytes =
493  const T masked_dict_bytes =
495  return (match_location >= 0) && (masked_bytes == masked_dict_bytes);
496  }
497 
499  decompress(const DictionaryEntry dict_bytes) const override
500  {
501  const T masked_dict_bytes =
504  bits | masked_dict_bytes);
505  }
506 };
507 
524 template <class T>
525 template <T value, T mask>
527  : public MaskedPattern<mask>
528 {
529  private:
530  static_assert(mask != 0, "The pattern's value mask must not be zero.");
531 
532  public:
533  MaskedValuePattern(const int number,
534  const uint64_t code,
535  const uint64_t metadata_length,
536  const int match_location,
537  const DictionaryEntry bytes,
538  const bool allocate = false)
539  : MaskedPattern<mask>(number, code, metadata_length, match_location,
540  bytes, allocate)
541  {
542  }
543 
544  static bool
545  isPattern(const DictionaryEntry& bytes, const DictionaryEntry& dict_bytes,
546  const int match_location)
547  {
548  // Compare the masked fixed value to the value being checked for
549  // patterns. Since the dictionary is not being used the match_location
550  // is irrelevant.
551  const T masked_bytes =
553  return ((value & mask) == masked_bytes);
554  }
555 
557  decompress(const DictionaryEntry dict_bytes) const override
558  {
561  }
562 };
563 
571 template <class T>
572 template <T mask, int location>
574  : public MaskedPattern<mask>
575 {
576  public:
577  LocatedMaskedPattern(const int number,
578  const uint64_t code,
579  const uint64_t metadata_length,
580  const int match_location,
581  const DictionaryEntry bytes,
582  const bool allocate = true)
583  : MaskedPattern<mask>(number, code, metadata_length, match_location,
584  bytes, allocate)
585  {
586  }
587 
588  static bool
589  isPattern(const DictionaryEntry& bytes, const DictionaryEntry& dict_bytes,
590  const int match_location)
591  {
592  // Besides doing the regular masked pattern matching, the match
593  // location must match perfectly with this instance's
594  return (match_location == location) &&
595  MaskedPattern<mask>::isPattern(bytes, dict_bytes, match_location);
596  }
597 };
598 
609 template <class T>
610 template <class RepT>
613 {
614  private:
615  static_assert(sizeof(T) > sizeof(RepT), "The repeated value's type must "
616  "be smaller than the dictionary entry's type.");
617 
619  RepT value;
620 
621  public:
622  RepeatedValuePattern(const int number,
623  const uint64_t code,
624  const uint64_t metadata_length,
625  const int match_location,
626  const DictionaryEntry bytes,
627  const bool allocate = true)
628  : DictionaryCompressor<T>::Pattern(number, code, metadata_length,
629  8 * sizeof(RepT), match_location, allocate),
630  value(DictionaryCompressor<T>::fromDictionaryEntry(bytes))
631  {
632  }
633 
634  static bool
635  isPattern(const DictionaryEntry& bytes, const DictionaryEntry& dict_bytes,
636  const int match_location)
637  {
638  // Parse the dictionary entry in a RepT granularity, and if all values
639  // are equal, this is a repeated value pattern. Since the dictionary
640  // is not being used, the match_location is irrelevant
641  T bytes_value = DictionaryCompressor<T>::fromDictionaryEntry(bytes);
642  const RepT rep_value = bytes_value;
643  for (int i = 0; i < (sizeof(T) / sizeof(RepT)); i++) {
644  RepT cur_value = bytes_value;
645  if (cur_value != rep_value) {
646  return false;
647  }
648  bytes_value >>= 8 * sizeof(RepT);
649  }
650  return true;
651  }
652 
654  decompress(const DictionaryEntry dict_bytes) const override
655  {
656  // The decompressed value is just multiple consecutive instances of
657  // the same value
658  T decomp_value = 0;
659  for (int i = 0; i < (sizeof(T) / sizeof(RepT)); i++) {
660  decomp_value <<= 8 * sizeof(RepT);
661  decomp_value |= value;
662  }
663  return DictionaryCompressor<T>::toDictionaryEntry(decomp_value);
664  }
665 };
666 
681 template <class T>
682 template <std::size_t DeltaSizeBits>
685 {
686  private:
687  static_assert(DeltaSizeBits < (sizeof(T) * 8),
688  "Delta size must be smaller than base size");
689 
696 
697  public:
698  DeltaPattern(const int number,
699  const uint64_t code,
700  const uint64_t metadata_length,
701  const int match_location,
702  const DictionaryEntry bytes)
703  : DictionaryCompressor<T>::Pattern(number, code, metadata_length,
704  DeltaSizeBits, match_location, false),
705  bytes(bytes)
706  {
707  }
708 
717  static bool
719  const DictionaryEntry& base_bytes)
720  {
721  const typename std::make_signed<T>::type limit = DeltaSizeBits ?
722  mask(DeltaSizeBits - 1) : 0;
723  const T value =
725  const T base =
727  const typename std::make_signed<T>::type delta = value - base;
728  return (delta >= -limit) && (delta <= limit);
729  }
730 
731  static bool
733  const DictionaryEntry& dict_bytes, const int match_location)
734  {
735  return (match_location >= 0) && isValidDelta(bytes, dict_bytes);
736  }
737 
739  decompress(const DictionaryEntry dict_bytes) const override
740  {
741  return bytes;
742  }
743 };
744 
755 template <class T>
756 template <unsigned N>
759 {
760  private:
761  static_assert((N > 0) & (N <= (sizeof(T) * 8)),
762  "The original data's type size must be smaller than the dictionary's");
763 
765  const T bits : N;
766 
767  public:
768  SignExtendedPattern(const int number,
769  const uint64_t code,
770  const uint64_t metadata_length,
771  const DictionaryEntry bytes,
772  const bool allocate = false)
773  : DictionaryCompressor<T>::Pattern(number, code, metadata_length, N,
774  -1, allocate),
775  bits(fromDictionaryEntry(bytes) & mask(N))
776  {
777  }
778 
779  static bool
781  const DictionaryEntry& dict_bytes, const int match_location)
782  {
784  return data == (T)szext<N>(data);
785  }
786 
788  decompress(const DictionaryEntry dict_bytes) const override
789  {
790  return toDictionaryEntry(sext<N>(bits));
791  }
792 };
793 
794 } // namespace compression
795 } // namespace gem5
796 
797 #endif //__MEM_CACHE_COMPRESSORS_DICTIONARY_COMPRESSOR_HH__
Defines global host-dependent types: Counter, Tick, and (indirectly) {int,uint}{8,...
const char data[]
Cycles is a wrapper class for representing cycle counts, i.e.
Definition: types.hh:79
virtual std::string getName(int number) const =0
Get meta-name assigned to the given pattern.
const std::size_t dictionarySize
Dictionary size.
virtual uint64_t getNumPatterns() const =0
Trick function to get the number of patterns.
std::size_t numEntries
Number of valid entries in the dictionary.
gem5::compression::BaseDictionaryCompressor::DictionaryStats dictionaryStats
Base cache compressor interface.
Definition: base.hh:66
BaseCacheCompressorParams Params
Definition: base.hh:202
virtual std::unique_ptr< CompressionData > compress(const std::vector< Chunk > &chunks, Cycles &comp_lat, Cycles &decomp_lat)=0
Apply the compression process to the cache line.
std::vector< std::unique_ptr< Pattern > > entries
The patterns matched in the original line.
A pattern that checks whether the difference of the value and the dictionary entries' is below a cert...
DeltaPattern(const int number, const uint64_t code, const uint64_t metadata_length, const int match_location, const DictionaryEntry bytes)
DictionaryEntry decompress(const DictionaryEntry dict_bytes) const override
Decompress the pattern.
static bool isValidDelta(const DictionaryEntry &bytes, const DictionaryEntry &base_bytes)
Compares a given value against a base to calculate their delta, and then determines whether it fits a...
static bool isPattern(const DictionaryEntry &bytes, const DictionaryEntry &dict_bytes, const int match_location)
A pattern that narrows the MaskedPattern by allowing a only single possible dictionary entry to be ma...
LocatedMaskedPattern(const int number, const uint64_t code, const uint64_t metadata_length, const int match_location, const DictionaryEntry bytes, const bool allocate=true)
static bool isPattern(const DictionaryEntry &bytes, const DictionaryEntry &dict_bytes, const int match_location)
A pattern that compares masked values against dictionary entries.
MaskedPattern(const int number, const uint64_t code, const uint64_t metadata_length, const int match_location, const DictionaryEntry bytes, const bool allocate=true)
const T bits
A copy of the bits that do not belong to the mask.
static bool isPattern(const DictionaryEntry &bytes, const DictionaryEntry &dict_bytes, const int match_location)
DictionaryEntry decompress(const DictionaryEntry dict_bytes) const override
Decompress the pattern.
A pattern that compares masked values to a masked portion of a fixed value.
static bool isPattern(const DictionaryEntry &bytes, const DictionaryEntry &dict_bytes, const int match_location)
MaskedValuePattern(const int number, const uint64_t code, const uint64_t metadata_length, const int match_location, const DictionaryEntry bytes, const bool allocate=false)
DictionaryEntry decompress(const DictionaryEntry dict_bytes) const override
Decompress the pattern.
The compressed data is composed of multiple pattern entries.
const int matchLocation
Index representing the the match location.
virtual DictionaryEntry decompress(const DictionaryEntry dict_bytes) const =0
Decompress the pattern.
const uint8_t length
Length, in bits, of the code and match location.
std::string print() const
Extract pattern's information to a string.
uint8_t getCode() const
Get code of this pattern.
bool shouldAllocate() const
Determine if pattern allocates a dictionary entry.
virtual std::size_t getSizeBits() const
Get size, in bits, of the pattern (excluding prefix).
Pattern(const int number, const uint64_t code, const uint64_t metadata_length, const uint64_t num_unmatched_bits, const int match_location, const bool allocate=true)
Default constructor.
int getPatternNumber() const
Get enum number associated to this pattern.
const bool allocate
Wether the pattern allocates a dictionary entry or not.
const uint8_t numUnmatchedBits
Number of unmatched bits.
uint8_t getMatchLocation() const
Get the index of the dictionary match location.
const uint8_t code
Code associated to the pattern.
virtual ~Pattern()=default
Default destructor.
A pattern that checks if dictionary entry sized values are solely composed of multiple copies of a si...
DictionaryEntry decompress(const DictionaryEntry dict_bytes) const override
Decompress the pattern.
RepeatedValuePattern(const int number, const uint64_t code, const uint64_t metadata_length, const int match_location, const DictionaryEntry bytes, const bool allocate=true)
static bool isPattern(const DictionaryEntry &bytes, const DictionaryEntry &dict_bytes, const int match_location)
A pattern that checks whether the value is an N bits sign-extended value, that is,...
SignExtendedPattern(const int number, const uint64_t code, const uint64_t metadata_length, const DictionaryEntry bytes, const bool allocate=false)
static bool isPattern(const DictionaryEntry &bytes, const DictionaryEntry &dict_bytes, const int match_location)
DictionaryEntry decompress(const DictionaryEntry dict_bytes) const override
Decompress the pattern.
A pattern containing the original uncompressed data.
UncompressedPattern(const int number, const uint64_t code, const uint64_t metadata_length, const int match_location, const DictionaryEntry bytes)
DictionaryEntry decompress(const DictionaryEntry dict_bytes) const override
Decompress the pattern.
const DictionaryEntry data
A copy of the original data.
static bool isPattern(const DictionaryEntry &bytes, const DictionaryEntry &dict_bytes, const int match_location)
A template version of the dictionary compressor that allows to choose the dictionary size.
virtual std::unique_ptr< Pattern > getPattern(const DictionaryEntry &bytes, const DictionaryEntry &dict_bytes, const int match_location) const =0
Since the factory cannot be instantiated here, classes that inherit from this base class have to impl...
static T fromDictionaryEntry(const DictionaryEntry &entry)
Turn a dictionary entry into a value.
std::vector< DictionaryEntry > dictionary
The dictionary.
virtual void addToDictionary(const DictionaryEntry data)=0
Add an entry to the dictionary.
virtual void resetDictionary()
Clear all dictionary entries.
std::unique_ptr< Pattern > compressValue(const T data)
Compress data.
virtual std::unique_ptr< DictionaryCompressor::CompData > instantiateDictionaryCompData() const
Instantiate a compression data of the sub-class compressor.
std::array< uint8_t, sizeof(T)> DictionaryEntry
Convenience typedef for a dictionary entry.
T decompressValue(const Pattern *pattern)
Decompress a pattern into a value that fits in a dictionary entry.
void decompress(const CompressionData *comp_data, uint64_t *data) override
Apply the decompression process to the compressed data.
std::unique_ptr< Base::CompressionData > compress(const std::vector< Chunk > &chunks)
Apply compression.
static DictionaryEntry toDictionaryEntry(T value)
Turn a value into a dictionary entry.
Statistics container.
Definition: group.hh:94
A vector of scalar stats.
Definition: statistics.hh:2007
constexpr T bits(T val, unsigned first, unsigned last)
Extract the bitfield from position 'first' to 'last' (inclusive) from 'val' and right justify it.
Definition: bitfield.hh:76
constexpr int popCount(uint64_t val)
Returns the number of set ones in the provided value.
Definition: bitfield.hh:334
constexpr uint64_t mask(unsigned nbits)
Generate a 64-bit mask of 'nbits' 1s, right justified.
Definition: bitfield.hh:63
Definition of a basic cache compressor.
Bitfield< 7 > i
Definition: misc_types.hh:67
Bitfield< 54 > p
Definition: pagetable.hh:70
Bitfield< 51, 12 > base
Definition: pagetable.hh:141
BitfieldType< SegDescriptorLimit > limit
Definition: misc.hh:931
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
std::string csprintf(const char *format, const Args &...args)
Definition: cprintf.hh:161
GEM5_DEPRECATED_NAMESPACE(GuestABI, guest_abi)
Declaration of Statistics objects.
statistics::Vector patterns
Number of data entries that were compressed to each pattern.
void regStats() override
Callback to set stat parameters.
DictionaryStats(BaseStats &base_group, BaseDictionaryCompressor &_compressor)
static std::unique_ptr< Pattern > getPattern(const DictionaryEntry &bytes, const DictionaryEntry &dict_bytes, const int match_location)
Create a factory to determine if input matches a pattern.
static std::unique_ptr< Pattern > getPattern(const DictionaryEntry &bytes, const DictionaryEntry &dict_bytes, const int match_location)

Generated on Wed Dec 21 2022 10:22:36 for gem5 by doxygen 1.9.1