diff --git a/src/mem/ruby/system/FixedLatencyMemoryControl.py b/src/mem/ruby/system/FixedLatencyMemoryControl.py new file mode 100644 --- /dev/null +++ b/src/mem/ruby/system/FixedLatencyMemoryControl.py @@ -0,0 +1,43 @@ +# Copyright (c) 2015 Advanced Micro Devices, Inc. +# 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: Sooraj Puthoor (Sooraj.Puthoor@amd.com) + +from m5.params import * +from m5.proxy import * +from m5.SimObject import SimObject +from AbstractMemory import AbstractMemory + +class FixedLatencyMemoryControl(AbstractMemory): + type = 'FixedLatencyMemoryControl' + cxx_class = 'FixedLatencyMemoryControl' + cxx_header = "mem/ruby/system/FixedLatencyMemoryControl.hh" + ruby_system = Param.RubySystem(Parent.any, "") + port = SlavePort("Slave port") + fixedLatency = Param.Int(100, "Fixed latency, in ruby cycles"); + # single-ported on the system interface side, instantiate with a + # crossbar in front of the controller for multiple ports + port = SlavePort("Slave port") diff --git a/src/mem/ruby/system/SConscript b/src/mem/ruby/system/SConscript --- a/src/mem/ruby/system/SConscript +++ b/src/mem/ruby/system/SConscript @@ -33,12 +33,14 @@ if env['PROTOCOL'] == 'None': Return() +SimObject('FixedLatencyMemoryControl.py') SimObject('RubySystem.py') SimObject('Sequencer.py') SimObject('WeightedLRUReplacementPolicy.py') Source('CacheRecorder.cc') Source('DMASequencer.cc') +Source('FixedLatencyMemoryControl.cc') Source('GPUCoalescer.cc') Source('RubyPort.cc') Source('RubyPortProxy.cc') # Node ID bb9212a4b8d11fc866310b357ec366e9b2b14503 # Parent e9e245ab10f9b797a39a2307e472fedf55735485 diff --git a/configs/common/Options.py b/configs/common/Options.py --- a/configs/common/Options.py +++ b/configs/common/Options.py @@ -90,6 +90,8 @@ parser.add_option("--mem-type", type="choice", default="DDR3_1600_x64", choices=MemConfig.mem_names(), help = "type of memory to use") + parser.add_option("--memory_latency", type="int", default="100", + help="Latency of fixed latency memory controller") parser.add_option("--mem-channels", type="int", default=1, help = "number of memory channels") parser.add_option("--mem-ranks", type="int", default=None, diff --git a/src/mem/ruby/system/FixedLatencyMemoryControl.hh b/src/mem/ruby/system/FixedLatencyMemoryControl.hh new file mode 100644 --- /dev/null +++ b/src/mem/ruby/system/FixedLatencyMemoryControl.hh @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2015 Advanced Micro Devices, Inc. + * 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: Brad Beckmann + */ + +#ifndef __MEM_FIXED_LATENCY_SYSTEM_MEMORY_CONTROL_HH__ +#define __MEM_FIXED_LATENCY_SYSTEM_MEMORY_CONTROL_HH__ + +////////////////////////////////////////////////////////////////////// +/* See RubyMemoryControl.hh for description about the differences between + the different memory controller models. */ + +#include +#include +#include +#include +#include + +#include + +#include "base/statistics.hh" +#include "mem/abstract_mem.hh" +#include "mem/protocol/MemoryMsg.hh" +#include "mem/ruby/common/Address.hh" +#include "mem/ruby/common/Consumer.hh" +#include "mem/ruby/profiler/MemCntrlProfiler.hh" +#include "mem/ruby/slicc_interface/Message.hh" +#include "mem/ruby/structures/MemoryNode.hh" +#include "mem/ruby/system/RubySystem.hh" +#include "params/FixedLatencyMemoryControl.hh" +#include "sim/sim_object.hh" + +class DetailedMemoryChannel; +class FixedLatencyMemoryControl; +class RubySystem; + +////////////////////////////////////////////////////////////////////// +/* The main memory controller: there is one such controller per Ruby + directory node. Each controller may have multiple independent + channels. */ +class FixedLatencyMemoryControl : public AbstractMemory, public Consumer +{ + public: + typedef FixedLatencyMemoryControlParams Params; + FixedLatencyMemoryControl(const Params *p); + void init(); + void reset(); + + ~FixedLatencyMemoryControl(); + + virtual BaseSlavePort& getSlavePort(const std::string& if_name, + PortID idx = InvalidPortID); + + void setDescription(const std::string& name) { m_description = name; }; + std::string getDescription() { return m_description; }; + + // Called from the directory: + bool recvTimingReq(PacketPtr pkt); + void recvFunctional(PacketPtr pkt); + bool areNSlotsAvailable(int n); + int m_controller_id; + + void printConfig(std::ostream& out); + void print(std::ostream& out) const; + void clearStats() const; + void printStats(std::ostream& out) const; + void regStats(); + void enqueueMemRef(MemoryNode& memRef); + void wakeup() { /* unimplemented */ assert(0); }; + const int getChannel(const Addr addr) const + { + /* unimplemented */ assert(0); + return 0; + } + const int getBank(const Addr addr) const + { + /* unimplemented */ assert(0); + return 0; + } + const int getRank(const Addr addr) const + { + /* unimplemented */ assert(0); + return 0; + } + const int getRow(const Addr addr) const + { + /* unimplemented */ assert(0); + return 0; + } + int getBanksPerRank() { /* unimplemented */ assert(0); return 0; } + int getRanksPerDimm() { /* unimplemented */ assert(0); return 0; } + int getDimmsPerChannel() { /* unimplemented */ assert(0); return 0; } + + bool functionalRead(Packet *pkt); + uint32_t functionalWrite(Packet *pkt); + + RubySystem *getRubySystem() { return m_ruby_system; } + + private: + // Private copy constructor and assignment operator + FixedLatencyMemoryControl (const FixedLatencyMemoryControl& obj); + FixedLatencyMemoryControl& operator=(const FixedLatencyMemoryControl& obj); + + private: + // For now, make use of a queued slave port to avoid dealing with + // flow control for the responses being sent back + class MemoryPort : public QueuedSlavePort + { + RespPacketQueue queue; + FixedLatencyMemoryControl& memory; + + public: + MemoryPort(const std::string& name, FixedLatencyMemoryControl& _memory); + + protected: + Tick recvAtomic(PacketPtr pkt); + + void recvFunctional(PacketPtr pkt); + + bool recvTimingReq(PacketPtr); + + virtual AddrRangeList getAddrRanges() const; + }; + + /** + * Our incoming port, for a multi-ported controller add a crossbar + * in front of it + */ + MemoryPort port; + + protected: + void enqueueToDirectory(MemoryNode req, Cycles latency); + + // data members + std::string m_description; + int m_msg_counter; + + // queues where memory requests live + std::list m_response_queue; // FIFO going back to the directory + + int m_fixedLatency; //Fixed latency of the controller in ruby cycles + int m_mem_bus_cycle_multiplier; // ratio of Ruby:MemCntrl clocks + + RubySystem *m_ruby_system; + + // Fixed latency memory controller is a place holder + // for a more realistic memory controller to be implemented + // in the future. So, not using profiler with fixed memory controller. + // MemCntrlProfiler* m_profiler_ptr; + + class MemCntrlEvent : public Event + { + public: + MemCntrlEvent(FixedLatencyMemoryControl* _mem_cntrl) + { + mem_cntrl = _mem_cntrl; + } + private: + void process() { mem_cntrl->wakeup(); } + + FixedLatencyMemoryControl* mem_cntrl; + }; + + MemCntrlEvent m_event; +}; + +#endif // __MEM_FIXED_LATENCY_SYSTEM_MEMORY_CONTROL_HH__ diff --git a/src/mem/ruby/system/FixedLatencyMemoryControl.cc b/src/mem/ruby/system/FixedLatencyMemoryControl.cc new file mode 100644 --- /dev/null +++ b/src/mem/ruby/system/FixedLatencyMemoryControl.cc @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2015 Advanced Micro Devices, Inc. + * 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: Brad Beckmann + */ + +#include "mem/ruby/system/FixedLatencyMemoryControl.hh" + +#include +#include +#include + +#include "base/cprintf.hh" +#include "base/intmath.hh" +#include "base/random.hh" +#include "base/statistics.hh" +#include "debug/RubyMemory.hh" +#include "mem/ruby/common/Address.hh" +#include "mem/ruby/common/Consumer.hh" +#include "mem/ruby/network/Network.hh" +#include "mem/ruby/profiler/Profiler.hh" +#include "mem/ruby/slicc_interface/RubySlicc_ComponentMapping.hh" +#include "mem/ruby/system/RubySystem.hh" + +using namespace std; + +// Total number of controller instantiated (should be equal to number of Ruby directory nodes). +// This is used to assign ID's to the controllers. +static int s_num_controllers = 0; + +// **************************************************************** + +// CONSTRUCTOR +FixedLatencyMemoryControl::FixedLatencyMemoryControl(const Params *p) + : AbstractMemory(p), Consumer(this), port(name() + ".port", *this), + m_ruby_system(p->ruby_system), m_event(this) +{ + m_controller_id = s_num_controllers++; + + // Initialize parameters from RubyParams + + // Memory controller parameters + m_fixedLatency = p->fixedLatency; +} + +void +FixedLatencyMemoryControl::init() +{ + m_msg_counter = 0; + + m_mem_bus_cycle_multiplier = + ceil(static_cast(clockPeriod()) / + static_cast(m_ruby_system->clockPeriod())); + + if (clockPeriod() % m_ruby_system->clockPeriod() != 0) { + warn("Memory control clock not a multiple of the Ruby clock." + "\tThe memory controller will run at an effective clock freq. of %lld Hz\n", + SimClock::Frequency / ((long long int) (m_ruby_system->clockPeriod() * + m_mem_bus_cycle_multiplier))); + } +} + +BaseSlavePort& +FixedLatencyMemoryControl::getSlavePort(const string &if_name, PortID idx) +{ + if (if_name != "port") { + return MemObject::getSlavePort(if_name, idx); + } else { + return port; + } +} + +void +FixedLatencyMemoryControl::reset() +{ + m_msg_counter = 0; +} + +FixedLatencyMemoryControl::~FixedLatencyMemoryControl() +{ + cout << "FixedLatencyMemoryControl destructor.\n"; +} + + +// enqueue new request from directory +bool +FixedLatencyMemoryControl::recvTimingReq(PacketPtr pkt) +{ + // Arrival time is in memory controller clock cycles. + // This memory controller uses it only in DPRINTFs. + Cycles arrival_time = curCycle(); + Addr addr = pkt->getAddr(); + bool is_mem_read = pkt->isRead(); + + access(pkt); + MemoryNode thisReq(arrival_time, pkt, addr, is_mem_read, !is_mem_read); + + thisReq.m_msg_counter = m_msg_counter; + m_msg_counter++; + DPRINTF(RubyMemory, "Memory request%7d: %#08x %c arrived at %10d\n", + thisReq.m_msg_counter, thisReq.m_addr, thisReq.m_is_mem_read ? 'R':'W', + thisReq.m_time * clockPeriod()); + + // return latency in ruby cycles + Cycles return_latency = Cycles(m_fixedLatency); + enqueueToDirectory(thisReq, return_latency); + return true; +} + +bool FixedLatencyMemoryControl::areNSlotsAvailable(int n) +{ + return true; +} + +void +FixedLatencyMemoryControl::print(ostream& out) const +{ +} + +void +FixedLatencyMemoryControl::printConfig(ostream& out) +{ +} + +void +FixedLatencyMemoryControl::clearStats() const +{ +} + +void +FixedLatencyMemoryControl::printStats(ostream& out) const +{ +} + +// Queue up a completed request to send back to directory +void +FixedLatencyMemoryControl::enqueueToDirectory(MemoryNode req, Cycles latency) +{ + Tick arrival_time = clockEdge(latency); + PacketPtr pkt = req.pkt; + + // access already turned the packet into a response + assert(pkt->isResponse()); + + // queue the packet in the response queue to be sent out after + // the static latency has passed + port.schedTimingResp(pkt, arrival_time); + + DPRINTF(RubyMemory, "Enqueueing msg %#08x %c back to directory at %15d\n", + req.m_addr, req.m_is_mem_read ? 'R':'W', arrival_time); +} + +FixedLatencyMemoryControl * +FixedLatencyMemoryControlParams::create() +{ + return new FixedLatencyMemoryControl(this); +} + +void +FixedLatencyMemoryControl::regStats() +{ + // Fixed latency memory controller is a place holder + // for a more realistic memory controller to be implemented + // in the future. So, not using profiler with fixed memory controller. + // m_profiler_ptr->regStats(); + AbstractMemory::regStats(); +} + +void +FixedLatencyMemoryControl::enqueueMemRef(MemoryNode& memRef) +{ + // Assuming memRef.m_time represents arrival time of this packet + // and also assuming memRef.m_time is in ruby cycles + Cycles return_latency = memRef.m_time + Cycles(m_fixedLatency); + enqueueToDirectory(memRef, return_latency); +} + +bool +FixedLatencyMemoryControl::functionalRead(Packet *pkt) +{ + for (std::list::iterator it = m_response_queue.begin(); + it != m_response_queue.end(); ++it) { + PacketPtr msg = (*it).pkt; + if (pkt->checkFunctional(msg)) { + return true; + } + } + return false; +} + +uint32_t +FixedLatencyMemoryControl::functionalWrite(Packet *pkt) +{ + uint32_t num_functional_writes = 0; + + for (std::list::iterator it = m_response_queue.begin(); + it != m_response_queue.end(); ++it) { + PacketPtr msg = (*it).pkt; + if (pkt->checkFunctional(msg)) { + num_functional_writes++; + } + } + + return num_functional_writes; +} + +FixedLatencyMemoryControl::MemoryPort::MemoryPort(const std::string& name, + FixedLatencyMemoryControl& _memory) + : QueuedSlavePort(name, &_memory, queue), queue(_memory, *this), + memory(_memory) +{ } + +AddrRangeList +FixedLatencyMemoryControl::MemoryPort::getAddrRanges() const +{ + AddrRangeList ranges; + ranges.push_back(memory.getAddrRange()); + return ranges; +} + +void +FixedLatencyMemoryControl::MemoryPort::recvFunctional(PacketPtr pkt) +{ + pkt->pushLabel(memory.name()); + + if (!queue.checkFunctional(pkt)) { + // Default implementation of SimpleTimingPort::recvFunctional() + // calls recvAtomic() and throws away the latency; we can save a + // little here by just not calculating the latency. + memory.functionalWrite(pkt); + } + + pkt->popLabel(); +} + +Tick +FixedLatencyMemoryControl::MemoryPort::recvAtomic(PacketPtr pkt) +{ + panic("This controller does not support recv atomic!\n"); +} + +bool +FixedLatencyMemoryControl::MemoryPort::recvTimingReq(PacketPtr pkt) +{ + // pass it to the memory controller + return memory.recvTimingReq(pkt); +}