GarnetSyntheticTraffic.cc revision 11661:2bc3962f59fe
1/* 2 * Copyright (c) 2016 Georgia Institute of Technology 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Tushar Krishna 29 */ 30 31#include <cmath> 32#include <iomanip> 33#include <set> 34#include <string> 35#include <vector> 36 37#include "base/misc.hh" 38#include "base/random.hh" 39#include "base/statistics.hh" 40#include "cpu/testers/garnet_synthetic_traffic/GarnetSyntheticTraffic.hh" 41#include "debug/GarnetSyntheticTraffic.hh" 42#include "mem/mem_object.hh" 43#include "mem/packet.hh" 44#include "mem/port.hh" 45#include "mem/request.hh" 46#include "sim/sim_events.hh" 47#include "sim/stats.hh" 48#include "sim/system.hh" 49 50using namespace std; 51 52int TESTER_NETWORK=0; 53 54bool 55GarnetSyntheticTraffic::CpuPort::recvTimingResp(PacketPtr pkt) 56{ 57 tester->completeRequest(pkt); 58 return true; 59} 60 61void 62GarnetSyntheticTraffic::CpuPort::recvReqRetry() 63{ 64 tester->doRetry(); 65} 66 67void 68GarnetSyntheticTraffic::sendPkt(PacketPtr pkt) 69{ 70 if (!cachePort.sendTimingReq(pkt)) { 71 retryPkt = pkt; // RubyPort will retry sending 72 } 73 numPacketsSent++; 74} 75 76GarnetSyntheticTraffic::GarnetSyntheticTraffic(const Params *p) 77 : MemObject(p), 78 tickEvent(this), 79 cachePort("GarnetSyntheticTraffic", this), 80 retryPkt(NULL), 81 size(p->memory_size), 82 blockSizeBits(p->block_offset), 83 numDestinations(p->num_dest), 84 simCycles(p->sim_cycles), 85 numPacketsMax(p->num_packets_max), 86 numPacketsSent(0), 87 singleSender(p->single_sender), 88 singleDest(p->single_dest), 89 trafficType(p->traffic_type), 90 injRate(p->inj_rate), 91 injVnet(p->inj_vnet), 92 precision(p->precision), 93 responseLimit(p->response_limit), 94 masterId(p->system->getMasterId(name())) 95{ 96 // set up counters 97 noResponseCycles = 0; 98 schedule(tickEvent, 0); 99 100 initTrafficType(); 101 if (trafficStringToEnum.count(trafficType) == 0) { 102 fatal("Unknown Traffic Type: %s!\n", traffic); 103 } 104 traffic = trafficStringToEnum[trafficType]; 105 106 id = TESTER_NETWORK++; 107 DPRINTF(GarnetSyntheticTraffic,"Config Created: Name = %s , and id = %d\n", 108 name(), id); 109} 110 111BaseMasterPort & 112GarnetSyntheticTraffic::getMasterPort(const std::string &if_name, PortID idx) 113{ 114 if (if_name == "test") 115 return cachePort; 116 else 117 return MemObject::getMasterPort(if_name, idx); 118} 119 120void 121GarnetSyntheticTraffic::init() 122{ 123 numPacketsSent = 0; 124} 125 126 127void 128GarnetSyntheticTraffic::completeRequest(PacketPtr pkt) 129{ 130 Request *req = pkt->req; 131 132 DPRINTF(GarnetSyntheticTraffic, 133 "Completed injection of %s packet for address %x\n", 134 pkt->isWrite() ? "write" : "read\n", 135 req->getPaddr()); 136 137 assert(pkt->isResponse()); 138 noResponseCycles = 0; 139 delete req; 140 delete pkt; 141} 142 143 144void 145GarnetSyntheticTraffic::tick() 146{ 147 if (++noResponseCycles >= responseLimit) { 148 fatal("%s deadlocked at cycle %d\n", name(), curTick()); 149 } 150 151 // make new request based on injection rate 152 // (injection rate's range depends on precision) 153 // - generate a random number between 0 and 10^precision 154 // - send pkt if this number is < injRate*(10^precision) 155 bool sendAllowedThisCycle; 156 double injRange = pow((double) 10, (double) precision); 157 unsigned trySending = random_mt.random<unsigned>(0, (int) injRange); 158 if (trySending < injRate*injRange) 159 sendAllowedThisCycle = true; 160 else 161 sendAllowedThisCycle = false; 162 163 // always generatePkt unless fixedPkts or singleSender is enabled 164 if (sendAllowedThisCycle) { 165 bool senderEnable = true; 166 167 if (numPacketsMax >= 0 && numPacketsSent >= numPacketsMax) 168 senderEnable = false; 169 170 if (singleSender >= 0 && id != singleSender) 171 senderEnable = false; 172 173 if (senderEnable) 174 generatePkt(); 175 } 176 177 // Schedule wakeup 178 if (curTick() >= simCycles) 179 exitSimLoop("Network Tester completed simCycles"); 180 else { 181 if (!tickEvent.scheduled()) 182 schedule(tickEvent, clockEdge(Cycles(1))); 183 } 184} 185 186void 187GarnetSyntheticTraffic::generatePkt() 188{ 189 int num_destinations = numDestinations; 190 int radix = (int) sqrt(num_destinations); 191 unsigned destination = id; 192 int dest_x = -1; 193 int dest_y = -1; 194 int source = id; 195 int src_x = id%radix; 196 int src_y = id/radix; 197 198 if (singleDest >= 0) 199 { 200 destination = singleDest; 201 } else if (traffic == UNIFORM_RANDOM_) { 202 destination = random_mt.random<unsigned>(0, num_destinations - 1); 203 } else if (traffic == BIT_COMPLEMENT_) { 204 dest_x = radix - src_x - 1; 205 dest_y = radix - src_y - 1; 206 destination = dest_y*radix + dest_x; 207 } else if (traffic == BIT_REVERSE_) { 208 unsigned int straight = source; 209 unsigned int reverse = source & 1; // LSB 210 211 int num_bits = (int) log2(num_destinations); 212 213 for (int i = 1; i < num_bits; i++) 214 { 215 reverse <<= 1; 216 straight >>= 1; 217 reverse |= (straight & 1); // LSB 218 } 219 destination = reverse; 220 } else if (traffic == BIT_ROTATION_) { 221 if (source%2 == 0) 222 destination = source/2; 223 else // (source%2 == 1) 224 destination = ((source/2) + (num_destinations/2)); 225 } else if (traffic == NEIGHBOR_) { 226 dest_x = (src_x + 1) % radix; 227 dest_y = src_y; 228 destination = dest_y*radix + dest_x; 229 } else if (traffic == SHUFFLE_) { 230 if (source < num_destinations/2) 231 destination = source*2; 232 else 233 destination = (source*2 - num_destinations + 1); 234 } else if (traffic == TRANSPOSE_) { 235 dest_x = src_y; 236 dest_y = src_x; 237 destination = dest_y*radix + dest_x; 238 } else if (traffic == TORNADO_) { 239 dest_x = (src_x + (int) ceil(radix/2) - 1) % radix; 240 dest_y = src_y; 241 destination = dest_y*radix + dest_x; 242 } 243 else { 244 fatal("Unknown Traffic Type: %s!\n", traffic); 245 } 246 247 // The source of the packets is a cache. 248 // The destination of the packets is a directory. 249 // The destination bits are embedded in the address after byte-offset. 250 Addr paddr = destination; 251 paddr <<= blockSizeBits; 252 unsigned access_size = 1; // Does not affect Ruby simulation 253 254 // Modeling different coherence msg types over different msg classes. 255 // 256 // GarnetSyntheticTraffic assumes the Garnet_standalone coherence protocol 257 // which models three message classes/virtual networks. 258 // These are: request, forward, response. 259 // requests and forwards are "control" packets (typically 8 bytes), 260 // while responses are "data" packets (typically 72 bytes). 261 // 262 // Life of a packet from the tester into the network: 263 // (1) This function generatePkt() generates packets of one of the 264 // following 3 types (randomly) : ReadReq, INST_FETCH, WriteReq 265 // (2) mem/ruby/system/RubyPort.cc converts these to RubyRequestType_LD, 266 // RubyRequestType_IFETCH, RubyRequestType_ST respectively 267 // (3) mem/ruby/system/Sequencer.cc sends these to the cache controllers 268 // in the coherence protocol. 269 // (4) Network_test-cache.sm tags RubyRequestType:LD, 270 // RubyRequestType:IFETCH and RubyRequestType:ST as 271 // Request, Forward, and Response events respectively; 272 // and injects them into virtual networks 0, 1 and 2 respectively. 273 // It immediately calls back the sequencer. 274 // (5) The packet traverses the network (simple/garnet) and reaches its 275 // destination (Directory), and network stats are updated. 276 // (6) Network_test-dir.sm simply drops the packet. 277 // 278 MemCmd::Command requestType; 279 280 Request *req = nullptr; 281 Request::Flags flags; 282 283 // Inject in specific Vnet 284 // Vnet 0 and 1 are for control packets (1-flit) 285 // Vnet 2 is for data packets (5-flit) 286 int injReqType = injVnet; 287 288 if (injReqType < 0 || injReqType > 2) 289 { 290 // randomly inject in any vnet 291 injReqType = random_mt.random(0, 2); 292 } 293 294 if (injReqType == 0) { 295 // generate packet for virtual network 0 296 requestType = MemCmd::ReadReq; 297 req = new Request(paddr, access_size, flags, masterId); 298 } else if (injReqType == 1) { 299 // generate packet for virtual network 1 300 requestType = MemCmd::ReadReq; 301 flags.set(Request::INST_FETCH); 302 req = new Request(0, 0x0, access_size, flags, masterId, 0x0, 0); 303 req->setPaddr(paddr); 304 } else { // if (injReqType == 2) 305 // generate packet for virtual network 2 306 requestType = MemCmd::WriteReq; 307 req = new Request(paddr, access_size, flags, masterId); 308 } 309 310 req->setContext(id); 311 312 //No need to do functional simulation 313 //We just do timing simulation of the network 314 315 DPRINTF(GarnetSyntheticTraffic, 316 "Generated packet with destination %d, embedded in address %x\n", 317 destination, req->getPaddr()); 318 319 PacketPtr pkt = new Packet(req, requestType); 320 pkt->dataDynamic(new uint8_t[req->getSize()]); 321 pkt->senderState = NULL; 322 323 sendPkt(pkt); 324} 325 326void 327GarnetSyntheticTraffic::initTrafficType() 328{ 329 trafficStringToEnum["bit_complement"] = BIT_COMPLEMENT_; 330 trafficStringToEnum["bit_reverse"] = BIT_REVERSE_; 331 trafficStringToEnum["bit_rotation"] = BIT_ROTATION_; 332 trafficStringToEnum["neighbor"] = NEIGHBOR_; 333 trafficStringToEnum["shuffle"] = SHUFFLE_; 334 trafficStringToEnum["tornado"] = TORNADO_; 335 trafficStringToEnum["transpose"] = TRANSPOSE_; 336 trafficStringToEnum["uniform_random"] = UNIFORM_RANDOM_; 337} 338 339void 340GarnetSyntheticTraffic::doRetry() 341{ 342 if (cachePort.sendTimingReq(retryPkt)) { 343 retryPkt = NULL; 344 } 345} 346 347void 348GarnetSyntheticTraffic::printAddr(Addr a) 349{ 350 cachePort.printAddr(a); 351} 352 353 354GarnetSyntheticTraffic * 355GarnetSyntheticTrafficParams::create() 356{ 357 return new GarnetSyntheticTraffic(this); 358} 359