summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/base/output.cc2
-rw-r--r--src/base/output.hh20
-rw-r--r--src/mem/CommMonitor.py3
-rw-r--r--src/mem/SConscript8
-rw-r--r--src/mem/comm_monitor.cc48
-rw-r--r--src/mem/comm_monitor.hh12
-rw-r--r--src/proto/SConscript1
-rw-r--r--src/proto/packet.proto58
-rw-r--r--tests/configs/tgen-simple-mem.py4
9 files changed, 139 insertions, 17 deletions
diff --git a/src/base/output.cc b/src/base/output.cc
index ee2e196ed..c0ddd0fae 100644
--- a/src/base/output.cc
+++ b/src/base/output.cc
@@ -145,7 +145,7 @@ OutputDirectory::directory() const
return dir;
}
-inline string
+string
OutputDirectory::resolve(const string &name) const
{
return (name[0] != PATH_SEPARATOR) ? dir + name : name;
diff --git a/src/base/output.hh b/src/base/output.hh
index 68d9daf85..ef628882d 100644
--- a/src/base/output.hh
+++ b/src/base/output.hh
@@ -52,16 +52,6 @@ class OutputDirectory
/** System-specific path separator character */
static const char PATH_SEPARATOR = '/';
- /**
- * Returns relative file names prepended with name of this directory.
- * Returns absolute file names unaltered.
- *
- * @param name file name to prepend with directory name
- * @return file name prepended with base directory name or unaltered
- * absolute file name
- */
- std::string resolve(const std::string &name) const;
-
protected:
/**
* Determines whether given file name corresponds to standard output
@@ -80,6 +70,16 @@ class OutputDirectory
/** Destructor. */
~OutputDirectory();
+ /**
+ * Returns relative file names prepended with name of this directory.
+ * Returns absolute file names unaltered.
+ *
+ * @param name file name to prepend with directory name
+ * @return file name prepended with base directory name or unaltered
+ * absolute file name
+ */
+ std::string resolve(const std::string &name) const;
+
/** Opens a file (optionally compressed).
*
* Will open a file as a compressed stream if filename ends in .gz.
diff --git a/src/mem/CommMonitor.py b/src/mem/CommMonitor.py
index a34a57db4..3f9106cc4 100644
--- a/src/mem/CommMonitor.py
+++ b/src/mem/CommMonitor.py
@@ -49,6 +49,9 @@ class CommMonitor(MemObject):
master = MasterPort("Master port")
slave = SlavePort("Slave port")
+ # packet trace output file, disabled by default
+ trace_file = Param.String("", "Packet trace output file")
+
# control the sample period window length of this monitor
sample_period = Param.Clock("1ms", "Sample period for histograms")
diff --git a/src/mem/SConscript b/src/mem/SConscript
index 374f904a8..ca89418b5 100644
--- a/src/mem/SConscript
+++ b/src/mem/SConscript
@@ -30,17 +30,21 @@
Import('*')
+# Only build the communication if we have support for protobuf as the
+# tracing relies on it
+if env['HAVE_PROTOBUF']:
+ SimObject('CommMonitor.py')
+ Source('comm_monitor.cc')
+
SimObject('AddrMapper.py')
SimObject('Bridge.py')
SimObject('Bus.py')
-SimObject('CommMonitor.py')
SimObject('MemObject.py')
Source('addr_mapper.cc')
Source('bridge.cc')
Source('bus.cc')
Source('coherent_bus.cc')
-Source('comm_monitor.cc')
Source('mem_object.cc')
Source('mport.cc')
Source('noncoherent_bus.cc')
diff --git a/src/mem/comm_monitor.cc b/src/mem/comm_monitor.cc
index 7e98f64f6..88e549cbb 100644
--- a/src/mem/comm_monitor.cc
+++ b/src/mem/comm_monitor.cc
@@ -38,9 +38,12 @@
* Andreas Hansson
*/
+#include "base/callback.hh"
+#include "base/output.hh"
#include "base/trace.hh"
#include "debug/CommMonitor.hh"
#include "mem/comm_monitor.hh"
+#include "proto/packet.pb.h"
#include "sim/stats.hh"
CommMonitor::CommMonitor(Params* params)
@@ -51,8 +54,31 @@ CommMonitor::CommMonitor(Params* params)
samplePeriodTicks(params->sample_period),
readAddrMask(params->read_addr_mask),
writeAddrMask(params->write_addr_mask),
- stats(params)
+ stats(params),
+ traceStream(NULL)
{
+ // If we are using a trace file, then open the file,
+ if (params->trace_file != "") {
+ // If the trace file is not specified as an absolute path,
+ // append the current simulation output directory
+ std::string filename = simout.resolve(params->trace_file);
+ traceStream = new ProtoOutputStream(filename);
+
+ // Create a protobuf message for the header and write it to
+ // the stream
+ Message::PacketHeader header_msg;
+ header_msg.set_obj_id(name());
+ header_msg.set_tick_freq(SimClock::Frequency);
+ traceStream->write(header_msg);
+
+ // Register a callback to compensate for the destructor not
+ // being called. The callback forces the stream to flush and
+ // closes the output file.
+ Callback* cb = new MakeCallback<CommMonitor,
+ &CommMonitor::closeStreams>(this);
+ registerExitCallback(cb);
+ }
+
// keep track of the sample period both in ticks and absolute time
samplePeriod.setTick(params->sample_period);
@@ -61,6 +87,13 @@ CommMonitor::CommMonitor(Params* params)
name(), samplePeriodTicks, samplePeriod);
}
+void
+CommMonitor::closeStreams()
+{
+ if (traceStream != NULL)
+ delete traceStream;
+}
+
CommMonitor*
CommMonitorParams::create()
{
@@ -154,6 +187,19 @@ CommMonitor::recvTimingReq(PacketPtr pkt)
pkt->senderState = senderState;
}
+ if (successful && traceStream != NULL) {
+ // Create a protobuf message representing the
+ // packet. Currently we do not preserve the flags in the
+ // trace.
+ Message::Packet pkt_msg;
+ pkt_msg.set_tick(curTick());
+ pkt_msg.set_cmd(pkt->cmdToIndex());
+ pkt_msg.set_addr(pkt->getAddr());
+ pkt_msg.set_size(pkt->getSize());
+
+ traceStream->write(pkt_msg);
+ }
+
if (successful && isRead) {
DPRINTF(CommMonitor, "Forwarded read request\n");
diff --git a/src/mem/comm_monitor.hh b/src/mem/comm_monitor.hh
index e59b8c467..271ae5fff 100644
--- a/src/mem/comm_monitor.hh
+++ b/src/mem/comm_monitor.hh
@@ -45,6 +45,7 @@
#include "base/time.hh"
#include "mem/mem_object.hh"
#include "params/CommMonitor.hh"
+#include "proto/protoio.hh"
/**
* The communication monitor is a MemObject which can monitor statistics of
@@ -75,7 +76,13 @@ class CommMonitor : public MemObject
CommMonitor(Params* params);
/** Destructor */
- ~CommMonitor() { }
+ ~CommMonitor() {}
+
+ /**
+ * Callback to flush and close all open output streams on exit. If
+ * we were calling the destructor it could be done there.
+ */
+ void closeStreams();
virtual BaseMasterPort& getMasterPort(const std::string& if_name,
PortID idx = InvalidPortID);
@@ -427,6 +434,9 @@ class CommMonitor : public MemObject
/** Instantiate stats */
MonitorStats stats;
+
+ /** Output stream for a potential trace. */
+ ProtoOutputStream* traceStream;
};
#endif //__MEM_COMM_MONITOR_HH__
diff --git a/src/proto/SConscript b/src/proto/SConscript
index ade891737..9bb6fd428 100644
--- a/src/proto/SConscript
+++ b/src/proto/SConscript
@@ -41,4 +41,5 @@ Import('*')
# Only build if we have protobuf support
if env['HAVE_PROTOBUF']:
+ ProtoBuf('packet.proto')
Source('protoio.cc')
diff --git a/src/proto/packet.proto b/src/proto/packet.proto
new file mode 100644
index 000000000..bfeee6a44
--- /dev/null
+++ b/src/proto/packet.proto
@@ -0,0 +1,58 @@
+// Copyright (c) 2012 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 Hansson
+
+// Put all the generated messages in a namespace
+package Message;
+
+// Packet header with the identifier describing what object captured
+// the trace, the version of this file format, and the tick frequency
+// for all the packet time stamps.
+message PacketHeader {
+ required string obj_id = 1;
+ optional uint32 ver = 2 [default = 0];
+ required uint64 tick_freq = 3;
+}
+
+// Each packet in the trace contains a tick (which can be translated
+// to absolute time using the frequency in the header), the command,
+// the address, and the size in bytes
+message Packet {
+ required uint64 tick = 1;
+ required uint32 cmd = 2;
+ required uint64 addr = 3;
+ required uint32 size = 4;
+}
diff --git a/tests/configs/tgen-simple-mem.py b/tests/configs/tgen-simple-mem.py
index 1a95acb54..ae7364214 100644
--- a/tests/configs/tgen-simple-mem.py
+++ b/tests/configs/tgen-simple-mem.py
@@ -46,8 +46,8 @@ cpu = TrafficGen(config_file = "tests/quick/se/70.tgen/tgen-simple-mem.cfg")
system = System(cpu = cpu, physmem = SimpleMemory(),
membus = NoncoherentBus(clock="1GHz", width = 16))
-# add a communication monitor
-system.monitor = CommMonitor()
+# add a communication monitor, and also trace all the packets
+system.monitor = CommMonitor(trace_file = "monitor.ptrc.gz")
# connect the traffic generator to the bus via a communication monitor
system.cpu.port = system.monitor.slave