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