arch, cpu, dev, gpu, mem, sim, python: start using getPort.
[gem5.git] / src / cpu / testers / traffic_gen / base.cc
1 /*
2 * Copyright (c) 2012-2013, 2016-2018 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Thomas Grass
38 * Andreas Hansson
39 * Sascha Bischoff
40 */
41 #include "cpu/testers/traffic_gen/base.hh"
42
43 #include <sstream>
44
45 #include "base/intmath.hh"
46 #include "base/random.hh"
47 #include "config/have_protobuf.hh"
48 #include "cpu/testers/traffic_gen/base_gen.hh"
49 #include "cpu/testers/traffic_gen/dram_gen.hh"
50 #include "cpu/testers/traffic_gen/dram_rot_gen.hh"
51 #include "cpu/testers/traffic_gen/exit_gen.hh"
52 #include "cpu/testers/traffic_gen/idle_gen.hh"
53 #include "cpu/testers/traffic_gen/linear_gen.hh"
54 #include "cpu/testers/traffic_gen/random_gen.hh"
55 #include "cpu/testers/traffic_gen/stream_gen.hh"
56 #include "debug/Checkpoint.hh"
57 #include "debug/TrafficGen.hh"
58 #include "params/BaseTrafficGen.hh"
59 #include "sim/sim_exit.hh"
60 #include "sim/stats.hh"
61 #include "sim/system.hh"
62
63 #if HAVE_PROTOBUF
64 #include "cpu/testers/traffic_gen/trace_gen.hh"
65 #endif
66
67
68 using namespace std;
69
70 BaseTrafficGen::BaseTrafficGen(const BaseTrafficGenParams* p)
71 : MemObject(p),
72 system(p->system),
73 elasticReq(p->elastic_req),
74 progressCheck(p->progress_check),
75 noProgressEvent([this]{ noProgress(); }, name()),
76 nextTransitionTick(0),
77 nextPacketTick(0),
78 port(name() + ".port", *this),
79 retryPkt(NULL),
80 retryPktTick(0),
81 updateEvent([this]{ update(); }, name()),
82 masterID(system->getMasterId(this)),
83 streamGenerator(StreamGen::create(p))
84 {
85 }
86
87 BaseTrafficGen::~BaseTrafficGen()
88 {
89 }
90
91 Port &
92 BaseTrafficGen::getPort(const string &if_name, PortID idx)
93 {
94 if (if_name == "port") {
95 return port;
96 } else {
97 return MemObject::getPort(if_name, idx);
98 }
99 }
100
101 void
102 BaseTrafficGen::init()
103 {
104 MemObject::init();
105
106 if (!port.isConnected())
107 fatal("The port of %s is not connected!\n", name());
108 }
109
110 DrainState
111 BaseTrafficGen::drain()
112 {
113 if (!updateEvent.scheduled()) {
114 // no event has been scheduled yet (e.g. switched from atomic mode)
115 return DrainState::Drained;
116 }
117
118 if (retryPkt == NULL) {
119 // shut things down
120 nextPacketTick = MaxTick;
121 nextTransitionTick = MaxTick;
122 deschedule(updateEvent);
123 return DrainState::Drained;
124 } else {
125 return DrainState::Draining;
126 }
127 }
128
129 void
130 BaseTrafficGen::serialize(CheckpointOut &cp) const
131 {
132 warn("%s serialization does not keep all traffic generator"
133 " internal state\n", name());
134
135 DPRINTF(Checkpoint, "Serializing BaseTrafficGen\n");
136
137 // save ticks of the graph event if it is scheduled
138 Tick nextEvent = updateEvent.scheduled() ? updateEvent.when() : 0;
139
140 DPRINTF(TrafficGen, "Saving nextEvent=%llu\n", nextEvent);
141
142 SERIALIZE_SCALAR(nextEvent);
143
144 SERIALIZE_SCALAR(nextTransitionTick);
145
146 SERIALIZE_SCALAR(nextPacketTick);
147 }
148
149 void
150 BaseTrafficGen::unserialize(CheckpointIn &cp)
151 {
152 warn("%s serialization does not restore all traffic generator"
153 " internal state\n", name());
154
155 // restore scheduled events
156 Tick nextEvent;
157 UNSERIALIZE_SCALAR(nextEvent);
158 if (nextEvent != 0)
159 schedule(updateEvent, nextEvent);
160
161 UNSERIALIZE_SCALAR(nextTransitionTick);
162
163 UNSERIALIZE_SCALAR(nextPacketTick);
164 }
165
166 void
167 BaseTrafficGen::update()
168 {
169 // shift our progress-tracking event forward
170 reschedule(noProgressEvent, curTick() + progressCheck, true);
171
172 // if we have reached the time for the next state transition, then
173 // perform the transition
174 if (curTick() >= nextTransitionTick) {
175 transition();
176 } else {
177 assert(curTick() >= nextPacketTick);
178 // get the next packet and try to send it
179 PacketPtr pkt = activeGenerator->getNextPacket();
180
181 // If generating stream/substream IDs are enabled,
182 // try to pick and assign them to the new packet
183 if (streamGenerator) {
184 auto sid = streamGenerator->pickStreamID();
185 auto ssid = streamGenerator->pickSubStreamID();
186
187 pkt->req->setStreamId(sid);
188
189 if (streamGenerator->ssidValid()) {
190 pkt->req->setSubStreamId(ssid);
191 }
192 }
193
194 // suppress packets that are not destined for a memory, such as
195 // device accesses that could be part of a trace
196 if (pkt && system->isMemAddr(pkt->getAddr())) {
197 numPackets++;
198 if (!port.sendTimingReq(pkt)) {
199 retryPkt = pkt;
200 retryPktTick = curTick();
201 }
202 } else if (pkt) {
203 DPRINTF(TrafficGen, "Suppressed packet %s 0x%x\n",
204 pkt->cmdString(), pkt->getAddr());
205
206 ++numSuppressed;
207 if (!(static_cast<int>(numSuppressed.value()) % 10000))
208 warn("%s suppressed %d packets with non-memory addresses\n",
209 name(), numSuppressed.value());
210
211 delete pkt;
212 pkt = nullptr;
213 }
214 }
215
216 // if we are waiting for a retry, do not schedule any further
217 // events, in the case of a transition or a successful send, go
218 // ahead and determine when the next update should take place
219 if (retryPkt == NULL) {
220 nextPacketTick = activeGenerator->nextPacketTick(elasticReq, 0);
221 scheduleUpdate();
222 }
223 }
224
225 void
226 BaseTrafficGen::transition()
227 {
228 if (activeGenerator)
229 activeGenerator->exit();
230
231 activeGenerator = nextGenerator();
232
233 if (activeGenerator) {
234 const Tick duration = activeGenerator->duration;
235 if (duration != MaxTick && duration != 0) {
236 // we could have been delayed and not transitioned on the
237 // exact tick when we were supposed to (due to back
238 // pressure when sending a packet)
239 nextTransitionTick = curTick() + duration;
240 } else {
241 nextTransitionTick = MaxTick;
242 }
243
244 activeGenerator->enter();
245 nextPacketTick = activeGenerator->nextPacketTick(elasticReq, 0);
246 } else {
247 nextPacketTick = MaxTick;
248 nextTransitionTick = MaxTick;
249 assert(!updateEvent.scheduled());
250 }
251 }
252
253 void
254 BaseTrafficGen::scheduleUpdate()
255 {
256 // Has the generator run out of work? In that case, force a
257 // transition if a transition period hasn't been configured.
258 while (activeGenerator &&
259 nextPacketTick == MaxTick && nextTransitionTick == MaxTick) {
260 transition();
261 }
262
263 if (!activeGenerator)
264 return;
265
266 // schedule next update event based on either the next execute
267 // tick or the next transition, which ever comes first
268 const Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
269
270 DPRINTF(TrafficGen, "Next event scheduled at %lld\n", nextEventTick);
271
272 // The next transition tick may be in the past if there was a
273 // retry, so ensure that we don't schedule anything in the past.
274 schedule(updateEvent, std::max(curTick(), nextEventTick));
275 }
276
277 void
278 BaseTrafficGen::start()
279 {
280 transition();
281 scheduleUpdate();
282 }
283
284 void
285 BaseTrafficGen::recvReqRetry()
286 {
287 assert(retryPkt != NULL);
288
289 DPRINTF(TrafficGen, "Received retry\n");
290 numRetries++;
291 // attempt to send the packet, and if we are successful start up
292 // the machinery again
293 if (port.sendTimingReq(retryPkt)) {
294 retryPkt = NULL;
295 // remember how much delay was incurred due to back-pressure
296 // when sending the request, we also use this to derive
297 // the tick for the next packet
298 Tick delay = curTick() - retryPktTick;
299 retryPktTick = 0;
300 retryTicks += delay;
301
302 if (drainState() != DrainState::Draining) {
303 // packet is sent, so find out when the next one is due
304 nextPacketTick = activeGenerator->nextPacketTick(elasticReq,
305 delay);
306 scheduleUpdate();
307 } else {
308 // shut things down
309 nextPacketTick = MaxTick;
310 nextTransitionTick = MaxTick;
311 signalDrainDone();
312 }
313 }
314 }
315
316 void
317 BaseTrafficGen::noProgress()
318 {
319 fatal("BaseTrafficGen %s spent %llu ticks without making progress",
320 name(), progressCheck);
321 }
322
323 void
324 BaseTrafficGen::regStats()
325 {
326 ClockedObject::regStats();
327
328 // Initialise all the stats
329 using namespace Stats;
330
331 numPackets
332 .name(name() + ".numPackets")
333 .desc("Number of packets generated");
334
335 numSuppressed
336 .name(name() + ".numSuppressed")
337 .desc("Number of suppressed packets to non-memory space");
338
339 numRetries
340 .name(name() + ".numRetries")
341 .desc("Number of retries");
342
343 retryTicks
344 .name(name() + ".retryTicks")
345 .desc("Time spent waiting due to back-pressure (ticks)");
346 }
347
348 std::shared_ptr<BaseGen>
349 BaseTrafficGen::createIdle(Tick duration)
350 {
351 return std::shared_ptr<BaseGen>(new IdleGen(*this, masterID, duration));
352 }
353
354 std::shared_ptr<BaseGen>
355 BaseTrafficGen::createExit(Tick duration)
356 {
357 return std::shared_ptr<BaseGen>(new ExitGen(*this, masterID, duration));
358 }
359
360 std::shared_ptr<BaseGen>
361 BaseTrafficGen::createLinear(Tick duration,
362 Addr start_addr, Addr end_addr, Addr blocksize,
363 Tick min_period, Tick max_period,
364 uint8_t read_percent, Addr data_limit)
365 {
366 return std::shared_ptr<BaseGen>(new LinearGen(*this, masterID,
367 duration, start_addr,
368 end_addr, blocksize,
369 system->cacheLineSize(),
370 min_period, max_period,
371 read_percent, data_limit));
372 }
373
374 std::shared_ptr<BaseGen>
375 BaseTrafficGen::createRandom(Tick duration,
376 Addr start_addr, Addr end_addr, Addr blocksize,
377 Tick min_period, Tick max_period,
378 uint8_t read_percent, Addr data_limit)
379 {
380 return std::shared_ptr<BaseGen>(new RandomGen(*this, masterID,
381 duration, start_addr,
382 end_addr, blocksize,
383 system->cacheLineSize(),
384 min_period, max_period,
385 read_percent, data_limit));
386 }
387
388 std::shared_ptr<BaseGen>
389 BaseTrafficGen::createDram(Tick duration,
390 Addr start_addr, Addr end_addr, Addr blocksize,
391 Tick min_period, Tick max_period,
392 uint8_t read_percent, Addr data_limit,
393 unsigned int num_seq_pkts, unsigned int page_size,
394 unsigned int nbr_of_banks_DRAM,
395 unsigned int nbr_of_banks_util,
396 unsigned int addr_mapping,
397 unsigned int nbr_of_ranks)
398 {
399 return std::shared_ptr<BaseGen>(new DramGen(*this, masterID,
400 duration, start_addr,
401 end_addr, blocksize,
402 system->cacheLineSize(),
403 min_period, max_period,
404 read_percent, data_limit,
405 num_seq_pkts, page_size,
406 nbr_of_banks_DRAM,
407 nbr_of_banks_util,
408 addr_mapping,
409 nbr_of_ranks));
410 }
411
412 std::shared_ptr<BaseGen>
413 BaseTrafficGen::createDramRot(Tick duration,
414 Addr start_addr, Addr end_addr, Addr blocksize,
415 Tick min_period, Tick max_period,
416 uint8_t read_percent, Addr data_limit,
417 unsigned int num_seq_pkts,
418 unsigned int page_size,
419 unsigned int nbr_of_banks_DRAM,
420 unsigned int nbr_of_banks_util,
421 unsigned int addr_mapping,
422 unsigned int nbr_of_ranks,
423 unsigned int max_seq_count_per_rank)
424 {
425 return std::shared_ptr<BaseGen>(new DramRotGen(*this, masterID,
426 duration, start_addr,
427 end_addr, blocksize,
428 system->cacheLineSize(),
429 min_period, max_period,
430 read_percent, data_limit,
431 num_seq_pkts, page_size,
432 nbr_of_banks_DRAM,
433 nbr_of_banks_util,
434 addr_mapping,
435 nbr_of_ranks,
436 max_seq_count_per_rank));
437 }
438
439 std::shared_ptr<BaseGen>
440 BaseTrafficGen::createTrace(Tick duration,
441 const std::string& trace_file, Addr addr_offset)
442 {
443 #if HAVE_PROTOBUF
444 return std::shared_ptr<BaseGen>(
445 new TraceGen(*this, masterID, duration, trace_file, addr_offset));
446 #else
447 panic("Can't instantiate trace generation without Protobuf support!\n");
448 #endif
449 }
450
451 bool
452 BaseTrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
453 {
454 delete pkt;
455
456 return true;
457 }