traffic_gen.cc revision 9718
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      port(name() + ".port", *this),
60      updateEvent(this)
61{
62}
63
64TrafficGen*
65TrafficGenParams::create()
66{
67    return new TrafficGen(this);
68}
69
70BaseMasterPort&
71TrafficGen::getMasterPort(const string& if_name, PortID idx)
72{
73    if (if_name == "port") {
74        return port;
75    } else {
76        return MemObject::getMasterPort(if_name, idx);
77    }
78}
79
80void
81TrafficGen::init()
82{
83    if (!port.isConnected())
84        fatal("The port of %s is not connected!\n", name());
85
86    // if the system is in timing mode active the request generator
87    if (system->isTimingMode()) {
88        DPRINTF(TrafficGen, "Timing mode, activating request generator\n");
89
90        parseConfig();
91
92        // enter initial state
93        enterState(currState);
94    } else {
95        DPRINTF(TrafficGen,
96                "Traffic generator is only active in timing mode\n");
97    }
98}
99
100void
101TrafficGen::initState()
102{
103    // when not restoring from a checkpoint, make sure we kick things off
104    if (system->isTimingMode()) {
105        schedule(updateEvent, nextEventTick());
106    } else {
107        DPRINTF(TrafficGen,
108                "Traffic generator is only active in timing mode\n");
109    }
110}
111
112unsigned int
113TrafficGen::drain(DrainManager *dm)
114{
115    // @todo we should also stop putting new requests in the queue and
116    // either interrupt the current state or wait for a transition
117    return port.drain(dm);
118}
119
120void
121TrafficGen::serialize(ostream &os)
122{
123    DPRINTF(Checkpoint, "Serializing TrafficGen\n");
124
125    // save ticks of the graph event if it is scheduled
126    Tick nextEvent = updateEvent.scheduled() ?
127        updateEvent.when() : 0;
128
129    DPRINTF(TrafficGen, "Saving nextEvent=%llu\n",
130            nextEvent);
131
132    SERIALIZE_SCALAR(nextEvent);
133
134    SERIALIZE_SCALAR(nextTransitionTick);
135
136    // @todo: also serialise the current state, figure out the best
137    // way to drain and restore
138}
139
140void
141TrafficGen::unserialize(Checkpoint* cp, const string& section)
142{
143    // restore scheduled events
144    Tick nextEvent;
145    UNSERIALIZE_SCALAR(nextEvent);
146    if (nextEvent != 0) {
147        schedule(updateEvent, nextEvent);
148    }
149
150    UNSERIALIZE_SCALAR(nextTransitionTick);
151}
152
153void
154TrafficGen::update()
155{
156    // schedule next update event based on either the next execute
157    // tick or the next transition, which ever comes first
158    Tick nextEvent = nextEventTick();
159    DPRINTF(TrafficGen, "Updating state graph, next event at %lld\n",
160            nextEvent);
161    schedule(updateEvent, nextEvent);
162
163    // perform the update associated with the current update event
164
165    // if we have reached the time for the next state transition, then
166    // perform the transition
167    if (curTick() >= nextTransitionTick) {
168        transition();
169    } else {
170        // we are still in the current state and should execute it
171        PacketPtr pkt = states[currState]->getNextPacket();
172        port.schedTimingReq(pkt, curTick());
173    }
174}
175
176void
177TrafficGen::parseConfig()
178{
179    // keep track of the transitions parsed to create the matrix when
180    // done
181    vector<Transition> transitions;
182
183    // open input file
184    ifstream infile;
185    infile.open(configFile.c_str(), ifstream::in);
186    if (!infile.is_open()) {
187        fatal("Traffic generator %s config file not found at %s\n",
188              name(), configFile);
189    }
190
191    // read line by line and determine the action based on the first
192    // keyword
193    string keyword;
194    string line;
195
196    while (getline(infile, line).good()) {
197        // see if this line is a comment line, and if so skip it
198        if (line.find('#') != 1) {
199            // create an input stream for the tokenization
200            istringstream is(line);
201
202            // determine the keyword
203            is >> keyword;
204
205            if (keyword == "STATE") {
206                // parse the behaviour of this state
207                uint32_t id;
208                Tick duration;
209                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