Hello Nikos Nikoleris,

I'd like you to do a code review. Please visit

    https://gem5-review.googlesource.com/8121

to review the following change.


Change subject: stats: Add beta support for HDF5 stat dumps
......................................................................

stats: Add beta support for HDF5 stat dumps

This changeset add support for stat dumps in the HDF5 file
format. HDF5 is a binary data format that represents data in a
file-system-like balanced tree. It has native support for
N-dimensional arrays and binary data (e.g., frame buffers).

It has the following benefits over traditional text stat files:

  * Efficient storage of time series (multiple stat dumps)

  * Fast lookup of stats

  * Plenty of existing tooling (e.g., Python libraries and graphical
    viewers)

  * File format can be used to store frame buffers together with
    normal stats.

Drawbacks:

  * Large startup cost (single stat dump larger than text equivalent)

  * Stat dumps are slower than text

Known limitations:

  * Inferred stat paths don't always match the object hierarchy since
    they are inferred from the stat name. Fixing this would require a
    significant stat framework refactor. This means that the file
    format isn't entirely stable.

  * Distributions and histograms aren't supported.

HDF5 stat output can be enabled using the 'h5' URL scheme when
overriding the stat file name on gem5's command line. The following
parameters are supported:

  * chunking (unsigned): Number of time steps to pre-allocate
    (default: 10)

  * desc (bool): Output stat descriptions (default: True)

  * formulas (bool): Output derived stats (default: True)

Example gem5 command line:

./build/ARM/gem5.opt \
  --stats-file="h5://stats.h5?desc=False;formulas=False" \
  configs/example/fs.py

Example Python stat consumer that computes IPC:
  import h5py

  f = h5py.File('stats.h5', 'r')
  group = f['/system/cpu']
  for i, c in zip(group['committedInsts'], group['numCycles']):
      print i, c, i / c

Change-Id: I351c6cbff2fb7bef9012f47876ba227ed288975b
Signed-off-by: Andreas Sandberg <andreas.sandb...@arm.com>
Reviewed-by: Nikos Nikoleris <nikos.nikole...@arm.com>
---
M SConstruct
M src/base/SConscript
A src/base/stats/hdf5.cc
A src/base/stats/hdf5.hh
M src/python/m5/stats/__init__.py
M src/python/pybind11/stats.cc
6 files changed, 497 insertions(+), 5 deletions(-)



diff --git a/SConstruct b/SConstruct
index df647e7..ff13911 100755
--- a/SConstruct
+++ b/SConstruct
@@ -1,6 +1,6 @@
 # -*- mode:python -*-

-# Copyright (c) 2013, 2015-2017 ARM Limited
+# Copyright (c) 2013, 2015-2018 ARM Limited
 # All rights reserved.
 #
 # The license below extends only to copyright in the software and shall
@@ -901,6 +901,15 @@
 main['HAVE_PERF_ATTR_EXCLUDE_HOST'] = conf.CheckMember(
     'linux/perf_event.h', 'struct perf_event_attr', 'exclude_host')

+have_hdf5 = \
+    conf.CheckLibWithHeader('hdf5', 'hdf5.h', 'C',
+                            'H5Fcreate("", 0, 0, 0);') and \
+    conf.CheckLibWithHeader('hdf5_cpp', 'H5Cpp.h', 'C++',
+                            'H5::H5File("", 0);')
+if not have_hdf5:
+    print "Warning: Couldn't find any HDF5 C++ libraries. Disabling"
+    print "         HDF5 support."
+

 ######################################################################
 #
@@ -1003,14 +1012,15 @@
     EnumVariable('PROTOCOL', 'Coherence protocol for Ruby', 'None',
                   all_protocols),
     EnumVariable('BACKTRACE_IMPL', 'Post-mortem dump implementation',
-                 backtrace_impls[-1], backtrace_impls)
+                 backtrace_impls[-1], backtrace_impls),
+    BoolVariable('USE_HDF5', 'Enable the HDF5 support', have_hdf5),
     )

