traffic_gen.cc revision 9717:dd2e46b239c1
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      nextTransitionTick(0),
58      port(name() + ".port", *this),
59      updateEvent(this)
60{
61    parseConfig(p->config_file, masterID);
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        // enter initial state
91        enterState(currState);
92    } else {
93        DPRINTF(TrafficGen,
94                "Traffic generator is only active in timing mode\n");
95    }
96}
97
98void
99TrafficGen::initState()
100{
101    // when not restoring from a checkpoint, make sure we kick things off
102    if (system->isTimingMode()) {
103        schedule(updateEvent, nextEventTick());
104    } else {
105        DPRINTF(TrafficGen,
106                "Traffic generator is only active in timing mode\n");
107    }
108}
109
110unsigned int
111TrafficGen::drain(DrainManager *dm)
112{
113    // @todo we should also stop putting new requests in the queue and
114    // either interrupt the current state or wait for a transition
115    return port.drain(dm);
116}
117
118void
119TrafficGen::serialize(ostream &os)
120{
121    DPRINTF(Checkpoint, "Serializing TrafficGen\n");
122
123    // save ticks of the graph event if it is scheduled
124    Tick nextEvent = updateEvent.scheduled() ?
125        updateEvent.when() : 0;
126
127    DPRINTF(TrafficGen, "Saving nextEvent=%llu\n",
128            nextEvent);
129
130    SERIALIZE_SCALAR(nextEvent);
131
132    SERIALIZE_SCALAR(nextTransitionTick);
133
134    // @todo: also serialise the current state, figure out the best
135    // way to drain and restore
136}
137
138void
139TrafficGen::unserialize(Checkpoint* cp, const string& section)
140{
141    // restore scheduled events
142    Tick nextEvent;
143    UNSERIALIZE_SCALAR(nextEvent);
144    if (nextEvent != 0) {
145        schedule(updateEvent, nextEvent);
146    }
147
148    UNSERIALIZE_SCALAR(nextTransitionTick);
149}
150
151void
152TrafficGen::update()
153{
154    // schedule next update event based on either the next execute
155    // tick or the next transition, which ever comes first
156    Tick nextEvent = nextEventTick();
157    DPRINTF(TrafficGen, "Updating state graph, next event at %lld\n",
158            nextEvent);
159    schedule(updateEvent, nextEvent);
160
161    // perform the update associated with the current update event
162
163    // if we have reached the time for the next state transition, then
164    // perform the transition
165    if (curTick() >= nextTransitionTick) {
166        transition();
167    } else {
168        // we are still in the current state and should execute it
169        states[currState]->execute();
170    }
171}
172
173void
174TrafficGen::parseConfig(const string& file_name, MasterID master_id)
175{
176    // keep track of the transitions parsed to create the matrix when
177    // done
178    vector<Transition> transitions;
179
180    // open input file
181    ifstream infile;
182    infile.open(file_name.c_str(), ifstream::in);
183    if (!infile.is_open()) {
184        fatal("Traffic generator %s config file not found at %s\n",
185              name(), file_name);
186    }
187
188    // read line by line and determine the action based on the first
189    // keyword
190    string keyword;
191    string line;
192
193    while (getline(infile, line).good()) {
194        // see if this line is a comment line, and if so skip it
195        if (line.find('#') != 1) {
196            // create an input stream for the tokenization
197            istringstream is(line);
198
199            // determine the keyword
200            is >> keyword;
201
202            if (keyword == "STATE") {
203                // parse the behaviour of this state
204                uint32_t id;
205                Tick duration;
206                string mode;
207
208                is >> id >> duration >> mode;
209
210                if (mode == "TRACE") {
211                    string traceFile;
212                    Addr addrOffset;
213
214                    is >> traceFile >> addrOffset;
215
216                    states[id] = new TraceGen(port, master_id, duration,
217                                              traceFile, addrOffset);
218                    DPRINTF(TrafficGen, "State: %d TraceGen\n", id);
219                } else if (mode == "IDLE") {
220                    states[id] = new IdleGen(port, master_id, duration);
221                    DPRINTF(TrafficGen, "State: %d IdleGen\n", id);
222                } else if (mode == "LINEAR" || mode == "RANDOM") {
223                    uint32_t read_percent;
224                    Addr start_addr;
225                    Addr end_addr;
226                    Addr blocksize;
227                    Tick min_period;
228                    Tick max_period;
229                    Addr data_limit;
230
231                    is >> read_percent >> start_addr >> end_addr >>
232                        blocksize >> min_period >> max_period >> data_limit;
233
234                    DPRINTF(TrafficGen, "%s, addr %x to %x, size %d,"
235                            " period %d to %d, %d%% reads\n",
236                            mode, start_addr, end_addr, blocksize, min_period,
237                            max_period, read_percent);
238
239                    if (read_percent > 100)
240                        panic("%s cannot have more than 100% reads", name());
241
242                    if (mode == "LINEAR") {
243                        states[id] = new LinearGen(port, master_id,
244                                                   duration, start_addr,
245                                                   end_addr, blocksize,
246                                                   min_period, max_period,
247                                                   read_percent, data_limit);
248                        DPRINTF(TrafficGen, "State: %d LinearGen\n", id);
249                    } else if (mode == "RANDOM") {
250                        states[id] = new RandomGen(port, master_id,
251                                                   duration, start_addr,
252                                                   end_addr, blocksize,
253                                                   min_period, max_period,
254                                                   read_percent, data_limit);
255                        DPRINTF(TrafficGen, "State: %d RandomGen\n", id);
256                    }
257                } else {
258                    fatal("%s: Unknown traffic generator mode: %s",
259                          name(), mode);
260                }
261            } else if (keyword == "TRANSITION") {
262                Transition transition;
263
264                is >> transition.from >> transition.to >> transition.p;
265
266                transitions.push_back(transition);
267
268                DPRINTF(TrafficGen, "Transition: %d -> %d\n", transition.from,
269                        transition.to);
270            } else if (keyword == "INIT") {
271                // set the initial state as the active state
272                is >> currState;
273
274                DPRINTF(TrafficGen, "Initial state: %d\n", currState);
275            }
276        }
277    }
278
279    // resize and populate state transition matrix
280    transitionMatrix.resize(transitions.size());
281    for (size_t i = 0; i < transitions.size(); i++) {
282        transitionMatrix[i].resize(transitions.size());
283    }
284
285    for (vector<Transition>::iterator t = transitions.begin();
286         t != transitions.end(); ++t) {
287        transitionMatrix[t->from][t->to] = t->p;
288    }
289
290    // ensure the egress edges do not have a probability larger than
291    // one
292    for (size_t i = 0; i < transitions.size(); i++) {
293        double sum = 0;
294        for (size_t j = 0; j < transitions.size(); j++) {
295            sum += transitionMatrix[i][j];
296        }
297
298        // avoid comparing floating point numbers
299        if (abs(sum - 1.0) > 0.001)
300            fatal("%s has transition probability != 1 for state %d\n",
301                  name(), i);
302    }
303
304    // close input file
305    infile.close();
306}
307
308void
309TrafficGen::transition()
310{
311    // exit the current state
312    states[currState]->exit();
313
314    // determine next state
315    double p = random_mt.gen_real1();
316    assert(currState < transitionMatrix.size());
317    double cumulative = 0.0;
318    size_t i = 0;
319    do {
320        cumulative += transitionMatrix[currState][i];
321        ++i;
322    } while (cumulative < p && i < transitionMatrix[currState].size());
323
324    enterState(i - 1);
325}
326
327void
328TrafficGen::enterState(uint32_t newState)
329{
330    DPRINTF(TrafficGen, "Transition to state %d\n", newState);
331
332    currState = newState;
333    nextTransitionTick += states[currState]->duration;
334    states[currState]->enter();
335}
336
337bool
338TrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
339{
340    delete pkt->req;
341    delete pkt;
342
343    return true;
344}
345