traffic_gen.cc (9722:2ddec848b8e8) traffic_gen.cc (9814:7ad2b0186a32)
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/random.hh"
45#include "cpu/testers/traffic_gen/traffic_gen.hh"
46#include "debug/Checkpoint.hh"
47#include "debug/TrafficGen.hh"
48#include "sim/stats.hh"
49#include "sim/system.hh"
50
51using namespace std;
52
53TrafficGen::TrafficGen(const TrafficGenParams* p)
54 : MemObject(p),
55 system(p->system),
56 masterID(system->getMasterId(name())),
57 configFile(p->config_file),
58 elasticReq(p->elastic_req),
59 nextTransitionTick(0),
60 nextPacketTick(0),
61 port(name() + ".port", *this),
62 retryPkt(NULL),
63 retryPktTick(0),
64 updateEvent(this),
65 drainManager(NULL)
66{
67}
68
69TrafficGen*
70TrafficGenParams::create()
71{
72 return new TrafficGen(this);
73}
74
75BaseMasterPort&
76TrafficGen::getMasterPort(const string& if_name, PortID idx)
77{
78 if (if_name == "port") {
79 return port;
80 } else {
81 return MemObject::getMasterPort(if_name, idx);
82 }
83}
84
85void
86TrafficGen::init()
87{
88 if (!port.isConnected())
89 fatal("The port of %s is not connected!\n", name());
90
91 // if the system is in timing mode active the request generator
92 if (system->isTimingMode()) {
93 DPRINTF(TrafficGen, "Timing mode, activating request generator\n");
94
95 parseConfig();
96
97 // enter initial state
98 enterState(currState);
99 } else {
100 DPRINTF(TrafficGen,
101 "Traffic generator is only active in timing mode\n");
102 }
103}
104
105void
106TrafficGen::initState()
107{
108 // when not restoring from a checkpoint, make sure we kick things off
109 if (system->isTimingMode()) {
110 // call nextPacketTick on the state to advance it
111 nextPacketTick = states[currState]->nextPacketTick(elasticReq, 0);
112 schedule(updateEvent, std::min(nextPacketTick, nextTransitionTick));
113 } else {
114 DPRINTF(TrafficGen,
115 "Traffic generator is only active in timing mode\n");
116 }
117}
118
119unsigned int
120TrafficGen::drain(DrainManager *dm)
121{
122 if (retryPkt == NULL) {
123 // shut things down
124 nextPacketTick = MaxTick;
125 nextTransitionTick = MaxTick;
126 deschedule(updateEvent);
127 return 0;
128 } else {
129 drainManager = dm;
130 return 1;
131 }
132}
133
134void
135TrafficGen::serialize(ostream &os)
136{
137 DPRINTF(Checkpoint, "Serializing TrafficGen\n");
138
139 // save ticks of the graph event if it is scheduled
140 Tick nextEvent = updateEvent.scheduled() ? updateEvent.when() : 0;
141
142 DPRINTF(TrafficGen, "Saving nextEvent=%llu\n", nextEvent);
143
144 SERIALIZE_SCALAR(nextEvent);
145
146 SERIALIZE_SCALAR(nextTransitionTick);
147
148 SERIALIZE_SCALAR(nextPacketTick);
149
150 SERIALIZE_SCALAR(currState);
151}
152
153void
154TrafficGen::unserialize(Checkpoint* cp, const string& section)
155{
156 // restore scheduled events
157 Tick nextEvent;
158 UNSERIALIZE_SCALAR(nextEvent);
159 if (nextEvent != 0) {
160 schedule(updateEvent, nextEvent);
161 }
162
163 UNSERIALIZE_SCALAR(nextTransitionTick);
164
165 UNSERIALIZE_SCALAR(nextPacketTick);
166
167 // @todo In the case of a stateful generator state such as the
168 // trace player we would also have to restore the position in the
169 // trace playback and the tick offset
170 UNSERIALIZE_SCALAR(currState);
171}
172
173void
174TrafficGen::update()
175{
176 // if we have reached the time for the next state transition, then
177 // perform the transition
178 if (curTick() >= nextTransitionTick) {
179 transition();
180 } else {
181 assert(curTick() >= nextPacketTick);
182 // get the next packet and try to send it
183 PacketPtr pkt = states[currState]->getNextPacket();
184 numPackets++;
185 if (!port.sendTimingReq(pkt)) {
186 retryPkt = pkt;
187 retryPktTick = curTick();
188 }
189 }
190
191 // if we are waiting for a retry, do not schedule any further
192 // events, in the case of a transition or a successful send, go
193 // ahead and determine when the next update should take place
194 if (retryPkt == NULL) {
195 // schedule next update event based on either the next execute
196 // tick or the next transition, which ever comes first
197 nextPacketTick = states[currState]->nextPacketTick(elasticReq, 0);
198 Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
199 DPRINTF(TrafficGen, "Next event scheduled at %lld\n", nextEventTick);
200 schedule(updateEvent, nextEventTick);
201 }
202}
203
204void
205TrafficGen::parseConfig()
206{
207 // keep track of the transitions parsed to create the matrix when
208 // done
209 vector<Transition> transitions;
210
211 // open input file
212 ifstream infile;
213 infile.open(configFile.c_str(), ifstream::in);
214 if (!infile.is_open()) {
215 fatal("Traffic generator %s config file not found at %s\n",
216 name(), configFile);
217 }
218
219 // read line by line and determine the action based on the first
220 // keyword
221 string keyword;
222 string line;
223
224 while (getline(infile, line).good()) {
225 // see if this line is a comment line, and if so skip it
226 if (line.find('#') != 1) {
227 // create an input stream for the tokenization
228 istringstream is(line);
229
230 // determine the keyword
231 is >> keyword;
232
233 if (keyword == "STATE") {
234 // parse the behaviour of this state
235 uint32_t id;
236 Tick duration;
237 string mode;
238
239 is >> id >> duration >> mode;
240
241 if (mode == "TRACE") {
242 string traceFile;
243 Addr addrOffset;
244
245 is >> traceFile >> addrOffset;
246
247 states[id] = new TraceGen(name(), masterID, duration,
248 traceFile, addrOffset);
249 DPRINTF(TrafficGen, "State: %d TraceGen\n", id);
250 } else if (mode == "IDLE") {
251 states[id] = new IdleGen(name(), masterID, duration);
252 DPRINTF(TrafficGen, "State: %d IdleGen\n", id);
253 } else if (mode == "LINEAR" || mode == "RANDOM") {
254 uint32_t read_percent;
255 Addr start_addr;
256 Addr end_addr;
257 Addr blocksize;
258 Tick min_period;
259 Tick max_period;
260 Addr data_limit;
261
262 is >> read_percent >> start_addr >> end_addr >>
263 blocksize >> min_period >> max_period >> data_limit;
264
265 DPRINTF(TrafficGen, "%s, addr %x to %x, size %d,"
266 " period %d to %d, %d%% reads\n",
267 mode, start_addr, end_addr, blocksize, min_period,
268 max_period, read_percent);
269
270
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/random.hh"
45#include "cpu/testers/traffic_gen/traffic_gen.hh"
46#include "debug/Checkpoint.hh"
47#include "debug/TrafficGen.hh"
48#include "sim/stats.hh"
49#include "sim/system.hh"
50
51using namespace std;
52
53TrafficGen::TrafficGen(const TrafficGenParams* p)
54 : MemObject(p),
55 system(p->system),
56 masterID(system->getMasterId(name())),
57 configFile(p->config_file),
58 elasticReq(p->elastic_req),
59 nextTransitionTick(0),
60 nextPacketTick(0),
61 port(name() + ".port", *this),
62 retryPkt(NULL),
63 retryPktTick(0),
64 updateEvent(this),
65 drainManager(NULL)
66{
67}
68
69TrafficGen*
70TrafficGenParams::create()
71{
72 return new TrafficGen(this);
73}
74
75BaseMasterPort&
76TrafficGen::getMasterPort(const string& if_name, PortID idx)
77{
78 if (if_name == "port") {
79 return port;
80 } else {
81 return MemObject::getMasterPort(if_name, idx);
82 }
83}
84
85void
86TrafficGen::init()
87{
88 if (!port.isConnected())
89 fatal("The port of %s is not connected!\n", name());
90
91 // if the system is in timing mode active the request generator
92 if (system->isTimingMode()) {
93 DPRINTF(TrafficGen, "Timing mode, activating request generator\n");
94
95 parseConfig();
96
97 // enter initial state
98 enterState(currState);
99 } else {
100 DPRINTF(TrafficGen,
101 "Traffic generator is only active in timing mode\n");
102 }
103}
104
105void
106TrafficGen::initState()
107{
108 // when not restoring from a checkpoint, make sure we kick things off
109 if (system->isTimingMode()) {
110 // call nextPacketTick on the state to advance it
111 nextPacketTick = states[currState]->nextPacketTick(elasticReq, 0);
112 schedule(updateEvent, std::min(nextPacketTick, nextTransitionTick));
113 } else {
114 DPRINTF(TrafficGen,
115 "Traffic generator is only active in timing mode\n");
116 }
117}
118
119unsigned int
120TrafficGen::drain(DrainManager *dm)
121{
122 if (retryPkt == NULL) {
123 // shut things down
124 nextPacketTick = MaxTick;
125 nextTransitionTick = MaxTick;
126 deschedule(updateEvent);
127 return 0;
128 } else {
129 drainManager = dm;
130 return 1;
131 }
132}
133
134void
135TrafficGen::serialize(ostream &os)
136{
137 DPRINTF(Checkpoint, "Serializing TrafficGen\n");
138
139 // save ticks of the graph event if it is scheduled
140 Tick nextEvent = updateEvent.scheduled() ? updateEvent.when() : 0;
141
142 DPRINTF(TrafficGen, "Saving nextEvent=%llu\n", nextEvent);
143
144 SERIALIZE_SCALAR(nextEvent);
145
146 SERIALIZE_SCALAR(nextTransitionTick);
147
148 SERIALIZE_SCALAR(nextPacketTick);
149
150 SERIALIZE_SCALAR(currState);
151}
152
153void
154TrafficGen::unserialize(Checkpoint* cp, const string& section)
155{
156 // restore scheduled events
157 Tick nextEvent;
158 UNSERIALIZE_SCALAR(nextEvent);
159 if (nextEvent != 0) {
160 schedule(updateEvent, nextEvent);
161 }
162
163 UNSERIALIZE_SCALAR(nextTransitionTick);
164
165 UNSERIALIZE_SCALAR(nextPacketTick);
166
167 // @todo In the case of a stateful generator state such as the
168 // trace player we would also have to restore the position in the
169 // trace playback and the tick offset
170 UNSERIALIZE_SCALAR(currState);
171}
172
173void
174TrafficGen::update()
175{
176 // if we have reached the time for the next state transition, then
177 // perform the transition
178 if (curTick() >= nextTransitionTick) {
179 transition();
180 } else {
181 assert(curTick() >= nextPacketTick);
182 // get the next packet and try to send it
183 PacketPtr pkt = states[currState]->getNextPacket();
184 numPackets++;
185 if (!port.sendTimingReq(pkt)) {
186 retryPkt = pkt;
187 retryPktTick = curTick();
188 }
189 }
190
191 // if we are waiting for a retry, do not schedule any further
192 // events, in the case of a transition or a successful send, go
193 // ahead and determine when the next update should take place
194 if (retryPkt == NULL) {
195 // schedule next update event based on either the next execute
196 // tick or the next transition, which ever comes first
197 nextPacketTick = states[currState]->nextPacketTick(elasticReq, 0);
198 Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
199 DPRINTF(TrafficGen, "Next event scheduled at %lld\n", nextEventTick);
200 schedule(updateEvent, nextEventTick);
201 }
202}
203
204void
205TrafficGen::parseConfig()
206{
207 // keep track of the transitions parsed to create the matrix when
208 // done
209 vector<Transition> transitions;
210
211 // open input file
212 ifstream infile;
213 infile.open(configFile.c_str(), ifstream::in);
214 if (!infile.is_open()) {
215 fatal("Traffic generator %s config file not found at %s\n",
216 name(), configFile);
217 }
218
219 // read line by line and determine the action based on the first
220 // keyword
221 string keyword;
222 string line;
223
224 while (getline(infile, line).good()) {
225 // see if this line is a comment line, and if so skip it
226 if (line.find('#') != 1) {
227 // create an input stream for the tokenization
228 istringstream is(line);
229
230 // determine the keyword
231 is >> keyword;
232
233 if (keyword == "STATE") {
234 // parse the behaviour of this state
235 uint32_t id;
236 Tick duration;
237 string mode;
238
239 is >> id >> duration >> mode;
240
241 if (mode == "TRACE") {
242 string traceFile;
243 Addr addrOffset;
244
245 is >> traceFile >> addrOffset;
246
247 states[id] = new TraceGen(name(), masterID, duration,
248 traceFile, addrOffset);
249 DPRINTF(TrafficGen, "State: %d TraceGen\n", id);
250 } else if (mode == "IDLE") {
251 states[id] = new IdleGen(name(), masterID, duration);
252 DPRINTF(TrafficGen, "State: %d IdleGen\n", id);
253 } else if (mode == "LINEAR" || mode == "RANDOM") {
254 uint32_t read_percent;
255 Addr start_addr;
256 Addr end_addr;
257 Addr blocksize;
258 Tick min_period;
259 Tick max_period;
260 Addr data_limit;
261
262 is >> read_percent >> start_addr >> end_addr >>
263 blocksize >> min_period >> max_period >> data_limit;
264
265 DPRINTF(TrafficGen, "%s, addr %x to %x, size %d,"
266 " period %d to %d, %d%% reads\n",
267 mode, start_addr, end_addr, blocksize, min_period,
268 max_period, read_percent);
269
270
271 if (port.deviceBlockSize() &&
272 blocksize > port.deviceBlockSize())
271 if (blocksize > system->cacheLineSize())
273 fatal("TrafficGen %s block size (%d) is larger than "
272 fatal("TrafficGen %s block size (%d) is larger than "
274 "port block size (%d)\n", name(),
275 blocksize, port.deviceBlockSize());
273 "system block size (%d)\n", name(),
274 blocksize, system->cacheLineSize());
276
277 if (read_percent > 100)
278 fatal("%s cannot have more than 100% reads", name());
279
280 if (min_period > max_period)
281 fatal("%s cannot have min_period > max_period", name());
282
283 if (mode == "LINEAR") {
284 states[id] = new LinearGen(name(), masterID,
285 duration, start_addr,
286 end_addr, blocksize,
287 min_period, max_period,
288 read_percent, data_limit);
289 DPRINTF(TrafficGen, "State: %d LinearGen\n", id);
290 } else if (mode == "RANDOM") {
291 states[id] = new RandomGen(name(), masterID,
292 duration, start_addr,
293 end_addr, blocksize,
294 min_period, max_period,
295 read_percent, data_limit);
296 DPRINTF(TrafficGen, "State: %d RandomGen\n", id);
297 }
298 } else {
299 fatal("%s: Unknown traffic generator mode: %s",
300 name(), mode);
301 }
302 } else if (keyword == "TRANSITION") {
303 Transition transition;
304
305 is >> transition.from >> transition.to >> transition.p;
306
307 transitions.push_back(transition);
308
309 DPRINTF(TrafficGen, "Transition: %d -> %d\n", transition.from,
310 transition.to);
311 } else if (keyword == "INIT") {
312 // set the initial state as the active state
313 is >> currState;
314
315 DPRINTF(TrafficGen, "Initial state: %d\n", currState);
316 }
317 }
318 }
319
320 // resize and populate state transition matrix
321 transitionMatrix.resize(states.size());
322 for (size_t i = 0; i < states.size(); i++) {
323 transitionMatrix[i].resize(states.size());
324 }
325
326 for (vector<Transition>::iterator t = transitions.begin();
327 t != transitions.end(); ++t) {
328 transitionMatrix[t->from][t->to] = t->p;
329 }
330
331 // ensure the egress edges do not have a probability larger than
332 // one
333 for (size_t i = 0; i < states.size(); i++) {
334 double sum = 0;
335 for (size_t j = 0; j < states.size(); j++) {
336 sum += transitionMatrix[i][j];
337 }
338
339 // avoid comparing floating point numbers
340 if (abs(sum - 1.0) > 0.001)
341 fatal("%s has transition probability != 1 for state %d\n",
342 name(), i);
343 }
344
345 // close input file
346 infile.close();
347}
348
349void
350TrafficGen::transition()
351{
352 // exit the current state
353 states[currState]->exit();
354
355 // determine next state
356 double p = random_mt.gen_real1();
357 assert(currState < transitionMatrix.size());
358 double cumulative = 0.0;
359 size_t i = 0;
360 do {
361 cumulative += transitionMatrix[currState][i];
362 ++i;
363 } while (cumulative < p && i < transitionMatrix[currState].size());
364
365 enterState(i - 1);
366}
367
368void
369TrafficGen::enterState(uint32_t newState)
370{
371 DPRINTF(TrafficGen, "Transition to state %d\n", newState);
372
373 currState = newState;
374 // we could have been delayed and not transitioned on the exact
375 // tick when we were supposed to (due to back pressure when
376 // sending a packet)
377 nextTransitionTick = curTick() + states[currState]->duration;
378 states[currState]->enter();
379}
380
381void
382TrafficGen::recvRetry()
383{
384 assert(retryPkt != NULL);
385
386 DPRINTF(TrafficGen, "Received retry\n");
387 numRetries++;
388 // attempt to send the packet, and if we are successful start up
389 // the machinery again
390 if (port.sendTimingReq(retryPkt)) {
391 retryPkt = NULL;
392 // remember how much delay was incurred due to back-pressure
393 // when sending the request, we also use this to derive
394 // the tick for the next packet
395 Tick delay = curTick() - retryPktTick;
396 retryPktTick = 0;
397 retryTicks += delay;
398
399 if (drainManager == NULL) {
400 // packet is sent, so find out when the next one is due
401 nextPacketTick = states[currState]->nextPacketTick(elasticReq,
402 delay);
403 Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
404 schedule(updateEvent, std::max(curTick(), nextEventTick));
405 } else {
406 // shut things down
407 nextPacketTick = MaxTick;
408 nextTransitionTick = MaxTick;
409 drainManager->signalDrainDone();
410 // Clear the drain event once we're done with it.
411 drainManager = NULL;
412 }
413 }
414}
415
416void
417TrafficGen::regStats()
418{
419 // Initialise all the stats
420 using namespace Stats;
421
422 numPackets
423 .name(name() + ".numPackets")
424 .desc("Number of packets generated");
425
426 numRetries
427 .name(name() + ".numRetries")
428 .desc("Number of retries");
429
430 retryTicks
431 .name(name() + ".retryTicks")
432 .desc("Time spent waiting due to back-pressure (ticks)");
433}
434
435bool
436TrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
437{
438 delete pkt->req;
439 delete pkt;
440
441 return true;
442}
275
276 if (read_percent > 100)
277 fatal("%s cannot have more than 100% reads", name());
278
279 if (min_period > max_period)
280 fatal("%s cannot have min_period > max_period", name());
281
282 if (mode == "LINEAR") {
283 states[id] = new LinearGen(name(), masterID,
284 duration, start_addr,
285 end_addr, blocksize,
286 min_period, max_period,
287 read_percent, data_limit);
288 DPRINTF(TrafficGen, "State: %d LinearGen\n", id);
289 } else if (mode == "RANDOM") {
290 states[id] = new RandomGen(name(), masterID,
291 duration, start_addr,
292 end_addr, blocksize,
293 min_period, max_period,
294 read_percent, data_limit);
295 DPRINTF(TrafficGen, "State: %d RandomGen\n", id);
296 }
297 } else {
298 fatal("%s: Unknown traffic generator mode: %s",
299 name(), mode);
300 }
301 } else if (keyword == "TRANSITION") {
302 Transition transition;
303
304 is >> transition.from >> transition.to >> transition.p;
305
306 transitions.push_back(transition);
307
308 DPRINTF(TrafficGen, "Transition: %d -> %d\n", transition.from,
309 transition.to);
310 } else if (keyword == "INIT") {
311 // set the initial state as the active state
312 is >> currState;
313
314 DPRINTF(TrafficGen, "Initial state: %d\n", currState);
315 }
316 }
317 }
318
319 // resize and populate state transition matrix
320 transitionMatrix.resize(states.size());
321 for (size_t i = 0; i < states.size(); i++) {
322 transitionMatrix[i].resize(states.size());
323 }
324
325 for (vector<Transition>::iterator t = transitions.begin();
326 t != transitions.end(); ++t) {
327 transitionMatrix[t->from][t->to] = t->p;
328 }
329
330 // ensure the egress edges do not have a probability larger than
331 // one
332 for (size_t i = 0; i < states.size(); i++) {
333 double sum = 0;
334 for (size_t j = 0; j < states.size(); j++) {
335 sum += transitionMatrix[i][j];
336 }
337
338 // avoid comparing floating point numbers
339 if (abs(sum - 1.0) > 0.001)
340 fatal("%s has transition probability != 1 for state %d\n",
341 name(), i);
342 }
343
344 // close input file
345 infile.close();
346}
347
348void
349TrafficGen::transition()
350{
351 // exit the current state
352 states[currState]->exit();
353
354 // determine next state
355 double p = random_mt.gen_real1();
356 assert(currState < transitionMatrix.size());
357 double cumulative = 0.0;
358 size_t i = 0;
359 do {
360 cumulative += transitionMatrix[currState][i];
361 ++i;
362 } while (cumulative < p && i < transitionMatrix[currState].size());
363
364 enterState(i - 1);
365}
366
367void
368TrafficGen::enterState(uint32_t newState)
369{
370 DPRINTF(TrafficGen, "Transition to state %d\n", newState);
371
372 currState = newState;
373 // we could have been delayed and not transitioned on the exact
374 // tick when we were supposed to (due to back pressure when
375 // sending a packet)
376 nextTransitionTick = curTick() + states[currState]->duration;
377 states[currState]->enter();
378}
379
380void
381TrafficGen::recvRetry()
382{
383 assert(retryPkt != NULL);
384
385 DPRINTF(TrafficGen, "Received retry\n");
386 numRetries++;
387 // attempt to send the packet, and if we are successful start up
388 // the machinery again
389 if (port.sendTimingReq(retryPkt)) {
390 retryPkt = NULL;
391 // remember how much delay was incurred due to back-pressure
392 // when sending the request, we also use this to derive
393 // the tick for the next packet
394 Tick delay = curTick() - retryPktTick;
395 retryPktTick = 0;
396 retryTicks += delay;
397
398 if (drainManager == NULL) {
399 // packet is sent, so find out when the next one is due
400 nextPacketTick = states[currState]->nextPacketTick(elasticReq,
401 delay);
402 Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
403 schedule(updateEvent, std::max(curTick(), nextEventTick));
404 } else {
405 // shut things down
406 nextPacketTick = MaxTick;
407 nextTransitionTick = MaxTick;
408 drainManager->signalDrainDone();
409 // Clear the drain event once we're done with it.
410 drainManager = NULL;
411 }
412 }
413}
414
415void
416TrafficGen::regStats()
417{
418 // Initialise all the stats
419 using namespace Stats;
420
421 numPackets
422 .name(name() + ".numPackets")
423 .desc("Number of packets generated");
424
425 numRetries
426 .name(name() + ".numRetries")
427 .desc("Number of retries");
428
429 retryTicks
430 .name(name() + ".retryTicks")
431 .desc("Time spent waiting due to back-pressure (ticks)");
432}
433
434bool
435TrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
436{
437 delete pkt->req;
438 delete pkt;
439
440 return true;
441}