traffic_gen.cc revision 9584:1a21964b7227
112837Sgabeblack@google.com/*
212837Sgabeblack@google.com * Copyright (c) 2012 ARM Limited
312837Sgabeblack@google.com * All rights reserved
412837Sgabeblack@google.com *
512837Sgabeblack@google.com * The license below extends only to copyright in the software and shall
612837Sgabeblack@google.com * not be construed as granting a license to any other intellectual
712837Sgabeblack@google.com * property including but not limited to intellectual property relating
812837Sgabeblack@google.com * to a hardware implementation of the functionality of the software
912837Sgabeblack@google.com * licensed hereunder.  You may use the software subject to the license
1012837Sgabeblack@google.com * terms below provided that you ensure that this notice is replicated
1112837Sgabeblack@google.com * unmodified and in its entirety in all distributions of the software,
1212837Sgabeblack@google.com * modified or unmodified, in source code or in binary form.
1312837Sgabeblack@google.com *
1412837Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without
1512837Sgabeblack@google.com * modification, are permitted provided that the following conditions are
1612837Sgabeblack@google.com * met: redistributions of source code must retain the above copyright
1712837Sgabeblack@google.com * notice, this list of conditions and the following disclaimer;
1812837Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright
1912837Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the
2012837Sgabeblack@google.com * documentation and/or other materials provided with the distribution;
2112837Sgabeblack@google.com * neither the name of the copyright holders nor the names of its
2212837Sgabeblack@google.com * contributors may be used to endorse or promote products derived from
2312837Sgabeblack@google.com * this software without specific prior written permission.
2412837Sgabeblack@google.com *
2512837Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2612837Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2712837Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2812837Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2912837Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3012837Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3112982Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3212982Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3313059Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3412982Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3513207Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3612953Sgabeblack@google.com *
3712837Sgabeblack@google.com * Authors: Thomas Grass
3812982Sgabeblack@google.com *          Andreas Hansson
3912837Sgabeblack@google.com *          Sascha Bischoff
4012837Sgabeblack@google.com */
4112990Sgabeblack@google.com
4212990Sgabeblack@google.com#include <sstream>
4312990Sgabeblack@google.com
4413077Sgabeblack@google.com#include "base/random.hh"
4512990Sgabeblack@google.com#include "cpu/testers/traffic_gen/traffic_gen.hh"
4612990Sgabeblack@google.com#include "debug/Checkpoint.hh"
4712990Sgabeblack@google.com#include "debug/TrafficGen.hh"
4812990Sgabeblack@google.com#include "proto/packet.pb.h"
4912990Sgabeblack@google.com#include "sim/stats.hh"
5012990Sgabeblack@google.com#include "sim/system.hh"
5112990Sgabeblack@google.com
5212990Sgabeblack@google.comusing namespace std;
5312990Sgabeblack@google.com
5412990Sgabeblack@google.comTrafficGen::TrafficGen(const TrafficGenParams* p)
5512990Sgabeblack@google.com    : MemObject(p),
5613077Sgabeblack@google.com      system(p->system),
5713077Sgabeblack@google.com      masterID(system->getMasterId(name())),
5813077Sgabeblack@google.com      port(name() + ".port", *this),
5912990Sgabeblack@google.com      stateGraph(*this, port, p->config_file, masterID),
6012990Sgabeblack@google.com      updateStateGraphEvent(this)
6112990Sgabeblack@google.com{
6212954Sgabeblack@google.com}
6313042Sgabeblack@google.com
6413042Sgabeblack@google.comTrafficGen*
6513042Sgabeblack@google.comTrafficGenParams::create()
6613042Sgabeblack@google.com{
6713042Sgabeblack@google.com    return new TrafficGen(this);
6812982Sgabeblack@google.com}
6912982Sgabeblack@google.com
7012982Sgabeblack@google.comBaseMasterPort&
7112982Sgabeblack@google.comTrafficGen::getMasterPort(const string& if_name, PortID idx)
7213077Sgabeblack@google.com{
7313077Sgabeblack@google.com    if (if_name == "port") {
7413077Sgabeblack@google.com        return port;
7513094Sgabeblack@google.com    } else {
7613094Sgabeblack@google.com        return MemObject::getMasterPort(if_name, idx);
7713094Sgabeblack@google.com    }
7812990Sgabeblack@google.com}
7913207Sgabeblack@google.com
8013207Sgabeblack@google.comvoid
8113191Sgabeblack@google.comTrafficGen::init()
8213191Sgabeblack@google.com{
8313059Sgabeblack@google.com    if (!port.isConnected())
8413059Sgabeblack@google.com        fatal("The port of %s is not connected!\n", name());
8513281Sgabeblack@google.com
8613281Sgabeblack@google.com    // if the system is in timing mode active the request generator
8712982Sgabeblack@google.com    if (system->isTimingMode()) {
8812982Sgabeblack@google.com        DPRINTF(TrafficGen, "Timing mode, activating request generator\n");
8912982Sgabeblack@google.com
9012982Sgabeblack@google.com        // enter initial state
9112982Sgabeblack@google.com        stateGraph.enterState(stateGraph.currState);
9213156Sgabeblack@google.com    } else {
9313077Sgabeblack@google.com        DPRINTF(TrafficGen,
9413077Sgabeblack@google.com                "Traffic generator is only active in timing mode\n");
9513188Sgabeblack@google.com    }
9613207Sgabeblack@google.com}
9713207Sgabeblack@google.com
9813273Sgabeblack@google.comvoid
9913273Sgabeblack@google.comTrafficGen::initState()
10013053Sgabeblack@google.com{
10113188Sgabeblack@google.com    // when not restoring from a checkpoint, make sure we kick things off
10213207Sgabeblack@google.com    if (system->isTimingMode()) {
10313207Sgabeblack@google.com        Tick nextStateGraphEvent = stateGraph.nextEventTick();
10413191Sgabeblack@google.com        schedule(updateStateGraphEvent, nextStateGraphEvent);
10513191Sgabeblack@google.com    } else {
10613188Sgabeblack@google.com        DPRINTF(TrafficGen,
10713188Sgabeblack@google.com                "Traffic generator is only active in timing mode\n");
10813188Sgabeblack@google.com    }
10913188Sgabeblack@google.com}
11013059Sgabeblack@google.com
11112982Sgabeblack@google.comunsigned int
11212953Sgabeblack@google.comTrafficGen::drain(DrainManager *dm)
11312953Sgabeblack@google.com{
11412953Sgabeblack@google.com    // @todo we should also stop putting new requests in the queue and
11512837Sgabeblack@google.com    // either interrupt the current state or wait for a transition
11613077Sgabeblack@google.com    return port.drain(dm);
11713077Sgabeblack@google.com}
11813077Sgabeblack@google.com
11913156Sgabeblack@google.comvoid
12013156Sgabeblack@google.comTrafficGen::serialize(ostream &os)
12113156Sgabeblack@google.com{
12213156Sgabeblack@google.com    DPRINTF(Checkpoint, "Serializing TrafficGen\n");
12313156Sgabeblack@google.com
12413188Sgabeblack@google.com    // save ticks of the graph event if it is scheduled
12513188Sgabeblack@google.com    Tick nextStateGraphEvent = updateStateGraphEvent.scheduled() ?
12613207Sgabeblack@google.com        updateStateGraphEvent.when() : 0;
12713207Sgabeblack@google.com
12813191Sgabeblack@google.com    DPRINTF(TrafficGen, "Saving nextStateGraphEvent=%llu\n",
12913191Sgabeblack@google.com            nextStateGraphEvent);
13013188Sgabeblack@google.com
13113188Sgabeblack@google.com    SERIALIZE_SCALAR(nextStateGraphEvent);
13213188Sgabeblack@google.com
13313188Sgabeblack@google.com    Tick nextTransitionTick = stateGraph.nextTransitionTick;
13413059Sgabeblack@google.com    SERIALIZE_SCALAR(nextTransitionTick);
13512982Sgabeblack@google.com
13612990Sgabeblack@google.com    // @todo: also serialise the current state, figure out the best
13712982Sgabeblack@google.com    // way to drain and restore
13812990Sgabeblack@google.com}
13912982Sgabeblack@google.com
14012982Sgabeblack@google.comvoid
14112982Sgabeblack@google.comTrafficGen::unserialize(Checkpoint* cp, const string& section)
14212953Sgabeblack@google.com{
14312953Sgabeblack@google.com    // restore scheduled events
14412953Sgabeblack@google.com    Tick nextStateGraphEvent;
14512982Sgabeblack@google.com    UNSERIALIZE_SCALAR(nextStateGraphEvent);
14612982Sgabeblack@google.com    if (nextStateGraphEvent != 0) {
14712982Sgabeblack@google.com        schedule(updateStateGraphEvent, nextStateGraphEvent);
14812990Sgabeblack@google.com    }
14912982Sgabeblack@google.com
15012982Sgabeblack@google.com    Tick nextTransitionTick;
15112982Sgabeblack@google.com    UNSERIALIZE_SCALAR(nextTransitionTick);
15212982Sgabeblack@google.com    stateGraph.nextTransitionTick = nextTransitionTick;
15312982Sgabeblack@google.com}
15412982Sgabeblack@google.com
15512982Sgabeblack@google.comvoid
15612990Sgabeblack@google.comTrafficGen::updateStateGraph()
15713188Sgabeblack@google.com{
15813207Sgabeblack@google.com    // schedule next update event based on either the next execute
15913207Sgabeblack@google.com    // tick or the next transition, which ever comes first
16013191Sgabeblack@google.com    Tick nextStateGraphEvent = stateGraph.nextEventTick();
16113191Sgabeblack@google.com    DPRINTF(TrafficGen, "Updating state graph, next event at %lld\n",
16213188Sgabeblack@google.com            nextStateGraphEvent);
16313188Sgabeblack@google.com    schedule(updateStateGraphEvent, nextStateGraphEvent);
16413188Sgabeblack@google.com
16513188Sgabeblack@google.com    // perform the update associated with the current update event
16613059Sgabeblack@google.com    stateGraph.update();
16712982Sgabeblack@google.com}
16812990Sgabeblack@google.com
16912982Sgabeblack@google.comvoid
17012990Sgabeblack@google.comTrafficGen::StateGraph::parseConfig(const string& file_name,
17112982Sgabeblack@google.com                                    MasterID master_id)
17212982Sgabeblack@google.com{
17312982Sgabeblack@google.com    // keep track of the transitions parsed to create the matrix when
17412953Sgabeblack@google.com    // done
17512953Sgabeblack@google.com    vector<Transition> transitions;
17613156Sgabeblack@google.com
17713156Sgabeblack@google.com    // open input file
17813156Sgabeblack@google.com    ifstream infile;
17913156Sgabeblack@google.com    infile.open(file_name.c_str(), ifstream::in);
18013156Sgabeblack@google.com    if (!infile.is_open()) {
18113156Sgabeblack@google.com        fatal("Traffic generator %s config file not found at %s\n",
18213156Sgabeblack@google.com              owner.name(), file_name);
18313156Sgabeblack@google.com    }
18412837Sgabeblack@google.com
18512837Sgabeblack@google.com    // read line by line and determine the action based on the first
18612982Sgabeblack@google.com    // keyword
18712837Sgabeblack@google.com    string keyword;
18812982Sgabeblack@google.com    string line;
18912982Sgabeblack@google.com
19012982Sgabeblack@google.com    while (getline(infile, line).good()) {
19112837Sgabeblack@google.com        // see if this line is a comment line, and if so skip it
19212837Sgabeblack@google.com        if (line.find('#') != 1) {
19312982Sgabeblack@google.com            // create an input stream for the tokenization
19412982Sgabeblack@google.com            istringstream is(line);
19512982Sgabeblack@google.com
19612982Sgabeblack@google.com            // determine the keyword
19712837Sgabeblack@google.com            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
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
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}
619