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

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

mem-cache: Create cache compressor

Create basic template for cache compressors. A basic compressor
must implement a compression and a decompression method.

We also implement a compressor for when compression is not used.

Change-Id: I83dc4d2b8d2bc5ed9f760c938edfa4ebdd6b8583
---
M src/mem/cache/Cache.py
A src/mem/cache/compressors/Compressors.py
A src/mem/cache/compressors/SConscript
A src/mem/cache/compressors/base.cc
A src/mem/cache/compressors/base.hh
A src/mem/cache/compressors/no_compressor.cc
A src/mem/cache/compressors/no_compressor.hh
M src/mem/cache/superblock_blk.cc
M src/mem/cache/superblock_blk.hh
M src/mem/cache/tags/Tags.py
M src/mem/cache/tags/compressed_tags.cc
M src/mem/cache/tags/compressed_tags.hh
12 files changed, 728 insertions(+), 5 deletions(-)



diff --git a/src/mem/cache/Cache.py b/src/mem/cache/Cache.py
index f23d8bc..3336c0c 100644
--- a/src/mem/cache/Cache.py
+++ b/src/mem/cache/Cache.py
@@ -41,6 +41,7 @@

 from m5.params import *
 from m5.proxy import *
+from Compressors import *
 from MemObject import MemObject
 from Prefetcher import BasePrefetcher
 from ReplacementPolicies import *
@@ -85,6 +86,8 @@
     replacement_policy = Param.BaseReplacementPolicy(LRURP(),
         "Replacement policy")

+    compressor = Param.BaseCacheCompressor(NoCompressor(),
+        "Cache compressor.")
     max_compression_ratio = Param.Int(2,
         "Maximum number of compressed blocks per tag.")

