traffic_gen.cc revision 9719:b67ea6252629
1/*
2 * Copyright (c) 2012-2013 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 "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      configFile(p->config_file),
58      nextTransitionTick(0),
59      nextPacketTick(0),
60      port(name() + ".port", *this),
61      retryPkt(NULL),
62      retryPktTick(0),
63      updateEvent(this),
64      drainManager(NULL)
65{
66}
67
68TrafficGen*
69TrafficGenParams::create()
70{
71    return new TrafficGen(this);
72}
73
74BaseMasterPort&
75TrafficGen::getMasterPort(const string& if_name, PortID idx)
76{
77    if (if_name == "port") {
78        return port;
79    } else {
80        return MemObject::getMasterPort(if_name, idx);
81    }
82}
83
84void
85TrafficGen::init()
86{
87    if (!port.isConnected())
88        fatal("The port of %s is not connected!\n", name());
89
90    // if the system is in timing mode active the request generator
91    if (system->isTimingMode()) {
92        DPRINTF(TrafficGen, "Timing mode, activating request generator\n");
93
94        parseConfig();
95
96        // enter initial state
97        enterState(currState);
98    } else {
99        DPRINTF(TrafficGen,
100                "Traffic generator is only active in timing mode\n");
101    }
102}
103
104void
105TrafficGen::initState()
106{
107    // when not restoring from a checkpoint, make sure we kick things off
108    if (system->isTimingMode()) {
109        // call nextPacketTick on the state to advance it
110        nextPacketTick = states[currState]->nextPacketTick();
111        schedule(updateEvent, std::min(nextPacketTick, nextTransitionTick));
112    } else {
113        DPRINTF(TrafficGen,
114                "Traffic generator is only active in timing mode\n");
115    }
116}
117
118unsigned int
119TrafficGen::drain(DrainManager *dm)
120{
121    if (retryPkt == NULL) {
122        // shut things down
123        nextPacketTick = MaxTick;
124        nextTransitionTick = MaxTick;
125        deschedule(updateEvent);
126        return 0;
127    } else {
128        drainManager = dm;
129        return 1;
130    }
131}
132
133void
134TrafficGen::serialize(ostream &os)
135{
136    DPRINTF(Checkpoint, "Serializing TrafficGen\n");
137
138    // save ticks of the graph event if it is scheduled
139    Tick nextEvent = updateEvent.scheduled() ? updateEvent.when() : 0;
140
141    DPRINTF(TrafficGen, "Saving nextEvent=%llu\n", nextEvent);
142
143    SERIALIZE_SCALAR(nextEvent);
144
145    SERIALIZE_SCALAR(nextTransitionTick);
146
147    SERIALIZE_SCALAR(nextPacketTick);
148
149    SERIALIZE_SCALAR(currState);
150}
151
152void
153TrafficGen::unserialize(Checkpoint* cp, const string& section)
154{
155    // restore scheduled events
156    Tick nextEvent;
157    UNSERIALIZE_SCALAR(nextEvent);
158    if (nextEvent != 0) {
159        schedule(updateEvent, nextEvent);
160    }
161
162    UNSERIALIZE_SCALAR(nextTransitionTick);
163
164    UNSERIALIZE_SCALAR(nextPacketTick);
165
166    // @todo In the case of a stateful generator state such as the
167    // trace player we would also have to restore the position in the
168    // trace playback
169    UNSERIALIZE_SCALAR(currState);
170}
171
172void
173TrafficGen::update()
174{
175    // if we have reached the time for the next state transition, then
176    // perform the transition
177    if (curTick() >= nextTransitionTick) {
178        transition();
179    } else {
180        assert(curTick() >= nextPacketTick);
181        // get the next packet and try to send it
182        PacketPtr pkt = states[currState]->getNextPacket();
183        numPackets++;
184        if (!port.sendTimingReq(pkt)) {
185            retryPkt = pkt;
186            retryPktTick = curTick();
187        }
188    }
189
190    // if we are waiting for a retry, do not schedule any further
191    // events, in the case of a transition or a successful send, go
192    // ahead and determine when the next update should take place
193    if (retryPkt == NULL) {
194        // schedule next update event based on either the next execute
195        // tick or the next transition, which ever comes first
196        nextPacketTick = states[currState]->nextPacketTick();
197        Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
198        DPRINTF(TrafficGen, "Next event scheduled at %lld\n", nextEventTick);
199        schedule(updateEvent, nextEventTick);
200    }
201}
202
203void
204TrafficGen::parseConfig()
205{
206    // keep track of the transitions parsed to create the matrix when
207    // done
208    vector<Transition> transitions;
209
210    // open input file
211    ifstream infile;
212    infile.open(configFile.c_str(), ifstream::in);
213    if (!infile.is_open()) {
214        fatal("Traffic generator %s config file not found at %s\n",
215              name(), configFile);
216    }
217
218    // read line by line and determine the action based on the first
219    // keyword
220    string keyword;
221    string line;
222
223    while (getline(infile, line).good()) {
224        // see if this line is a comment line, and if so skip it
225        if (line.find('#') != 1) {
226            // create an input stream for the tokenization
227            istringstream is(line);
228
229            // determine the keyword
230            is >> keyword;
231
232            if (keyword == "STATE") {
233                // parse the behaviour of this state
234                uint32_t id;
235                Tick duration;
236                string mode;
237
238                is >> id >> duration >> mode;
239
240                if (mode == "TRACE") {
241                    string traceFile;
242                    Addr addrOffset;
243
244                    is >> traceFile >> addrOffset;
245
246                    states[id] = new TraceGen(name(), masterID, duration,
247                                              traceFile, addrOffset);
248                    DPRINTF(TrafficGen, "State: %d TraceGen\n", id);
249                } else if (mode == "IDLE") {
250                    states[id] = new IdleGen(name(), masterID, duration);
251                    DPRINTF(TrafficGen, "State: %d IdleGen\n", id);
252                } else if (mode == "LINEAR" || mode == "RANDOM") {
253                    uint32_t read_percent;
254                    Addr start_addr;
255                    Addr end_addr;
256                    Addr blocksize;
257                    Tick min_period;
258                    Tick max_period;
259                    Addr data_limit;
260
261                    is >> read_percent >> start_addr >> end_addr >>
262                        blocksize >> min_period >> max_period >> data_limit;
263
264                    DPRINTF(TrafficGen, "%s, addr %x to %x, size %d,"
265                            " period %d to %d, %d%% reads\n",
266                            mode, start_addr, end_addr, blocksize, min_period,
267                            max_period, read_percent);
268
269
270                    if (port.deviceBlockSize() &&
271                        blocksize > port.deviceBlockSize())
272                        fatal("TrafficGen %s block size (%d) is larger than "
273                              "port block size (%d)\n", name(),
274                              blocksize, port.deviceBlockSize());
275
276                    if (read_percent > 100)
277                        fatal("%s cannot have more than 100% reads", name());
278
279                    if (mode == "LINEAR") {
280                        states[id] = new LinearGen(name(), masterID,
281                                                   duration, start_addr,
282                                                   end_addr, blocksize,
283                                                   min_period, max_period,
284                                                   read_percent, data_limit);
285                        DPRINTF(TrafficGen, "State: %d LinearGen\n", id);
286                    } else if (mode == "RANDOM") {
287                        states[id] = new RandomGen(name(), masterID,
288                                                   duration, start_addr,
289                                                   end_addr, blocksize,
290                                                   min_period, max_period,
291                                                   read_percent, data_limit);
292                        DPRINTF(TrafficGen, "State: %d RandomGen\n", id);
293                    }
294                } else {
295                    fatal("%s: Unknown traffic generator mode: %s",
296                          name(), mode);
297                }
298            } else if (keyword == "TRANSITION") {
299                Transition transition;
300
301                is >> transition.from >> transition.to >> transition.p;
302
303                transitions.push_back(transition);
304
305                DPRINTF(TrafficGen, "Transition: %d -> %d\n", transition.from,
306                        transition.to);
307            } else if (keyword == "INIT") {
308                // set the initial state as the active state
309                is >> currState;
310
311                DPRINTF(TrafficGen, "Initial state: %d\n", currState);
312            }
313        }
314    }
315
316    // resize and populate state transition matrix
317    transitionMatrix.resize(transitions.size());
318    for (size_t i = 0; i < transitions.size(); i++) {
319        transitionMatrix[i].resize(transitions.size());
320    }
321
322    for (vector<Transition>::iterator t = transitions.begin();
323         t != transitions.end(); ++t) {
324        transitionMatrix[t->from][t->to] = t->p;
325    }
326
327    // ensure the egress edges do not have a probability larger than
328    // one
329    for (size_t i = 0; i < transitions.size(); i++) {
330        double sum = 0;
331        for (size_t j = 0; j < transitions.size(); j++) {
332            sum += transitionMatrix[i][j];
333        }
334
335        // avoid comparing floating point numbers
336        if (abs(sum - 1.0) > 0.001)
337            fatal("%s has transition probability != 1 for state %d\n",
338                  name(), i);
339    }
340
341    // close input file
342    infile.close();
343}
344
345void
346TrafficGen::transition()
347{
348    // exit the current state
349    states[currState]->exit();
350
351    // determine next state
352    double p = random_mt.gen_real1();
353    assert(currState < transitionMatrix.size());
354    double cumulative = 0.0;
355    size_t i = 0;
356    do {
357        cumulative += transitionMatrix[currState][i];
358        ++i;
359    } while (cumulative < p && i < transitionMatrix[currState].size());
360
361    enterState(i - 1);
362}
363
364void
365TrafficGen::enterState(uint32_t newState)
366{
367    DPRINTF(TrafficGen, "Transition to state %d\n", newState);
368
369    currState = newState;
370    // we could have been delayed and not transitioned on the exact
371    // tick when we were supposed to (due to back pressure when
372    // sending a packet)
373    nextTransitionTick = curTick() + states[currState]->duration;
374    states[currState]->enter();
375}
376
377void
378TrafficGen::recvRetry()
379{
380    assert(retryPkt != NULL);
381
382    DPRINTF(TrafficGen, "Received retry\n");
383    numRetries++;
384    // attempt to send the packet, and if we are successful start up
385    // the machinery again
386    if (port.sendTimingReq(retryPkt)) {
387        retryPkt = NULL;
388        // remember how much delay was incurred due to back-pressure
389        // when sending the request
390        Tick delay = curTick() - retryPktTick;
391        retryPktTick = 0;
392        retryTicks += delay;
393
394        if (drainManager == NULL) {
395            // packet is sent, so find out when the next one is due
396            nextPacketTick = states[currState]->nextPacketTick();
397            Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
398            schedule(updateEvent, std::max(curTick(), nextEventTick));
399        } else {
400            // shut things down
401            nextPacketTick = MaxTick;
402            nextTransitionTick = MaxTick;
403            drainManager->signalDrainDone();
404            // Clear the drain event once we're done with it.
405            drainManager = NULL;
406        }
407    }
408}
409
410void
411TrafficGen::regStats()
412{
413    // Initialise all the stats
414    using namespace Stats;
415
416    numPackets
417        .name(name() + ".numPackets")
418        .desc("Number of packets generated");
419
420    numRetries
421        .name(name() + ".numRetries")
422        .desc("Number of retries");
423
424    retryTicks
425        .name(name() + ".retryTicks")
426        .desc("Time spent waiting due to back-pressure (ticks)");
427}
428
429bool
430TrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
431{
432    delete pkt->req;
433    delete pkt;
434
435    return true;
436}
437