2 * Copyright (c) 2012-2013, 2016-2018 ARM Limited
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.
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.
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.
37 * Authors: Thomas Grass
41 #include "cpu/testers/traffic_gen/base.hh"
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"
64 #include "cpu/testers/traffic_gen/trace_gen.hh"
70 BaseTrafficGen::BaseTrafficGen(const BaseTrafficGenParams
* p
)
73 elasticReq(p
->elastic_req
),
74 progressCheck(p
->progress_check
),
75 noProgressEvent([this]{ noProgress(); }, name()),
76 nextTransitionTick(0),
78 port(name() + ".port", *this),
81 updateEvent([this]{ update(); }, name()),
82 masterID(system
->getMasterId(this)),
83 streamGenerator(StreamGen::create(p
))
87 BaseTrafficGen::~BaseTrafficGen()
92 BaseTrafficGen::getPort(const string
&if_name
, PortID idx
)
94 if (if_name
== "port") {
97 return MemObject::getPort(if_name
, idx
);
102 BaseTrafficGen::init()
106 if (!port
.isConnected())
107 fatal("The port of %s is not connected!\n", name());
111 BaseTrafficGen::drain()
113 if (!updateEvent
.scheduled()) {
114 // no event has been scheduled yet (e.g. switched from atomic mode)
115 return DrainState::Drained
;
118 if (retryPkt
== NULL
) {
120 nextPacketTick
= MaxTick
;
121 nextTransitionTick
= MaxTick
;
122 deschedule(updateEvent
);
123 return DrainState::Drained
;
125 return DrainState::Draining
;
130 BaseTrafficGen::serialize(CheckpointOut
&cp
) const
132 warn("%s serialization does not keep all traffic generator"
133 " internal state\n", name());
135 DPRINTF(Checkpoint
, "Serializing BaseTrafficGen\n");
137 // save ticks of the graph event if it is scheduled
138 Tick nextEvent
= updateEvent
.scheduled() ? updateEvent
.when() : 0;
140 DPRINTF(TrafficGen
, "Saving nextEvent=%llu\n", nextEvent
);
142 SERIALIZE_SCALAR(nextEvent
);
144 SERIALIZE_SCALAR(nextTransitionTick
);
146 SERIALIZE_SCALAR(nextPacketTick
);
150 BaseTrafficGen::unserialize(CheckpointIn
&cp
)
152 warn("%s serialization does not restore all traffic generator"
153 " internal state\n", name());
155 // restore scheduled events
157 UNSERIALIZE_SCALAR(nextEvent
);
159 schedule(updateEvent
, nextEvent
);
161 UNSERIALIZE_SCALAR(nextTransitionTick
);
163 UNSERIALIZE_SCALAR(nextPacketTick
);
167 BaseTrafficGen::update()
169 // shift our progress-tracking event forward
170 reschedule(noProgressEvent
, curTick() + progressCheck
, true);
172 // if we have reached the time for the next state transition, then
173 // perform the transition
174 if (curTick() >= nextTransitionTick
) {
177 assert(curTick() >= nextPacketTick
);
178 // get the next packet and try to send it
179 PacketPtr pkt
= activeGenerator
->getNextPacket();
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();
187 pkt
->req
->setStreamId(sid
);
189 if (streamGenerator
->ssidValid()) {
190 pkt
->req
->setSubStreamId(ssid
);
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())) {
198 if (!port
.sendTimingReq(pkt
)) {
200 retryPktTick
= curTick();
203 DPRINTF(TrafficGen
, "Suppressed packet %s 0x%x\n",
204 pkt
->cmdString(), pkt
->getAddr());
207 if (!(static_cast<int>(numSuppressed
.value()) % 10000))
208 warn("%s suppressed %d packets with non-memory addresses\n",
209 name(), numSuppressed
.value());
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);
226 BaseTrafficGen::transition()
229 activeGenerator
->exit();
231 activeGenerator
= nextGenerator();
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
;
241 nextTransitionTick
= MaxTick
;
244 activeGenerator
->enter();
245 nextPacketTick
= activeGenerator
->nextPacketTick(elasticReq
, 0);
247 nextPacketTick
= MaxTick
;
248 nextTransitionTick
= MaxTick
;
249 assert(!updateEvent
.scheduled());
254 BaseTrafficGen::scheduleUpdate()
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
) {
263 if (!activeGenerator
)
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
);
270 DPRINTF(TrafficGen
, "Next event scheduled at %lld\n", nextEventTick
);
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
));
278 BaseTrafficGen::start()
285 BaseTrafficGen::recvReqRetry()
287 assert(retryPkt
!= NULL
);
289 DPRINTF(TrafficGen
, "Received retry\n");
291 // attempt to send the packet, and if we are successful start up
292 // the machinery again
293 if (port
.sendTimingReq(retryPkt
)) {
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
;
302 if (drainState() != DrainState::Draining
) {
303 // packet is sent, so find out when the next one is due
304 nextPacketTick
= activeGenerator
->nextPacketTick(elasticReq
,
309 nextPacketTick
= MaxTick
;
310 nextTransitionTick
= MaxTick
;
317 BaseTrafficGen::noProgress()
319 fatal("BaseTrafficGen %s spent %llu ticks without making progress",
320 name(), progressCheck
);
324 BaseTrafficGen::regStats()
326 ClockedObject::regStats();
328 // Initialise all the stats
329 using namespace Stats
;
332 .name(name() + ".numPackets")
333 .desc("Number of packets generated");
336 .name(name() + ".numSuppressed")
337 .desc("Number of suppressed packets to non-memory space");
340 .name(name() + ".numRetries")
341 .desc("Number of retries");
344 .name(name() + ".retryTicks")
345 .desc("Time spent waiting due to back-pressure (ticks)");
348 std::shared_ptr
<BaseGen
>
349 BaseTrafficGen::createIdle(Tick duration
)
351 return std::shared_ptr
<BaseGen
>(new IdleGen(*this, masterID
, duration
));
354 std::shared_ptr
<BaseGen
>
355 BaseTrafficGen::createExit(Tick duration
)
357 return std::shared_ptr
<BaseGen
>(new ExitGen(*this, masterID
, duration
));
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
)
366 return std::shared_ptr
<BaseGen
>(new LinearGen(*this, masterID
,
367 duration
, start_addr
,
369 system
->cacheLineSize(),
370 min_period
, max_period
,
371 read_percent
, data_limit
));
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
)
380 return std::shared_ptr
<BaseGen
>(new RandomGen(*this, masterID
,
381 duration
, start_addr
,
383 system
->cacheLineSize(),
384 min_period
, max_period
,
385 read_percent
, data_limit
));
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
)
399 return std::shared_ptr
<BaseGen
>(new DramGen(*this, masterID
,
400 duration
, start_addr
,
402 system
->cacheLineSize(),
403 min_period
, max_period
,
404 read_percent
, data_limit
,
405 num_seq_pkts
, page_size
,
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
)
425 return std::shared_ptr
<BaseGen
>(new DramRotGen(*this, masterID
,
426 duration
, start_addr
,
428 system
->cacheLineSize(),
429 min_period
, max_period
,
430 read_percent
, data_limit
,
431 num_seq_pkts
, page_size
,
436 max_seq_count_per_rank
));
439 std::shared_ptr
<BaseGen
>
440 BaseTrafficGen::createTrace(Tick duration
,
441 const std::string
& trace_file
, Addr addr_offset
)
444 return std::shared_ptr
<BaseGen
>(
445 new TraceGen(*this, masterID
, duration
, trace_file
, addr_offset
));
447 panic("Can't instantiate trace generation without Protobuf support!\n");
452 BaseTrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt
)