traffic_gen.cc revision 12810:485ca1c27812
1/*
2 * Copyright (c) 2012-2013, 2016-2018 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#include "cpu/testers/traffic_gen/traffic_gen.hh"
42
43#include <libgen.h>
44#include <unistd.h>
45
46#include <sstream>
47
48#include "base/intmath.hh"
49#include "base/random.hh"
50#include "cpu/testers/traffic_gen/dram_gen.hh"
51#include "cpu/testers/traffic_gen/dram_rot_gen.hh"
52#include "cpu/testers/traffic_gen/exit_gen.hh"
53#include "cpu/testers/traffic_gen/idle_gen.hh"
54#include "cpu/testers/traffic_gen/linear_gen.hh"
55#include "cpu/testers/traffic_gen/random_gen.hh"
56#include "cpu/testers/traffic_gen/trace_gen.hh"
57#include "debug/TrafficGen.hh"
58#include "params/TrafficGen.hh"
59#include "sim/stats.hh"
60#include "sim/system.hh"
61
62using namespace std;
63
64TrafficGen::TrafficGen(const TrafficGenParams* p)
65    : BaseTrafficGen(p),
66      configFile(p->config_file),
67      currState(0)
68{
69}
70
71TrafficGen*
72TrafficGenParams::create()
73{
74    return new TrafficGen(this);
75}
76
77void
78TrafficGen::init()
79{
80    BaseTrafficGen::init();
81
82    parseConfig();
83}
84
85void
86TrafficGen::initState()
87{
88    BaseTrafficGen::initState();
89
90    // when not restoring from a checkpoint, make sure we kick things off
91    if (system->isTimingMode()) {
92        DPRINTF(TrafficGen, "Timing mode, activating request generator\n");
93        start();
94    } else {
95        DPRINTF(TrafficGen,
96                "Traffic generator is only active in timing mode\n");
97    }
98}
99
100void
101TrafficGen::serialize(CheckpointOut &cp) const
102{
103    SERIALIZE_SCALAR(currState);
104
105    BaseTrafficGen::serialize(cp);
106}
107
108void
109TrafficGen::unserialize(CheckpointIn &cp)
110{
111    // @todo In the case of a stateful generator state such as the
112    // trace player we would also have to restore the position in the
113    // trace playback and the tick offset
114    UNSERIALIZE_SCALAR(currState);
115
116    BaseTrafficGen::unserialize(cp);
117}
118
119std::string
120TrafficGen::resolveFile(const std::string &name)
121{
122    // Do nothing for empty and absolute file names
123    if (name.empty() || name[0] == '/')
124        return name;
125
126    char *config_path = strdup(configFile.c_str());
127    char *config_dir = dirname(config_path);
128    const std::string config_rel = csprintf("%s/%s", config_dir, name);
129    free(config_path);
130
131    // Check the path relative to the config file first
132    if (access(config_rel.c_str(), R_OK) == 0)
133        return config_rel;
134
135    // Fall back to the old behavior and search relative to the
136    // current working directory.
137    return name;
138}
139
140void
141TrafficGen::parseConfig()
142{
143    // keep track of the transitions parsed to create the matrix when
144    // done
145    vector<Transition> transitions;
146
147    // open input file
148    ifstream infile;
149    infile.open(configFile.c_str(), ifstream::in);
150    if (!infile.is_open()) {
151        fatal("Traffic generator %s config file not found at %s\n",
152              name(), configFile);
153    }
154
155    bool init_state_set = false;
156
157    // read line by line and determine the action based on the first
158    // keyword
159    string keyword;
160    string line;
161
162    while (getline(infile, line).good()) {
163        // see if this line is a comment line, and if so skip it
164        if (line.find('#') != 1) {
165            // create an input stream for the tokenization
166            istringstream is(line);
167
168            // determine the keyword
169            is >> keyword;
170
171            if (keyword == "STATE") {
172                // parse the behaviour of this state
173                uint32_t id;
174                Tick duration;
175                string mode;
176
177                is >> id >> duration >> mode;
178
179                if (mode == "TRACE") {
180                    string traceFile;
181                    Addr addrOffset;
182
183                    is >> traceFile >> addrOffset;
184                    traceFile = resolveFile(traceFile);
185
186                    states[id].reset(new TraceGen(name(), masterID, duration,
187                                                  traceFile, addrOffset));
188                    DPRINTF(TrafficGen, "State: %d TraceGen\n", id);
189                } else if (mode == "IDLE") {
190                    states[id].reset(new IdleGen(name(), masterID, duration));
191                    DPRINTF(TrafficGen, "State: %d IdleGen\n", id);
192                } else if (mode == "EXIT") {
193                    states[id].reset(new ExitGen(name(), masterID, duration));
194                    DPRINTF(TrafficGen, "State: %d ExitGen\n", id);
195                } else if (mode == "LINEAR" || mode == "RANDOM" ||
196                           mode == "DRAM"   || mode == "DRAM_ROTATE") {
197                    uint32_t read_percent;
198                    Addr start_addr;
199                    Addr end_addr;
200                    Addr blocksize;
201                    Tick min_period;
202                    Tick max_period;
203                    Addr data_limit;
204
205                    is >> read_percent >> start_addr >> end_addr >>
206                        blocksize >> min_period >> max_period >> data_limit;
207
208                    DPRINTF(TrafficGen, "%s, addr %x to %x, size %d,"
209                            " period %d to %d, %d%% reads\n",
210                            mode, start_addr, end_addr, blocksize, min_period,
211                            max_period, read_percent);
212
213
214                    if (blocksize > system->cacheLineSize())
215                        fatal("TrafficGen %s block size (%d) is larger than "
216                              "cache line size (%d)\n", name(),
217                              blocksize, system->cacheLineSize());
218
219                    if (read_percent > 100)
220                        fatal("%s cannot have more than 100% reads", name());
221
222                    if (min_period > max_period)
223                        fatal("%s cannot have min_period > max_period", name());
224
225                    if (mode == "LINEAR") {
226                        states[id].reset(new LinearGen(name(), masterID,
227                                                   duration, start_addr,
228                                                   end_addr, blocksize,
229                                                   min_period, max_period,
230                                                   read_percent, data_limit));
231                        DPRINTF(TrafficGen, "State: %d LinearGen\n", id);
232                    } else if (mode == "RANDOM") {
233                        states[id].reset(new RandomGen(name(), masterID,
234                                                   duration, start_addr,
235                                                   end_addr, blocksize,
236                                                   min_period, max_period,
237                                                   read_percent, data_limit));
238                        DPRINTF(TrafficGen, "State: %d RandomGen\n", id);
239                    } else if (mode == "DRAM" || mode == "DRAM_ROTATE") {
240                        // stride size (bytes) of the request for achieving
241                        // required hit length
242                        unsigned int stride_size;
243                        unsigned int page_size;
244                        unsigned int nbr_of_banks_DRAM;
245                        unsigned int nbr_of_banks_util;
246                        unsigned int addr_mapping;
247                        unsigned int nbr_of_ranks;
248
249                        is >> stride_size >> page_size >> nbr_of_banks_DRAM >>
250                            nbr_of_banks_util >> addr_mapping >>
251                            nbr_of_ranks;
252
253                        if (stride_size > page_size)
254                            warn("DRAM generator stride size (%d) is greater "
255                                 "than page size (%d)  of the memory\n",
256                                 blocksize, page_size);
257
258                        if (nbr_of_banks_util > nbr_of_banks_DRAM)
259                            fatal("Attempting to use more banks (%d) than "
260                                  "what is available (%d)\n",
261                                  nbr_of_banks_util, nbr_of_banks_DRAM);
262
263                        // count the number of sequential packets to
264                        // generate
265                        unsigned int num_seq_pkts = 1;
266
267                        if (stride_size > blocksize) {
268                            num_seq_pkts = divCeil(stride_size, blocksize);
269                            DPRINTF(TrafficGen, "stride size: %d "
270                                    "block size: %d, num_seq_pkts: %d\n",
271                                    stride_size, blocksize, num_seq_pkts);
272                        }
273
274                        if (mode == "DRAM") {
275                            states[id].reset(new DramGen(name(), masterID,
276                                                     duration, start_addr,
277                                                     end_addr, blocksize,
278                                                     min_period, max_period,
279                                                     read_percent, data_limit,
280                                                     num_seq_pkts, page_size,
281                                                     nbr_of_banks_DRAM,
282                                                     nbr_of_banks_util,
283                                                     addr_mapping,
284                                                     nbr_of_ranks));
285                            DPRINTF(TrafficGen, "State: %d DramGen\n", id);
286                        } else {
287                            // Will rotate to the next rank after rotating
288                            // through all banks, for each command type.
289                            // In the 50% read case, series will be issued
290                            // for both RD & WR before the rank in incremented
291                            unsigned int max_seq_count_per_rank =
292                                (read_percent == 50) ? nbr_of_banks_util * 2
293                                                     : nbr_of_banks_util;
294
295                            states[id].reset(new DramRotGen(name(), masterID,
296                                                     duration, start_addr,
297                                                     end_addr, blocksize,
298                                                     min_period, max_period,
299                                                     read_percent, data_limit,
300                                                     num_seq_pkts, page_size,
301                                                     nbr_of_banks_DRAM,
302                                                     nbr_of_banks_util,
303                                                     addr_mapping,
304                                                     nbr_of_ranks,
305                                                     max_seq_count_per_rank));
306                            DPRINTF(TrafficGen, "State: %d DramRotGen\n", id);
307                        }
308                    }
309                } else {
310                    fatal("%s: Unknown traffic generator mode: %s",
311                          name(), mode);
312                }
313            } else if (keyword == "TRANSITION") {
314                Transition transition;
315
316                is >> transition.from >> transition.to >> transition.p;
317
318                transitions.push_back(transition);
319
320                DPRINTF(TrafficGen, "Transition: %d -> %d\n", transition.from,
321                        transition.to);
322            } else if (keyword == "INIT") {
323                // set the initial state as the active state
324                is >> currState;
325
326                init_state_set = true;
327
328                DPRINTF(TrafficGen, "Initial state: %d\n", currState);
329            }
330        }
331    }
332
333    if (!init_state_set)
334        fatal("%s: initial state not specified (add 'INIT <id>' line "
335              "to the config file)\n", name());
336
337    // resize and populate state transition matrix
338    transitionMatrix.resize(states.size());
339    for (size_t i = 0; i < states.size(); i++) {
340        transitionMatrix[i].resize(states.size());
341    }
342
343    for (vector<Transition>::iterator t = transitions.begin();
344         t != transitions.end(); ++t) {
345        transitionMatrix[t->from][t->to] = t->p;
346    }
347
348    // ensure the egress edges do not have a probability larger than
349    // one
350    for (size_t i = 0; i < states.size(); i++) {
351        double sum = 0;
352        for (size_t j = 0; j < states.size(); j++) {
353            sum += transitionMatrix[i][j];
354        }
355
356        // avoid comparing floating point numbers
357        if (abs(sum - 1.0) > 0.001)
358            fatal("%s has transition probability != 1 for state %d\n",
359                  name(), i);
360    }
361
362    // close input file
363    infile.close();
364}
365
366size_t
367TrafficGen::nextState()
368{
369    double p = random_mt.random<double>();
370    assert(currState < transitionMatrix.size());
371    double cumulative = 0.0;
372    size_t i = 0;
373    do {
374        cumulative += transitionMatrix[currState][i];
375        ++i;
376    } while (cumulative < p && i < transitionMatrix[currState].size());
377
378    return i - 1;
379}
380
381std::shared_ptr<BaseGen>
382TrafficGen::nextGenerator()
383{
384    // Return the initial state if there isn't an active generator,
385    // otherwise perform a state transition.
386    if (activeGenerator)
387        currState = nextState();
388
389    DPRINTF(TrafficGen, "Transition to state %d\n", currState);
390    return states[currState];
391}
392