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