diff options
-rw-r--r-- | src/base/output.cc | 2 | ||||
-rw-r--r-- | src/base/output.hh | 20 | ||||
-rw-r--r-- | src/mem/CommMonitor.py | 3 | ||||
-rw-r--r-- | src/mem/SConscript | 8 | ||||
-rw-r--r-- | src/mem/comm_monitor.cc | 48 | ||||
-rw-r--r-- | src/mem/comm_monitor.hh | 12 | ||||
-rw-r--r-- | src/proto/SConscript | 1 | ||||
-rw-r--r-- | src/proto/packet.proto | 58 | ||||
-rw-r--r-- | tests/configs/tgen-simple-mem.py | 4 |
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 |