traffic_gen.cc revision 9241
112027Sjungma@eit.uni-kl.de/*
212027Sjungma@eit.uni-kl.de * Copyright (c) 2012 ARM Limited
312027Sjungma@eit.uni-kl.de * All rights reserved
412027Sjungma@eit.uni-kl.de *
512027Sjungma@eit.uni-kl.de * The license below extends only to copyright in the software and shall
612027Sjungma@eit.uni-kl.de * not be construed as granting a license to any other intellectual
712027Sjungma@eit.uni-kl.de * property including but not limited to intellectual property relating
812027Sjungma@eit.uni-kl.de * to a hardware implementation of the functionality of the software
912027Sjungma@eit.uni-kl.de * licensed hereunder.  You may use the software subject to the license
1012027Sjungma@eit.uni-kl.de * terms below provided that you ensure that this notice is replicated
1112027Sjungma@eit.uni-kl.de * unmodified and in its entirety in all distributions of the software,
1212027Sjungma@eit.uni-kl.de * modified or unmodified, in source code or in binary form.
1312027Sjungma@eit.uni-kl.de *
1412027Sjungma@eit.uni-kl.de * Redistribution and use in source and binary forms, with or without
1512027Sjungma@eit.uni-kl.de * modification, are permitted provided that the following conditions are
1612027Sjungma@eit.uni-kl.de * met: redistributions of source code must retain the above copyright
1712027Sjungma@eit.uni-kl.de * notice, this list of conditions and the following disclaimer;
1812027Sjungma@eit.uni-kl.de * redistributions in binary form must reproduce the above copyright
1912027Sjungma@eit.uni-kl.de * notice, this list of conditions and the following disclaimer in the
2012027Sjungma@eit.uni-kl.de * documentation and/or other materials provided with the distribution;
2112027Sjungma@eit.uni-kl.de * neither the name of the copyright holders nor the names of its
2212027Sjungma@eit.uni-kl.de * contributors may be used to endorse or promote products derived from
2312027Sjungma@eit.uni-kl.de * this software without specific prior written permission.
2412027Sjungma@eit.uni-kl.de *
2512027Sjungma@eit.uni-kl.de * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2612027Sjungma@eit.uni-kl.de * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2712027Sjungma@eit.uni-kl.de * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2812027Sjungma@eit.uni-kl.de * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2912027Sjungma@eit.uni-kl.de * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3012027Sjungma@eit.uni-kl.de * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3112027Sjungma@eit.uni-kl.de * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3212027Sjungma@eit.uni-kl.de * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3312027Sjungma@eit.uni-kl.de * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3412027Sjungma@eit.uni-kl.de * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3512027Sjungma@eit.uni-kl.de * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3612027Sjungma@eit.uni-kl.de *
3712027Sjungma@eit.uni-kl.de * Authors: Thomas Grass
3812027Sjungma@eit.uni-kl.de *          Andreas Hansson
3912027Sjungma@eit.uni-kl.de *          Sascha Bischoff
4012027Sjungma@eit.uni-kl.de */
4112027Sjungma@eit.uni-kl.de
4212027Sjungma@eit.uni-kl.de#include <sstream>
4312027Sjungma@eit.uni-kl.de
4412027Sjungma@eit.uni-kl.de#include "base/random.hh"
4512027Sjungma@eit.uni-kl.de#include "cpu/testers/traffic_gen/traffic_gen.hh"
4612027Sjungma@eit.uni-kl.de#include "debug/Checkpoint.hh"
4712027Sjungma@eit.uni-kl.de#include "debug/TrafficGen.hh"
4812027Sjungma@eit.uni-kl.de#include "sim/stats.hh"
4912027Sjungma@eit.uni-kl.de#include "sim/system.hh"
5012027Sjungma@eit.uni-kl.de
5112027Sjungma@eit.uni-kl.deusing namespace std;
5212027Sjungma@eit.uni-kl.de
5312027Sjungma@eit.uni-kl.deTrafficGen::TrafficGen(const TrafficGenParams* p)
5412027Sjungma@eit.uni-kl.de    : MemObject(p),
5512027Sjungma@eit.uni-kl.de      system(p->system),
5612027Sjungma@eit.uni-kl.de      masterID(system->getMasterId(name())),
5712027Sjungma@eit.uni-kl.de      port(name() + ".port", *this),
5812027Sjungma@eit.uni-kl.de      stateGraph(*this, port, p->config_file, masterID),
5912027Sjungma@eit.uni-kl.de      updateStateGraphEvent(this)
6012027Sjungma@eit.uni-kl.de{
6112027Sjungma@eit.uni-kl.de}
6212027Sjungma@eit.uni-kl.de
6312027Sjungma@eit.uni-kl.deTrafficGen*
6412027Sjungma@eit.uni-kl.deTrafficGenParams::create()
6512027Sjungma@eit.uni-kl.de{
6612027Sjungma@eit.uni-kl.de    return new TrafficGen(this);
6712027Sjungma@eit.uni-kl.de}
6812027Sjungma@eit.uni-kl.de
6912027Sjungma@eit.uni-kl.deMasterPort&
7012027Sjungma@eit.uni-kl.deTrafficGen::getMasterPort(const string& if_name, int idx)
7112027Sjungma@eit.uni-kl.de{
7212027Sjungma@eit.uni-kl.de    if (if_name == "port") {
7312027Sjungma@eit.uni-kl.de        return port;
7412027Sjungma@eit.uni-kl.de    } else {
7512027Sjungma@eit.uni-kl.de        return MemObject::getMasterPort(if_name, idx);
7612027Sjungma@eit.uni-kl.de    }
7712027Sjungma@eit.uni-kl.de}
7812027Sjungma@eit.uni-kl.de
7912027Sjungma@eit.uni-kl.devoid
8012027Sjungma@eit.uni-kl.deTrafficGen::init()
8112027Sjungma@eit.uni-kl.de{
8212027Sjungma@eit.uni-kl.de    if (!port.isConnected())
8312027Sjungma@eit.uni-kl.de        fatal("The port of %s is not connected!\n", name());
8412027Sjungma@eit.uni-kl.de
8512027Sjungma@eit.uni-kl.de    Enums::MemoryMode mode = system->getMemoryMode();
8612027Sjungma@eit.uni-kl.de
8712027Sjungma@eit.uni-kl.de    // if the system is in timing mode active the request generator
8812027Sjungma@eit.uni-kl.de    if (mode == Enums::timing) {
8912027Sjungma@eit.uni-kl.de        DPRINTF(TrafficGen, "Timing mode, activating request generator\n");
9012027Sjungma@eit.uni-kl.de
9112027Sjungma@eit.uni-kl.de        // enter initial state
9212027Sjungma@eit.uni-kl.de        stateGraph.enterState(stateGraph.currState);
9312027Sjungma@eit.uni-kl.de    } else {
9412027Sjungma@eit.uni-kl.de        DPRINTF(TrafficGen,
9512027Sjungma@eit.uni-kl.de                "Traffic generator is only active in timing mode\n");
9612027Sjungma@eit.uni-kl.de    }
9712027Sjungma@eit.uni-kl.de}
9812027Sjungma@eit.uni-kl.de
9912027Sjungma@eit.uni-kl.devoid
10012027Sjungma@eit.uni-kl.deTrafficGen::initState()
10112027Sjungma@eit.uni-kl.de{
10212027Sjungma@eit.uni-kl.de    // when not restoring from a checkpoint, make sure we kick things off
10312027Sjungma@eit.uni-kl.de    if (system->getMemoryMode() == Enums::timing) {
10412027Sjungma@eit.uni-kl.de        Tick nextStateGraphEvent = stateGraph.nextEventTick();
10512027Sjungma@eit.uni-kl.de        schedule(updateStateGraphEvent, nextStateGraphEvent);
10612027Sjungma@eit.uni-kl.de    } else {
10712027Sjungma@eit.uni-kl.de        DPRINTF(TrafficGen,
10812027Sjungma@eit.uni-kl.de                "Traffic generator is only active in timing mode\n");
10912027Sjungma@eit.uni-kl.de    }
11012027Sjungma@eit.uni-kl.de}
11112027Sjungma@eit.uni-kl.de
11212027Sjungma@eit.uni-kl.deunsigned int
11312027Sjungma@eit.uni-kl.deTrafficGen::drain(Event* drain_event)
11412027Sjungma@eit.uni-kl.de{
11512027Sjungma@eit.uni-kl.de    // @todo we should also stop putting new requests in the queue and
11612027Sjungma@eit.uni-kl.de    // either interrupt the current state or wait for a transition
11712027Sjungma@eit.uni-kl.de    return port.drain(drain_event);
11812027Sjungma@eit.uni-kl.de}
11912027Sjungma@eit.uni-kl.de
12012027Sjungma@eit.uni-kl.devoid
12112027Sjungma@eit.uni-kl.deTrafficGen::serialize(ostream &os)
12212027Sjungma@eit.uni-kl.de{
12312027Sjungma@eit.uni-kl.de    DPRINTF(Checkpoint, "Serializing TrafficGen\n");
12412027Sjungma@eit.uni-kl.de
12512027Sjungma@eit.uni-kl.de    // save ticks of the graph event if it is scheduled
12612027Sjungma@eit.uni-kl.de    Tick nextStateGraphEvent = updateStateGraphEvent.scheduled() ?
12712027Sjungma@eit.uni-kl.de        updateStateGraphEvent.when() : 0;
12812027Sjungma@eit.uni-kl.de
12912027Sjungma@eit.uni-kl.de    DPRINTF(TrafficGen, "Saving nextStateGraphEvent=%llu\n",
13012027Sjungma@eit.uni-kl.de            nextStateGraphEvent);
13112027Sjungma@eit.uni-kl.de
13212027Sjungma@eit.uni-kl.de    SERIALIZE_SCALAR(nextStateGraphEvent);
13312027Sjungma@eit.uni-kl.de
13412027Sjungma@eit.uni-kl.de    Tick nextTransitionTick = stateGraph.nextTransitionTick;
13512027Sjungma@eit.uni-kl.de    SERIALIZE_SCALAR(nextTransitionTick);
13612027Sjungma@eit.uni-kl.de
13712027Sjungma@eit.uni-kl.de    // @todo: also serialise the current state, figure out the best
13812027Sjungma@eit.uni-kl.de    // way to drain and restore
13912027Sjungma@eit.uni-kl.de}
14012027Sjungma@eit.uni-kl.de
14112027Sjungma@eit.uni-kl.devoid
14212027Sjungma@eit.uni-kl.deTrafficGen::unserialize(Checkpoint* cp, const string& section)
14312027Sjungma@eit.uni-kl.de{
144    // restore scheduled events
145    Tick nextStateGraphEvent;
146    UNSERIALIZE_SCALAR(nextStateGraphEvent);
147    if (nextStateGraphEvent != 0) {
148        schedule(updateStateGraphEvent, nextStateGraphEvent);
149    }
150
151    Tick nextTransitionTick;
152    UNSERIALIZE_SCALAR(nextTransitionTick);
153    stateGraph.nextTransitionTick = nextTransitionTick;
154}
155
156void
157TrafficGen::updateStateGraph()
158{
159    // schedule next update event based on either the next execute
160    // tick or the next transition, which ever comes first
161    Tick nextStateGraphEvent = stateGraph.nextEventTick();
162    DPRINTF(TrafficGen, "Updating state graph, next event at %lld\n",
163            nextStateGraphEvent);
164    schedule(updateStateGraphEvent, nextStateGraphEvent);
165
166    // perform the update associated with the current update event
167    stateGraph.update();
168}
169
170void
171TrafficGen::StateGraph::parseConfig(const string& file_name,
172                                    MasterID master_id)
173{
174    // keep track of the transitions parsed to create the matrix when
175    // done
176    vector<Transition> transitions;
177
178    // open input file
179    ifstream infile;
180    infile.open(file_name.c_str(), ifstream::in);
181    if (!infile.is_open()) {
182        fatal("Traffic generator %s config file not found at %s\n",
183              owner.name(), file_name);
184    }
185
186    // read line by line and determine the action based on the first
187    // keyword
188    string keyword;
189    string line;
190
191    while (getline(infile, line).good()) {
192        // see if this line is a comment line, and if so skip it
193        if (line.find('#') != 1) {
194            // create an input stream for the tokenization
195            istringstream is(line);
196
197            // determine the keyword
198            is >> keyword;
199
200            if (keyword == "STATE") {
201                // parse the behaviour of this state
202                uint32_t id;
203                Tick duration;
204                string mode;
205
206                is >> id >> duration >> mode;
207
208                if (mode == "TRACE") {
209                    string traceFile;
210                    Addr addrOffset;
211
212                    is >> traceFile >> addrOffset;
213
214                    states[id] = new TraceGen(port, master_id, duration,
215                                              traceFile, addrOffset);
216                    DPRINTF(TrafficGen, "State: %d TraceGen\n", id);
217                } else if (mode == "IDLE") {
218                    states[id] = new IdleGen(port, master_id, duration);
219                    DPRINTF(TrafficGen, "State: %d IdleGen\n", id);
220                } else if (mode == "LINEAR" || mode == "RANDOM") {
221                    uint32_t read_percent;
222                    Addr start_addr;
223                    Addr end_addr;
224                    Addr blocksize;
225                    Tick min_period;
226                    Tick max_period;
227                    Addr data_limit;
228
229                    is >> read_percent >> start_addr >> end_addr >>
230                        blocksize >> min_period >> max_period >> data_limit;
231
232                    DPRINTF(TrafficGen, "%s, addr %x to %x, size %d,"
233                            " period %d to %d, %d%% reads\n",
234                            mode, start_addr, end_addr, blocksize, min_period,
235                            max_period, read_percent);
236
237                    if (read_percent > 100)
238                        panic("%s cannot have more than 100% reads", name());
239
240                    if (mode == "LINEAR") {
241                        states[id] = new LinearGen(port, master_id,
242                                                   duration, start_addr,
243                                                   end_addr, blocksize,
244                                                   min_period, max_period,
245                                                   read_percent, data_limit);
246                        DPRINTF(TrafficGen, "State: %d LinearGen\n", id);
247                    } else if (mode == "RANDOM") {
248                        states[id] = new RandomGen(port, master_id,
249                                                   duration, start_addr,
250                                                   end_addr, blocksize,
251                                                   min_period, max_period,
252                                                   read_percent, data_limit);
253                        DPRINTF(TrafficGen, "State: %d RandomGen\n", id);
254                    }
255                } else {
256                    fatal("%s: Unknown traffic generator mode: %s",
257                          name(), mode);
258                }
259            } else if (keyword == "TRANSITION") {
260                Transition transition;
261
262                is >> transition.from >> transition.to >> transition.p;
263
264                transitions.push_back(transition);
265
266                DPRINTF(TrafficGen, "Transition: %d -> %d\n", transition.from,
267                        transition.to);
268            } else if (keyword == "INIT") {
269                // set the initial state as the active state
270                is >> currState;
271
272                DPRINTF(TrafficGen, "Initial state: %d\n", currState);
273            }
274        }
275    }
276
277    // resize and populate state transition matrix
278    transitionMatrix.resize(transitions.size());
279    for (size_t i = 0; i < transitions.size(); i++) {
280        transitionMatrix[i].resize(transitions.size());
281    }
282
283    for (vector<Transition>::iterator t = transitions.begin();
284         t != transitions.end(); ++t) {
285        transitionMatrix[t->from][t->to] = t->p;
286    }
287
288    // ensure the egress edges do not have a probability larger than
289    // one
290    for (size_t i = 0; i < transitions.size(); i++) {
291        double sum = 0;
292        for (size_t j = 0; j < transitions.size(); j++) {
293            sum += transitionMatrix[i][j];
294        }
295
296        // avoid comparing floating point numbers
297        if (abs(sum - 1.0) > 0.001)
298            fatal("%s has transition probability != 1 for state %d\n",
299                  name(), i);
300    }
301
302    // close input file
303    infile.close();
304}
305
306void
307TrafficGen::StateGraph::update()
308{
309    // if we have reached the time for the next state transition, then
310    // perform the transition
311    if (curTick() >= nextTransitionTick) {
312        transition();
313    } else {
314        // we are still in the current state and should execute it
315        states[currState]->execute();
316    }
317}
318
319void
320TrafficGen::StateGraph::transition()
321{
322    // exit the current state
323    states[currState]->exit();
324
325    // determine next state
326    double p = random_mt.gen_real1();
327    assert(currState < transitionMatrix.size());
328    double cumulative = transitionMatrix[currState][0];
329    size_t i = 1;
330    while (p < cumulative && i != transitionMatrix[currState].size()) {
331        cumulative += transitionMatrix[currState][i];
332        ++i;
333    }
334    enterState(i);
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
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::LinearGen::enter()
356{
357    // reset the address and the data counter
358    nextAddr = startAddr;
359    dataManipulated = 0;
360
361    // this test only needs to happen once, but cannot be performed
362    // before init() is called and the ports are connected
363    if (port.deviceBlockSize() && blocksize > port.deviceBlockSize())
364        fatal("TrafficGen %s block size (%d) is larger than port"
365              " block size (%d)\n", blocksize, port.deviceBlockSize());
366
367}
368
369void
370TrafficGen::StateGraph::LinearGen::execute()
371{
372    // choose if we generate a read or a write here
373    bool isRead = random_mt.random<uint8_t>(0, 100) < readPercent;
374
375    if (readPercent == 0)
376        assert(!isRead);
377
378    DPRINTF(TrafficGen, "LinearGen::execute: %c to addr %x, size %d\n",
379            isRead ? 'r' : 'w', nextAddr, blocksize);
380
381    // Create new request
382    Request::Flags flags;
383    Request *req = new Request(nextAddr, blocksize, flags, masterID);
384
385    PacketPtr pkt = new Packet(req, isRead ? MemCmd::ReadReq :
386                               MemCmd::WriteReq);
387
388    uint8_t* pkt_data = new uint8_t[req->getSize()];
389    pkt->dataDynamicArray(pkt_data);
390
391    if (!isRead) {
392        memset(pkt_data, 0xA, req->getSize());
393    }
394
395    port.schedTimingReq(pkt, curTick());
396
397    // increment the address
398    nextAddr += blocksize;
399
400    // Add the amount of data manipulated to the total
401    dataManipulated += blocksize;
402}
403
404Tick
405TrafficGen::StateGraph::LinearGen::nextExecuteTick()
406{
407    // If we have reached the end of the address space, reset the
408    // address to the start of the range
409    if (nextAddr + blocksize > endAddr) {
410        DPRINTF(TrafficGen, "Wrapping address to the start of "
411                "the range\n");
412        nextAddr = startAddr;
413    }
414
415    // Check to see if we have reached the data limit. If dataLimit is
416    // zero we do not have a data limit and therefore we will keep
417    // generating requests for the entire residency in this state.
418    if (dataLimit && dataManipulated >= dataLimit) {
419        DPRINTF(TrafficGen, "Data limit for LinearGen reached.\n");
420        // there are no more requests, therefore return MaxTick
421        return MaxTick;
422    } else {
423        // return the time when the next request should take place
424        return curTick() + random_mt.random<Tick>(minPeriod, maxPeriod);
425    }
426}
427
428void
429TrafficGen::StateGraph::RandomGen::enter()
430{
431    // reset the counter to zero
432    dataManipulated = 0;
433
434    // this test only needs to happen once, but cannot be performed
435    // before init() is called and the ports are connected
436    if (port.deviceBlockSize() && blocksize > port.deviceBlockSize())
437        fatal("TrafficGen %s block size (%d) is larger than port"
438              " block size (%d)\n", name(), blocksize, port.deviceBlockSize());
439}
440
441void
442TrafficGen::StateGraph::RandomGen::execute()
443{
444    // choose if we generate a read or a write here
445    bool isRead = random_mt.random<uint8_t>(0, 100) < readPercent;
446
447    if (readPercent == 0)
448        assert(!isRead);
449
450    // address of the request
451    Addr addr = random_mt.random<Addr>(startAddr, endAddr - 1);
452
453    // round down to start address of block
454    addr -= addr % blocksize;
455
456    DPRINTF(TrafficGen, "RandomGen::execute: %c to addr %x, size %d\n",
457            isRead ? 'r' : 'w', addr, blocksize);
458
459    // create new request packet
460    Request::Flags flags;
461    Request *req = new Request(addr, blocksize, flags, masterID);
462
463    PacketPtr pkt = new Packet(req, isRead ? MemCmd::ReadReq :
464                               MemCmd::WriteReq);
465
466    uint8_t* pkt_data = new uint8_t[req->getSize()];
467    pkt->dataDynamicArray(pkt_data);
468
469    if (!isRead) {
470        memset(pkt_data, 0xA, req->getSize());
471    }
472
473    port.schedTimingReq(pkt, curTick());
474
475    // Add the amount of data manipulated to the total
476    dataManipulated += blocksize;
477}
478
479Tick
480TrafficGen::StateGraph::RandomGen::nextExecuteTick()
481{
482    // Check to see if we have reached the data limit. If dataLimit is
483    // zero we do not have a data limit and therefore we will keep
484    // generating requests for the entire residency in this state.
485    if (dataLimit && dataManipulated >= dataLimit)
486    {
487        DPRINTF(TrafficGen, "Data limit for RandomGen reached.\n");
488        // No more requests. Return MaxTick.
489        return MaxTick;
490    } else {
491        // Return the time when the next request should take place.
492        return curTick() + random_mt.random<Tick>(minPeriod, maxPeriod);
493    }
494}
495
496Tick
497TrafficGen::StateGraph::TraceGen::nextExecuteTick() {
498    // We need to look at the next line to calculate the next time an
499    // event occurs, or potentially return MaxTick to signal that
500    // nothing has to be done.
501    string buffer;
502    if (!traceComplete && trace.good()){
503        getline(trace, buffer);
504        DPRINTF(TrafficGen, "Input trace: %s\n", buffer);
505    } else {
506        // We are at the end of the file, thus we have no more data in
507        // the trace Return MaxTick to signal that there will be no
508        // more transactions in this active period for the state.
509        return MaxTick;
510    }
511
512    //Reset the nextElement to the default values
513    currElement = nextElement;
514    nextElement.clear();
515
516    // Check that we have something to process. This assume no EOF at
517    // the end of the line.
518    if (buffer.size() > 0 && !trace.eof()) {
519        istringstream iss(buffer);
520
521        char rOrW, ch;
522        iss >> rOrW;
523        iss >> ch; assert(ch == ',');
524        iss >> nextElement.addr;
525        iss >> ch; assert(ch == ',');
526        iss >> nextElement.blocksize;
527        iss >> ch; assert(ch == ',');
528        iss >> nextElement.tick;
529
530        if (rOrW == 'r') {
531            nextElement.cmd = MemCmd::ReadReq;
532        } else if (rOrW == 'w') {
533            nextElement.cmd = MemCmd::WriteReq;
534        } else {
535            fatal("Incorrect trace file format!\n");
536        }
537    }
538
539    // Check that we have a valid request
540    if (!nextElement.isValid()) {
541        // If it is not valid, assume that we have reached the end of
542        // the trace.  Even if this is not the case, we do not know
543        // what to do with the request as it makes no sense.
544        if (trace.good()) {
545            // Trace is good, therefore we are not at the end of the
546            // file. This means that the input trace cannot be read
547            // correctly or it contains data that makes no sense.
548            warn("Unable to read the trace file format\n");
549            warn("%s", buffer);
550        }
551
552        traceComplete = true;
553        return MaxTick;
554    }
555
556    DPRINTF(TrafficGen, "currElement: %c addr %d size %d tick %d (%d)\n",
557            currElement.cmd.isRead() ? 'r' : 'w',
558            currElement.addr,
559            currElement.blocksize,
560            currElement.tick + tickOffset,
561            currElement.tick);
562
563    DPRINTF(TrafficGen, "nextElement: %c addr %d size %d tick %d (%d)\n",
564            nextElement.cmd.isRead() ? 'r' : 'w',
565            nextElement.addr,
566            nextElement.blocksize,
567            nextElement.tick + tickOffset,
568            nextElement.tick);
569
570    return tickOffset + nextElement.tick;
571}
572
573void
574TrafficGen::StateGraph::TraceGen::enter() {
575    // update the trace offset to the time where the state was entered.
576    tickOffset = curTick();
577
578    // seek to the start of the input trace file
579    trace.seekg(0, ifstream::beg);
580    trace.clear();
581
582    // clear everything
583    nextElement.clear();
584    currElement.clear();
585
586    traceComplete = false;
587}
588
589void
590TrafficGen::StateGraph::TraceGen::execute() {
591    // it is the responsibility of nextExecuteTick to prevent the
592    // state graph from executing the state if it should not
593    assert(currElement.isValid());
594
595    DPRINTF(TrafficGen, "TraceGen::execute: %c %d %d %d\n",
596            currElement.cmd.isRead() ? 'r' : 'w',
597            currElement.addr,
598            currElement.blocksize,
599            currElement.tick);
600
601    Request::Flags flags;
602    Request *req = new Request(currElement.addr + addrOffset,
603                               currElement.blocksize, flags, masterID);
604
605    PacketPtr pkt = new Packet(req, currElement.cmd);
606
607    uint8_t* pkt_data = new uint8_t[req->getSize()];
608    pkt->dataDynamicArray(pkt_data);
609
610    if (currElement.cmd.isWrite()) {
611        memset(pkt_data, 0xA, req->getSize());
612    }
613
614    port.schedTimingReq(pkt, curTick());
615}
616
617void
618TrafficGen::StateGraph::TraceGen::exit() {
619    // Check if we reached the end of the trace file. If we did not
620    // then we want to generate a warning stating that not the entire
621    // trace was played.
622    if (!trace.eof()) {
623        warn("Trace player %s was unable to replay the entire trace!\n",
624             name());
625    }
626
627    // clear any previous error flags for the input trace file
628    trace.clear();
629}
630
631bool
632TrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
633{
634    delete pkt->req;
635    delete pkt;
636
637    return true;
638}
639