traffic_gen.cc (11393:48b748cc6497) traffic_gen.cc (11491:6ffc99023568)
1/*
1/*
2 * Copyright (c) 2012-2013 ARM Limited
2 * Copyright (c) 2012-2013, 2016 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
42#include <sstream>
43
44#include "base/intmath.hh"
45#include "base/random.hh"
46#include "cpu/testers/traffic_gen/traffic_gen.hh"
47#include "debug/Checkpoint.hh"
48#include "debug/TrafficGen.hh"
49#include "sim/stats.hh"
50#include "sim/system.hh"
51
52using namespace std;
53
54TrafficGen::TrafficGen(const TrafficGenParams* p)
55 : MemObject(p),
56 system(p->system),
57 masterID(system->getMasterId(name())),
58 configFile(p->config_file),
59 elasticReq(p->elastic_req),
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
42#include <sstream>
43
44#include "base/intmath.hh"
45#include "base/random.hh"
46#include "cpu/testers/traffic_gen/traffic_gen.hh"
47#include "debug/Checkpoint.hh"
48#include "debug/TrafficGen.hh"
49#include "sim/stats.hh"
50#include "sim/system.hh"
51
52using namespace std;
53
54TrafficGen::TrafficGen(const TrafficGenParams* p)
55 : MemObject(p),
56 system(p->system),
57 masterID(system->getMasterId(name())),
58 configFile(p->config_file),
59 elasticReq(p->elastic_req),
60 progressCheck(p->progress_check),
61 noProgressEvent(this),
60 nextTransitionTick(0),
61 nextPacketTick(0),
62 currState(0),
63 port(name() + ".port", *this),
64 retryPkt(NULL),
65 retryPktTick(0),
66 updateEvent(this),
67 numSuppressed(0)
68{
69}
70
71TrafficGen*
72TrafficGenParams::create()
73{
74 return new TrafficGen(this);
75}
76
77BaseMasterPort&
78TrafficGen::getMasterPort(const string& if_name, PortID idx)
79{
80 if (if_name == "port") {
81 return port;
82 } else {
83 return MemObject::getMasterPort(if_name, idx);
84 }
85}
86
87void
88TrafficGen::init()
89{
90 if (!port.isConnected())
91 fatal("The port of %s is not connected!\n", name());
92
93 // if the system is in timing mode active the request generator
94 if (system->isTimingMode()) {
95 DPRINTF(TrafficGen, "Timing mode, activating request generator\n");
96
97 parseConfig();
98
99 // enter initial state
100 enterState(currState);
101 } else {
102 DPRINTF(TrafficGen,
103 "Traffic generator is only active in timing mode\n");
104 }
105}
106
107void
108TrafficGen::initState()
109{
110 // when not restoring from a checkpoint, make sure we kick things off
111 if (system->isTimingMode()) {
112 // call nextPacketTick on the state to advance it
113 nextPacketTick = states[currState]->nextPacketTick(elasticReq, 0);
114 schedule(updateEvent, std::min(nextPacketTick, nextTransitionTick));
115 } else {
116 DPRINTF(TrafficGen,
117 "Traffic generator is only active in timing mode\n");
118 }
119}
120
121DrainState
122TrafficGen::drain()
123{
124 if (!updateEvent.scheduled()) {
125 // no event has been scheduled yet (e.g. switched from atomic mode)
126 return DrainState::Drained;
127 }
128
129 if (retryPkt == NULL) {
130 // shut things down
131 nextPacketTick = MaxTick;
132 nextTransitionTick = MaxTick;
133 deschedule(updateEvent);
134 return DrainState::Drained;
135 } else {
136 return DrainState::Draining;
137 }
138}
139
140void
141TrafficGen::serialize(CheckpointOut &cp) const
142{
143 DPRINTF(Checkpoint, "Serializing TrafficGen\n");
144
145 // save ticks of the graph event if it is scheduled
146 Tick nextEvent = updateEvent.scheduled() ? updateEvent.when() : 0;
147
148 DPRINTF(TrafficGen, "Saving nextEvent=%llu\n", nextEvent);
149
150 SERIALIZE_SCALAR(nextEvent);
151
152 SERIALIZE_SCALAR(nextTransitionTick);
153
154 SERIALIZE_SCALAR(nextPacketTick);
155
156 SERIALIZE_SCALAR(currState);
157}
158
159void
160TrafficGen::unserialize(CheckpointIn &cp)
161{
162 // restore scheduled events
163 Tick nextEvent;
164 UNSERIALIZE_SCALAR(nextEvent);
165 if (nextEvent != 0) {
166 schedule(updateEvent, nextEvent);
167 }
168
169 UNSERIALIZE_SCALAR(nextTransitionTick);
170
171 UNSERIALIZE_SCALAR(nextPacketTick);
172
173 // @todo In the case of a stateful generator state such as the
174 // trace player we would also have to restore the position in the
175 // trace playback and the tick offset
176 UNSERIALIZE_SCALAR(currState);
177}
178
179void
180TrafficGen::update()
181{
62 nextTransitionTick(0),
63 nextPacketTick(0),
64 currState(0),
65 port(name() + ".port", *this),
66 retryPkt(NULL),
67 retryPktTick(0),
68 updateEvent(this),
69 numSuppressed(0)
70{
71}
72
73TrafficGen*
74TrafficGenParams::create()
75{
76 return new TrafficGen(this);
77}
78
79BaseMasterPort&
80TrafficGen::getMasterPort(const string& if_name, PortID idx)
81{
82 if (if_name == "port") {
83 return port;
84 } else {
85 return MemObject::getMasterPort(if_name, idx);
86 }
87}
88
89void
90TrafficGen::init()
91{
92 if (!port.isConnected())
93 fatal("The port of %s is not connected!\n", name());
94
95 // if the system is in timing mode active the request generator
96 if (system->isTimingMode()) {
97 DPRINTF(TrafficGen, "Timing mode, activating request generator\n");
98
99 parseConfig();
100
101 // enter initial state
102 enterState(currState);
103 } else {
104 DPRINTF(TrafficGen,
105 "Traffic generator is only active in timing mode\n");
106 }
107}
108
109void
110TrafficGen::initState()
111{
112 // when not restoring from a checkpoint, make sure we kick things off
113 if (system->isTimingMode()) {
114 // call nextPacketTick on the state to advance it
115 nextPacketTick = states[currState]->nextPacketTick(elasticReq, 0);
116 schedule(updateEvent, std::min(nextPacketTick, nextTransitionTick));
117 } else {
118 DPRINTF(TrafficGen,
119 "Traffic generator is only active in timing mode\n");
120 }
121}
122
123DrainState
124TrafficGen::drain()
125{
126 if (!updateEvent.scheduled()) {
127 // no event has been scheduled yet (e.g. switched from atomic mode)
128 return DrainState::Drained;
129 }
130
131 if (retryPkt == NULL) {
132 // shut things down
133 nextPacketTick = MaxTick;
134 nextTransitionTick = MaxTick;
135 deschedule(updateEvent);
136 return DrainState::Drained;
137 } else {
138 return DrainState::Draining;
139 }
140}
141
142void
143TrafficGen::serialize(CheckpointOut &cp) const
144{
145 DPRINTF(Checkpoint, "Serializing TrafficGen\n");
146
147 // save ticks of the graph event if it is scheduled
148 Tick nextEvent = updateEvent.scheduled() ? updateEvent.when() : 0;
149
150 DPRINTF(TrafficGen, "Saving nextEvent=%llu\n", nextEvent);
151
152 SERIALIZE_SCALAR(nextEvent);
153
154 SERIALIZE_SCALAR(nextTransitionTick);
155
156 SERIALIZE_SCALAR(nextPacketTick);
157
158 SERIALIZE_SCALAR(currState);
159}
160
161void
162TrafficGen::unserialize(CheckpointIn &cp)
163{
164 // restore scheduled events
165 Tick nextEvent;
166 UNSERIALIZE_SCALAR(nextEvent);
167 if (nextEvent != 0) {
168 schedule(updateEvent, nextEvent);
169 }
170
171 UNSERIALIZE_SCALAR(nextTransitionTick);
172
173 UNSERIALIZE_SCALAR(nextPacketTick);
174
175 // @todo In the case of a stateful generator state such as the
176 // trace player we would also have to restore the position in the
177 // trace playback and the tick offset
178 UNSERIALIZE_SCALAR(currState);
179}
180
181void
182TrafficGen::update()
183{
184 // shift our progress-tracking event forward
185 reschedule(noProgressEvent, curTick() + progressCheck, true);
186
182 // if we have reached the time for the next state transition, then
183 // perform the transition
184 if (curTick() >= nextTransitionTick) {
185 transition();
186 } else {
187 assert(curTick() >= nextPacketTick);
188 // get the next packet and try to send it
189 PacketPtr pkt = states[currState]->getNextPacket();
190
191 // suppress packets that are not destined for a memory, such as
192 // device accesses that could be part of a trace
193 if (system->isMemAddr(pkt->getAddr())) {
194 numPackets++;
195 if (!port.sendTimingReq(pkt)) {
196 retryPkt = pkt;
197 retryPktTick = curTick();
198 }
199 } else {
200 DPRINTF(TrafficGen, "Suppressed packet %s 0x%x\n",
201 pkt->cmdString(), pkt->getAddr());
202
203 ++numSuppressed;
204 if (numSuppressed % 10000)
205 warn("%s suppressed %d packets with non-memory addresses\n",
206 name(), numSuppressed);
207
208 delete pkt->req;
209 delete pkt;
210 pkt = nullptr;
211 }
212 }
213
214 // if we are waiting for a retry, do not schedule any further
215 // events, in the case of a transition or a successful send, go
216 // ahead and determine when the next update should take place
217 if (retryPkt == NULL) {
218 // schedule next update event based on either the next execute
219 // tick or the next transition, which ever comes first
220 nextPacketTick = states[currState]->nextPacketTick(elasticReq, 0);
221 Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
222 DPRINTF(TrafficGen, "Next event scheduled at %lld\n", nextEventTick);
223 schedule(updateEvent, nextEventTick);
224 }
225}
226
227void
228TrafficGen::parseConfig()
229{
230 // keep track of the transitions parsed to create the matrix when
231 // done
232 vector<Transition> transitions;
233
234 // open input file
235 ifstream infile;
236 infile.open(configFile.c_str(), ifstream::in);
237 if (!infile.is_open()) {
238 fatal("Traffic generator %s config file not found at %s\n",
239 name(), configFile);
240 }
241
242 bool init_state_set = false;
243
244 // read line by line and determine the action based on the first
245 // keyword
246 string keyword;
247 string line;
248
249 while (getline(infile, line).good()) {
250 // see if this line is a comment line, and if so skip it
251 if (line.find('#') != 1) {
252 // create an input stream for the tokenization
253 istringstream is(line);
254
255 // determine the keyword
256 is >> keyword;
257
258 if (keyword == "STATE") {
259 // parse the behaviour of this state
260 uint32_t id;
261 Tick duration;
262 string mode;
263
264 is >> id >> duration >> mode;
265
266 if (mode == "TRACE") {
267 string traceFile;
268 Addr addrOffset;
269
270 is >> traceFile >> addrOffset;
271
272 states[id] = new TraceGen(name(), masterID, duration,
273 traceFile, addrOffset);
274 DPRINTF(TrafficGen, "State: %d TraceGen\n", id);
275 } else if (mode == "IDLE") {
276 states[id] = new IdleGen(name(), masterID, duration);
277 DPRINTF(TrafficGen, "State: %d IdleGen\n", id);
278 } else if (mode == "LINEAR" || mode == "RANDOM" ||
279 mode == "DRAM" || mode == "DRAM_ROTATE") {
280 uint32_t read_percent;
281 Addr start_addr;
282 Addr end_addr;
283 Addr blocksize;
284 Tick min_period;
285 Tick max_period;
286 Addr data_limit;
287
288 is >> read_percent >> start_addr >> end_addr >>
289 blocksize >> min_period >> max_period >> data_limit;
290
291 DPRINTF(TrafficGen, "%s, addr %x to %x, size %d,"
292 " period %d to %d, %d%% reads\n",
293 mode, start_addr, end_addr, blocksize, min_period,
294 max_period, read_percent);
295
296
297 if (blocksize > system->cacheLineSize())
298 fatal("TrafficGen %s block size (%d) is larger than "
299 "cache line size (%d)\n", name(),
300 blocksize, system->cacheLineSize());
301
302 if (read_percent > 100)
303 fatal("%s cannot have more than 100% reads", name());
304
305 if (min_period > max_period)
306 fatal("%s cannot have min_period > max_period", name());
307
308 if (mode == "LINEAR") {
309 states[id] = new LinearGen(name(), masterID,
310 duration, start_addr,
311 end_addr, blocksize,
312 min_period, max_period,
313 read_percent, data_limit);
314 DPRINTF(TrafficGen, "State: %d LinearGen\n", id);
315 } else if (mode == "RANDOM") {
316 states[id] = new RandomGen(name(), masterID,
317 duration, start_addr,
318 end_addr, blocksize,
319 min_period, max_period,
320 read_percent, data_limit);
321 DPRINTF(TrafficGen, "State: %d RandomGen\n", id);
322 } else if (mode == "DRAM" || mode == "DRAM_ROTATE") {
323 // stride size (bytes) of the request for achieving
324 // required hit length
325 unsigned int stride_size;
326 unsigned int page_size;
327 unsigned int nbr_of_banks_DRAM;
328 unsigned int nbr_of_banks_util;
329 unsigned int addr_mapping;
330 unsigned int nbr_of_ranks;
331
332 is >> stride_size >> page_size >> nbr_of_banks_DRAM >>
333 nbr_of_banks_util >> addr_mapping >>
334 nbr_of_ranks;
335
336 if (stride_size > page_size)
337 warn("DRAM generator stride size (%d) is greater "
338 "than page size (%d) of the memory\n",
339 blocksize, page_size);
340
341 if (nbr_of_banks_util > nbr_of_banks_DRAM)
342 fatal("Attempting to use more banks (%d) than "
343 "what is available (%d)\n",
344 nbr_of_banks_util, nbr_of_banks_DRAM);
345
346 // count the number of sequential packets to
347 // generate
348 unsigned int num_seq_pkts = 1;
349
350 if (stride_size > blocksize) {
351 num_seq_pkts = divCeil(stride_size, blocksize);
352 DPRINTF(TrafficGen, "stride size: %d "
353 "block size: %d, num_seq_pkts: %d\n",
354 stride_size, blocksize, num_seq_pkts);
355 }
356
357 if (mode == "DRAM") {
358 states[id] = new DramGen(name(), masterID,
359 duration, start_addr,
360 end_addr, blocksize,
361 min_period, max_period,
362 read_percent, data_limit,
363 num_seq_pkts, page_size,
364 nbr_of_banks_DRAM,
365 nbr_of_banks_util,
366 addr_mapping,
367 nbr_of_ranks);
368 DPRINTF(TrafficGen, "State: %d DramGen\n", id);
369 } else {
370 // Will rotate to the next rank after rotating
371 // through all banks, for each command type.
372 // In the 50% read case, series will be issued
373 // for both RD & WR before the rank in incremented
374 unsigned int max_seq_count_per_rank =
375 (read_percent == 50) ? nbr_of_banks_util * 2
376 : nbr_of_banks_util;
377
378 states[id] = new DramRotGen(name(), masterID,
379 duration, start_addr,
380 end_addr, blocksize,
381 min_period, max_period,
382 read_percent, data_limit,
383 num_seq_pkts, page_size,
384 nbr_of_banks_DRAM,
385 nbr_of_banks_util,
386 addr_mapping,
387 nbr_of_ranks,
388 max_seq_count_per_rank);
389 DPRINTF(TrafficGen, "State: %d DramRotGen\n", id);
390 }
391 }
392 } else {
393 fatal("%s: Unknown traffic generator mode: %s",
394 name(), mode);
395 }
396 } else if (keyword == "TRANSITION") {
397 Transition transition;
398
399 is >> transition.from >> transition.to >> transition.p;
400
401 transitions.push_back(transition);
402
403 DPRINTF(TrafficGen, "Transition: %d -> %d\n", transition.from,
404 transition.to);
405 } else if (keyword == "INIT") {
406 // set the initial state as the active state
407 is >> currState;
408
409 init_state_set = true;
410
411 DPRINTF(TrafficGen, "Initial state: %d\n", currState);
412 }
413 }
414 }
415
416 if (!init_state_set)
417 fatal("%s: initial state not specified (add 'INIT <id>' line "
418 "to the config file)\n", name());
419
420 // resize and populate state transition matrix
421 transitionMatrix.resize(states.size());
422 for (size_t i = 0; i < states.size(); i++) {
423 transitionMatrix[i].resize(states.size());
424 }
425
426 for (vector<Transition>::iterator t = transitions.begin();
427 t != transitions.end(); ++t) {
428 transitionMatrix[t->from][t->to] = t->p;
429 }
430
431 // ensure the egress edges do not have a probability larger than
432 // one
433 for (size_t i = 0; i < states.size(); i++) {
434 double sum = 0;
435 for (size_t j = 0; j < states.size(); j++) {
436 sum += transitionMatrix[i][j];
437 }
438
439 // avoid comparing floating point numbers
440 if (abs(sum - 1.0) > 0.001)
441 fatal("%s has transition probability != 1 for state %d\n",
442 name(), i);
443 }
444
445 // close input file
446 infile.close();
447}
448
449void
450TrafficGen::transition()
451{
452 // exit the current state
453 states[currState]->exit();
454
455 // determine next state
456 double p = random_mt.random<double>();
457 assert(currState < transitionMatrix.size());
458 double cumulative = 0.0;
459 size_t i = 0;
460 do {
461 cumulative += transitionMatrix[currState][i];
462 ++i;
463 } while (cumulative < p && i < transitionMatrix[currState].size());
464
465 enterState(i - 1);
466}
467
468void
469TrafficGen::enterState(uint32_t newState)
470{
471 DPRINTF(TrafficGen, "Transition to state %d\n", newState);
472
473 currState = newState;
474 // we could have been delayed and not transitioned on the exact
475 // tick when we were supposed to (due to back pressure when
476 // sending a packet)
477 nextTransitionTick = curTick() + states[currState]->duration;
478 states[currState]->enter();
479}
480
481void
482TrafficGen::recvReqRetry()
483{
484 assert(retryPkt != NULL);
485
486 DPRINTF(TrafficGen, "Received retry\n");
487 numRetries++;
488 // attempt to send the packet, and if we are successful start up
489 // the machinery again
490 if (port.sendTimingReq(retryPkt)) {
491 retryPkt = NULL;
492 // remember how much delay was incurred due to back-pressure
493 // when sending the request, we also use this to derive
494 // the tick for the next packet
495 Tick delay = curTick() - retryPktTick;
496 retryPktTick = 0;
497 retryTicks += delay;
498
499 if (drainState() != DrainState::Draining) {
500 // packet is sent, so find out when the next one is due
501 nextPacketTick = states[currState]->nextPacketTick(elasticReq,
502 delay);
503 Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
504 schedule(updateEvent, std::max(curTick(), nextEventTick));
505 } else {
506 // shut things down
507 nextPacketTick = MaxTick;
508 nextTransitionTick = MaxTick;
509 signalDrainDone();
510 }
511 }
512}
513
514void
187 // if we have reached the time for the next state transition, then
188 // perform the transition
189 if (curTick() >= nextTransitionTick) {
190 transition();
191 } else {
192 assert(curTick() >= nextPacketTick);
193 // get the next packet and try to send it
194 PacketPtr pkt = states[currState]->getNextPacket();
195
196 // suppress packets that are not destined for a memory, such as
197 // device accesses that could be part of a trace
198 if (system->isMemAddr(pkt->getAddr())) {
199 numPackets++;
200 if (!port.sendTimingReq(pkt)) {
201 retryPkt = pkt;
202 retryPktTick = curTick();
203 }
204 } else {
205 DPRINTF(TrafficGen, "Suppressed packet %s 0x%x\n",
206 pkt->cmdString(), pkt->getAddr());
207
208 ++numSuppressed;
209 if (numSuppressed % 10000)
210 warn("%s suppressed %d packets with non-memory addresses\n",
211 name(), numSuppressed);
212
213 delete pkt->req;
214 delete pkt;
215 pkt = nullptr;
216 }
217 }
218
219 // if we are waiting for a retry, do not schedule any further
220 // events, in the case of a transition or a successful send, go
221 // ahead and determine when the next update should take place
222 if (retryPkt == NULL) {
223 // schedule next update event based on either the next execute
224 // tick or the next transition, which ever comes first
225 nextPacketTick = states[currState]->nextPacketTick(elasticReq, 0);
226 Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
227 DPRINTF(TrafficGen, "Next event scheduled at %lld\n", nextEventTick);
228 schedule(updateEvent, nextEventTick);
229 }
230}
231
232void
233TrafficGen::parseConfig()
234{
235 // keep track of the transitions parsed to create the matrix when
236 // done
237 vector<Transition> transitions;
238
239 // open input file
240 ifstream infile;
241 infile.open(configFile.c_str(), ifstream::in);
242 if (!infile.is_open()) {
243 fatal("Traffic generator %s config file not found at %s\n",
244 name(), configFile);
245 }
246
247 bool init_state_set = false;
248
249 // read line by line and determine the action based on the first
250 // keyword
251 string keyword;
252 string line;
253
254 while (getline(infile, line).good()) {
255 // see if this line is a comment line, and if so skip it
256 if (line.find('#') != 1) {
257 // create an input stream for the tokenization
258 istringstream is(line);
259
260 // determine the keyword
261 is >> keyword;
262
263 if (keyword == "STATE") {
264 // parse the behaviour of this state
265 uint32_t id;
266 Tick duration;
267 string mode;
268
269 is >> id >> duration >> mode;
270
271 if (mode == "TRACE") {
272 string traceFile;
273 Addr addrOffset;
274
275 is >> traceFile >> addrOffset;
276
277 states[id] = new TraceGen(name(), masterID, duration,
278 traceFile, addrOffset);
279 DPRINTF(TrafficGen, "State: %d TraceGen\n", id);
280 } else if (mode == "IDLE") {
281 states[id] = new IdleGen(name(), masterID, duration);
282 DPRINTF(TrafficGen, "State: %d IdleGen\n", id);
283 } else if (mode == "LINEAR" || mode == "RANDOM" ||
284 mode == "DRAM" || mode == "DRAM_ROTATE") {
285 uint32_t read_percent;
286 Addr start_addr;
287 Addr end_addr;
288 Addr blocksize;
289 Tick min_period;
290 Tick max_period;
291 Addr data_limit;
292
293 is >> read_percent >> start_addr >> end_addr >>
294 blocksize >> min_period >> max_period >> data_limit;
295
296 DPRINTF(TrafficGen, "%s, addr %x to %x, size %d,"
297 " period %d to %d, %d%% reads\n",
298 mode, start_addr, end_addr, blocksize, min_period,
299 max_period, read_percent);
300
301
302 if (blocksize > system->cacheLineSize())
303 fatal("TrafficGen %s block size (%d) is larger than "
304 "cache line size (%d)\n", name(),
305 blocksize, system->cacheLineSize());
306
307 if (read_percent > 100)
308 fatal("%s cannot have more than 100% reads", name());
309
310 if (min_period > max_period)
311 fatal("%s cannot have min_period > max_period", name());
312
313 if (mode == "LINEAR") {
314 states[id] = new LinearGen(name(), masterID,
315 duration, start_addr,
316 end_addr, blocksize,
317 min_period, max_period,
318 read_percent, data_limit);
319 DPRINTF(TrafficGen, "State: %d LinearGen\n", id);
320 } else if (mode == "RANDOM") {
321 states[id] = new RandomGen(name(), masterID,
322 duration, start_addr,
323 end_addr, blocksize,
324 min_period, max_period,
325 read_percent, data_limit);
326 DPRINTF(TrafficGen, "State: %d RandomGen\n", id);
327 } else if (mode == "DRAM" || mode == "DRAM_ROTATE") {
328 // stride size (bytes) of the request for achieving
329 // required hit length
330 unsigned int stride_size;
331 unsigned int page_size;
332 unsigned int nbr_of_banks_DRAM;
333 unsigned int nbr_of_banks_util;
334 unsigned int addr_mapping;
335 unsigned int nbr_of_ranks;
336
337 is >> stride_size >> page_size >> nbr_of_banks_DRAM >>
338 nbr_of_banks_util >> addr_mapping >>
339 nbr_of_ranks;
340
341 if (stride_size > page_size)
342 warn("DRAM generator stride size (%d) is greater "
343 "than page size (%d) of the memory\n",
344 blocksize, page_size);
345
346 if (nbr_of_banks_util > nbr_of_banks_DRAM)
347 fatal("Attempting to use more banks (%d) than "
348 "what is available (%d)\n",
349 nbr_of_banks_util, nbr_of_banks_DRAM);
350
351 // count the number of sequential packets to
352 // generate
353 unsigned int num_seq_pkts = 1;
354
355 if (stride_size > blocksize) {
356 num_seq_pkts = divCeil(stride_size, blocksize);
357 DPRINTF(TrafficGen, "stride size: %d "
358 "block size: %d, num_seq_pkts: %d\n",
359 stride_size, blocksize, num_seq_pkts);
360 }
361
362 if (mode == "DRAM") {
363 states[id] = new DramGen(name(), masterID,
364 duration, start_addr,
365 end_addr, blocksize,
366 min_period, max_period,
367 read_percent, data_limit,
368 num_seq_pkts, page_size,
369 nbr_of_banks_DRAM,
370 nbr_of_banks_util,
371 addr_mapping,
372 nbr_of_ranks);
373 DPRINTF(TrafficGen, "State: %d DramGen\n", id);
374 } else {
375 // Will rotate to the next rank after rotating
376 // through all banks, for each command type.
377 // In the 50% read case, series will be issued
378 // for both RD & WR before the rank in incremented
379 unsigned int max_seq_count_per_rank =
380 (read_percent == 50) ? nbr_of_banks_util * 2
381 : nbr_of_banks_util;
382
383 states[id] = new DramRotGen(name(), masterID,
384 duration, start_addr,
385 end_addr, blocksize,
386 min_period, max_period,
387 read_percent, data_limit,
388 num_seq_pkts, page_size,
389 nbr_of_banks_DRAM,
390 nbr_of_banks_util,
391 addr_mapping,
392 nbr_of_ranks,
393 max_seq_count_per_rank);
394 DPRINTF(TrafficGen, "State: %d DramRotGen\n", id);
395 }
396 }
397 } else {
398 fatal("%s: Unknown traffic generator mode: %s",
399 name(), mode);
400 }
401 } else if (keyword == "TRANSITION") {
402 Transition transition;
403
404 is >> transition.from >> transition.to >> transition.p;
405
406 transitions.push_back(transition);
407
408 DPRINTF(TrafficGen, "Transition: %d -> %d\n", transition.from,
409 transition.to);
410 } else if (keyword == "INIT") {
411 // set the initial state as the active state
412 is >> currState;
413
414 init_state_set = true;
415
416 DPRINTF(TrafficGen, "Initial state: %d\n", currState);
417 }
418 }
419 }
420
421 if (!init_state_set)
422 fatal("%s: initial state not specified (add 'INIT <id>' line "
423 "to the config file)\n", name());
424
425 // resize and populate state transition matrix
426 transitionMatrix.resize(states.size());
427 for (size_t i = 0; i < states.size(); i++) {
428 transitionMatrix[i].resize(states.size());
429 }
430
431 for (vector<Transition>::iterator t = transitions.begin();
432 t != transitions.end(); ++t) {
433 transitionMatrix[t->from][t->to] = t->p;
434 }
435
436 // ensure the egress edges do not have a probability larger than
437 // one
438 for (size_t i = 0; i < states.size(); i++) {
439 double sum = 0;
440 for (size_t j = 0; j < states.size(); j++) {
441 sum += transitionMatrix[i][j];
442 }
443
444 // avoid comparing floating point numbers
445 if (abs(sum - 1.0) > 0.001)
446 fatal("%s has transition probability != 1 for state %d\n",
447 name(), i);
448 }
449
450 // close input file
451 infile.close();
452}
453
454void
455TrafficGen::transition()
456{
457 // exit the current state
458 states[currState]->exit();
459
460 // determine next state
461 double p = random_mt.random<double>();
462 assert(currState < transitionMatrix.size());
463 double cumulative = 0.0;
464 size_t i = 0;
465 do {
466 cumulative += transitionMatrix[currState][i];
467 ++i;
468 } while (cumulative < p && i < transitionMatrix[currState].size());
469
470 enterState(i - 1);
471}
472
473void
474TrafficGen::enterState(uint32_t newState)
475{
476 DPRINTF(TrafficGen, "Transition to state %d\n", newState);
477
478 currState = newState;
479 // we could have been delayed and not transitioned on the exact
480 // tick when we were supposed to (due to back pressure when
481 // sending a packet)
482 nextTransitionTick = curTick() + states[currState]->duration;
483 states[currState]->enter();
484}
485
486void
487TrafficGen::recvReqRetry()
488{
489 assert(retryPkt != NULL);
490
491 DPRINTF(TrafficGen, "Received retry\n");
492 numRetries++;
493 // attempt to send the packet, and if we are successful start up
494 // the machinery again
495 if (port.sendTimingReq(retryPkt)) {
496 retryPkt = NULL;
497 // remember how much delay was incurred due to back-pressure
498 // when sending the request, we also use this to derive
499 // the tick for the next packet
500 Tick delay = curTick() - retryPktTick;
501 retryPktTick = 0;
502 retryTicks += delay;
503
504 if (drainState() != DrainState::Draining) {
505 // packet is sent, so find out when the next one is due
506 nextPacketTick = states[currState]->nextPacketTick(elasticReq,
507 delay);
508 Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
509 schedule(updateEvent, std::max(curTick(), nextEventTick));
510 } else {
511 // shut things down
512 nextPacketTick = MaxTick;
513 nextTransitionTick = MaxTick;
514 signalDrainDone();
515 }
516 }
517}
518
519void
520TrafficGen::noProgress()
521{
522 fatal("TrafficGen %s spent %llu ticks without making progress",
523 name(), progressCheck);
524}
525
526void
515TrafficGen::regStats()
516{
517 // Initialise all the stats
518 using namespace Stats;
519
520 numPackets
521 .name(name() + ".numPackets")
522 .desc("Number of packets generated");
523
524 numRetries
525 .name(name() + ".numRetries")
526 .desc("Number of retries");
527
528 retryTicks
529 .name(name() + ".retryTicks")
530 .desc("Time spent waiting due to back-pressure (ticks)");
531}
532
533bool
534TrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
535{
536 delete pkt->req;
537 delete pkt;
538
539 return true;
540}
527TrafficGen::regStats()
528{
529 // Initialise all the stats
530 using namespace Stats;
531
532 numPackets
533 .name(name() + ".numPackets")
534 .desc("Number of packets generated");
535
536 numRetries
537 .name(name() + ".numRetries")
538 .desc("Number of retries");
539
540 retryTicks
541 .name(name() + ".retryTicks")
542 .desc("Time spent waiting due to back-pressure (ticks)");
543}
544
545bool
546TrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
547{
548 delete pkt->req;
549 delete pkt;
550
551 return true;
552}