diff --git a/src/mem/cache/compressors/Compressors.py b/src/mem/cache/compressors/Compressors.py
new file mode 100644
index 0000000..b67f638
--- /dev/null
+++ b/src/mem/cache/compressors/Compressors.py
@@ -0,0 +1,44 @@
+# 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
+
+from m5.params import *
+from m5.proxy import *
+from ClockedObject import ClockedObject
+
+class BaseCacheCompressor(ClockedObject):
+    type = 'BaseCacheCompressor'
+    abstract = True
+    cxx_header = "mem/cache/compressors/base.hh"
+
+    line_size = Param.Int(Parent.cache_line_size,
+                               "Cache line size in bytes")
+
+class NoCompressor(BaseCacheCompressor):
+    type = 'NoCompressor'
+    cxx_class = 'NoCompressor'
+    cxx_header = "mem/cache/compressors/no_compressor.hh"
diff --git a/src/mem/cache/compressors/SConscript b/src/mem/cache/compressors/SConscript
new file mode 100644
index 0000000..3c6cfce
--- /dev/null
+++ b/src/mem/cache/compressors/SConscript
@@ -0,0 +1,36 @@
+# -*- mode:python -*-
+
+# 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
+
+Import('*')
+
+SimObject('Compressors.py')
+
+Source('base.cc')
+Source('no_compressor.cc')
diff --git a/src/mem/cache/compressors/base.cc b/src/mem/cache/compressors/base.cc
new file mode 100644
index 0000000..0f60eca
--- /dev/null
+++ b/src/mem/cache/compressors/base.cc
@@ -0,0 +1,105 @@
+/*
+ * 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 a basic cache compressor.
+ */
+
+#include "mem/cache/compressors/base.hh"
+
+#include <algorithm>
+#include <cstdint>
+
+#include "params/BaseCacheCompressor.hh"
+
+CompressionData::CompressionData(std::size_t line_size,
+                                 const uint8_t* cache_line)
+    :
+      #ifdef DEBUG_COMPRESSION
+      _cacheLine(cache_line, cache_line + line_size),
+      #endif
+      _size(0), lineSize(line_size)
+{
+}
+
+CompressionData::~CompressionData()
+{
+}
+
+void
+CompressionData::setSize(std::size_t size)
+{
+    _size = size;
+}
+
+std::size_t
+CompressionData::getSize() const
+{
+    return _size;
+}
+
+#ifdef DEBUG_COMPRESSION
+bool
+matchLine(uint8_t* cache_line) const
+{
+    return std::memcmp(_cacheLine.data(), cache_line, lineSize) == 0;
+}
+#endif
+
+BaseCacheCompressor::BaseCacheCompressor(const Params *p)
+    : ClockedObject(p), lineSize(p->line_size)
+{
+}
+
+std::unique_ptr<CompressionData>
+BaseCacheCompressor::compress(const uint8_t* cache_line)
+{
+    Cycles lat;
+    return compress(cache_line, lat);
+}
+
+Cycles
+BaseCacheCompressor::decompress(const CompressionData* comp_data)
+{
+    uint8_t cache_line[lineSize];
+
+    // Make sure we've got something to decompress
+    assert(comp_data != nullptr);
+
+    // Apply decompression
+    Cycles lat = decompress(comp_data, cache_line);
+
+    #ifdef DEBUG_COMPRESSION
+    // Check if decompressed line matches original cache line
+    assert(comp_data->matchLine(cache_line));
+    #endif
+
+    return lat;
+}
diff --git a/src/mem/cache/compressors/base.hh b/src/mem/cache/compressors/base.hh
new file mode 100644
index 0000000..fc36942
--- /dev/null
+++ b/src/mem/cache/compressors/base.hh
@@ -0,0 +1,176 @@
+/*
+ * 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 a basic cache compressor.
+ * A cache compressor must consist of a compression and a decompression
+ * methods. It must also be aware of the size of an uncompressed cache
+ * line.
+ */
+
+#ifndef __MEM_CACHE_COMPRESSORS_BASE_HH__
+#define __MEM_CACHE_COMPRESSORS_BASE_HH__
+
+#include <cstdint>
+
+#include "base/types.hh"
+#include "sim/clocked_object.hh"
+
+// Uncomment this line if debugging compression
+//#define DEBUG_COMPRESSION
+
+struct BaseCacheCompressorParams;
+
+class CompressionData {
+  private:
+    #ifdef DEBUG_COMPRESSION
+    /**
+     * Keep original cache line for debugging purposes.
+     */
+    const std::vector<uint8_t> _cacheLine;
+    #endif
+
+    /**
+     * Compressed cache line size (in bytes).
+     */
+    std::size_t _size;
+
+    /**
+     * Uncompressed cache line size (in bytes).
+     */
+    const std::size_t lineSize;
+
+  public:
+    /**
+     * Default constructor.
+     *
+     * @param line_size Cache line size (in bytes).
+     * @param cache_line Cache line to which compression is applied.
+     */
+    CompressionData(std::size_t line_size, const uint8_t* cache_line);
+
+    /**
+     * Virtual destructor. Without it unique_ptr will cause mem leak.
+     */
+    virtual ~CompressionData();
+
+    /**
+     * Set compression size (in bytes).
+     *
+     * @param size Compressed data size.
+     */
+    void setSize(std::size_t size);
+
+    /**
+     * Get compression size (in bytes).
+     *
+     * @return Compressed data size.
+     */
+    std::size_t getSize() const;
+
+    #ifdef DEBUG_COMPRESSION
+    /**
+     * Checks if a cache line matches the original cache line for this
+     * compression data. Useful when debugging compression/decompression.
+     *
+     * @param cache_line Line to compare against.
+     * @return True if lines match.
+     */
+    bool matchLine(uint8_t* cache_line) const;
+    #endif
+};
+
+/**
+ * Base cache compressor interface. Every cache compressor must implement a
+ * compression and a decompression method.
+ */
+class BaseCacheCompressor : public ClockedObject {
+  protected:
+    /**
+     * Uncompressed cache line size (in bytes).
+     */
+    const std::size_t lineSize;
+
+    /**
+     * Apply the compression process to the cache line.
+     * Returns the number of cycles used by the compressor, however it is
+ * usually covered by a good pipelined execution, and is currently ignored.
+     *
+     * @param cache_line The cache line to be compressed.
+     * @param Compression latency in number of cycles.
+     * @return Cache line after compression.
+     */
+    virtual std::unique_ptr<CompressionData> compress(
+        const uint8_t* cache_line, Cycles& lat) = 0;
+
+    /**
+     * Apply the decompression process to the compressed data.
+     *
+     * @param comp_data Compressed cache line.
+     * @param cache_line The cache line to be decompressed.
+     * @return Decompression latency in number of cycles.
+     */
+    virtual Cycles decompress(const CompressionData* comp_data,
+                              uint8_t* cache_line) = 0;
+
+  public:
+    /** Convenience typedef. */
+     typedef BaseCacheCompressorParams Params;
+
+    /**
+     * Default constructor.
+     */
+    BaseCacheCompressor(const Params *p);
+
+    /**
+     * Default destructor.
+     */
+    virtual ~BaseCacheCompressor() {};
+
+    /**
+     * Apply the compression process to the cache line. Ignores compression
+     * cycles.
+     *
+     * @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);
+
+    /**
+     * Apply the decompression process to the compressed data.
+     *
+     * @param comp_data Compressed cache line.
+     * @return Decompression latency in number of cycles.
+     */
+    Cycles decompress(const CompressionData* comp_data);
+};
+
+#endif //__MEM_CACHE_COMPRESSORS_BASE_HH__
diff --git a/src/mem/cache/compressors/no_compressor.cc b/src/mem/cache/compressors/no_compressor.cc
new file mode 100644
index 0000000..d30ce19
--- /dev/null
+++ b/src/mem/cache/compressors/no_compressor.cc
@@ -0,0 +1,90 @@
+/*
+ * 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 a compressor that does not compress.
+ * It should be used when compression is not used.
+ */
+
+#include "mem/cache/compressors/no_compressor.hh"
+
+#include <algorithm>
+#include <cstdint>
+
+#include "params/NoCompressor.hh"
+
+NoCompressor::NoCompressorCompData::NoCompressorCompData(std::size_t line_size,
+    const uint8_t* cache_line)
+    : CompressionData(line_size, cache_line),
+      _cacheLine(cache_line, cache_line + line_size)
+{
+    // As there is no compression, the compressed line size is
+    // equal to the original cache line size
+    setSize(line_size);
+}
+
+NoCompressor::NoCompressorCompData::~NoCompressorCompData()
+{
+}
+
+void
+NoCompressor::NoCompressorCompData::getLine(uint8_t* cache_line) const
+{
+    std::copy(_cacheLine.begin(), _cacheLine.end(), cache_line);
+}
+
+NoCompressor::NoCompressor(const Params *p) : BaseCacheCompressor(p)
+{
+}
+
+std::unique_ptr<CompressionData>
+NoCompressor::compress(const uint8_t* cache_line, Cycles& lat)
+{
+    // The compression latency is zero, as no compression is done
+    lat = Cycles(0);
+
+    return std::unique_ptr<NoCompressorCompData>(
+               new NoCompressorCompData(lineSize, cache_line));
+}
+
+Cycles
+NoCompressor::decompress(const CompressionData* comp_data, uint8_t* cache_line)
+{
+ static_cast<const NoCompressorCompData*>(comp_data)->getLine(cache_line);
+
+    // The decompression latency is zero, as no decompression is done
+    return Cycles(0);
+}
+
+NoCompressor *
+NoCompressorParams::create()
+{
+    return new NoCompressor(this);
+}
diff --git a/src/mem/cache/compressors/no_compressor.hh b/src/mem/cache/compressors/no_compressor.hh
new file mode 100644
index 0000000..7928cbc
--- /dev/null
+++ b/src/mem/cache/compressors/no_compressor.hh
@@ -0,0 +1,124 @@
+/*
+ * 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 a compressor that does not compress.
+ * It should be used when compression is not used.
+ */
+
+#ifndef __MEM_CACHE_COMPRESSORS_NO_COMPRESSOR_HH__
+#define __MEM_CACHE_COMPRESSORS_NO_COMPRESSOR_HH__
+
+#include <cstdint>
+
+#include "base/types.hh"
+#include "mem/cache/compressors/base.hh"
+
+struct NoCompressorParams;
+
+/**
+ * Dummy compressor for when compression is not done. The compressed data is + * equal to the original line, and thus the size matches the cache line size.
+ */
+class NoCompressor : public BaseCacheCompressor {
+  private:
+    /**
+     * Compression data for when compression is not done. It contains the
+     * original cache line, and nothing else.
+     */
+    class NoCompressorCompData : public CompressionData {
+      private:
+        /**
+         * The compressed data is the original cache line.
+         */
+        const std::vector<uint8_t> _cacheLine;
+
+      public:
+        /**
+         * Default constructor.
+         *
+         * @param line_size Cache line size (in bytes).
+         * @param cache_line Cache line to which compression is applied.
+         */
+        NoCompressorCompData(std::size_t line_size,
+                             const uint8_t* cache_line);
+
+        /**
+         * Default destructor.
+         */
+        ~NoCompressorCompData();
+
+        /**
+         * Get original cache line.
+         *
+         * @param cache_line Initialized container to write cache line to.
+         */
+        void getLine(uint8_t* cache_line) const;
+    };
+
+  protected:
+    /**
+ * Apply the compression process to the cache line. The compressed line is
+     * equal to the uncompressed, and the compression latency is zero.
+     *
+     * @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, however no decompression is needed, so the latency
+     * is zero.
+     *
+     * @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;
+
+  public:
+    /** Convenience typedef. */
+     typedef NoCompressorParams Params;
+
+    /**
+     * Default constructor.
+     */
+    NoCompressor(const Params *p);
+
+    /**
+     * Default destructor.
+     */
+    ~NoCompressor() {};
+};
+
+#endif //__MEM_CACHE_COMPRESSORS_NO_COMPRESSOR_HH__
diff --git a/src/mem/cache/superblock_blk.cc b/src/mem/cache/superblock_blk.cc
index 988fa14..87fb455 100644
--- a/src/mem/cache/superblock_blk.cc
+++ b/src/mem/cache/superblock_blk.cc
@@ -42,7 +42,8 @@
 #include "base/logging.hh"

 CompressionBlk::CompressionBlk()
