traffic_gen.cc revision 10360:919c02740209
14120Sgblack@eecs.umich.edu/*
24120Sgblack@eecs.umich.edu * Copyright (c) 2012-2013 ARM Limited
34120Sgblack@eecs.umich.edu * All rights reserved
44120Sgblack@eecs.umich.edu *
54120Sgblack@eecs.umich.edu * The license below extends only to copyright in the software and shall
64120Sgblack@eecs.umich.edu * not be construed as granting a license to any other intellectual
74120Sgblack@eecs.umich.edu * property including but not limited to intellectual property relating
84120Sgblack@eecs.umich.edu * to a hardware implementation of the functionality of the software
94120Sgblack@eecs.umich.edu * licensed hereunder.  You may use the software subject to the license
104120Sgblack@eecs.umich.edu * terms below provided that you ensure that this notice is replicated
114120Sgblack@eecs.umich.edu * unmodified and in its entirety in all distributions of the software,
124120Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form.
134120Sgblack@eecs.umich.edu *
144120Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
154120Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
164120Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
174120Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
184120Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
194120Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
204120Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
214120Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
224120Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
234120Sgblack@eecs.umich.edu * this software without specific prior written permission.
244120Sgblack@eecs.umich.edu *
254120Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
264120Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
274120Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
284120Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
294120Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
304120Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
314120Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
324120Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
334120Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
344120Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
354120Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
364120Sgblack@eecs.umich.edu *
374120Sgblack@eecs.umich.edu * Authors: Thomas Grass
384120Sgblack@eecs.umich.edu *          Andreas Hansson
394120Sgblack@eecs.umich.edu *          Sascha Bischoff
404120Sgblack@eecs.umich.edu */
414120Sgblack@eecs.umich.edu
424120Sgblack@eecs.umich.edu#include <sstream>
434120Sgblack@eecs.umich.edu
444120Sgblack@eecs.umich.edu#include "base/intmath.hh"
454120Sgblack@eecs.umich.edu#include "base/random.hh"
464120Sgblack@eecs.umich.edu#include "cpu/testers/traffic_gen/traffic_gen.hh"
474120Sgblack@eecs.umich.edu#include "debug/Checkpoint.hh"
484120Sgblack@eecs.umich.edu#include "debug/TrafficGen.hh"
494120Sgblack@eecs.umich.edu#include "sim/stats.hh"
504120Sgblack@eecs.umich.edu#include "sim/system.hh"
514120Sgblack@eecs.umich.edu
524120Sgblack@eecs.umich.eduusing namespace std;
534120Sgblack@eecs.umich.edu
544120Sgblack@eecs.umich.eduTrafficGen::TrafficGen(const TrafficGenParams* p)
554120Sgblack@eecs.umich.edu    : MemObject(p),
564120Sgblack@eecs.umich.edu      system(p->system),
574120Sgblack@eecs.umich.edu      masterID(system->getMasterId(name())),
584120Sgblack@eecs.umich.edu      configFile(p->config_file),
594120Sgblack@eecs.umich.edu      elasticReq(p->elastic_req),
604120Sgblack@eecs.umich.edu      nextTransitionTick(0),
614148Sgblack@eecs.umich.edu      nextPacketTick(0),
624148Sgblack@eecs.umich.edu      currState(0),
634148Sgblack@eecs.umich.edu      port(name() + ".port", *this),
644148Sgblack@eecs.umich.edu      retryPkt(NULL),
654120Sgblack@eecs.umich.edu      retryPktTick(0),
664120Sgblack@eecs.umich.edu      updateEvent(this),
674120Sgblack@eecs.umich.edu      drainManager(NULL)
684148Sgblack@eecs.umich.edu{
694148Sgblack@eecs.umich.edu}
704148Sgblack@eecs.umich.edu
714148Sgblack@eecs.umich.eduTrafficGen*
724148Sgblack@eecs.umich.eduTrafficGenParams::create()
734148Sgblack@eecs.umich.edu{
744148Sgblack@eecs.umich.edu    return new TrafficGen(this);
754148Sgblack@eecs.umich.edu}
764148Sgblack@eecs.umich.edu
774148Sgblack@eecs.umich.eduBaseMasterPort&
784148Sgblack@eecs.umich.eduTrafficGen::getMasterPort(const string& if_name, PortID idx)
794148Sgblack@eecs.umich.edu{
804148Sgblack@eecs.umich.edu    if (if_name == "port") {
814148Sgblack@eecs.umich.edu        return port;
824148Sgblack@eecs.umich.edu    } else {
834148Sgblack@eecs.umich.edu        return MemObject::getMasterPort(if_name, idx);
844148Sgblack@eecs.umich.edu    }
854148Sgblack@eecs.umich.edu}
864148Sgblack@eecs.umich.edu
874148Sgblack@eecs.umich.eduvoid
884148Sgblack@eecs.umich.eduTrafficGen::init()
894148Sgblack@eecs.umich.edu{
904148Sgblack@eecs.umich.edu    if (!port.isConnected())
914148Sgblack@eecs.umich.edu        fatal("The port of %s is not connected!\n", name());
924148Sgblack@eecs.umich.edu
934148Sgblack@eecs.umich.edu    // if the system is in timing mode active the request generator
944148Sgblack@eecs.umich.edu    if (system->isTimingMode()) {
954148Sgblack@eecs.umich.edu        DPRINTF(TrafficGen, "Timing mode, activating request generator\n");
964148Sgblack@eecs.umich.edu
974148Sgblack@eecs.umich.edu        parseConfig();
984148Sgblack@eecs.umich.edu
994148Sgblack@eecs.umich.edu        // enter initial state
1004148Sgblack@eecs.umich.edu        enterState(currState);
1014148Sgblack@eecs.umich.edu    } else {
1024148Sgblack@eecs.umich.edu        DPRINTF(TrafficGen,
1034148Sgblack@eecs.umich.edu                "Traffic generator is only active in timing mode\n");
1044148Sgblack@eecs.umich.edu    }
1054148Sgblack@eecs.umich.edu}
1064148Sgblack@eecs.umich.edu
1074148Sgblack@eecs.umich.eduvoid
1084148Sgblack@eecs.umich.eduTrafficGen::initState()
1094148Sgblack@eecs.umich.edu{
1104148Sgblack@eecs.umich.edu    // when not restoring from a checkpoint, make sure we kick things off
1114148Sgblack@eecs.umich.edu    if (system->isTimingMode()) {
1124148Sgblack@eecs.umich.edu        // call nextPacketTick on the state to advance it
1134148Sgblack@eecs.umich.edu        nextPacketTick = states[currState]->nextPacketTick(elasticReq, 0);
1144148Sgblack@eecs.umich.edu        schedule(updateEvent, std::min(nextPacketTick, nextTransitionTick));
1154148Sgblack@eecs.umich.edu    } else {
1164148Sgblack@eecs.umich.edu        DPRINTF(TrafficGen,
1174148Sgblack@eecs.umich.edu                "Traffic generator is only active in timing mode\n");
1184148Sgblack@eecs.umich.edu    }
1194148Sgblack@eecs.umich.edu}
1204148Sgblack@eecs.umich.edu
1214148Sgblack@eecs.umich.eduunsigned int
1224148Sgblack@eecs.umich.eduTrafficGen::drain(DrainManager *dm)
1234148Sgblack@eecs.umich.edu{
1244148Sgblack@eecs.umich.edu    if (!updateEvent.scheduled()) {
1254148Sgblack@eecs.umich.edu        // no event has been scheduled yet (e.g. switched from atomic mode)
1264148Sgblack@eecs.umich.edu        return 0;
1274148Sgblack@eecs.umich.edu    }
1284120Sgblack@eecs.umich.edu
1294120Sgblack@eecs.umich.edu    if (retryPkt == NULL) {
1304120Sgblack@eecs.umich.edu        // shut things down
131        nextPacketTick = MaxTick;
132        nextTransitionTick = MaxTick;
133        deschedule(updateEvent);
134        return 0;
135    } else {
136        drainManager = dm;
137        return 1;
138    }
139}
140
141void
142TrafficGen::serialize(ostream &os)
143{
144    DPRINTF(Checkpoint, "Serializing TrafficGen\n");
145
146    // save ticks of the graph event if it is scheduled
147    Tick nextEvent = updateEvent.scheduled() ? updateEvent.when() : 0;
148
149    DPRINTF(TrafficGen, "Saving nextEvent=%llu\n", nextEvent);
150
151    SERIALIZE_SCALAR(nextEvent);
152
153    SERIALIZE_SCALAR(nextTransitionTick);
154
155    SERIALIZE_SCALAR(nextPacketTick);
156
157    SERIALIZE_SCALAR(currState);
158}
159
160void
161TrafficGen::unserialize(Checkpoint* cp, const string& section)
162{
163    // restore scheduled events
164    Tick nextEvent;
165    UNSERIALIZE_SCALAR(nextEvent);
166    if (nextEvent != 0) {
167        schedule(updateEvent, nextEvent);
168    }
169
170    UNSERIALIZE_SCALAR(nextTransitionTick);
171
172    UNSERIALIZE_SCALAR(nextPacketTick);
173
174    // @todo In the case of a stateful generator state such as the
175    // trace player we would also have to restore the position in the
176    // trace playback and the tick offset
177    UNSERIALIZE_SCALAR(currState);
178}
179
180void
181TrafficGen::update()
182{
183    // if we have reached the time for the next state transition, then
184    // perform the transition
185    if (curTick() >= nextTransitionTick) {
186        transition();
187    } else {
188        assert(curTick() >= nextPacketTick);
189        // get the next packet and try to send it
190        PacketPtr pkt = states[currState]->getNextPacket();
191
192        // suppress packets that are not destined for a memory, such as
193        // device accesses that could be part of a trace
194        if (system->isMemAddr(pkt->getAddr())) {
195            numPackets++;
196            if (!port.sendTimingReq(pkt)) {
197                retryPkt = pkt;
198                retryPktTick = curTick();
199            }
200        } else {
201            DPRINTF(TrafficGen, "Suppressed packet %s 0x%x\n",
202                    pkt->cmdString(), pkt->getAddr());
203        }
204    }
205
206    // if we are waiting for a retry, do not schedule any further
207    // events, in the case of a transition or a successful send, go
208    // ahead and determine when the next update should take place
209    if (retryPkt == NULL) {
210        // schedule next update event based on either the next execute
211        // tick or the next transition, which ever comes first
212        nextPacketTick = states[currState]->nextPacketTick(elasticReq, 0);
213        Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
214        DPRINTF(TrafficGen, "Next event scheduled at %lld\n", nextEventTick);
215        schedule(updateEvent, nextEventTick);
216    }
217}
218
219void
220TrafficGen::parseConfig()
221{
222    // keep track of the transitions parsed to create the matrix when
223    // done
224    vector<Transition> transitions;
225
226    // open input file
227    ifstream infile;
228    infile.open(configFile.c_str(), ifstream::in);
229    if (!infile.is_open()) {
230        fatal("Traffic generator %s config file not found at %s\n",
231              name(), configFile);
232    }
233
234    bool init_state_set = false;
235
236    // read line by line and determine the action based on the first
237    // keyword
238    string keyword;
239    string line;
240
241    while (getline(infile, line).good()) {
242        // see if this line is a comment line, and if so skip it
243        if (line.find('#') != 1) {
244            // create an input stream for the tokenization
245            istringstream is(line);
246
247            // determine the keyword
248            is >> keyword;
249
250            if (keyword == "STATE") {
251                // parse the behaviour of this state
252                uint32_t id;
253                Tick duration;
254                string mode;
255
256                is >> id >> duration >> mode;
257
258                if (mode == "TRACE") {
259                    string traceFile;
260                    Addr addrOffset;
261
262                    is >> traceFile >> addrOffset;
263
264                    states[id] = new TraceGen(name(), masterID, duration,
265                                              traceFile, addrOffset);
266                    DPRINTF(TrafficGen, "State: %d TraceGen\n", id);
267                } else if (mode == "IDLE") {
268                    states[id] = new IdleGen(name(), masterID, duration);
269                    DPRINTF(TrafficGen, "State: %d IdleGen\n", id);
270                } else if (mode == "LINEAR" || mode == "RANDOM" ||
271                           mode == "DRAM") {
272                    uint32_t read_percent;
273                    Addr start_addr;
274                    Addr end_addr;
275                    Addr blocksize;
276                    Tick min_period;
277                    Tick max_period;
278                    Addr data_limit;
279
280                    is >> read_percent >> start_addr >> end_addr >>
281                        blocksize >> min_period >> max_period >> data_limit;
282
283                    DPRINTF(TrafficGen, "%s, addr %x to %x, size %d,"
284                            " period %d to %d, %d%% reads\n",
285                            mode, start_addr, end_addr, blocksize, min_period,
286                            max_period, read_percent);
287
288
289                    if (blocksize > system->cacheLineSize())
290                        fatal("TrafficGen %s block size (%d) is larger than "
291                              "cache line size (%d)\n", name(),
292                              blocksize, system->cacheLineSize());
293
294                    if (read_percent > 100)
295                        fatal("%s cannot have more than 100% reads", name());
296
297                    if (min_period > max_period)
298                        fatal("%s cannot have min_period > max_period", name());
299
300                    if (mode == "LINEAR") {
301                        states[id] = new LinearGen(name(), masterID,
302                                                   duration, start_addr,
303                                                   end_addr, blocksize,
304                                                   min_period, max_period,
305                                                   read_percent, data_limit);
306                        DPRINTF(TrafficGen, "State: %d LinearGen\n", id);
307                    } else if (mode == "RANDOM") {
308                        states[id] = new RandomGen(name(), masterID,
309                                                   duration, start_addr,
310                                                   end_addr, blocksize,
311                                                   min_period, max_period,
312                                                   read_percent, data_limit);
313                        DPRINTF(TrafficGen, "State: %d RandomGen\n", id);
314                    } else if (mode == "DRAM") {
315                        // stride size (bytes) of the request for achieving
316                        // required hit length
317                        unsigned int stride_size;
318                        unsigned int page_size;
319                        unsigned int nbr_of_banks_DRAM;
320                        unsigned int nbr_of_banks_util;
321                        unsigned int addr_mapping;
322
323                        is >> stride_size >> page_size >> nbr_of_banks_DRAM >>
324                            nbr_of_banks_util >> addr_mapping;
325
326                        if (stride_size > page_size)
327                            warn("DRAM generator stride size (%d) is greater "
328                                 "than page size (%d)  of the memory\n",
329                                 blocksize, page_size);
330
331                        if (nbr_of_banks_util > nbr_of_banks_DRAM)
332                            fatal("Attempting to use more banks (%) than "
333                                  "what is available (%)\n",
334                                  nbr_of_banks_util, nbr_of_banks_DRAM);
335
336                        if (nbr_of_banks_util > nbr_of_banks_DRAM)
337                            fatal("Attempting to use more banks (%) than "
338                                  "what is available (%)\n",
339                                  nbr_of_banks_util, nbr_of_banks_DRAM);
340
341                        // count the number of sequential packets to
342                        // generate
343                        unsigned int num_seq_pkts = 1;
344
345                        if (stride_size > blocksize) {
346                            num_seq_pkts = divCeil(stride_size, blocksize);
347                            DPRINTF(TrafficGen, "stride size: %d "
348                                    "block size: %d, num_seq_pkts: %d\n",
349                                    stride_size, blocksize, num_seq_pkts);
350                        }
351
352                        states[id] = new DramGen(name(), masterID,
353                                                 duration, start_addr,
354                                                 end_addr, blocksize,
355                                                 min_period, max_period,
356                                                 read_percent, data_limit,
357                                                 num_seq_pkts, page_size,
358                                                 nbr_of_banks_DRAM,
359                                                 nbr_of_banks_util,
360                                                 addr_mapping);
361                        DPRINTF(TrafficGen, "State: %d DramGen\n", id);
362                    }
363                } else {
364                    fatal("%s: Unknown traffic generator mode: %s",
365                          name(), mode);
366                }
367            } else if (keyword == "TRANSITION") {
368                Transition transition;
369
370                is >> transition.from >> transition.to >> transition.p;
371
372                transitions.push_back(transition);
373
374                DPRINTF(TrafficGen, "Transition: %d -> %d\n", transition.from,
375                        transition.to);
376            } else if (keyword == "INIT") {
377                // set the initial state as the active state
378                is >> currState;
379
380                init_state_set = true;
381
382                DPRINTF(TrafficGen, "Initial state: %d\n", currState);
383            }
384        }
385    }
386
387    if (!init_state_set)
388        fatal("%s: initial state not specified (add 'INIT <id>' line "
389              "to the config file)\n", name());
390
391    // resize and populate state transition matrix
392    transitionMatrix.resize(states.size());
393    for (size_t i = 0; i < states.size(); i++) {
394        transitionMatrix[i].resize(states.size());
395    }
396
397    for (vector<Transition>::iterator t = transitions.begin();
398         t != transitions.end(); ++t) {
399        transitionMatrix[t->from][t->to] = t->p;
400    }
401
402    // ensure the egress edges do not have a probability larger than
403    // one
404    for (size_t i = 0; i < states.size(); i++) {
405        double sum = 0;
406        for (size_t j = 0; j < states.size(); j++) {
407            sum += transitionMatrix[i][j];
408        }
409
410        // avoid comparing floating point numbers
411        if (abs(sum - 1.0) > 0.001)
412            fatal("%s has transition probability != 1 for state %d\n",
413                  name(), i);
414    }
415
416    // close input file
417    infile.close();
418}
419
420void
421TrafficGen::transition()
422{
423    // exit the current state
424    states[currState]->exit();
425
426    // determine next state
427    double p = random_mt.random<double>();
428    assert(currState < transitionMatrix.size());
429    double cumulative = 0.0;
430    size_t i = 0;
431    do {
432        cumulative += transitionMatrix[currState][i];
433        ++i;
434    } while (cumulative < p && i < transitionMatrix[currState].size());
435
436    enterState(i - 1);
437}
438
439void
440TrafficGen::enterState(uint32_t newState)
441{
442    DPRINTF(TrafficGen, "Transition to state %d\n", newState);
443
444    currState = newState;
445    // we could have been delayed and not transitioned on the exact
446    // tick when we were supposed to (due to back pressure when
447    // sending a packet)
448    nextTransitionTick = curTick() + states[currState]->duration;
449    states[currState]->enter();
450}
451
452void
453TrafficGen::recvRetry()
454{
455    assert(retryPkt != NULL);
456
457    DPRINTF(TrafficGen, "Received retry\n");
458    numRetries++;
459    // attempt to send the packet, and if we are successful start up
460    // the machinery again
461    if (port.sendTimingReq(retryPkt)) {
462        retryPkt = NULL;
463        // remember how much delay was incurred due to back-pressure
464        // when sending the request, we also use this to derive
465        // the tick for the next packet
466        Tick delay = curTick() - retryPktTick;
467        retryPktTick = 0;
468        retryTicks += delay;
469
470        if (drainManager == NULL) {
471            // packet is sent, so find out when the next one is due
472            nextPacketTick = states[currState]->nextPacketTick(elasticReq,
473                                                               delay);
474            Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
475            schedule(updateEvent, std::max(curTick(), nextEventTick));
476        } else {
477            // shut things down
478            nextPacketTick = MaxTick;
479            nextTransitionTick = MaxTick;
480            drainManager->signalDrainDone();
481            // Clear the drain event once we're done with it.
482            drainManager = NULL;
483        }
484    }
485}
486
487void
488TrafficGen::regStats()
489{
490    // Initialise all the stats
491    using namespace Stats;
492
493    numPackets
494        .name(name() + ".numPackets")
495        .desc("Number of packets generated");
496
497    numRetries
498        .name(name() + ".numRetries")
499        .desc("Number of retries");
500
501    retryTicks
502        .name(name() + ".retryTicks")
503        .desc("Time spent waiting due to back-pressure (ticks)");
504}
505
506bool
507TrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
508{
509    delete pkt->req;
510    delete pkt;
511
512    return true;
513}
514