traffic_gen.cc revision 9720
112027Sjungma@eit.uni-kl.de/*
212027Sjungma@eit.uni-kl.de * Copyright (c) 2012-2013 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      configFile(p->config_file),
5812027Sjungma@eit.uni-kl.de      elasticReq(p->elastic_req),
5912027Sjungma@eit.uni-kl.de      nextTransitionTick(0),
6012027Sjungma@eit.uni-kl.de      nextPacketTick(0),
6112027Sjungma@eit.uni-kl.de      port(name() + ".port", *this),
6212027Sjungma@eit.uni-kl.de      retryPkt(NULL),
6312027Sjungma@eit.uni-kl.de      retryPktTick(0),
6412027Sjungma@eit.uni-kl.de      updateEvent(this),
6512027Sjungma@eit.uni-kl.de      drainManager(NULL)
6612027Sjungma@eit.uni-kl.de{
6712027Sjungma@eit.uni-kl.de}
6812027Sjungma@eit.uni-kl.de
6912027Sjungma@eit.uni-kl.deTrafficGen*
7012027Sjungma@eit.uni-kl.deTrafficGenParams::create()
7112027Sjungma@eit.uni-kl.de{
7212027Sjungma@eit.uni-kl.de    return new TrafficGen(this);
7312027Sjungma@eit.uni-kl.de}
7412027Sjungma@eit.uni-kl.de
7512027Sjungma@eit.uni-kl.deBaseMasterPort&
7612027Sjungma@eit.uni-kl.deTrafficGen::getMasterPort(const string& if_name, PortID idx)
7712027Sjungma@eit.uni-kl.de{
7812027Sjungma@eit.uni-kl.de    if (if_name == "port") {
7912027Sjungma@eit.uni-kl.de        return port;
8012027Sjungma@eit.uni-kl.de    } else {
8112027Sjungma@eit.uni-kl.de        return MemObject::getMasterPort(if_name, idx);
8212027Sjungma@eit.uni-kl.de    }
8312027Sjungma@eit.uni-kl.de}
8412027Sjungma@eit.uni-kl.de
8512027Sjungma@eit.uni-kl.devoid
8612027Sjungma@eit.uni-kl.deTrafficGen::init()
8712027Sjungma@eit.uni-kl.de{
8812027Sjungma@eit.uni-kl.de    if (!port.isConnected())
8912027Sjungma@eit.uni-kl.de        fatal("The port of %s is not connected!\n", name());
9012027Sjungma@eit.uni-kl.de
9112027Sjungma@eit.uni-kl.de    // if the system is in timing mode active the request generator
9212027Sjungma@eit.uni-kl.de    if (system->isTimingMode()) {
9312027Sjungma@eit.uni-kl.de        DPRINTF(TrafficGen, "Timing mode, activating request generator\n");
9412027Sjungma@eit.uni-kl.de
9512027Sjungma@eit.uni-kl.de        parseConfig();
9612027Sjungma@eit.uni-kl.de
9712027Sjungma@eit.uni-kl.de        // enter initial state
9812027Sjungma@eit.uni-kl.de        enterState(currState);
9912027Sjungma@eit.uni-kl.de    } else {
10012027Sjungma@eit.uni-kl.de        DPRINTF(TrafficGen,
10112027Sjungma@eit.uni-kl.de                "Traffic generator is only active in timing mode\n");
10212027Sjungma@eit.uni-kl.de    }
10312027Sjungma@eit.uni-kl.de}
10412027Sjungma@eit.uni-kl.de
10512027Sjungma@eit.uni-kl.devoid
10612027Sjungma@eit.uni-kl.deTrafficGen::initState()
10712027Sjungma@eit.uni-kl.de{
10812027Sjungma@eit.uni-kl.de    // when not restoring from a checkpoint, make sure we kick things off
10912027Sjungma@eit.uni-kl.de    if (system->isTimingMode()) {
11012027Sjungma@eit.uni-kl.de        // call nextPacketTick on the state to advance it
11112027Sjungma@eit.uni-kl.de        nextPacketTick = states[currState]->nextPacketTick(elasticReq, 0);
11212027Sjungma@eit.uni-kl.de        schedule(updateEvent, std::min(nextPacketTick, nextTransitionTick));
11312027Sjungma@eit.uni-kl.de    } else {
11412027Sjungma@eit.uni-kl.de        DPRINTF(TrafficGen,
11512027Sjungma@eit.uni-kl.de                "Traffic generator is only active in timing mode\n");
11612027Sjungma@eit.uni-kl.de    }
11712027Sjungma@eit.uni-kl.de}
11812027Sjungma@eit.uni-kl.de
11912027Sjungma@eit.uni-kl.deunsigned int
12012027Sjungma@eit.uni-kl.deTrafficGen::drain(DrainManager *dm)
12112027Sjungma@eit.uni-kl.de{
12212027Sjungma@eit.uni-kl.de    if (retryPkt == NULL) {
12312027Sjungma@eit.uni-kl.de        // shut things down
12412027Sjungma@eit.uni-kl.de        nextPacketTick = MaxTick;
12512027Sjungma@eit.uni-kl.de        nextTransitionTick = MaxTick;
12612027Sjungma@eit.uni-kl.de        deschedule(updateEvent);
12712027Sjungma@eit.uni-kl.de        return 0;
12812027Sjungma@eit.uni-kl.de    } else {
12912027Sjungma@eit.uni-kl.de        drainManager = dm;
13012027Sjungma@eit.uni-kl.de        return 1;
13112027Sjungma@eit.uni-kl.de    }
13212027Sjungma@eit.uni-kl.de}
13312027Sjungma@eit.uni-kl.de
13412027Sjungma@eit.uni-kl.devoid
13512027Sjungma@eit.uni-kl.deTrafficGen::serialize(ostream &os)
13612027Sjungma@eit.uni-kl.de{
13712027Sjungma@eit.uni-kl.de    DPRINTF(Checkpoint, "Serializing TrafficGen\n");
13812027Sjungma@eit.uni-kl.de
13912027Sjungma@eit.uni-kl.de    // save ticks of the graph event if it is scheduled
14012027Sjungma@eit.uni-kl.de    Tick nextEvent = updateEvent.scheduled() ? updateEvent.when() : 0;
14112027Sjungma@eit.uni-kl.de
14212027Sjungma@eit.uni-kl.de    DPRINTF(TrafficGen, "Saving nextEvent=%llu\n", nextEvent);
14312027Sjungma@eit.uni-kl.de
144    SERIALIZE_SCALAR(nextEvent);
145
146    SERIALIZE_SCALAR(nextTransitionTick);
147
148    SERIALIZE_SCALAR(nextPacketTick);
149
150    SERIALIZE_SCALAR(currState);
151}
152
153void
154TrafficGen::unserialize(Checkpoint* cp, const string& section)
155{
156    // restore scheduled events
157    Tick nextEvent;
158    UNSERIALIZE_SCALAR(nextEvent);
159    if (nextEvent != 0) {
160        schedule(updateEvent, nextEvent);
161    }
162
163    UNSERIALIZE_SCALAR(nextTransitionTick);
164
165    UNSERIALIZE_SCALAR(nextPacketTick);
166
167    // @todo In the case of a stateful generator state such as the
168    // trace player we would also have to restore the position in the
169    // trace playback and the tick offset
170    UNSERIALIZE_SCALAR(currState);
171}
172
173void
174TrafficGen::update()
175{
176    // if we have reached the time for the next state transition, then
177    // perform the transition
178    if (curTick() >= nextTransitionTick) {
179        transition();
180    } else {
181        assert(curTick() >= nextPacketTick);
182        // get the next packet and try to send it
183        PacketPtr pkt = states[currState]->getNextPacket();
184        numPackets++;
185        if (!port.sendTimingReq(pkt)) {
186            retryPkt = pkt;
187            retryPktTick = curTick();
188        }
189    }
190
191    // if we are waiting for a retry, do not schedule any further
192    // events, in the case of a transition or a successful send, go
193    // ahead and determine when the next update should take place
194    if (retryPkt == NULL) {
195        // schedule next update event based on either the next execute
196        // tick or the next transition, which ever comes first
197        nextPacketTick = states[currState]->nextPacketTick(elasticReq, 0);
198        Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
199        DPRINTF(TrafficGen, "Next event scheduled at %lld\n", nextEventTick);
200        schedule(updateEvent, nextEventTick);
201    }
202}
203
204void
205TrafficGen::parseConfig()
206{
207    // keep track of the transitions parsed to create the matrix when
208    // done
209    vector<Transition> transitions;
210
211    // open input file
212    ifstream infile;
213    infile.open(configFile.c_str(), ifstream::in);
214    if (!infile.is_open()) {
215        fatal("Traffic generator %s config file not found at %s\n",
216              name(), configFile);
217    }
218
219    // read line by line and determine the action based on the first
220    // keyword
221    string keyword;
222    string line;
223
224    while (getline(infile, line).good()) {
225        // see if this line is a comment line, and if so skip it
226        if (line.find('#') != 1) {
227            // create an input stream for the tokenization
228            istringstream is(line);
229
230            // determine the keyword
231            is >> keyword;
232
233            if (keyword == "STATE") {
234                // parse the behaviour of this state
235                uint32_t id;
236                Tick duration;
237                string mode;
238
239                is >> id >> duration >> mode;
240
241                if (mode == "TRACE") {
242                    string traceFile;
243                    Addr addrOffset;
244
245                    is >> traceFile >> addrOffset;
246
247                    states[id] = new TraceGen(name(), masterID, duration,
248                                              traceFile, addrOffset);
249                    DPRINTF(TrafficGen, "State: %d TraceGen\n", id);
250                } else if (mode == "IDLE") {
251                    states[id] = new IdleGen(name(), masterID, duration);
252                    DPRINTF(TrafficGen, "State: %d IdleGen\n", id);
253                } else if (mode == "LINEAR" || mode == "RANDOM") {
254                    uint32_t read_percent;
255                    Addr start_addr;
256                    Addr end_addr;
257                    Addr blocksize;
258                    Tick min_period;
259                    Tick max_period;
260                    Addr data_limit;
261
262                    is >> read_percent >> start_addr >> end_addr >>
263                        blocksize >> min_period >> max_period >> data_limit;
264
265                    DPRINTF(TrafficGen, "%s, addr %x to %x, size %d,"
266                            " period %d to %d, %d%% reads\n",
267                            mode, start_addr, end_addr, blocksize, min_period,
268                            max_period, read_percent);
269
270
271                    if (port.deviceBlockSize() &&
272                        blocksize > port.deviceBlockSize())
273                        fatal("TrafficGen %s block size (%d) is larger than "
274                              "port block size (%d)\n", name(),
275                              blocksize, port.deviceBlockSize());
276
277                    if (read_percent > 100)
278                        fatal("%s cannot have more than 100% reads", name());
279
280                    if (mode == "LINEAR") {
281                        states[id] = new LinearGen(name(), masterID,
282                                                   duration, start_addr,
283                                                   end_addr, blocksize,
284                                                   min_period, max_period,
285                                                   read_percent, data_limit);
286                        DPRINTF(TrafficGen, "State: %d LinearGen\n", id);
287                    } else if (mode == "RANDOM") {
288                        states[id] = new RandomGen(name(), masterID,
289                                                   duration, start_addr,
290                                                   end_addr, blocksize,
291                                                   min_period, max_period,
292                                                   read_percent, data_limit);
293                        DPRINTF(TrafficGen, "State: %d RandomGen\n", id);
294                    }
295                } else {
296                    fatal("%s: Unknown traffic generator mode: %s",
297                          name(), mode);
298                }
299            } else if (keyword == "TRANSITION") {
300                Transition transition;
301
302                is >> transition.from >> transition.to >> transition.p;
303
304                transitions.push_back(transition);
305
306                DPRINTF(TrafficGen, "Transition: %d -> %d\n", transition.from,
307                        transition.to);
308            } else if (keyword == "INIT") {
309                // set the initial state as the active state
310                is >> currState;
311
312                DPRINTF(TrafficGen, "Initial state: %d\n", currState);
313            }
314        }
315    }
316
317    // resize and populate state transition matrix
318    transitionMatrix.resize(transitions.size());
319    for (size_t i = 0; i < transitions.size(); i++) {
320        transitionMatrix[i].resize(transitions.size());
321    }
322
323    for (vector<Transition>::iterator t = transitions.begin();
324         t != transitions.end(); ++t) {
325        transitionMatrix[t->from][t->to] = t->p;
326    }
327
328    // ensure the egress edges do not have a probability larger than
329    // one
330    for (size_t i = 0; i < transitions.size(); i++) {
331        double sum = 0;
332        for (size_t j = 0; j < transitions.size(); j++) {
333            sum += transitionMatrix[i][j];
334        }
335
336        // avoid comparing floating point numbers
337        if (abs(sum - 1.0) > 0.001)
338            fatal("%s has transition probability != 1 for state %d\n",
339                  name(), i);
340    }
341
342    // close input file
343    infile.close();
344}
345
346void
347TrafficGen::transition()
348{
349    // exit the current state
350    states[currState]->exit();
351
352    // determine next state
353    double p = random_mt.gen_real1();
354    assert(currState < transitionMatrix.size());
355    double cumulative = 0.0;
356    size_t i = 0;
357    do {
358        cumulative += transitionMatrix[currState][i];
359        ++i;
360    } while (cumulative < p && i < transitionMatrix[currState].size());
361
362    enterState(i - 1);
363}
364
365void
366TrafficGen::enterState(uint32_t newState)
367{
368    DPRINTF(TrafficGen, "Transition to state %d\n", newState);
369
370    currState = newState;
371    // we could have been delayed and not transitioned on the exact
372    // tick when we were supposed to (due to back pressure when
373    // sending a packet)
374    nextTransitionTick = curTick() + states[currState]->duration;
375    states[currState]->enter();
376}
377
378void
379TrafficGen::recvRetry()
380{
381    assert(retryPkt != NULL);
382
383    DPRINTF(TrafficGen, "Received retry\n");
384    numRetries++;
385    // attempt to send the packet, and if we are successful start up
386    // the machinery again
387    if (port.sendTimingReq(retryPkt)) {
388        retryPkt = NULL;
389        // remember how much delay was incurred due to back-pressure
390        // when sending the request, we also use this to derive
391        // the tick for the next packet
392        Tick delay = curTick() - retryPktTick;
393        retryPktTick = 0;
394        retryTicks += delay;
395
396        if (drainManager == NULL) {
397            // packet is sent, so find out when the next one is due
398            nextPacketTick = states[currState]->nextPacketTick(elasticReq,
399                                                               delay);
400            Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
401            schedule(updateEvent, std::max(curTick(), nextEventTick));
402        } else {
403            // shut things down
404            nextPacketTick = MaxTick;
405            nextTransitionTick = MaxTick;
406            drainManager->signalDrainDone();
407            // Clear the drain event once we're done with it.
408            drainManager = NULL;
409        }
410    }
411}
412
413void
414TrafficGen::regStats()
415{
416    // Initialise all the stats
417    using namespace Stats;
418
419    numPackets
420        .name(name() + ".numPackets")
421        .desc("Number of packets generated");
422
423    numRetries
424        .name(name() + ".numRetries")
425        .desc("Number of retries");
426
427    retryTicks
428        .name(name() + ".retryTicks")
429        .desc("Time spent waiting due to back-pressure (ticks)");
430}
431
432bool
433TrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
434{
435    delete pkt->req;
436    delete pkt;
437
438    return true;
439}
440