-    : CacheBlk(), _superblock(nullptr), _superblockOffset(0)
+    : CacheBlk(), _superblock(nullptr), _superblockOffset(0),
+      _compressionData(nullptr)
 {
 }

@@ -78,8 +79,22 @@
 }

 void
+CompressionBlk::setCompressionData(
+    std::unique_ptr<CompressionData>& compression_data)
+{
+    _compressionData = std::move(compression_data);
+}
+
+const CompressionData*
+CompressionBlk::getCompressionData() const
+{
+    return _compressionData.get();
+}
+
+void
 CompressionBlk::insert(const Addr tag, const bool is_secure,
-                       const int src_master_ID, const uint32_t task_ID)
+                       const int src_master_ID, const uint32_t task_ID,
+                       std::unique_ptr<CompressionData>& compression_data)
 {
     // Make sure it is not overwriting another superblock
     panic_if((_superblock && _superblock->isValid()) &&
@@ -91,6 +106,9 @@

     // Set superblock tag
     _superblock->setTag(tag);
+
+    // Set compression data
+    setCompressionData(compression_data);
 }

 bool
@@ -111,6 +129,26 @@
                            return blk->isValid() && blk->isSecure();});
 }

+int
+SuperblockBlk::countValidBlocks() const
+{
+    // Count the number of valid blocks in this superblock
+    return std::count_if(blks.begin(), blks.end(),
+ [](const CompressionBlk* blk){return blk->isValid();});
+}
+
+std::size_t
+SuperblockBlk::getUsedSize() const
+{
+    std::size_t size = 0;
+    for (const auto& blk : blks) {
+        if (blk->isValid()) {
+            size += blk->getCompressionData()->getSize();
+        }
+    }
+    return size;
+}
+
 void
 SuperblockBlk::setTag(const Addr tag)
 {
diff --git a/src/mem/cache/superblock_blk.hh b/src/mem/cache/superblock_blk.hh
index 613f6cf..85160c0 100644
--- a/src/mem/cache/superblock_blk.hh
+++ b/src/mem/cache/superblock_blk.hh
@@ -40,6 +40,7 @@
 #include <vector>

 #include "mem/cache/blk.hh"
+#include "mem/cache/compressors/base.hh"
 #include "mem/cache/replacement_policies/base.hh"

 class SuperblockBlk;
@@ -61,6 +62,19 @@
      */
     int _superblockOffset;

+    /**
+     * Data contained by this block in a compressed format.
+     */
+    std::unique_ptr<CompressionData> _compressionData;
+
+    /**
+     * Set data as compressed by the chosen compression method.
+     *
+     * @param compression_data The compression data.
+     */
+    void setCompressionData(
+        std::unique_ptr<CompressionData>& compression_data);
+
   public:
     CompressionBlk();
     CompressionBlk(const CompressionBlk&) = delete;
@@ -103,6 +117,13 @@
     Addr getTag() const;

     /**
+     * Get compression data.
+     *
+     * @return The compression data.
+     */
+    const CompressionData* getCompressionData() const;
+
+    /**
      * Set member variables when a block insertion occurs. Resets reference
      * count to 1 (the insertion counts as a reference), and touch block if
      * it hadn't been touched previously. Sets the insertion tick to the
@@ -112,9 +133,11 @@
      * @param is_secure Whether the block is in secure space or not.
      * @param src_master_ID The source requestor ID.
      * @param task_ID The new task ID.
+     * @param compression_data The compression data.
      */
void insert(const Addr tag, const bool is_secure, const int src_master_ID,
-                const uint32_t task_ID);
+                const uint32_t task_ID,
+                std::unique_ptr<CompressionData>& compression_data);
 };

 /**
@@ -157,6 +180,20 @@
     bool isSecure() const;

     /**
+     * Count the number of valid blocks in this superblock.
+     *
+     * @return Number of valid blocks.
+     */
+    int countValidBlocks() const;
+
+    /**
+     * Get the occupied size (in bytes) of the blocks in this superblock.
+     *
+     * @return The occupied size.
+     */
+    std::size_t getUsedSize() const;
+
+    /**
      * Set tag associated to this block.
      *
      * @param The tag value.
diff --git a/src/mem/cache/tags/Tags.py b/src/mem/cache/tags/Tags.py
index 46f4339..1bd70e3 100644
--- a/src/mem/cache/tags/Tags.py
+++ b/src/mem/cache/tags/Tags.py
@@ -38,6 +38,7 @@
 from m5.params import *
 from m5.proxy import *
 from ClockedObject import ClockedObject
+from Compressors import *

 class BaseTags(ClockedObject):
     type = 'BaseTags'
@@ -110,6 +111,10 @@
     replacement_policy = Param.BaseReplacementPolicy(
         Parent.replacement_policy, "Replacement policy")

+    # Get the cache compression method
+    compressor = Param.BaseCacheCompressor(Parent.compressor,
+        "Cache compressor.")
+
     # Cache compression for parallel accesses is very inefficient, as a
     # decompression must be done per data block
     sequential_access = True
diff --git a/src/mem/cache/tags/compressed_tags.cc b/src/mem/cache/tags/compressed_tags.cc
index ecbf050..05db826 100644
--- a/src/mem/cache/tags/compressed_tags.cc
+++ b/src/mem/cache/tags/compressed_tags.cc
@@ -44,13 +44,14 @@
 #include "base/types.hh"
 #include "debug/CacheRepl.hh"
 #include "mem/cache/base.hh"
+#include "mem/cache/compressors/base.hh"
 #include "mem/cache/replacement_policies/base.hh"
 #include "mem/request.hh"
 #include "params/CompressedTags.hh"

 CompressedTags::CompressedTags(const Params *p)
     : BaseTags(p), assoc(p->assoc), allocAssoc(p->assoc),
-      replacementPolicy(p->replacement_policy),
+      replacementPolicy(p->replacement_policy), compressor(p->compressor),
       maxCR(p->max_compression_ratio),
numSuperblocks(numBlocks / maxCR), numSets(numSuperblocks / p->assoc),
       blks(numBlocks), superblockBlks(numSuperblocks), sets(numSets),
@@ -119,6 +120,17 @@
     }
 }

+bool
+CompressedTags::canCoAllocate(const SuperblockBlk* superblock,
+ const CompressionData* compression_data) const
+{
+    // Simple co-allocation function: two blocks with compression ratio of
+    // up to 50% can share a superblock
+    return (superblock->countValidBlocks() < 2) &&
+           (superblock->getUsedSize() + compression_data->getSize() <=
+            blkSize) && (compression_data->getSize() <= blkSize/2);
+}
+
 void
 CompressedTags::invalidate(CacheBlk *blk)
 {
@@ -202,11 +214,25 @@
         // Cache hit
         lat = accessLatency;

+ // The compressor is called to decompress data. Although the data is + // stored uncompressed, even if a compressor is used, the compression
+        // and decompression methods are called to calculate the amount of
+        // cycles used.
+        if (blk->isValid()){
+            lat += compressor->decompress(
+                       compression_blk->getCompressionData());
+        }
+
         // Check if the block to be accessed is available. If not,
         // apply the accessLatency on top of block->whenReady.
         if (blk->whenReady > curTick() &&
             cache->ticksToCycles(blk->whenReady - curTick()) >
             accessLatency) {
+            // TODO I think this should have been:
+            // lat = max(cache->ticksToCycles(blk->whenReady - curTick(),
+            //                        accessLatency) + decompressLatency;
+            // as from my understanding, the block access latency is
+            // "parallel" to the whenReady cycle
             lat += cache->ticksToCycles(blk->whenReady - curTick());
         }

@@ -274,11 +300,26 @@
         // It would be a hit if victim was valid, and upgrades do not call
         // findVictim, so it cannot happen
         assert(!victim->isValid());
+
+        // The compressor is called to check if the new block can be co-
+        // allocated in the superblock. If not, we must evict the whole
+        // superblock
+        std::unique_ptr<CompressionData> compression_data =
+            compressor->compress(pkt->getConstPtr<uint8_t>());
+
+        // Check for co-allocation
+        evictSuperblock = !canCoAllocate(victim_superblock,
+                                         compression_data.get());
     }

     // The whole superblock must be evicted to make room for the new one
     if (evictSuperblock) {
         for (const auto& blk : victim_superblock->blks){
+            // Decompress block to calculate victim search latency
+            if (blk->isValid()) {
+                lat += compressor->decompress(blk->getCompressionData());
+            }
+
             evict_blks.push_back(blk);
         }
     }
@@ -296,13 +337,23 @@
     // Insert block
     BaseTags::insertBlock(pkt, blk);

+    // The compressor is called to compress data before insertion.
+    // Although the data is stored uncompressed, even if a compressor
+    // is used, the compression/decompression methods are called to
+ // calculate the amount of cycles needed on accesses (by the decompressor). + // @todo compression is being called twice for a successful insertion, and
+    //       this messes the stats. Fix it to be called just once.
+    std::unique_ptr<CompressionData> compression_data =
+        compressor->compress(pkt->getConstPtr<uint8_t>());
+
     // Get block's superblock
     CompressionBlk* compression_blk = static_cast<CompressionBlk*>(blk);
     const SuperblockBlk* superblock = compression_blk->getSuperblock();

     // Set block's metadata
     compression_blk->insert(extractTag(pkt->getAddr()), pkt->isSecure(),
-                            pkt->req->masterId(), pkt->req->taskId());
+                            pkt->req->masterId(), pkt->req->taskId(),
+                            compression_data);

     // When a block is inserted, the tag is only a newly used tag if the
     // superblock was not previously present in the cache.
diff --git a/src/mem/cache/tags/compressed_tags.hh b/src/mem/cache/tags/compressed_tags.hh
index 7092ff7..f3ac320 100644
--- a/src/mem/cache/tags/compressed_tags.hh
+++ b/src/mem/cache/tags/compressed_tags.hh
@@ -43,6 +43,7 @@
 #include "mem/cache/tags/base.hh"
 #include "mem/packet.hh"

+class BaseCacheCompressor;
 class BaseReplacementPolicy;
 class ReplaceableEntry;
 struct CompressedTagsParams;
@@ -82,6 +83,9 @@
     /** Replacement policy. */
     BaseReplacementPolicy *replacementPolicy;

+    /** Compression method being used. */
+    BaseCacheCompressor* compressor;
+
     /** Maximum compression ratio. */
     const unsigned maxCR;

@@ -125,6 +129,16 @@
     virtual ~CompressedTags() {};

     /**
+ * Checks whether a superblock can co-allocate given compressed data block.
+     *
+     * @param superblock Superblock to check.
+     * @param compression_data Compressed data of new block to co-allocate.
+     * @return True if block can be co-allocated in superblock.
+     */
+    virtual bool canCoAllocate(const SuperblockBlk* superblock,
+ const CompressionData* compression_data) const;
+
+    /**
      * This function updates the tags when a block is invalidated but does
* not invalidate the block itself. It also updates the replacement data.
      *

--
To view, visit https://gem5-review.googlesource.com/11100
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: I83dc4d2b8d2bc5ed9f760c938edfa4ebdd6b8583
Gerrit-Change-Number: 11100
Gerrit-PatchSet: 1
Gerrit-Owner: Daniel Carvalho <[email protected]>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list
[email protected]
http://m5sim.org/mailman/listinfo/gem5-dev

Reply via email to