# These variables get exported to #defines in config/*.hh (see src/SConscript). export_vars += ['USE_FENV', 'SS_COMPATIBLE_FP', 'TARGET_ISA', 'TARGET_GPU_ISA',
                 'CP_ANNOTATE', 'USE_POSIX_CLOCK', 'USE_KVM', 'USE_TUNTAP',
                 'PROTOCOL', 'HAVE_PROTOBUF', 'HAVE_PERF_ATTR_EXCLUDE_HOST',
-                'USE_PNG']
+                'USE_PNG', 'USE_HDF5']

 ###################################################
 #
diff --git a/src/base/SConscript b/src/base/SConscript
index a90b784..1f241c9 100644
--- a/src/base/SConscript
+++ b/src/base/SConscript
@@ -78,6 +78,8 @@
 Source('loader/symtab.cc')

 Source('stats/text.cc')
+if env['USE_HDF5']:
+    Source('stats/hdf5.cc')

 GTest('bituniontest', 'bituniontest.cc')

diff --git a/src/base/stats/hdf5.cc b/src/base/stats/hdf5.cc
new file mode 100644
index 0000000..308bb10
--- /dev/null
+++ b/src/base/stats/hdf5.cc
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2016-2018 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * 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: Andreas Sandberg
+ */
+
+#include "base/stats/hdf5.hh"
+
+#include "base/logging.hh"
+#include "base/stats/info.hh"
+
+template<typename T>
+bool emptyStrings(const T &labels)
+{
+    for (const auto &s : labels) {
+        if (!s.empty())
+            return false;
+    }
+    return true;
+}
+
+
+namespace Stats {
+
+Hdf5::Hdf5(const std::string &file, unsigned chunking,
+           bool desc, bool formulas)
+    : fname(file), timeChunk(chunking),
+      enableDescriptions(desc), enableFormula(formulas),
+      dumpCount(0)
+{
+    // Tell the library not to print exceptions by default. There are
+    // cases where we rely on exceptions to determine if we need to
+    // create a node or if we can just open it.
+    H5::Exception::dontPrint();
+}
+
+Hdf5::~Hdf5()
+{
+}
+
+
+void
+Hdf5::begin()
+{
+    h5File = H5::H5File(fname,
+                        dumpCount > 0 ? H5F_ACC_RDWR : H5F_ACC_TRUNC);
+}
+
+void
+Hdf5::end()
+{
+    assert(valid());
+
+    dumpCount++;
+}
+
+bool
+Hdf5::valid() const
+{
+    return true;
+}
+
+
+void
+Hdf5::visit(const ScalarInfo &info)
+{
+    // Since this stat is a scalar, we need 1-dimensional value in the
+    // stat file. The Hdf5::appendStat helper will populate the size
+    // of the first dimension (time).
+    hsize_t fdims[1] = { 0, };
+    double data[1] = { info.result(), };
+
+    appendStat(info, 1, fdims, data);
+}
+
+void
+Hdf5::visit(const VectorInfo &info)
+{
+    appendVectorInfo(info);
+}
+
+void
+Hdf5::visit(const DistInfo &info)
+{
+    warn_once("HDF5 stat files don't support distributions.\n");
+}
+
+void
+Hdf5::visit(const VectorDistInfo &info)
+{
+    warn_once("HDF5 stat files don't support vector distributions.\n");
+}
+
+void
+Hdf5::visit(const Vector2dInfo &info)
+{
+    // Request a 3-dimensional stat, the first dimension will be
+    // populated by the Hdf5::appendStat() helper. The remaining two
+    // dimensions correspond to the stat instance.
+    hsize_t fdims[3] = { 0, info.x, info.y };
+    H5::DataSet data_set = appendStat(info, 3, fdims, info.cvec.data());
+
+    if (dumpCount == 0) {
+        if (!info.subnames.empty() && !emptyStrings(info.subnames))
+            addMetaData(data_set, "subnames", info.subnames);
+
+        if (!info.y_subnames.empty() && !emptyStrings(info.y_subnames))
+            addMetaData(data_set, "y_subnames", info.y_subnames);
+
+        if (!info.subdescs.empty() && !emptyStrings(info.subdescs))
+            addMetaData(data_set, "subdescs", info.subdescs);
+    }
+}
+
+void
+Hdf5::visit(const FormulaInfo &info)
+{
+    if (!enableFormula)
+        return;
+
+    H5::DataSet data_set = appendVectorInfo(info);
+
+    if (dumpCount == 0)
+        addMetaData(data_set, "equation", info.str());
+}
+
+void
+Hdf5::visit(const SparseHistInfo &info)
+{
+    warn_once("HDF5 stat files don't support sparse histograms.\n");
+}
+
+H5::DataSet
+Hdf5::appendVectorInfo(const VectorInfo &info)
+{
+    const VResult &vr(info.result());
+    // Request a 2-dimensional stat, the first dimension will be
+    // populated by the Hdf5::appendStat() helper. The remaining
+    // dimension correspond to the stat instance.
+    hsize_t fdims[2] = { 0, vr.size() };
+    H5::DataSet data_set = appendStat(info, 2, fdims, vr.data());
+
+    if (dumpCount == 0) {
+        if (!info.subnames.empty() && !emptyStrings(info.subnames))
+            addMetaData(data_set, "subnames", info.subnames);
+
+        if (!info.subdescs.empty() && !emptyStrings(info.subdescs))
+            addMetaData(data_set, "subdescs", info.subdescs);
+    }
+
+    return data_set;
+}
+
+H5::DataSet
+Hdf5::appendStat(const Info &info, int rank, hsize_t *dims, const double *data)
+{
+    auto stat_path = statPath(info);
+    H5::Group group = stat_path.first;
+    std::string &stat = stat_path.second;
+    H5::DataSet data_set;
+    H5::DataSpace fspace;
+
+    dims[0] = dumpCount + 1;
+    if (dumpCount > 0) {
+        data_set = group.openDataSet(stat);
+        data_set.extend(dims);
+        fspace = data_set.getSpace();
+    } else {
+        H5::DSetCreatPropList props;
+
+        // Setup max dimensions based on the requested file dimensions
+        std::vector<hsize_t> max_dims(rank);
+        std::copy(dims, dims + rank, max_dims.begin());
+        max_dims[0] = H5S_UNLIMITED;
+
+        // Setup chunking
+        std::vector<hsize_t> chunk_dims(rank);
+        std::copy(dims, dims + rank, chunk_dims.begin());
+        chunk_dims[0] = timeChunk;
+        props.setChunk(rank, chunk_dims.data());
+
+        // Enable compression
+        props.setDeflate(1);
+
+        fspace = H5::DataSpace(rank, dims, max_dims.data());
+        data_set = group.createDataSet(stat, H5::PredType::NATIVE_DOUBLE,
+                                       fspace, props);
+
+        if (enableDescriptions && !info.desc.empty()) {
+            addMetaData(data_set, "description", info.desc);
+        }
+    }
+
+    // The first dimension is time which isn't included in data.
+    dims[0] = 1;
+    H5::DataSpace mspace(rank, dims);
+    std::vector<hsize_t> foffset(rank, 0);
+    foffset[0] = dumpCount;
+
+    fspace.selectHyperslab(H5S_SELECT_SET, dims, foffset.data());
+    data_set.write(data, H5::PredType::NATIVE_DOUBLE, mspace, fspace);
+
+    return data_set;
+}
+
+void
+Hdf5::addMetaData(H5::DataSet &loc, const char *name,
+                  const std::vector<const char *> &labels)
+{
+    H5::StrType type(H5::PredType::C_S1, H5T_VARIABLE);
+    hsize_t dims[1] = { labels.size(), };
+    H5::DataSpace space(1, dims);
+    H5::Attribute attribute = loc.createAttribute(name, type, space);
+    attribute.write(type, labels.data());
+}
+
+void
+Hdf5::addMetaData(H5::DataSet &loc, const char *name,
+                  const std::vector<std::string> &labels)
+{
+    std::vector<const char *> cstrs(labels.size());
+    for (int i = 0; i < labels.size(); ++i)
+        cstrs[i] = labels[i].c_str();
+
+    addMetaData(loc, name, cstrs);
+}
+
+void
+Hdf5::addMetaData(H5::DataSet &loc, const char *name,
+                  const std::string &value)
+{
+    H5::StrType type(H5::PredType::C_S1, value.length() + 1);
+    hsize_t dims[1] = { 1, };
+    H5::DataSpace space(1, dims);
+    H5::Attribute attribute = loc.createAttribute(name, type, space);
+    attribute.write(type, value.c_str());
+}
+
+void
+Hdf5::addMetaData(H5::DataSet &loc, const char *name, double value)
+{
+    hsize_t dims[1] = { 1, };
+    H5::DataSpace space(1, dims);
+    H5::Attribute attribute = loc.createAttribute(
+        name, H5::PredType::NATIVE_DOUBLE, space);
+    attribute.write(H5::PredType::NATIVE_DOUBLE, &value);
+}
+
+
+
+std::pair<H5::Group, std::string>
+Hdf5::statPath(const Info &info)
+{
+    const std::string &name(info.name);
+    const size_t attr_pos = name.rfind('.');
+    if (attr_pos != std::string::npos) {
+        const std::string group_path(name, 0, attr_pos);
+        const std::string attr(name, attr_pos + 1);
+
+        return make_pair(requireGroupPath(h5File, group_path), attr);
+    } else {
+        return make_pair(requireGroupPath(h5File, "/"), name);
+    }
+}
+
+H5::Group
+Hdf5::requireGroupPath(H5::CommonFG &base, const std::string &path)
+{
+    const size_t delim(path.find("."));
+    if (delim != std::string::npos) {
+        const std::string elem(path, 0, delim);
+        const std::string remainder(path, delim + 1);
+        assert(!remainder.empty());
+        H5::Group group = requireGroup(base, elem);
+
+        return requireGroupPath(group, remainder);
+    } else {
+        return requireGroup(base, path);
+    }
+}
+
+H5::Group
+Hdf5::requireGroup(H5::CommonFG &base, const std::string &name)
+{
+    try {
+        return base.openGroup(name);
+    } catch (H5::FileIException e) {
+        return base.createGroup(name);
+    } catch (H5::GroupIException e) {
+        return base.createGroup(name);
+    }
+}
+
+
+std::unique_ptr<Output>
+initHDF5(const std::string &filename, unsigned chunking,
+         bool desc, bool formulas)
+{
+    return  std::unique_ptr<Output>(
+        new Hdf5(filename, chunking, desc, formulas));
+}
+
+}; // namespace Stats
diff --git a/src/base/stats/hdf5.hh b/src/base/stats/hdf5.hh
new file mode 100644
index 0000000..cec83c0
--- /dev/null
+++ b/src/base/stats/hdf5.hh
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2016-2018 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * 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: Andreas Sandberg
+ */
+
+#ifndef __BASE_STATS_HDF5_HH__
+#define __BASE_STATS_HDF5_HH__
+
+#include <H5Cpp.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/output.hh"
+#include "base/stats/output.hh"
+#include "base/stats/types.hh"
+
+namespace Stats {
+
+class Hdf5 : public Output
+{
+  public:
+ Hdf5(const std::string &file, unsigned chunking, bool desc, bool formulas);
+
+    ~Hdf5();
+
+    Hdf5() = delete;
+    Hdf5(const Hdf5 &other) = delete;
+
+  public: // Output interface
+    void begin() override;
+    void end() override;
+    bool valid() const override;
+
+    void visit(const ScalarInfo &info) override;
+    void visit(const VectorInfo &info) override;
+    void visit(const DistInfo &info) override;
+    void visit(const VectorDistInfo &info) override;
+    void visit(const Vector2dInfo &info) override;
+    void visit(const FormulaInfo &info) override;
+    void visit(const SparseHistInfo &info) override;
+
+  protected:
+    H5::DataSet appendVectorInfo(const VectorInfo &info);
+
+    H5::DataSet appendStat(const Info &info, int rank, hsize_t *fdims,
+                           const double *data);
+
+    void addMetaData(H5::DataSet &loc, const char *name,
+                     const std::vector<const char *> &labels);
+    void addMetaData(H5::DataSet &loc, const char *name,
+                     const std::vector<std::string> &labels);
+    void addMetaData(H5::DataSet &loc, const char *name,
+                     const std::string &value);
+    void addMetaData(H5::DataSet &loc, const char *name, double value);
+
+    std::pair<H5::Group, std::string> statPath(const Info &info);
+ H5::Group requireGroupPath(H5::CommonFG &base, const std::string &path);
+    H5::Group requireGroup(H5::CommonFG &base, const std::string &name);
+
+  protected:
+    const std::string fname;
+    const hsize_t timeChunk;
+    const bool enableDescriptions;
+    const bool enableFormula;
+
+    unsigned dumpCount;
+    H5::H5File h5File;
+};
+
+std::unique_ptr<Output> initHDF5(
+    const std::string &filename,unsigned chunking = 10,
+    bool desc = true, bool formulas = true);
+
+} // namespace Stats
+
+#endif // __BASE_STATS_HDF5_HH__
diff --git a/src/python/m5/stats/__init__.py b/src/python/m5/stats/__init__.py
index ba91f22..b436b26 100644
--- a/src/python/m5/stats/__init__.py
+++ b/src/python/m5/stats/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2017 ARM Limited
+# Copyright (c) 2017-2018 ARM Limited
 # All rights reserved.
 #
 # The license below extends only to copyright in the software and shall
