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