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