traffic_gen.cc (9584:1a21964b7227) traffic_gen.cc (9666:74aca4cb081e)
1/*
2 * Copyright (c) 2012 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"
1/*
2 * Copyright (c) 2012 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 "proto/packet.pb.h"
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 port(name() + ".port", *this),
59 stateGraph(*this, port, p->config_file, masterID),
60 updateStateGraphEvent(this)
61{
62}
63
64TrafficGen*
65TrafficGenParams::create()
66{
67 return new TrafficGen(this);
68}
69
70BaseMasterPort&
71TrafficGen::getMasterPort(const string& if_name, PortID idx)
72{
73 if (if_name == "port") {
74 return port;
75 } else {
76 return MemObject::getMasterPort(if_name, idx);
77 }
78}
79
80void
81TrafficGen::init()
82{
83 if (!port.isConnected())
84 fatal("The port of %s is not connected!\n", name());
85
86 // if the system is in timing mode active the request generator
87 if (system->isTimingMode()) {
88 DPRINTF(TrafficGen, "Timing mode, activating request generator\n");
89
90 // enter initial state
91 stateGraph.enterState(stateGraph.currState);
92 } else {
93 DPRINTF(TrafficGen,
94 "Traffic generator is only active in timing mode\n");
95 }
96}
97
98void
99TrafficGen::initState()
100{
101 // when not restoring from a checkpoint, make sure we kick things off
102 if (system->isTimingMode()) {
103 Tick nextStateGraphEvent = stateGraph.nextEventTick();
104 schedule(updateStateGraphEvent, nextStateGraphEvent);
105 } else {
106 DPRINTF(TrafficGen,
107 "Traffic generator is only active in timing mode\n");
108 }
109}
110
111unsigned int
112TrafficGen::drain(DrainManager *dm)
113{
114 // @todo we should also stop putting new requests in the queue and
115 // either interrupt the current state or wait for a transition
116 return port.drain(dm);
117}
118
119void
120TrafficGen::serialize(ostream &os)
121{
122 DPRINTF(Checkpoint, "Serializing TrafficGen\n");
123
124 // save ticks of the graph event if it is scheduled
125 Tick nextStateGraphEvent = updateStateGraphEvent.scheduled() ?
126 updateStateGraphEvent.when() : 0;
127
128 DPRINTF(TrafficGen, "Saving nextStateGraphEvent=%llu\n",
129 nextStateGraphEvent);
130
131 SERIALIZE_SCALAR(nextStateGraphEvent);
132
133 Tick nextTransitionTick = stateGraph.nextTransitionTick;
134 SERIALIZE_SCALAR(nextTransitionTick);
135
136 // @todo: also serialise the current state, figure out the best
137 // way to drain and restore
138}
139
140void
141TrafficGen::unserialize(Checkpoint* cp, const string& section)
142{
143 // restore scheduled events
144 Tick nextStateGraphEvent;
145 UNSERIALIZE_SCALAR(nextStateGraphEvent);
146 if (nextStateGraphEvent != 0) {
147 schedule(updateStateGraphEvent, nextStateGraphEvent);
148 }
149
150 Tick nextTransitionTick;
151 UNSERIALIZE_SCALAR(nextTransitionTick);
152 stateGraph.nextTransitionTick = nextTransitionTick;
153}
154
155void
156TrafficGen::updateStateGraph()
157{
158 // schedule next update event based on either the next execute
159 // tick or the next transition, which ever comes first
160 Tick nextStateGraphEvent = stateGraph.nextEventTick();
161 DPRINTF(TrafficGen, "Updating state graph, next event at %lld\n",
162 nextStateGraphEvent);
163 schedule(updateStateGraphEvent, nextStateGraphEvent);
164
165 // perform the update associated with the current update event
166 stateGraph.update();
167}
168
169void
170TrafficGen::StateGraph::parseConfig(const string& file_name,
171 MasterID master_id)
172{
173 // keep track of the transitions parsed to create the matrix when
174 // done
175 vector<Transition> transitions;
176
177 // open input file
178 ifstream infile;
179 infile.open(file_name.c_str(), ifstream::in);
180 if (!infile.is_open()) {
181 fatal("Traffic generator %s config file not found at %s\n",
182 owner.name(), file_name);
183 }
184
185 // read line by line and determine the action based on the first
186 // keyword
187 string keyword;
188 string line;
189
190 while (getline(infile, line).good()) {
191 // see if this line is a comment line, and if so skip it
192 if (line.find('#') != 1) {
193 // create an input stream for the tokenization
194 istringstream is(line);
195
196 // determine the keyword
197 is >> keyword;
198
199 if (keyword == "STATE") {
200 // parse the behaviour of this state
201 uint32_t id;
202 Tick duration;
203 string mode;
204
205 is >> id >> duration >> mode;
206
207 if (mode == "TRACE") {
208 string traceFile;
209 Addr addrOffset;
210
211 is >> traceFile >> addrOffset;
212
213 states[id] = new TraceGen(port, master_id, duration,
214 traceFile, addrOffset);
215 DPRINTF(TrafficGen, "State: %d TraceGen\n", id);
216 } else if (mode == "IDLE") {
217 states[id] = new IdleGen(port, master_id, duration);
218 DPRINTF(TrafficGen, "State: %d IdleGen\n", id);
219 } else if (mode == "LINEAR" || mode == "RANDOM") {
220 uint32_t read_percent;
221 Addr start_addr;
222 Addr end_addr;
223 Addr blocksize;
224 Tick min_period;
225 Tick max_period;
226 Addr data_limit;
227
228 is >> read_percent >> start_addr >> end_addr >>
229 blocksize >> min_period >> max_period >> data_limit;
230
231 DPRINTF(TrafficGen, "%s, addr %x to %x, size %d,"
232 " period %d to %d, %d%% reads\n",
233 mode, start_addr, end_addr, blocksize, min_period,
234 max_period, read_percent);
235
236 if (read_percent > 100)
237 panic("%s cannot have more than 100% reads", name());
238
239 if (mode == "LINEAR") {
240 states[id] = new LinearGen(port, master_id,
241 duration, start_addr,
242 end_addr, blocksize,
243 min_period, max_period,
244 read_percent, data_limit);
245 DPRINTF(TrafficGen, "State: %d LinearGen\n", id);
246 } else if (mode == "RANDOM") {
247 states[id] = new RandomGen(port, master_id,
248 duration, start_addr,
249 end_addr, blocksize,
250 min_period, max_period,
251 read_percent, data_limit);
252 DPRINTF(TrafficGen, "State: %d RandomGen\n", id);
253 }
254 } else {
255 fatal("%s: Unknown traffic generator mode: %s",
256 name(), mode);
257 }
258 } else if (keyword == "TRANSITION") {
259 Transition transition;
260
261 is >> transition.from >> transition.to >> transition.p;
262
263 transitions.push_back(transition);
264
265 DPRINTF(TrafficGen, "Transition: %d -> %d\n", transition.from,
266 transition.to);
267 } else if (keyword == "INIT") {
268 // set the initial state as the active state
269 is >> currState;
270
271 DPRINTF(TrafficGen, "Initial state: %d\n", currState);
272 }
273 }
274 }
275
276 // resize and populate state transition matrix
277 transitionMatrix.resize(transitions.size());
278 for (size_t i = 0; i < transitions.size(); i++) {
279 transitionMatrix[i].resize(transitions.size());
280 }
281
282 for (vector<Transition>::iterator t = transitions.begin();
283 t != transitions.end(); ++t) {
284 transitionMatrix[t->from][t->to] = t->p;
285 }
286
287 // ensure the egress edges do not have a probability larger than
288 // one
289 for (size_t i = 0; i < transitions.size(); i++) {
290 double sum = 0;
291 for (size_t j = 0; j < transitions.size(); j++) {
292 sum += transitionMatrix[i][j];
293 }
294
295 // avoid comparing floating point numbers
296 if (abs(sum - 1.0) > 0.001)
297 fatal("%s has transition probability != 1 for state %d\n",
298 name(), i);
299 }
300
301 // close input file
302 infile.close();
303}
304
305void
306TrafficGen::StateGraph::update()
307{
308 // if we have reached the time for the next state transition, then
309 // perform the transition
310 if (curTick() >= nextTransitionTick) {
311 transition();
312 } else {
313 // we are still in the current state and should execute it
314 states[currState]->execute();
315 }
316}
317
318void
319TrafficGen::StateGraph::transition()
320{
321 // exit the current state
322 states[currState]->exit();
323
324 // determine next state
325 double p = random_mt.gen_real1();
326 assert(currState < transitionMatrix.size());
327 double cumulative = 0.0;
328 size_t i = 0;
329 do {
330 cumulative += transitionMatrix[currState][i];
331 ++i;
332 } while (cumulative < p && i < transitionMatrix[currState].size());
333
334 enterState(i - 1);
335}
336
337void
338TrafficGen::StateGraph::enterState(uint32_t newState)
339{
340 DPRINTF(TrafficGen, "Transition to state %d\n", newState);
341
342 currState = newState;
343 nextTransitionTick += states[currState]->duration;
344 states[currState]->enter();
345}
346
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 port(name() + ".port", *this),
58 stateGraph(*this, port, p->config_file, masterID),
59 updateStateGraphEvent(this)
60{
61}
62
63TrafficGen*
64TrafficGenParams::create()
65{
66 return new TrafficGen(this);
67}
68
69BaseMasterPort&
70TrafficGen::getMasterPort(const string& if_name, PortID idx)
71{
72 if (if_name == "port") {
73 return port;
74 } else {
75 return MemObject::getMasterPort(if_name, idx);
76 }
77}
78
79void
80TrafficGen::init()
81{
82 if (!port.isConnected())
83 fatal("The port of %s is not connected!\n", name());
84
85 // if the system is in timing mode active the request generator
86 if (system->isTimingMode()) {
87 DPRINTF(TrafficGen, "Timing mode, activating request generator\n");
88
89 // enter initial state
90 stateGraph.enterState(stateGraph.currState);
91 } else {
92 DPRINTF(TrafficGen,
93 "Traffic generator is only active in timing mode\n");
94 }
95}
96
97void
98TrafficGen::initState()
99{
100 // when not restoring from a checkpoint, make sure we kick things off
101 if (system->isTimingMode()) {
102 Tick nextStateGraphEvent = stateGraph.nextEventTick();
103 schedule(updateStateGraphEvent, nextStateGraphEvent);
104 } else {
105 DPRINTF(TrafficGen,
106 "Traffic generator is only active in timing mode\n");
107 }
108}
109
110unsigned int
111TrafficGen::drain(DrainManager *dm)
112{
113 // @todo we should also stop putting new requests in the queue and
114 // either interrupt the current state or wait for a transition
115 return port.drain(dm);
116}
117
118void
119TrafficGen::serialize(ostream &os)
120{
121 DPRINTF(Checkpoint, "Serializing TrafficGen\n");
122
123 // save ticks of the graph event if it is scheduled
124 Tick nextStateGraphEvent = updateStateGraphEvent.scheduled() ?
125 updateStateGraphEvent.when() : 0;
126
127 DPRINTF(TrafficGen, "Saving nextStateGraphEvent=%llu\n",
128 nextStateGraphEvent);
129
130 SERIALIZE_SCALAR(nextStateGraphEvent);
131
132 Tick nextTransitionTick = stateGraph.nextTransitionTick;
133 SERIALIZE_SCALAR(nextTransitionTick);
134
135 // @todo: also serialise the current state, figure out the best
136 // way to drain and restore
137}
138
139void
140TrafficGen::unserialize(Checkpoint* cp, const string& section)
141{
142 // restore scheduled events
143 Tick nextStateGraphEvent;
144 UNSERIALIZE_SCALAR(nextStateGraphEvent);
145 if (nextStateGraphEvent != 0) {
146 schedule(updateStateGraphEvent, nextStateGraphEvent);
147 }
148
149 Tick nextTransitionTick;
150 UNSERIALIZE_SCALAR(nextTransitionTick);
151 stateGraph.nextTransitionTick = nextTransitionTick;
152}
153
154void
155TrafficGen::updateStateGraph()
156{
157 // schedule next update event based on either the next execute
158 // tick or the next transition, which ever comes first
159 Tick nextStateGraphEvent = stateGraph.nextEventTick();
160 DPRINTF(TrafficGen, "Updating state graph, next event at %lld\n",
161 nextStateGraphEvent);
162 schedule(updateStateGraphEvent, nextStateGraphEvent);
163
164 // perform the update associated with the current update event
165 stateGraph.update();
166}
167
168void
169TrafficGen::StateGraph::parseConfig(const string& file_name,
170 MasterID master_id)
171{
172 // keep track of the transitions parsed to create the matrix when
173 // done
174 vector<Transition> transitions;
175
176 // open input file
177 ifstream infile;
178 infile.open(file_name.c_str(), ifstream::in);
179 if (!infile.is_open()) {
180 fatal("Traffic generator %s config file not found at %s\n",
181 owner.name(), file_name);
182 }
183
184 // read line by line and determine the action based on the first
185 // keyword
186 string keyword;
187 string line;
188
189 while (getline(infile, line).good()) {
190 // see if this line is a comment line, and if so skip it
191 if (line.find('#') != 1) {
192 // create an input stream for the tokenization
193 istringstream is(line);
194
195 // determine the keyword
196 is >> keyword;
197
198 if (keyword == "STATE") {
199 // parse the behaviour of this state
200 uint32_t id;
201 Tick duration;
202 string mode;
203
204 is >> id >> duration >> mode;
205
206 if (mode == "TRACE") {
207 string traceFile;
208 Addr addrOffset;
209
210 is >> traceFile >> addrOffset;
211
212 states[id] = new TraceGen(port, master_id, duration,
213 traceFile, addrOffset);
214 DPRINTF(TrafficGen, "State: %d TraceGen\n", id);
215 } else if (mode == "IDLE") {
216 states[id] = new IdleGen(port, master_id, duration);
217 DPRINTF(TrafficGen, "State: %d IdleGen\n", id);
218 } else if (mode == "LINEAR" || mode == "RANDOM") {
219 uint32_t read_percent;
220 Addr start_addr;
221 Addr end_addr;
222 Addr blocksize;
223 Tick min_period;
224 Tick max_period;
225 Addr data_limit;
226
227 is >> read_percent >> start_addr >> end_addr >>
228 blocksize >> min_period >> max_period >> data_limit;
229
230 DPRINTF(TrafficGen, "%s, addr %x to %x, size %d,"
231 " period %d to %d, %d%% reads\n",
232 mode, start_addr, end_addr, blocksize, min_period,
233 max_period, read_percent);
234
235 if (read_percent > 100)
236 panic("%s cannot have more than 100% reads", name());
237
238 if (mode == "LINEAR") {
239 states[id] = new LinearGen(port, master_id,
240 duration, start_addr,
241 end_addr, blocksize,
242 min_period, max_period,
243 read_percent, data_limit);
244 DPRINTF(TrafficGen, "State: %d LinearGen\n", id);
245 } else if (mode == "RANDOM") {
246 states[id] = new RandomGen(port, master_id,
247 duration, start_addr,
248 end_addr, blocksize,
249 min_period, max_period,
250 read_percent, data_limit);
251 DPRINTF(TrafficGen, "State: %d RandomGen\n", id);
252 }
253 } else {
254 fatal("%s: Unknown traffic generator mode: %s",
255 name(), mode);
256 }
257 } else if (keyword == "TRANSITION") {
258 Transition transition;
259
260 is >> transition.from >> transition.to >> transition.p;
261
262 transitions.push_back(transition);
263
264 DPRINTF(TrafficGen, "Transition: %d -> %d\n", transition.from,
265 transition.to);
266 } else if (keyword == "INIT") {
267 // set the initial state as the active state
268 is >> currState;
269
270 DPRINTF(TrafficGen, "Initial state: %d\n", currState);
271 }
272 }
273 }
274
275 // resize and populate state transition matrix
276 transitionMatrix.resize(transitions.size());
277 for (size_t i = 0; i < transitions.size(); i++) {
278 transitionMatrix[i].resize(transitions.size());
279 }
280
281 for (vector<Transition>::iterator t = transitions.begin();
282 t != transitions.end(); ++t) {
283 transitionMatrix[t->from][t->to] = t->p;
284 }
285
286 // ensure the egress edges do not have a probability larger than
287 // one
288 for (size_t i = 0; i < transitions.size(); i++) {
289 double sum = 0;
290 for (size_t j = 0; j < transitions.size(); j++) {
291 sum += transitionMatrix[i][j];
292 }
293
294 // avoid comparing floating point numbers
295 if (abs(sum - 1.0) > 0.001)
296 fatal("%s has transition probability != 1 for state %d\n",
297 name(), i);
298 }
299
300 // close input file
301 infile.close();
302}
303
304void
305TrafficGen::StateGraph::update()
306{
307 // if we have reached the time for the next state transition, then
308 // perform the transition
309 if (curTick() >= nextTransitionTick) {
310 transition();
311 } else {
312 // we are still in the current state and should execute it
313 states[currState]->execute();
314 }
315}
316
317void
318TrafficGen::StateGraph::transition()
319{
320 // exit the current state
321 states[currState]->exit();
322
323 // determine next state
324 double p = random_mt.gen_real1();
325 assert(currState < transitionMatrix.size());
326 double cumulative = 0.0;
327 size_t i = 0;
328 do {
329 cumulative += transitionMatrix[currState][i];
330 ++i;
331 } while (cumulative < p && i < transitionMatrix[currState].size());
332
333 enterState(i - 1);
334}
335
336void
337TrafficGen::StateGraph::enterState(uint32_t newState)
338{
339 DPRINTF(TrafficGen, "Transition to state %d\n", newState);
340
341 currState = newState;
342 nextTransitionTick += states[currState]->duration;
343 states[currState]->enter();
344}
345
347TrafficGen::StateGraph::BaseGen::BaseGen(QueuedMasterPort& _port,
348 MasterID master_id,
349 Tick _duration)
350 : port(_port), masterID(master_id), duration(_duration)
351{
352}
353
354void
355TrafficGen::StateGraph::BaseGen::send(Addr addr, unsigned size,
356 const MemCmd& cmd)
357{
358 // Create new request
359 Request::Flags flags;
360 Request *req = new Request(addr, size, flags, masterID);
361
362 // Embed it in a packet
363 PacketPtr pkt = new Packet(req, cmd);
364
365 uint8_t* pkt_data = new uint8_t[req->getSize()];
366 pkt->dataDynamicArray(pkt_data);
367
368 if (cmd.isWrite()) {
369 memset(pkt_data, 0xA, req->getSize());
370 }
371
372 port.schedTimingReq(pkt, curTick());
373}
374
375void
376TrafficGen::StateGraph::LinearGen::enter()
377{
378 // reset the address and the data counter
379 nextAddr = startAddr;
380 dataManipulated = 0;
381
382 // this test only needs to happen once, but cannot be performed
383 // before init() is called and the ports are connected
384 if (port.deviceBlockSize() && blocksize > port.deviceBlockSize())
385 fatal("TrafficGen %s block size (%d) is larger than port"
386 " block size (%d)\n", blocksize, port.deviceBlockSize());
387
388}
389
390void
391TrafficGen::StateGraph::LinearGen::execute()
392{
393 // choose if we generate a read or a write here
394 bool isRead = readPercent != 0 &&
395 (readPercent == 100 || random_mt.random<uint8_t>(0, 100) < readPercent);
396
397 assert((readPercent == 0 && !isRead) || (readPercent == 100 && isRead) ||
398 readPercent != 100);
399
400 DPRINTF(TrafficGen, "LinearGen::execute: %c to addr %x, size %d\n",
401 isRead ? 'r' : 'w', nextAddr, blocksize);
402
403 send(nextAddr, blocksize, isRead ? MemCmd::ReadReq : MemCmd::WriteReq);
404
405 // increment the address
406 nextAddr += blocksize;
407
408 // Add the amount of data manipulated to the total
409 dataManipulated += blocksize;
410}
411
412Tick
413TrafficGen::StateGraph::LinearGen::nextExecuteTick()
414{
415 // If we have reached the end of the address space, reset the
416 // address to the start of the range
417 if (nextAddr + blocksize > endAddr) {
418 DPRINTF(TrafficGen, "Wrapping address to the start of "
419 "the range\n");
420 nextAddr = startAddr;
421 }
422
423 // Check to see if we have reached the data limit. If dataLimit is
424 // zero we do not have a data limit and therefore we will keep
425 // generating requests for the entire residency in this state.
426 if (dataLimit && dataManipulated >= dataLimit) {
427 DPRINTF(TrafficGen, "Data limit for LinearGen reached.\n");
428 // there are no more requests, therefore return MaxTick
429 return MaxTick;
430 } else {
431 // return the time when the next request should take place
432 return curTick() + random_mt.random<Tick>(minPeriod, maxPeriod);
433 }
434}
435
436void
437TrafficGen::StateGraph::RandomGen::enter()
438{
439 // reset the counter to zero
440 dataManipulated = 0;
441
442 // this test only needs to happen once, but cannot be performed
443 // before init() is called and the ports are connected
444 if (port.deviceBlockSize() && blocksize > port.deviceBlockSize())
445 fatal("TrafficGen %s block size (%d) is larger than port"
446 " block size (%d)\n", name(), blocksize, port.deviceBlockSize());
447}
448
449void
450TrafficGen::StateGraph::RandomGen::execute()
451{
452 // choose if we generate a read or a write here
453 bool isRead = readPercent != 0 &&
454 (readPercent == 100 || random_mt.random<uint8_t>(0, 100) < readPercent);
455
456 assert((readPercent == 0 && !isRead) || (readPercent == 100 && isRead) ||
457 readPercent != 100);
458
459 // address of the request
460 Addr addr = random_mt.random<Addr>(startAddr, endAddr - 1);
461
462 // round down to start address of block
463 addr -= addr % blocksize;
464
465 DPRINTF(TrafficGen, "RandomGen::execute: %c to addr %x, size %d\n",
466 isRead ? 'r' : 'w', addr, blocksize);
467
468 // send a new request packet
469 send(addr, blocksize, isRead ? MemCmd::ReadReq : MemCmd::WriteReq);
470
471 // Add the amount of data manipulated to the total
472 dataManipulated += blocksize;
473}
474
475Tick
476TrafficGen::StateGraph::RandomGen::nextExecuteTick()
477{
478 // Check to see if we have reached the data limit. If dataLimit is
479 // zero we do not have a data limit and therefore we will keep
480 // generating requests for the entire residency in this state.
481 if (dataLimit && dataManipulated >= dataLimit)
482 {
483 DPRINTF(TrafficGen, "Data limit for RandomGen reached.\n");
484 // No more requests. Return MaxTick.
485 return MaxTick;
486 } else {
487 // Return the time when the next request should take place.
488 return curTick() + random_mt.random<Tick>(minPeriod, maxPeriod);
489 }
490}
491
492TrafficGen::StateGraph::TraceGen::InputStream::InputStream(const string&
493 filename)
494 : trace(filename)
495{
496 // Create a protobuf message for the header and read it from the stream
497 Message::PacketHeader header_msg;
498 if (!trace.read(header_msg)) {
499 panic("Failed to read packet header from %s\n", filename);
500
501 if (header_msg.tick_freq() != SimClock::Frequency) {
502 panic("Trace %s was recorded with a different tick frequency %d\n",
503 header_msg.tick_freq());
504 }
505 }
506}
507
508void
509TrafficGen::StateGraph::TraceGen::InputStream::reset()
510{
511 trace.reset();
512}
513
514bool
346bool
515TrafficGen::StateGraph::TraceGen::InputStream::read(TraceElement& element)
516{
517 Message::Packet pkt_msg;
518 if (trace.read(pkt_msg)) {
519 element.cmd = pkt_msg.cmd();
520 element.addr = pkt_msg.addr();
521 element.blocksize = pkt_msg.size();
522 element.tick = pkt_msg.tick();
523 return true;
524 }
525
526 // We have reached the end of the file
527 return false;
528}
529
530Tick
531TrafficGen::StateGraph::TraceGen::nextExecuteTick() {
532 if (traceComplete)
533 // We are at the end of the file, thus we have no more data in
534 // the trace Return MaxTick to signal that there will be no
535 // more transactions in this active period for the state.
536 return MaxTick;
537
538
539 //Reset the nextElement to the default values
540 currElement = nextElement;
541 nextElement.clear();
542
543 // We need to look at the next line to calculate the next time an
544 // event occurs, or potentially return MaxTick to signal that
545 // nothing has to be done.
546 if (!trace.read(nextElement)) {
547 traceComplete = true;
548 return MaxTick;
549 }
550
551 DPRINTF(TrafficGen, "currElement: %c addr %d size %d tick %d (%d)\n",
552 currElement.cmd.isRead() ? 'r' : 'w',
553 currElement.addr,
554 currElement.blocksize,
555 currElement.tick + tickOffset,
556 currElement.tick);
557
558 DPRINTF(TrafficGen, "nextElement: %c addr %d size %d tick %d (%d)\n",
559 nextElement.cmd.isRead() ? 'r' : 'w',
560 nextElement.addr,
561 nextElement.blocksize,
562 nextElement.tick + tickOffset,
563 nextElement.tick);
564
565 return tickOffset + nextElement.tick;
566}
567
568void
569TrafficGen::StateGraph::TraceGen::enter() {
570 // update the trace offset to the time where the state was entered.
571 tickOffset = curTick();
572
573 // clear everything
574 nextElement.clear();
575 currElement.clear();
576
577 traceComplete = false;
578}
579
580void
581TrafficGen::StateGraph::TraceGen::execute() {
582 // it is the responsibility of nextExecuteTick to prevent the
583 // state graph from executing the state if it should not
584 assert(currElement.isValid());
585
586 DPRINTF(TrafficGen, "TraceGen::execute: %c %d %d %d\n",
587 currElement.cmd.isRead() ? 'r' : 'w',
588 currElement.addr,
589 currElement.blocksize,
590 currElement.tick);
591
592 send(currElement.addr + addrOffset, currElement.blocksize,
593 currElement.cmd);
594}
595
596void
597TrafficGen::StateGraph::TraceGen::exit() {
598 // Check if we reached the end of the trace file. If we did not
599 // then we want to generate a warning stating that not the entire
600 // trace was played.
601 if (!traceComplete) {
602 warn("Trace player %s was unable to replay the entire trace!\n",
603 name());
604 }
605
606 // Clear any flags and start over again from the beginning of the
607 // file
608 trace.reset();
609}
610
611bool
612TrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
613{
614 delete pkt->req;
615 delete pkt;
616
617 return true;
618}
347TrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
348{
349 delete pkt->req;
350 delete pkt;
351
352 return true;
353}