Daniel Carvalho has uploaded this change for review. ( https://gem5-review.googlesource.com/11105

Change subject: mem-cache: Create CPack compressor
......................................................................

mem-cache: Create CPack compressor

Implementation of C-Pack, as described in "C-Pack: A High-
Performance Microprocessor Cache Compression Algorithm".

C-Pack uses pattern matching schemes to detect and compress
frequently appearing data patterns. As in the original paper,
it divides the input in 32-bit words, and uses 6 patterns to
match with its dictionary.

For the patterns, each letter represents a byte: Z is a null
byte, M is a dictionary match, X is a new value. The patterns
are ZZZZ, XXXX, MMMM, MMXX, ZZZX, MMMX.

Change-Id: I2efc9db2c862620dcc1155300e39be558f9017e0
---
M src/mem/cache/compressors/Compressors.py
M src/mem/cache/compressors/SConscript
A src/mem/cache/compressors/cpack.cc
A src/mem/cache/compressors/cpack.hh
4 files changed, 400 insertions(+), 0 deletions(-)



diff --git a/src/mem/cache/compressors/Compressors.py b/src/mem/cache/compressors/Compressors.py
index b67f638..1901758 100644
--- a/src/mem/cache/compressors/Compressors.py
+++ b/src/mem/cache/compressors/Compressors.py
@@ -38,6 +38,11 @@
     line_size = Param.Int(Parent.cache_line_size,
                                "Cache line size in bytes")

+class CPack(BaseCacheCompressor):
+    type = 'CPack'
+    cxx_class = 'CPack'
+    cxx_header = "mem/cache/compressors/cpack.hh"
+
 class NoCompressor(BaseCacheCompressor):
     type = 'NoCompressor'
     cxx_class = 'NoCompressor'
diff --git a/src/mem/cache/compressors/SConscript b/src/mem/cache/compressors/SConscript
index 3c6cfce..8c05f16 100644
--- a/src/mem/cache/compressors/SConscript
+++ b/src/mem/cache/compressors/SConscript
@@ -33,4 +33,5 @@
 SimObject('Compressors.py')

 Source('base.cc')
+Source('cpack.cc')
 Source('no_compressor.cc')
diff --git a/src/mem/cache/compressors/cpack.cc b/src/mem/cache/compressors/cpack.cc
new file mode 100644
index 0000000..b896460
--- /dev/null
+++ b/src/mem/cache/compressors/cpack.cc
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2018 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 the CPack cache compressor.
+ */
+
+#include "mem/cache/compressors/cpack.hh"
+
+#include <algorithm>
+#include <cstdint>
+
+#include "params/CPack.hh"
+
+CPack::CPackCompData::CPackCompData(std::size_t dictionary_size,
+                                    const uint8_t* cache_line)
+    : CompressionData(dictionary_size/2, cache_line),
+      compWords(dictionary_size, 0)
+{
+}
+
+CPack::CPackCompData::~CPackCompData()
+{
+}
+
+CPack::CPack(const Params *p)
+    : BaseCacheCompressor(p), dictionarySize(2*lineSize)
+{
+    dictionary.resize(dictionarySize);
+
+    resetDictionary();
+}
+
+void
+CPack::resetDictionary()
+{
+    // Reset number of valid entries
+    numEntries = 0;
+
+    // Set all entries as 0
+    std::fill(dictionary.begin(), dictionary.end(), 0);
+}
+
+std::size_t
+CPack::compressWord(uint32_t data, uint64_t& comp_word)
+{
+    std::size_t size;          // Size of the compressed word
+    std::size_t numBMatch = 0; // Number of bytes matched so far
+
+    // Pattern matching (zzzz and zzzx)
+    if ((data & 0xFFFFFF00) == 0x00000000){
+        // Matched zzzx
+        if (data & 0x000000FF){
+            comp_word = (patternData[ZZZX].code<<8) | (data & 0x000000FF);
+            return patternData[ZZZX].length;
+        // Matched zzzz
+        } else {
+            comp_word = patternData[ZZZZ].code;
+            return patternData[ZZZZ].length;
+        }
+    }
+
+    // Default as uncompressed
+ comp_word = (static_cast<uint64_t>(patternData[XXXX].code) << 32) | data;
+    size = patternData[XXXX].length;
+
+    // Dictionary matching
+    for (std::size_t i = 0; i < numEntries; i++){
+        // Check if matched mmmm
+        if (dictionary[i] == data){
+            comp_word = (patternData[MMMM].code << dictWidth) | i;
+            size = patternData[MMMM].length;
+
+            // There's nothing better than a full match, so stop search
+            break;
+        // Check if matched mmmx
+        } else if ((numBMatch < 3) &&
+                   ((dictionary[i] & 0xFFFFFF00) == (data & 0xFFFFFF00))){
+            numBMatch = 3;
+ comp_word = (((patternData[MMMX].code << dictWidth) | i) << 8) |
+                        (data & 0x000000FF);
+            size = patternData[MMMX].length;
+        // Check if matched mmxx
+        } else if ((numBMatch < 2) &&
+                   ((dictionary[i] & 0xFFFF0000) == (data & 0xFFFF0000))){
+            numBMatch = 2;
+ comp_word = (((patternData[MMXX].code << dictWidth) | i) << 16) |
+                        (data & 0x0000FFFF);
+            size = patternData[MMXX].length;
+        }
+    }
+
+    // Push into dictionary
+    if (numEntries < dictionarySize) dictionary[numEntries++] = data;
+
+    return size;
+}
+
+std::unique_ptr<CompressionData>
+CPack::compress(const uint8_t* cache_line, Cycles& lat)
+{
+ std::unique_ptr<CPackCompData> comp_data = std::unique_ptr<CPackCompData>(
+        new CPackCompData(dictionarySize, cache_line));
+
+    // Compression size
+    std::size_t size = 0;
+
+    // Reset dictionary
+    resetDictionary();
+
+    // Compress every word sequentially
+    for (std::size_t i = 0; i < dictionarySize/2; i++) {
+        uint32_t firstWord = (cache_line[i]&0xFFFFFFFF00000000) >> 32;
+        uint32_t secondWord = cache_line[i]&0x00000000FFFFFFFF;
+
+        size += compressWord(firstWord, comp_data->compWords[2*i]);
+        size += compressWord(secondWord, comp_data->compWords[2*i+1]);
+    }
+
+    // Change size from bits to bytes
+    size = std::ceil(size/8);
+
+    // Set final compression size
+    comp_data->setSize(size);
+
+    // @todo Set compression latency
+    lat = Cycles(0);
+
+    // Return compressed line
+    return comp_data;
+}
+
+uint32_t
+CPack::decompressWord(uint64_t comp_data)
+{
+    // Check if matches xxxx
+    if (comp_data & 0x0000000100000000){
+        dictionary[numEntries] = comp_data;
+        return dictionary[numEntries++];
+    // Check if matches mmxx
+    } else if (comp_data & 0xF00000){
+        dictionary[numEntries] = (dictionary[(comp_data & 0xF0000) >> 16] &
+                                  0xFFFF0000) | (comp_data & 0x0000FFFF);
+        return dictionary[numEntries++];
+    // Check if matches mmmx
+    }else if (comp_data & 0xF000){
+        dictionary[numEntries] = (dictionary[(comp_data & 0xF00) >> 8] &
+                                  0xFFFFFF00) | (comp_data & 0x000000FF);
+        return dictionary[numEntries++];
+    // Check if matches zzzx
+    } else if (comp_data & 0xF00) return comp_data & 0xFF;
+    // Check if matches mmmm
+    else if (comp_data & 0xF0){
+        dictionary[numEntries] = dictionary[comp_data & 0xF];
+        return dictionary[numEntries++];
+    // Matches zzzz
+    } else return 0;
+}
+
+Cycles
+CPack::decompress(const CompressionData* comp_data, uint8_t* cache_line)
+{
+    const CPackCompData* cpack_comp_data =
+        static_cast<const CPackCompData*>(comp_data);
+
+    // Reset dictionary
+    resetDictionary();
+
+    // Decompress every word sequentially
+    for (std::size_t i = 0; i < dictionarySize/2; i+=8) {
+ uint32_t firstWord = decompressWord(cpack_comp_data->compWords[2*i]);
+        uint32_t secondWord = decompressWord(
+                                cpack_comp_data->compWords[2*i+1]);
+ cache_line[i] = (static_cast<uint64_t>(firstWord) << 32) | secondWord;
+    }
+
+    // @todo Return decompression latency
+    return Cycles(0);
+}
+
+
+CPack*
+CPackParams::create()
+{
+    return new CPack(this);
+}
diff --git a/src/mem/cache/compressors/cpack.hh b/src/mem/cache/compressors/cpack.hh
new file mode 100644
index 0000000..c310971
--- /dev/null
+++ b/src/mem/cache/compressors/cpack.hh
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2018 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
+ * Definition of the CPack cache compressor.
+ */
+
+#ifndef __MEM_CACHE_COMPRESSORS_CPACK_HH__
+#define __MEM_CACHE_COMPRESSORS_CPACK_HH__
+
+#include <cstdint>
+#include <vector>
+
+#include "base/types.hh"
+#include "mem/cache/compressors/base.hh"
+
+struct CPackParams;
+
+/**
+ * Implementation of CPack compression, from "C-Pack: A High-Performance
+ * Microprocessor Cache Compression Algorithm".
+ *
+ * The dictionary is composed of 32-bit entries.
+*/
+class CPack : public BaseCacheCompressor {
+  private:
+    /**
+     * Compression data for CPack. It consists of a vector of words.
+     */
+    class CPackCompData : public CompressionData {
+      public:
+        /**
+         * The compressed data, stored word by word.
+         */
+        std::vector<uint64_t> compWords;
+
+      public:
+        /**
+         * Default constructor.
+         *
+ * @param dictionary_size Number of 32-bit entries in the dictionary.
+         * @param cache_line Cache line to which compression is applied.
+         */
+ CPackCompData(std::size_t dictionary_size, const uint8_t* cache_line);
+
+        /**
+         * Default destructor.
+         */
+        ~CPackCompData();
+    };
+
+    /**
+     * Bits used to represent the index of a dictionary entry
+     * ((log of the number of entries in the dictionary) - 1).
+     */
+    static const std::size_t dictWidth = 4;
+
+    /**
+     * The patterns proposed in the paper. Each letter represents a byte:
+     * Z is a null byte, M is a dictionary match, X is a new value.
+     * These are used as indexes to reference the pattern data.
+     */
+    enum Pattern {ZZZZ, XXXX, MMMM, MMXX, ZZZX, MMMX};
+
+    /**
+ * The pattern data. Each pattern consists of an encoding and the size of
+     * its compressed data.
+     */
+    struct PatternData{
+        /**
+         * The opcode.
+         */
+        const uint32_t code;
+
+        /**
+         * Length, in bits (including metadata).
+         */
+        const uint32_t length;
+ } patternData[6] = {{0x0, 2}, {0x1, 34}, {0x2, 6}, {0xC, 24}, {0xD, 12},
+                        {0xE, 16}};
+
+    /**
+     * The dictionary.
+     */
+    std::vector<uint32_t> dictionary;
+
+    /**
+     * Dictionary size.
+     */
+    const std::size_t dictionarySize;
+
+    /**
+     * Number of valid entries in the dictionary.
+     */
+    std::size_t numEntries;
+
+    /**
+     * Compress a word.
+     *
+     * @param data Word to be compressed.
+     * @param comp_word Word after compression.
+     * @return Size of the compressed word.
+     */
+    std::size_t compressWord(uint32_t data, uint64_t& comp_word);
+
+    /**
+     * Decompress a word.
+     *
+     * @param comp_data The data to be decompressed.
+     * @return The decompressed word.
+     */
+    uint32_t decompressWord(uint64_t comp_data);
+
+    /**
+     * Clear all dictionary entries.
+     */
+    void resetDictionary();
+
+  public:
+    /** Convenience typedef. */
+     typedef CPackParams Params;
+
+    /**
+     * Default constructor.
+     */
+    CPack(const Params *p);
+
+    /**
+     * Default destructor.
+     */
+    ~CPack() {};
+
+    /**
+     * Apply compression.
+     *
+     * @param cache_line The cache line to be compressed.
+     * @param Compression latency in number of cycles.
+     * @return Cache line after compression.
+     */
+    std::unique_ptr<CompressionData> compress(const uint8_t* cache_line,
+                                              Cycles& lat) override;
+
+    /**
+     * Decompress data.
+     *
+     * @param comp_data Compressed cache line.
+     * @param cache_line The cache line to be decompressed.
+     * @return Decompression latency in number of cycles.
+     */
+ Cycles decompress(const CompressionData* comp_data, uint8_t* cache_line) + override;
+};
+
+#endif

--
To view, visit https://gem5-review.googlesource.com/11105
To unsubscribe, or for help writing mail filters, visit https://gem5-review.googlesource.com/settings

Gerrit-Project: public/gem5
Gerrit-Branch: master
Gerrit-Change-Id: I2efc9db2c862620dcc1155300e39be558f9017e0
Gerrit-Change-Number: 11105
Gerrit-PatchSet: 1
Gerrit-Owner: Daniel Carvalho <oda...@yahoo.com.br>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list
gem5-dev@gem5.org
http://m5sim.org/mailman/listinfo/gem5-dev

Reply via email to