2 * Copyright (c) 2016 Georgia Institute of Technology
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.
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.
29 #include "cpu/testers/garnet_synthetic_traffic/GarnetSyntheticTraffic.hh"
37 #include "base/logging.hh"
38 #include "base/random.hh"
39 #include "base/statistics.hh"
40 #include "debug/GarnetSyntheticTraffic.hh"
41 #include "mem/packet.hh"
42 #include "mem/port.hh"
43 #include "mem/request.hh"
44 #include "sim/sim_events.hh"
45 #include "sim/stats.hh"
46 #include "sim/system.hh"
53 GarnetSyntheticTraffic::CpuPort::recvTimingResp(PacketPtr pkt
)
55 tester
->completeRequest(pkt
);
60 GarnetSyntheticTraffic::CpuPort::recvReqRetry()
66 GarnetSyntheticTraffic::sendPkt(PacketPtr pkt
)
68 if (!cachePort
.sendTimingReq(pkt
)) {
69 retryPkt
= pkt
; // RubyPort will retry sending
74 GarnetSyntheticTraffic::GarnetSyntheticTraffic(const Params
&p
)
76 tickEvent([this]{ tick(); }, "GarnetSyntheticTraffic tick",
77 false, Event::CPU_Tick_Pri
),
78 cachePort("GarnetSyntheticTraffic", this),
81 blockSizeBits(p
.block_offset
),
82 numDestinations(p
.num_dest
),
83 simCycles(p
.sim_cycles
),
84 numPacketsMax(p
.num_packets_max
),
86 singleSender(p
.single_sender
),
87 singleDest(p
.single_dest
),
88 trafficType(p
.traffic_type
),
91 precision(p
.precision
),
92 responseLimit(p
.response_limit
),
93 requestorId(p
.system
->getRequestorId(this))
97 schedule(tickEvent
, 0);
100 if (trafficStringToEnum
.count(trafficType
) == 0) {
101 fatal("Unknown Traffic Type: %s!\n", traffic
);
103 traffic
= trafficStringToEnum
[trafficType
];
105 id
= TESTER_NETWORK
++;
106 DPRINTF(GarnetSyntheticTraffic
,"Config Created: Name = %s , and id = %d\n",
111 GarnetSyntheticTraffic::getPort(const std::string
&if_name
, PortID idx
)
113 if (if_name
== "test")
116 return ClockedObject::getPort(if_name
, idx
);
120 GarnetSyntheticTraffic::init()
127 GarnetSyntheticTraffic::completeRequest(PacketPtr pkt
)
129 DPRINTF(GarnetSyntheticTraffic
,
130 "Completed injection of %s packet for address %x\n",
131 pkt
->isWrite() ? "write" : "read\n",
132 pkt
->req
->getPaddr());
134 assert(pkt
->isResponse());
135 noResponseCycles
= 0;
141 GarnetSyntheticTraffic::tick()
143 if (++noResponseCycles
>= responseLimit
) {
144 fatal("%s deadlocked at cycle %d\n", name(), curTick());
147 // make new request based on injection rate
148 // (injection rate's range depends on precision)
149 // - generate a random number between 0 and 10^precision
150 // - send pkt if this number is < injRate*(10^precision)
151 bool sendAllowedThisCycle
;
152 double injRange
= pow((double) 10, (double) precision
);
153 unsigned trySending
= random_mt
.random
<unsigned>(0, (int) injRange
);
154 if (trySending
< injRate
*injRange
)
155 sendAllowedThisCycle
= true;
157 sendAllowedThisCycle
= false;
159 // always generatePkt unless fixedPkts or singleSender is enabled
160 if (sendAllowedThisCycle
) {
161 bool senderEnable
= true;
163 if (numPacketsMax
>= 0 && numPacketsSent
>= numPacketsMax
)
164 senderEnable
= false;
166 if (singleSender
>= 0 && id
!= singleSender
)
167 senderEnable
= false;
174 if (curTick() >= simCycles
)
175 exitSimLoop("Network Tester completed simCycles");
177 if (!tickEvent
.scheduled())
178 schedule(tickEvent
, clockEdge(Cycles(1)));
183 GarnetSyntheticTraffic::generatePkt()
185 int num_destinations
= numDestinations
;
186 int radix
= (int) sqrt(num_destinations
);
187 unsigned destination
= id
;
191 int src_x
= id
%radix
;
192 int src_y
= id
/radix
;
196 destination
= singleDest
;
197 } else if (traffic
== UNIFORM_RANDOM_
) {
198 destination
= random_mt
.random
<unsigned>(0, num_destinations
- 1);
199 } else if (traffic
== BIT_COMPLEMENT_
) {
200 dest_x
= radix
- src_x
- 1;
201 dest_y
= radix
- src_y
- 1;
202 destination
= dest_y
*radix
+ dest_x
;
203 } else if (traffic
== BIT_REVERSE_
) {
204 unsigned int straight
= source
;
205 unsigned int reverse
= source
& 1; // LSB
207 int num_bits
= (int) log2(num_destinations
);
209 for (int i
= 1; i
< num_bits
; i
++)
213 reverse
|= (straight
& 1); // LSB
215 destination
= reverse
;
216 } else if (traffic
== BIT_ROTATION_
) {
218 destination
= source
/2;
219 else // (source%2 == 1)
220 destination
= ((source
/2) + (num_destinations
/2));
221 } else if (traffic
== NEIGHBOR_
) {
222 dest_x
= (src_x
+ 1) % radix
;
224 destination
= dest_y
*radix
+ dest_x
;
225 } else if (traffic
== SHUFFLE_
) {
226 if (source
< num_destinations
/2)
227 destination
= source
*2;
229 destination
= (source
*2 - num_destinations
+ 1);
230 } else if (traffic
== TRANSPOSE_
) {
233 destination
= dest_y
*radix
+ dest_x
;
234 } else if (traffic
== TORNADO_
) {
235 dest_x
= (src_x
+ (int) ceil(radix
/2) - 1) % radix
;
237 destination
= dest_y
*radix
+ dest_x
;
240 fatal("Unknown Traffic Type: %s!\n", traffic
);
243 // The source of the packets is a cache.
244 // The destination of the packets is a directory.
245 // The destination bits are embedded in the address after byte-offset.
246 Addr paddr
= destination
;
247 paddr
<<= blockSizeBits
;
248 unsigned access_size
= 1; // Does not affect Ruby simulation
250 // Modeling different coherence msg types over different msg classes.
252 // GarnetSyntheticTraffic assumes the Garnet_standalone coherence protocol
253 // which models three message classes/virtual networks.
254 // These are: request, forward, response.
255 // requests and forwards are "control" packets (typically 8 bytes),
256 // while responses are "data" packets (typically 72 bytes).
258 // Life of a packet from the tester into the network:
259 // (1) This function generatePkt() generates packets of one of the
260 // following 3 types (randomly) : ReadReq, INST_FETCH, WriteReq
261 // (2) mem/ruby/system/RubyPort.cc converts these to RubyRequestType_LD,
262 // RubyRequestType_IFETCH, RubyRequestType_ST respectively
263 // (3) mem/ruby/system/Sequencer.cc sends these to the cache controllers
264 // in the coherence protocol.
265 // (4) Network_test-cache.sm tags RubyRequestType:LD,
266 // RubyRequestType:IFETCH and RubyRequestType:ST as
267 // Request, Forward, and Response events respectively;
268 // and injects them into virtual networks 0, 1 and 2 respectively.
269 // It immediately calls back the sequencer.
270 // (5) The packet traverses the network (simple/garnet) and reaches its
271 // destination (Directory), and network stats are updated.
272 // (6) Network_test-dir.sm simply drops the packet.
274 MemCmd::Command requestType
;
276 RequestPtr req
= nullptr;
277 Request::Flags flags
;
279 // Inject in specific Vnet
280 // Vnet 0 and 1 are for control packets (1-flit)
281 // Vnet 2 is for data packets (5-flit)
282 int injReqType
= injVnet
;
284 if (injReqType
< 0 || injReqType
> 2)
286 // randomly inject in any vnet
287 injReqType
= random_mt
.random(0, 2);
290 if (injReqType
== 0) {
291 // generate packet for virtual network 0
292 requestType
= MemCmd::ReadReq
;
293 req
= std::make_shared
<Request
>(paddr
, access_size
, flags
,
295 } else if (injReqType
== 1) {
296 // generate packet for virtual network 1
297 requestType
= MemCmd::ReadReq
;
298 flags
.set(Request::INST_FETCH
);
299 req
= std::make_shared
<Request
>(
300 0x0, access_size
, flags
, requestorId
, 0x0, 0);
301 req
->setPaddr(paddr
);
302 } else { // if (injReqType == 2)
303 // generate packet for virtual network 2
304 requestType
= MemCmd::WriteReq
;
305 req
= std::make_shared
<Request
>(paddr
, access_size
, flags
,
311 //No need to do functional simulation
312 //We just do timing simulation of the network
314 DPRINTF(GarnetSyntheticTraffic
,
315 "Generated packet with destination %d, embedded in address %x\n",
316 destination
, req
->getPaddr());
318 PacketPtr pkt
= new Packet(req
, requestType
);
319 pkt
->dataDynamic(new uint8_t[req
->getSize()]);
320 pkt
->senderState
= NULL
;
326 GarnetSyntheticTraffic::initTrafficType()
328 trafficStringToEnum
["bit_complement"] = BIT_COMPLEMENT_
;
329 trafficStringToEnum
["bit_reverse"] = BIT_REVERSE_
;
330 trafficStringToEnum
["bit_rotation"] = BIT_ROTATION_
;
331 trafficStringToEnum
["neighbor"] = NEIGHBOR_
;
332 trafficStringToEnum
["shuffle"] = SHUFFLE_
;
333 trafficStringToEnum
["tornado"] = TORNADO_
;
334 trafficStringToEnum
["transpose"] = TRANSPOSE_
;
335 trafficStringToEnum
["uniform_random"] = UNIFORM_RANDOM_
;
339 GarnetSyntheticTraffic::doRetry()
341 if (cachePort
.sendTimingReq(retryPkt
)) {
347 GarnetSyntheticTraffic::printAddr(Addr a
)
349 cachePort
.printAddr(a
);