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