traffic_gen.cc (10051:6157b07daac7) traffic_gen.cc (10128:013bba88efab)
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 (!updateEvent.scheduled()) {
123 // no event has been scheduled yet (e.g. switched from atomic mode)
124 return 0;
125 }
126
127 if (retryPkt == NULL) {
128 // shut things down
129 nextPacketTick = MaxTick;
130 nextTransitionTick = MaxTick;
131 deschedule(updateEvent);
132 return 0;
133 } else {
134 drainManager = dm;
135 return 1;
136 }
137}
138
139void
140TrafficGen::serialize(ostream &os)
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(Checkpoint* cp, const string& section)
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 numPackets++;
190 if (!port.sendTimingReq(pkt)) {
191 retryPkt = pkt;
192 retryPktTick = curTick();
193 }
194 }
195
196 // if we are waiting for a retry, do not schedule any further
197 // events, in the case of a transition or a successful send, go
198 // ahead and determine when the next update should take place
199 if (retryPkt == NULL) {
200 // schedule next update event based on either the next execute
201 // tick or the next transition, which ever comes first
202 nextPacketTick = states[currState]->nextPacketTick(elasticReq, 0);
203 Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
204 DPRINTF(TrafficGen, "Next event scheduled at %lld\n", nextEventTick);
205 schedule(updateEvent, nextEventTick);
206 }
207}
208
209void
210TrafficGen::parseConfig()
211{
212 // keep track of the transitions parsed to create the matrix when
213 // done
214 vector<Transition> transitions;
215
216 // open input file
217 ifstream infile;
218 infile.open(configFile.c_str(), ifstream::in);
219 if (!infile.is_open()) {
220 fatal("Traffic generator %s config file not found at %s\n",
221 name(), configFile);
222 }
223
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 (!updateEvent.scheduled()) {
123 // no event has been scheduled yet (e.g. switched from atomic mode)
124 return 0;
125 }
126
127 if (retryPkt == NULL) {
128 // shut things down
129 nextPacketTick = MaxTick;
130 nextTransitionTick = MaxTick;
131 deschedule(updateEvent);
132 return 0;
133 } else {
134 drainManager = dm;
135 return 1;
136 }
137}
138
139void
140TrafficGen::serialize(ostream &os)
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(Checkpoint* cp, const string& section)
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 numPackets++;
190 if (!port.sendTimingReq(pkt)) {
191 retryPkt = pkt;
192 retryPktTick = curTick();
193 }
194 }
195
196 // if we are waiting for a retry, do not schedule any further
197 // events, in the case of a transition or a successful send, go
198 // ahead and determine when the next update should take place
199 if (retryPkt == NULL) {
200 // schedule next update event based on either the next execute
201 // tick or the next transition, which ever comes first
202 nextPacketTick = states[currState]->nextPacketTick(elasticReq, 0);
203 Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
204 DPRINTF(TrafficGen, "Next event scheduled at %lld\n", nextEventTick);
205 schedule(updateEvent, nextEventTick);
206 }
207}
208
209void
210TrafficGen::parseConfig()
211{
212 // keep track of the transitions parsed to create the matrix when
213 // done
214 vector<Transition> transitions;
215
216 // open input file
217 ifstream infile;
218 infile.open(configFile.c_str(), ifstream::in);
219 if (!infile.is_open()) {
220 fatal("Traffic generator %s config file not found at %s\n",
221 name(), configFile);
222 }
223
224 bool init_state_set = false;
225
224 // read line by line and determine the action based on the first
225 // keyword
226 string keyword;
227 string line;
228
229 while (getline(infile, line).good()) {
230 // see if this line is a comment line, and if so skip it
231 if (line.find('#') != 1) {
232 // create an input stream for the tokenization
233 istringstream is(line);
234
235 // determine the keyword
236 is >> keyword;
237
238 if (keyword == "STATE") {
239 // parse the behaviour of this state
240 uint32_t id;
241 Tick duration;
242 string mode;
243
244 is >> id >> duration >> mode;
245
246 if (mode == "TRACE") {
247 string traceFile;
248 Addr addrOffset;
249
250 is >> traceFile >> addrOffset;
251
252 states[id] = new TraceGen(name(), masterID, duration,
253 traceFile, addrOffset);
254 DPRINTF(TrafficGen, "State: %d TraceGen\n", id);
255 } else if (mode == "IDLE") {
256 states[id] = new IdleGen(name(), masterID, duration);
257 DPRINTF(TrafficGen, "State: %d IdleGen\n", id);
258 } else if (mode == "LINEAR" || mode == "RANDOM") {
259 uint32_t read_percent;
260 Addr start_addr;
261 Addr end_addr;
262 Addr blocksize;
263 Tick min_period;
264 Tick max_period;
265 Addr data_limit;
266
267 is >> read_percent >> start_addr >> end_addr >>
268 blocksize >> min_period >> max_period >> data_limit;
269
270 DPRINTF(TrafficGen, "%s, addr %x to %x, size %d,"
271 " period %d to %d, %d%% reads\n",
272 mode, start_addr, end_addr, blocksize, min_period,
273 max_period, read_percent);
274
275
276 if (blocksize > system->cacheLineSize())
277 fatal("TrafficGen %s block size (%d) is larger than "
278 "system block size (%d)\n", name(),
279 blocksize, system->cacheLineSize());
280
281 if (read_percent > 100)
282 fatal("%s cannot have more than 100% reads", name());
283
284 if (min_period > max_period)
285 fatal("%s cannot have min_period > max_period", name());
286
287 if (mode == "LINEAR") {
288 states[id] = new LinearGen(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 LinearGen\n", id);
294 } else if (mode == "RANDOM") {
295 states[id] = new RandomGen(name(), masterID,
296 duration, start_addr,
297 end_addr, blocksize,
298 min_period, max_period,
299 read_percent, data_limit);
300 DPRINTF(TrafficGen, "State: %d RandomGen\n", id);
301 }
302 } else {
303 fatal("%s: Unknown traffic generator mode: %s",
304 name(), mode);
305 }
306 } else if (keyword == "TRANSITION") {
307 Transition transition;
308
309 is >> transition.from >> transition.to >> transition.p;
310
311 transitions.push_back(transition);
312
313 DPRINTF(TrafficGen, "Transition: %d -> %d\n", transition.from,
314 transition.to);
315 } else if (keyword == "INIT") {
316 // set the initial state as the active state
317 is >> currState;
318
226 // read line by line and determine the action based on the first
227 // keyword
228 string keyword;
229 string line;
230
231 while (getline(infile, line).good()) {
232 // see if this line is a comment line, and if so skip it
233 if (line.find('#') != 1) {
234 // create an input stream for the tokenization
235 istringstream is(line);
236
237 // determine the keyword
238 is >> keyword;
239
240 if (keyword == "STATE") {
241 // parse the behaviour of this state
242 uint32_t id;
243 Tick duration;
244 string mode;
245
246 is >> id >> duration >> mode;
247
248 if (mode == "TRACE") {
249 string traceFile;
250 Addr addrOffset;
251
252 is >> traceFile >> addrOffset;
253
254 states[id] = new TraceGen(name(), masterID, duration,
255 traceFile, addrOffset);
256 DPRINTF(TrafficGen, "State: %d TraceGen\n", id);
257 } else if (mode == "IDLE") {
258 states[id] = new IdleGen(name(), masterID, duration);
259 DPRINTF(TrafficGen, "State: %d IdleGen\n", id);
260 } else if (mode == "LINEAR" || mode == "RANDOM") {
261 uint32_t read_percent;
262 Addr start_addr;
263 Addr end_addr;
264 Addr blocksize;
265 Tick min_period;
266 Tick max_period;
267 Addr data_limit;
268
269 is >> read_percent >> start_addr >> end_addr >>
270 blocksize >> min_period >> max_period >> data_limit;
271
272 DPRINTF(TrafficGen, "%s, addr %x to %x, size %d,"
273 " period %d to %d, %d%% reads\n",
274 mode, start_addr, end_addr, blocksize, min_period,
275 max_period, read_percent);
276
277
278 if (blocksize > system->cacheLineSize())
279 fatal("TrafficGen %s block size (%d) is larger than "
280 "system block size (%d)\n", name(),
281 blocksize, system->cacheLineSize());
282
283 if (read_percent > 100)
284 fatal("%s cannot have more than 100% reads", name());
285
286 if (min_period > max_period)
287 fatal("%s cannot have min_period > max_period", name());
288
289 if (mode == "LINEAR") {
290 states[id] = new LinearGen(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 LinearGen\n", id);
296 } else if (mode == "RANDOM") {
297 states[id] = new RandomGen(name(), masterID,
298 duration, start_addr,
299 end_addr, blocksize,
300 min_period, max_period,
301 read_percent, data_limit);
302 DPRINTF(TrafficGen, "State: %d RandomGen\n", id);
303 }
304 } else {
305 fatal("%s: Unknown traffic generator mode: %s",
306 name(), mode);
307 }
308 } else if (keyword == "TRANSITION") {
309 Transition transition;
310
311 is >> transition.from >> transition.to >> transition.p;
312
313 transitions.push_back(transition);
314
315 DPRINTF(TrafficGen, "Transition: %d -> %d\n", transition.from,
316 transition.to);
317 } else if (keyword == "INIT") {
318 // set the initial state as the active state
319 is >> currState;
320
321 init_state_set = true;
322
319 DPRINTF(TrafficGen, "Initial state: %d\n", currState);
320 }
321 }
322 }
323
323 DPRINTF(TrafficGen, "Initial state: %d\n", currState);
324 }
325 }
326 }
327
328 if (!init_state_set)
329 fatal("%s: initial state not specified (add 'INIT <id>' line "
330 "to the config file)\n", name());
331
324 // resize and populate state transition matrix
325 transitionMatrix.resize(states.size());
326 for (size_t i = 0; i < states.size(); i++) {
327 transitionMatrix[i].resize(states.size());
328 }
329
330 for (vector<Transition>::iterator t = transitions.begin();
331 t != transitions.end(); ++t) {
332 transitionMatrix[t->from][t->to] = t->p;
333 }
334
335 // ensure the egress edges do not have a probability larger than
336 // one
337 for (size_t i = 0; i < states.size(); i++) {
338 double sum = 0;
339 for (size_t j = 0; j < states.size(); j++) {
340 sum += transitionMatrix[i][j];
341 }
342
343 // avoid comparing floating point numbers
344 if (abs(sum - 1.0) > 0.001)
345 fatal("%s has transition probability != 1 for state %d\n",
346 name(), i);
347 }
348
349 // close input file
350 infile.close();
351}
352
353void
354TrafficGen::transition()
355{
356 // exit the current state
357 states[currState]->exit();
358
359 // determine next state
360 double p = random_mt.gen_real1();
361 assert(currState < transitionMatrix.size());
362 double cumulative = 0.0;
363 size_t i = 0;
364 do {
365 cumulative += transitionMatrix[currState][i];
366 ++i;
367 } while (cumulative < p && i < transitionMatrix[currState].size());
368
369 enterState(i - 1);
370}
371
372void
373TrafficGen::enterState(uint32_t newState)
374{
375 DPRINTF(TrafficGen, "Transition to state %d\n", newState);
376
377 currState = newState;
378 // we could have been delayed and not transitioned on the exact
379 // tick when we were supposed to (due to back pressure when
380 // sending a packet)
381 nextTransitionTick = curTick() + states[currState]->duration;
382 states[currState]->enter();
383}
384
385void
386TrafficGen::recvRetry()
387{
388 assert(retryPkt != NULL);
389
390 DPRINTF(TrafficGen, "Received retry\n");
391 numRetries++;
392 // attempt to send the packet, and if we are successful start up
393 // the machinery again
394 if (port.sendTimingReq(retryPkt)) {
395 retryPkt = NULL;
396 // remember how much delay was incurred due to back-pressure
397 // when sending the request, we also use this to derive
398 // the tick for the next packet
399 Tick delay = curTick() - retryPktTick;
400 retryPktTick = 0;
401 retryTicks += delay;
402
403 if (drainManager == NULL) {
404 // packet is sent, so find out when the next one is due
405 nextPacketTick = states[currState]->nextPacketTick(elasticReq,
406 delay);
407 Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
408 schedule(updateEvent, std::max(curTick(), nextEventTick));
409 } else {
410 // shut things down
411 nextPacketTick = MaxTick;
412 nextTransitionTick = MaxTick;
413 drainManager->signalDrainDone();
414 // Clear the drain event once we're done with it.
415 drainManager = NULL;
416 }
417 }
418}
419
420void
421TrafficGen::regStats()
422{
423 // Initialise all the stats
424 using namespace Stats;
425
426 numPackets
427 .name(name() + ".numPackets")
428 .desc("Number of packets generated");
429
430 numRetries
431 .name(name() + ".numRetries")
432 .desc("Number of retries");
433
434 retryTicks
435 .name(name() + ".retryTicks")
436 .desc("Time spent waiting due to back-pressure (ticks)");
437}
438
439bool
440TrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
441{
442 delete pkt->req;
443 delete pkt;
444
445 return true;
446}
332 // resize and populate state transition matrix
333 transitionMatrix.resize(states.size());
334 for (size_t i = 0; i < states.size(); i++) {
335 transitionMatrix[i].resize(states.size());
336 }
337
338 for (vector<Transition>::iterator t = transitions.begin();
339 t != transitions.end(); ++t) {
340 transitionMatrix[t->from][t->to] = t->p;
341 }
342
343 // ensure the egress edges do not have a probability larger than
344 // one
345 for (size_t i = 0; i < states.size(); i++) {
346 double sum = 0;
347 for (size_t j = 0; j < states.size(); j++) {
348 sum += transitionMatrix[i][j];
349 }
350
351 // avoid comparing floating point numbers
352 if (abs(sum - 1.0) > 0.001)
353 fatal("%s has transition probability != 1 for state %d\n",
354 name(), i);
355 }
356
357 // close input file
358 infile.close();
359}
360
361void
362TrafficGen::transition()
363{
364 // exit the current state
365 states[currState]->exit();
366
367 // determine next state
368 double p = random_mt.gen_real1();
369 assert(currState < transitionMatrix.size());
370 double cumulative = 0.0;
371 size_t i = 0;
372 do {
373 cumulative += transitionMatrix[currState][i];
374 ++i;
375 } while (cumulative < p && i < transitionMatrix[currState].size());
376
377 enterState(i - 1);
378}
379
380void
381TrafficGen::enterState(uint32_t newState)
382{
383 DPRINTF(TrafficGen, "Transition to state %d\n", newState);
384
385 currState = newState;
386 // we could have been delayed and not transitioned on the exact
387 // tick when we were supposed to (due to back pressure when
388 // sending a packet)
389 nextTransitionTick = curTick() + states[currState]->duration;
390 states[currState]->enter();
391}
392
393void
394TrafficGen::recvRetry()
395{
396 assert(retryPkt != NULL);
397
398 DPRINTF(TrafficGen, "Received retry\n");
399 numRetries++;
400 // attempt to send the packet, and if we are successful start up
401 // the machinery again
402 if (port.sendTimingReq(retryPkt)) {
403 retryPkt = NULL;
404 // remember how much delay was incurred due to back-pressure
405 // when sending the request, we also use this to derive
406 // the tick for the next packet
407 Tick delay = curTick() - retryPktTick;
408 retryPktTick = 0;
409 retryTicks += delay;
410
411 if (drainManager == NULL) {
412 // packet is sent, so find out when the next one is due
413 nextPacketTick = states[currState]->nextPacketTick(elasticReq,
414 delay);
415 Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
416 schedule(updateEvent, std::max(curTick(), nextEventTick));
417 } else {
418 // shut things down
419 nextPacketTick = MaxTick;
420 nextTransitionTick = MaxTick;
421 drainManager->signalDrainDone();
422 // Clear the drain event once we're done with it.
423 drainManager = NULL;
424 }
425 }
426}
427
428void
429TrafficGen::regStats()
430{
431 // Initialise all the stats
432 using namespace Stats;
433
434 numPackets
435 .name(name() + ".numPackets")
436 .desc("Number of packets generated");
437
438 numRetries
439 .name(name() + ".numRetries")
440 .desc("Number of retries");
441
442 retryTicks
443 .name(name() + ".retryTicks")
444 .desc("Time spent waiting due to back-pressure (ticks)");
445}
446
447bool
448TrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
449{
450 delete pkt->req;
451 delete pkt;
452
453 return true;
454}