traffic_gen.cc revision 9718:1cfcc2960e9f
17008Snate@binkert.org/*
27008Snate@binkert.org * Copyright (c) 2012-2013 ARM Limited
37008Snate@binkert.org * All rights reserved
47008Snate@binkert.org *
57008Snate@binkert.org * The license below extends only to copyright in the software and shall
67008Snate@binkert.org * not be construed as granting a license to any other intellectual
77008Snate@binkert.org * property including but not limited to intellectual property relating
87008Snate@binkert.org * to a hardware implementation of the functionality of the software
97008Snate@binkert.org * licensed hereunder.  You may use the software subject to the license
107008Snate@binkert.org * terms below provided that you ensure that this notice is replicated
117008Snate@binkert.org * unmodified and in its entirety in all distributions of the software,
127008Snate@binkert.org * modified or unmodified, in source code or in binary form.
137008Snate@binkert.org *
147008Snate@binkert.org * Redistribution and use in source and binary forms, with or without
157008Snate@binkert.org * modification, are permitted provided that the following conditions are
167008Snate@binkert.org * met: redistributions of source code must retain the above copyright
177008Snate@binkert.org * notice, this list of conditions and the following disclaimer;
187008Snate@binkert.org * redistributions in binary form must reproduce the above copyright
197008Snate@binkert.org * notice, this list of conditions and the following disclaimer in the
207008Snate@binkert.org * documentation and/or other materials provided with the distribution;
217008Snate@binkert.org * neither the name of the copyright holders nor the names of its
227008Snate@binkert.org * contributors may be used to endorse or promote products derived from
237008Snate@binkert.org * this software without specific prior written permission.
247008Snate@binkert.org *
257008Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
267008Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
277008Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
286285Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2910472Sandreas.hansson@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3010472Sandreas.hansson@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
318232Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
329104Shestness@cs.utexas.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
337039Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3411339SMichael.Lebeane@amd.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
357039Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3611108Sdavid.hashe@amd.com *
376285Snate@binkert.org * Authors: Thomas Grass
3811702Smichael.lebeane@amd.com *          Andreas Hansson
3911702Smichael.lebeane@amd.com *          Sascha Bischoff
4011702Smichael.lebeane@amd.com */
4111702Smichael.lebeane@amd.com
4211702Smichael.lebeane@amd.com#include <sstream>
4311702Smichael.lebeane@amd.com
4411702Smichael.lebeane@amd.com#include "base/random.hh"
4511702Smichael.lebeane@amd.com#include "cpu/testers/traffic_gen/traffic_gen.hh"
4611702Smichael.lebeane@amd.com#include "debug/Checkpoint.hh"
476876Ssteve.reinhardt@amd.com#include "debug/TrafficGen.hh"
4811702Smichael.lebeane@amd.com#include "sim/stats.hh"
4911702Smichael.lebeane@amd.com#include "sim/system.hh"
506285Snate@binkert.org
516285Snate@binkert.orgusing namespace std;
526285Snate@binkert.org
537039Snate@binkert.orgTrafficGen::TrafficGen(const TrafficGenParams* p)
547039Snate@binkert.org    : MemObject(p),
556285Snate@binkert.org      system(p->system),
5611339SMichael.Lebeane@amd.com      masterID(system->getMasterId(name())),
5711443Sandreas.hansson@arm.com      configFile(p->config_file),
5811346Santhony.gutierrez@amd.com      nextTransitionTick(0),
5911346Santhony.gutierrez@amd.com      port(name() + ".port", *this),
6011346Santhony.gutierrez@amd.com      updateEvent(this)
6110518Snilay@cs.wisc.edu{
6210518Snilay@cs.wisc.edu}
637039Snate@binkert.org
648615Snilay@cs.wisc.eduTrafficGen*
656285Snate@binkert.orgTrafficGenParams::create()
6611702Smichael.lebeane@amd.com{
677544SBrad.Beckmann@amd.com    return new TrafficGen(this);
687544SBrad.Beckmann@amd.com}
697544SBrad.Beckmann@amd.com
7011025Snilay@cs.wisc.eduBaseMasterPort&
7110562Sandreas.hansson@arm.comTrafficGen::getMasterPort(const string& if_name, PortID idx)
728615Snilay@cs.wisc.edu{
738615Snilay@cs.wisc.edu    if (if_name == "port") {
746285Snate@binkert.org        return port;
7511702Smichael.lebeane@amd.com    } else {
7611702Smichael.lebeane@amd.com        return MemObject::getMasterPort(if_name, idx);
7711702Smichael.lebeane@amd.com    }
7811702Smichael.lebeane@amd.com}
7911702Smichael.lebeane@amd.com
8011702Smichael.lebeane@amd.comvoid
8111702Smichael.lebeane@amd.comTrafficGen::init()
8211702Smichael.lebeane@amd.com{
836285Snate@binkert.org    if (!port.isConnected())
8411702Smichael.lebeane@amd.com        fatal("The port of %s is not connected!\n", name());
8511702Smichael.lebeane@amd.com
8611702Smichael.lebeane@amd.com    // if the system is in timing mode active the request generator
8711702Smichael.lebeane@amd.com    if (system->isTimingMode()) {
8811702Smichael.lebeane@amd.com        DPRINTF(TrafficGen, "Timing mode, activating request generator\n");
8911702Smichael.lebeane@amd.com
9011702Smichael.lebeane@amd.com        parseConfig();
9111702Smichael.lebeane@amd.com
9211702Smichael.lebeane@amd.com        // enter initial state
936285Snate@binkert.org        enterState(currState);
9410472Sandreas.hansson@arm.com    } else {
9510472Sandreas.hansson@arm.com        DPRINTF(TrafficGen,
9611025Snilay@cs.wisc.edu                "Traffic generator is only active in timing mode\n");
9711702Smichael.lebeane@amd.com    }
987453Snate@binkert.org}
997039Snate@binkert.org
1006888SBrad.Beckmann@amd.comvoid
1017453Snate@binkert.orgTrafficGen::initState()
1027039Snate@binkert.org{
1036888SBrad.Beckmann@amd.com    // when not restoring from a checkpoint, make sure we kick things off
1047915SBrad.Beckmann@amd.com    if (system->isTimingMode()) {
1057915SBrad.Beckmann@amd.com        schedule(updateEvent, nextEventTick());
1067915SBrad.Beckmann@amd.com    } else {
1077915SBrad.Beckmann@amd.com        DPRINTF(TrafficGen,
1087039Snate@binkert.org                "Traffic generator is only active in timing mode\n");
1096888SBrad.Beckmann@amd.com    }
11011702Smichael.lebeane@amd.com}
11111702Smichael.lebeane@amd.com
1127039Snate@binkert.orgunsigned int
11311111Snilay@cs.wisc.eduTrafficGen::drain(DrainManager *dm)
1147453Snate@binkert.org{
1156285Snate@binkert.org    // @todo we should also stop putting new requests in the queue and
1167039Snate@binkert.org    // either interrupt the current state or wait for a transition
1176285Snate@binkert.org    return port.drain(dm);
1186285Snate@binkert.org}
1197039Snate@binkert.org
12011702Smichael.lebeane@amd.comvoid
1216285Snate@binkert.orgTrafficGen::serialize(ostream &os)
12211702Smichael.lebeane@amd.com{
12311702Smichael.lebeane@amd.com    DPRINTF(Checkpoint, "Serializing TrafficGen\n");
12411702Smichael.lebeane@amd.com
12511702Smichael.lebeane@amd.com    // save ticks of the graph event if it is scheduled
12611702Smichael.lebeane@amd.com    Tick nextEvent = updateEvent.scheduled() ?
12711702Smichael.lebeane@amd.com        updateEvent.when() : 0;
1287039Snate@binkert.org
1297039Snate@binkert.org    DPRINTF(TrafficGen, "Saving nextEvent=%llu\n",
13011702Smichael.lebeane@amd.com            nextEvent);
13111702Smichael.lebeane@amd.com
13211702Smichael.lebeane@amd.com    SERIALIZE_SCALAR(nextEvent);
13311702Smichael.lebeane@amd.com
13411702Smichael.lebeane@amd.com    SERIALIZE_SCALAR(nextTransitionTick);
13511702Smichael.lebeane@amd.com
1367039Snate@binkert.org    // @todo: also serialise the current state, figure out the best
1377039Snate@binkert.org    // way to drain and restore
1386285Snate@binkert.org}
13910472Sandreas.hansson@arm.com
14010472Sandreas.hansson@arm.comvoid
14111025Snilay@cs.wisc.eduTrafficGen::unserialize(Checkpoint* cp, const string& section)
14211025Snilay@cs.wisc.edu{
1436888SBrad.Beckmann@amd.com    // restore scheduled events
14411025Snilay@cs.wisc.edu    Tick nextEvent;
14511025Snilay@cs.wisc.edu    UNSERIALIZE_SCALAR(nextEvent);
1466888SBrad.Beckmann@amd.com    if (nextEvent != 0) {
1477453Snate@binkert.org        schedule(updateEvent, nextEvent);
1487039Snate@binkert.org    }
1496888SBrad.Beckmann@amd.com
1507453Snate@binkert.org    UNSERIALIZE_SCALAR(nextTransitionTick);
1517039Snate@binkert.org}
1527039Snate@binkert.org
1537039Snate@binkert.orgvoid
1547039Snate@binkert.orgTrafficGen::update()
1556888SBrad.Beckmann@amd.com{
1567039Snate@binkert.org    // schedule next update event based on either the next execute
1577453Snate@binkert.org    // tick or the next transition, which ever comes first
1587039Snate@binkert.org    Tick nextEvent = nextEventTick();
1597453Snate@binkert.org    DPRINTF(TrafficGen, "Updating state graph, next event at %lld\n",
1607039Snate@binkert.org            nextEvent);
1616888SBrad.Beckmann@amd.com    schedule(updateEvent, nextEvent);
1627039Snate@binkert.org
16311111Snilay@cs.wisc.edu    // perform the update associated with the current update event
1647453Snate@binkert.org
16510917Sbrandon.potter@amd.com    // if we have reached the time for the next state transition, then
1668160SBrad.Beckmann@amd.com    // perform the transition
1678160SBrad.Beckmann@amd.com    if (curTick() >= nextTransitionTick) {
1688160SBrad.Beckmann@amd.com        transition();
1696285Snate@binkert.org    } else {
1706285Snate@binkert.org        // we are still in the current state and should execute it
1717039Snate@binkert.org        PacketPtr pkt = states[currState]->getNextPacket();
17211702Smichael.lebeane@amd.com        port.schedTimingReq(pkt, curTick());
1736285Snate@binkert.org    }
17411702Smichael.lebeane@amd.com}
17511702Smichael.lebeane@amd.com
17611702Smichael.lebeane@amd.comvoid
17711702Smichael.lebeane@amd.comTrafficGen::parseConfig()
17811702Smichael.lebeane@amd.com{
1797039Snate@binkert.org    // keep track of the transitions parsed to create the matrix when
1807039Snate@binkert.org    // done
1817039Snate@binkert.org    vector<Transition> transitions;
1827039Snate@binkert.org
18310231Ssteve.reinhardt@amd.com    // open input file
1847915SBrad.Beckmann@amd.com    ifstream infile;
1857915SBrad.Beckmann@amd.com    infile.open(configFile.c_str(), ifstream::in);
1867915SBrad.Beckmann@amd.com    if (!infile.is_open()) {
1877915SBrad.Beckmann@amd.com        fatal("Traffic generator %s config file not found at %s\n",
18811702Smichael.lebeane@amd.com              name(), configFile);
1896285Snate@binkert.org    }
1906285Snate@binkert.org
1917039Snate@binkert.org    // read line by line and determine the action based on the first
19211702Smichael.lebeane@amd.com    // keyword
1936285Snate@binkert.org    string keyword;
19411778Santhony.gutierrez@amd.com    string line;
19511702Smichael.lebeane@amd.com
1966285Snate@binkert.org    while (getline(infile, line).good()) {
1976285Snate@binkert.org        // see if this line is a comment line, and if so skip it
1987039Snate@binkert.org        if (line.find('#') != 1) {
19910518Snilay@cs.wisc.edu            // create an input stream for the tokenization
20010518Snilay@cs.wisc.edu            istringstream is(line);
2019104Shestness@cs.utexas.edu
2029104Shestness@cs.utexas.edu            // determine the keyword
2039104Shestness@cs.utexas.edu            is >> keyword;
2049104Shestness@cs.utexas.edu
2056876Ssteve.reinhardt@amd.com            if (keyword == "STATE") {
2066876Ssteve.reinhardt@amd.com                // parse the behaviour of this state
2076876Ssteve.reinhardt@amd.com                uint32_t id;
2086876Ssteve.reinhardt@amd.com                Tick duration;
2096876Ssteve.reinhardt@amd.com                string mode;
210
211                is >> id >> duration >> mode;
212
213                if (mode == "TRACE") {
214                    string traceFile;
215                    Addr addrOffset;
216
217                    is >> traceFile >> addrOffset;
218
219                    states[id] = new TraceGen(name(), masterID, duration,
220                                              traceFile, addrOffset);
221                    DPRINTF(TrafficGen, "State: %d TraceGen\n", id);
222                } else if (mode == "IDLE") {
223                    states[id] = new IdleGen(name(), masterID, duration);
224                    DPRINTF(TrafficGen, "State: %d IdleGen\n", id);
225                } else if (mode == "LINEAR" || mode == "RANDOM") {
226                    uint32_t read_percent;
227                    Addr start_addr;
228                    Addr end_addr;
229                    Addr blocksize;
230                    Tick min_period;
231                    Tick max_period;
232                    Addr data_limit;
233
234                    is >> read_percent >> start_addr >> end_addr >>
235                        blocksize >> min_period >> max_period >> data_limit;
236
237                    DPRINTF(TrafficGen, "%s, addr %x to %x, size %d,"
238                            " period %d to %d, %d%% reads\n",
239                            mode, start_addr, end_addr, blocksize, min_period,
240                            max_period, read_percent);
241
242
243                    if (port.deviceBlockSize() &&
244                        blocksize > port.deviceBlockSize())
245                        fatal("TrafficGen %s block size (%d) is larger than "
246                              "port block size (%d)\n", name(),
247                              blocksize, port.deviceBlockSize());
248
249                    if (read_percent > 100)
250                        fatal("%s cannot have more than 100% reads", name());
251
252                    if (mode == "LINEAR") {
253                        states[id] = new LinearGen(name(), masterID,
254                                                   duration, start_addr,
255                                                   end_addr, blocksize,
256                                                   min_period, max_period,
257                                                   read_percent, data_limit);
258                        DPRINTF(TrafficGen, "State: %d LinearGen\n", id);
259                    } else if (mode == "RANDOM") {
260                        states[id] = new RandomGen(name(), masterID,
261                                                   duration, start_addr,
262                                                   end_addr, blocksize,
263                                                   min_period, max_period,
264                                                   read_percent, data_limit);
265                        DPRINTF(TrafficGen, "State: %d RandomGen\n", id);
266                    }
267                } else {
268                    fatal("%s: Unknown traffic generator mode: %s",
269                          name(), mode);
270                }
271            } else if (keyword == "TRANSITION") {
272                Transition transition;
273
274                is >> transition.from >> transition.to >> transition.p;
275
276                transitions.push_back(transition);
277
278                DPRINTF(TrafficGen, "Transition: %d -> %d\n", transition.from,
279                        transition.to);
280            } else if (keyword == "INIT") {
281                // set the initial state as the active state
282                is >> currState;
283
284                DPRINTF(TrafficGen, "Initial state: %d\n", currState);
285            }
286        }
287    }
288
289    // resize and populate state transition matrix
290    transitionMatrix.resize(transitions.size());
291    for (size_t i = 0; i < transitions.size(); i++) {
292        transitionMatrix[i].resize(transitions.size());
293    }
294
295    for (vector<Transition>::iterator t = transitions.begin();
296         t != transitions.end(); ++t) {
297        transitionMatrix[t->from][t->to] = t->p;
298    }
299
300    // ensure the egress edges do not have a probability larger than
301    // one
302    for (size_t i = 0; i < transitions.size(); i++) {
303        double sum = 0;
304        for (size_t j = 0; j < transitions.size(); j++) {
305            sum += transitionMatrix[i][j];
306        }
307
308        // avoid comparing floating point numbers
309        if (abs(sum - 1.0) > 0.001)
310            fatal("%s has transition probability != 1 for state %d\n",
311                  name(), i);
312    }
313
314    // close input file
315    infile.close();
316}
317
318void
319TrafficGen::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::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
347bool
348TrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
349{
350    delete pkt->req;
351    delete pkt;
352
353    return true;
354}
355