9d8732902b74c44b8ef9f75425103e0775ee7b43
2 * Copyright (c) 2012-2013, 2016 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/traffic_gen.hh"
48 #include "base/intmath.hh"
49 #include "base/random.hh"
50 #include "debug/Checkpoint.hh"
51 #include "debug/TrafficGen.hh"
52 #include "sim/stats.hh"
53 #include "sim/system.hh"
57 TrafficGen::TrafficGen(const TrafficGenParams
* p
)
60 masterID(system
->getMasterId(name())),
61 configFile(p
->config_file
),
62 elasticReq(p
->elastic_req
),
63 progressCheck(p
->progress_check
),
64 noProgressEvent([this]{ noProgress(); }, name()),
65 nextTransitionTick(0),
68 port(name() + ".port", *this),
71 updateEvent([this]{ update(); }, name()),
77 TrafficGenParams::create()
79 return new TrafficGen(this);
83 TrafficGen::getMasterPort(const string
& if_name
, PortID idx
)
85 if (if_name
== "port") {
88 return MemObject::getMasterPort(if_name
, idx
);
95 if (!port
.isConnected())
96 fatal("The port of %s is not connected!\n", name());
98 // if the system is in timing mode active the request generator
99 if (system
->isTimingMode()) {
100 DPRINTF(TrafficGen
, "Timing mode, activating request generator\n");
104 // enter initial state
105 enterState(currState
);
108 "Traffic generator is only active in timing mode\n");
113 TrafficGen::initState()
115 // when not restoring from a checkpoint, make sure we kick things off
116 if (system
->isTimingMode()) {
117 // call nextPacketTick on the state to advance it
118 nextPacketTick
= states
[currState
]->nextPacketTick(elasticReq
, 0);
119 schedule(updateEvent
, std::min(nextPacketTick
, nextTransitionTick
));
122 "Traffic generator is only active in timing mode\n");
129 if (!updateEvent
.scheduled()) {
130 // no event has been scheduled yet (e.g. switched from atomic mode)
131 return DrainState::Drained
;
134 if (retryPkt
== NULL
) {
136 nextPacketTick
= MaxTick
;
137 nextTransitionTick
= MaxTick
;
138 deschedule(updateEvent
);
139 return DrainState::Drained
;
141 return DrainState::Draining
;
146 TrafficGen::serialize(CheckpointOut
&cp
) const
148 DPRINTF(Checkpoint
, "Serializing TrafficGen\n");
150 // save ticks of the graph event if it is scheduled
151 Tick nextEvent
= updateEvent
.scheduled() ? updateEvent
.when() : 0;
153 DPRINTF(TrafficGen
, "Saving nextEvent=%llu\n", nextEvent
);
155 SERIALIZE_SCALAR(nextEvent
);
157 SERIALIZE_SCALAR(nextTransitionTick
);
159 SERIALIZE_SCALAR(nextPacketTick
);
161 SERIALIZE_SCALAR(currState
);
165 TrafficGen::unserialize(CheckpointIn
&cp
)
167 // restore scheduled events
169 UNSERIALIZE_SCALAR(nextEvent
);
170 if (nextEvent
!= 0) {
171 schedule(updateEvent
, nextEvent
);
174 UNSERIALIZE_SCALAR(nextTransitionTick
);
176 UNSERIALIZE_SCALAR(nextPacketTick
);
178 // @todo In the case of a stateful generator state such as the
179 // trace player we would also have to restore the position in the
180 // trace playback and the tick offset
181 UNSERIALIZE_SCALAR(currState
);
187 // shift our progress-tracking event forward
188 reschedule(noProgressEvent
, curTick() + progressCheck
, true);
190 // if we have reached the time for the next state transition, then
191 // perform the transition
192 if (curTick() >= nextTransitionTick
) {
195 assert(curTick() >= nextPacketTick
);
196 // get the next packet and try to send it
197 PacketPtr pkt
= states
[currState
]->getNextPacket();
199 // suppress packets that are not destined for a memory, such as
200 // device accesses that could be part of a trace
201 if (system
->isMemAddr(pkt
->getAddr())) {
203 if (!port
.sendTimingReq(pkt
)) {
205 retryPktTick
= curTick();
208 DPRINTF(TrafficGen
, "Suppressed packet %s 0x%x\n",
209 pkt
->cmdString(), pkt
->getAddr());
212 if (numSuppressed
% 10000)
213 warn("%s suppressed %d packets with non-memory addresses\n",
214 name(), numSuppressed
);
222 // if we are waiting for a retry, do not schedule any further
223 // events, in the case of a transition or a successful send, go
224 // ahead and determine when the next update should take place
225 if (retryPkt
== NULL
) {
226 // schedule next update event based on either the next execute
227 // tick or the next transition, which ever comes first
228 nextPacketTick
= states
[currState
]->nextPacketTick(elasticReq
, 0);
229 Tick nextEventTick
= std::min(nextPacketTick
, nextTransitionTick
);
230 DPRINTF(TrafficGen
, "Next event scheduled at %lld\n", nextEventTick
);
231 schedule(updateEvent
, nextEventTick
);
236 TrafficGen::resolveFile(const std::string
&name
)
238 // Do nothing for empty and absolute file names
239 if (name
.empty() || name
[0] == '/')
242 char *config_path
= strdup(configFile
.c_str());
243 char *config_dir
= dirname(config_path
);
244 const std::string config_rel
= csprintf("%s/%s", config_dir
, name
);
247 // Check the path relative to the config file first
248 if (access(config_rel
.c_str(), R_OK
) == 0)
251 // Fall back to the old behavior and search relative to the
252 // current working directory.
257 TrafficGen::parseConfig()
259 // keep track of the transitions parsed to create the matrix when
261 vector
<Transition
> transitions
;
265 infile
.open(configFile
.c_str(), ifstream::in
);
266 if (!infile
.is_open()) {
267 fatal("Traffic generator %s config file not found at %s\n",
271 bool init_state_set
= false;
273 // read line by line and determine the action based on the first
278 while (getline(infile
, line
).good()) {
279 // see if this line is a comment line, and if so skip it
280 if (line
.find('#') != 1) {
281 // create an input stream for the tokenization
282 istringstream
is(line
);
284 // determine the keyword
287 if (keyword
== "STATE") {
288 // parse the behaviour of this state
293 is
>> id
>> duration
>> mode
;
295 if (mode
== "TRACE") {
299 is
>> traceFile
>> addrOffset
;
300 traceFile
= resolveFile(traceFile
);
302 states
[id
] = new TraceGen(name(), masterID
, duration
,
303 traceFile
, addrOffset
);
304 DPRINTF(TrafficGen
, "State: %d TraceGen\n", id
);
305 } else if (mode
== "IDLE") {
306 states
[id
] = new IdleGen(name(), masterID
, duration
);
307 DPRINTF(TrafficGen
, "State: %d IdleGen\n", id
);
308 } else if (mode
== "LINEAR" || mode
== "RANDOM" ||
309 mode
== "DRAM" || mode
== "DRAM_ROTATE") {
310 uint32_t read_percent
;
318 is
>> read_percent
>> start_addr
>> end_addr
>>
319 blocksize
>> min_period
>> max_period
>> data_limit
;
321 DPRINTF(TrafficGen
, "%s, addr %x to %x, size %d,"
322 " period %d to %d, %d%% reads\n",
323 mode
, start_addr
, end_addr
, blocksize
, min_period
,
324 max_period
, read_percent
);
327 if (blocksize
> system
->cacheLineSize())
328 fatal("TrafficGen %s block size (%d) is larger than "
329 "cache line size (%d)\n", name(),
330 blocksize
, system
->cacheLineSize());
332 if (read_percent
> 100)
333 fatal("%s cannot have more than 100% reads", name());
335 if (min_period
> max_period
)
336 fatal("%s cannot have min_period > max_period", name());
338 if (mode
== "LINEAR") {
339 states
[id
] = new LinearGen(name(), masterID
,
340 duration
, start_addr
,
342 min_period
, max_period
,
343 read_percent
, data_limit
);
344 DPRINTF(TrafficGen
, "State: %d LinearGen\n", id
);
345 } else if (mode
== "RANDOM") {
346 states
[id
] = new RandomGen(name(), masterID
,
347 duration
, start_addr
,
349 min_period
, max_period
,
350 read_percent
, data_limit
);
351 DPRINTF(TrafficGen
, "State: %d RandomGen\n", id
);
352 } else if (mode
== "DRAM" || mode
== "DRAM_ROTATE") {
353 // stride size (bytes) of the request for achieving
354 // required hit length
355 unsigned int stride_size
;
356 unsigned int page_size
;
357 unsigned int nbr_of_banks_DRAM
;
358 unsigned int nbr_of_banks_util
;
359 unsigned int addr_mapping
;
360 unsigned int nbr_of_ranks
;
362 is
>> stride_size
>> page_size
>> nbr_of_banks_DRAM
>>
363 nbr_of_banks_util
>> addr_mapping
>>
366 if (stride_size
> page_size
)
367 warn("DRAM generator stride size (%d) is greater "
368 "than page size (%d) of the memory\n",
369 blocksize
, page_size
);
371 if (nbr_of_banks_util
> nbr_of_banks_DRAM
)
372 fatal("Attempting to use more banks (%d) than "
373 "what is available (%d)\n",
374 nbr_of_banks_util
, nbr_of_banks_DRAM
);
376 // count the number of sequential packets to
378 unsigned int num_seq_pkts
= 1;
380 if (stride_size
> blocksize
) {
381 num_seq_pkts
= divCeil(stride_size
, blocksize
);
382 DPRINTF(TrafficGen
, "stride size: %d "
383 "block size: %d, num_seq_pkts: %d\n",
384 stride_size
, blocksize
, num_seq_pkts
);
387 if (mode
== "DRAM") {
388 states
[id
] = new DramGen(name(), masterID
,
389 duration
, start_addr
,
391 min_period
, max_period
,
392 read_percent
, data_limit
,
393 num_seq_pkts
, page_size
,
398 DPRINTF(TrafficGen
, "State: %d DramGen\n", id
);
400 // Will rotate to the next rank after rotating
401 // through all banks, for each command type.
402 // In the 50% read case, series will be issued
403 // for both RD & WR before the rank in incremented
404 unsigned int max_seq_count_per_rank
=
405 (read_percent
== 50) ? nbr_of_banks_util
* 2
408 states
[id
] = new DramRotGen(name(), masterID
,
409 duration
, start_addr
,
411 min_period
, max_period
,
412 read_percent
, data_limit
,
413 num_seq_pkts
, page_size
,
418 max_seq_count_per_rank
);
419 DPRINTF(TrafficGen
, "State: %d DramRotGen\n", id
);
423 fatal("%s: Unknown traffic generator mode: %s",
426 } else if (keyword
== "TRANSITION") {
427 Transition transition
;
429 is
>> transition
.from
>> transition
.to
>> transition
.p
;
431 transitions
.push_back(transition
);
433 DPRINTF(TrafficGen
, "Transition: %d -> %d\n", transition
.from
,
435 } else if (keyword
== "INIT") {
436 // set the initial state as the active state
439 init_state_set
= true;
441 DPRINTF(TrafficGen
, "Initial state: %d\n", currState
);
447 fatal("%s: initial state not specified (add 'INIT <id>' line "
448 "to the config file)\n", name());
450 // resize and populate state transition matrix
451 transitionMatrix
.resize(states
.size());
452 for (size_t i
= 0; i
< states
.size(); i
++) {
453 transitionMatrix
[i
].resize(states
.size());
456 for (vector
<Transition
>::iterator t
= transitions
.begin();
457 t
!= transitions
.end(); ++t
) {
458 transitionMatrix
[t
->from
][t
->to
] = t
->p
;
461 // ensure the egress edges do not have a probability larger than
463 for (size_t i
= 0; i
< states
.size(); i
++) {
465 for (size_t j
= 0; j
< states
.size(); j
++) {
466 sum
+= transitionMatrix
[i
][j
];
469 // avoid comparing floating point numbers
470 if (abs(sum
- 1.0) > 0.001)
471 fatal("%s has transition probability != 1 for state %d\n",
480 TrafficGen::transition()
482 // exit the current state
483 states
[currState
]->exit();
485 // determine next state
486 double p
= random_mt
.random
<double>();
487 assert(currState
< transitionMatrix
.size());
488 double cumulative
= 0.0;
491 cumulative
+= transitionMatrix
[currState
][i
];
493 } while (cumulative
< p
&& i
< transitionMatrix
[currState
].size());
499 TrafficGen::enterState(uint32_t newState
)
501 DPRINTF(TrafficGen
, "Transition to state %d\n", newState
);
503 currState
= newState
;
504 // we could have been delayed and not transitioned on the exact
505 // tick when we were supposed to (due to back pressure when
507 nextTransitionTick
= curTick() + states
[currState
]->duration
;
508 states
[currState
]->enter();
512 TrafficGen::recvReqRetry()
514 assert(retryPkt
!= NULL
);
516 DPRINTF(TrafficGen
, "Received retry\n");
518 // attempt to send the packet, and if we are successful start up
519 // the machinery again
520 if (port
.sendTimingReq(retryPkt
)) {
522 // remember how much delay was incurred due to back-pressure
523 // when sending the request, we also use this to derive
524 // the tick for the next packet
525 Tick delay
= curTick() - retryPktTick
;
529 if (drainState() != DrainState::Draining
) {
530 // packet is sent, so find out when the next one is due
531 nextPacketTick
= states
[currState
]->nextPacketTick(elasticReq
,
533 Tick nextEventTick
= std::min(nextPacketTick
, nextTransitionTick
);
534 schedule(updateEvent
, std::max(curTick(), nextEventTick
));
537 nextPacketTick
= MaxTick
;
538 nextTransitionTick
= MaxTick
;
545 TrafficGen::noProgress()
547 fatal("TrafficGen %s spent %llu ticks without making progress",
548 name(), progressCheck
);
552 TrafficGen::regStats()
554 ClockedObject::regStats();
556 // Initialise all the stats
557 using namespace Stats
;
560 .name(name() + ".numPackets")
561 .desc("Number of packets generated");
564 .name(name() + ".numRetries")
565 .desc("Number of retries");
568 .name(name() + ".retryTicks")
569 .desc("Time spent waiting due to back-pressure (ticks)");
573 TrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt
)