@@ -115,13 +115,36 @@

     return _m5.stats.initText(fn, desc)

+@_url_factory
+def _hdf5Factory(fn, chunking=10, desc=True, formulas=True):
+    """Output stats in HDF5 format.
+
+    Parameters:
+ * chunking (unsigned): Number of time steps to pre-allocate (default: 10)
+      * desc (bool): Output stat descriptions (default: True)
+      * formulas (bool): Output derived stats (default: True)
+
+    Example:
+      h5://stats.h5?desc=False;chunking=100;formulas=False
+
+    """
+
+    if hasattr(_m5.stats, "initHDF5"):
+        return _m5.stats.initHDF5(fn, chunking, desc, formulas)
+    else:
+        fatal("$s: HDF5 support not enabled at compile time" % (
+            url.geturl(), ))
+
 factories = {
     # Default to the text factory if we're given a naked path
     "" : _textFactory,
     "file" : _textFactory,
     "text" : _textFactory,
+    "h5" : _hdf5Factory,
+    "hdf5" : _hdf5Factory,
 }

+
 def addStatVisitor(url):
     """Add a stat visitor specified using a URL string

diff --git a/src/python/pybind11/stats.cc b/src/python/pybind11/stats.cc
index 39d9ce8..f3d0549 100644
--- a/src/python/pybind11/stats.cc
+++ b/src/python/pybind11/stats.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 ARM Limited
+ * Copyright (c) 2017-2018 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -44,11 +44,17 @@
 #include "pybind11/pybind11.h"
 #include "pybind11/stl.h"

+#include "config/use_hdf5.hh"
+
 #include "base/statistics.hh"
 #include "base/stats/text.hh"
+#if USE_HDF5
+#include "base/stats/hdf5.hh"
+#endif
 #include "sim/stat_control.hh"
 #include "sim/stat_register.hh"

+
 namespace py = pybind11;

 namespace Stats {
@@ -77,6 +83,9 @@
     m
         .def("initSimStats", &Stats::initSimStats)
.def("initText", &Stats::initText, py::return_value_policy::reference)
+#if USE_HDF5
+        .def("initHDF5", &Stats::initHDF5)
+#endif
         .def("registerPythonStatsHandlers",
              &Stats::registerPythonStatsHandlers)
         .def("schedStatEvent", &Stats::schedStatEvent)

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

Gerrit-Project: public/gem5
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I351c6cbff2fb7bef9012f47876ba227ed288975b
Gerrit-Change-Number: 8121
Gerrit-PatchSet: 1
Gerrit-Owner: Andreas Sandberg <andreas.sandb...@arm.com>
Gerrit-Reviewer: Nikos Nikoleris <nikos.nikole...@arm.com>
_______________________________________________
gem5-dev mailing list
gem5-dev@gem5.org
http://m5sim.org/mailman/listinfo/gem5-dev

Reply via email to