base.cc revision 12812:8f14879aebe1
18999Suri.wiener@arm.com/*
28999Suri.wiener@arm.com * Copyright (c) 2012-2013, 2016-2018 ARM Limited
38999Suri.wiener@arm.com * All rights reserved
48999Suri.wiener@arm.com *
58999Suri.wiener@arm.com * The license below extends only to copyright in the software and shall
68999Suri.wiener@arm.com * not be construed as granting a license to any other intellectual
78999Suri.wiener@arm.com * property including but not limited to intellectual property relating
88999Suri.wiener@arm.com * to a hardware implementation of the functionality of the software
98999Suri.wiener@arm.com * licensed hereunder.  You may use the software subject to the license
108999Suri.wiener@arm.com * terms below provided that you ensure that this notice is replicated
118999Suri.wiener@arm.com * unmodified and in its entirety in all distributions of the software,
128999Suri.wiener@arm.com * modified or unmodified, in source code or in binary form.
138999Suri.wiener@arm.com *
148999Suri.wiener@arm.com * Redistribution and use in source and binary forms, with or without
158999Suri.wiener@arm.com * modification, are permitted provided that the following conditions are
168999Suri.wiener@arm.com * met: redistributions of source code must retain the above copyright
178999Suri.wiener@arm.com * notice, this list of conditions and the following disclaimer;
188999Suri.wiener@arm.com * redistributions in binary form must reproduce the above copyright
198999Suri.wiener@arm.com * notice, this list of conditions and the following disclaimer in the
208999Suri.wiener@arm.com * documentation and/or other materials provided with the distribution;
218999Suri.wiener@arm.com * neither the name of the copyright holders nor the names of its
228999Suri.wiener@arm.com * contributors may be used to endorse or promote products derived from
238999Suri.wiener@arm.com * this software without specific prior written permission.
248999Suri.wiener@arm.com *
258999Suri.wiener@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
268999Suri.wiener@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
278999Suri.wiener@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
288999Suri.wiener@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
298999Suri.wiener@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
308999Suri.wiener@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
318999Suri.wiener@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
328999Suri.wiener@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
338999Suri.wiener@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
348999Suri.wiener@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
358999Suri.wiener@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
368999Suri.wiener@arm.com *
378999Suri.wiener@arm.com * Authors: Thomas Grass
388999Suri.wiener@arm.com *          Andreas Hansson
398999Suri.wiener@arm.com *          Sascha Bischoff
408999Suri.wiener@arm.com */
418999Suri.wiener@arm.com#include "cpu/testers/traffic_gen/base.hh"
428999Suri.wiener@arm.com
438999Suri.wiener@arm.com#include <sstream>
448999Suri.wiener@arm.com
458999Suri.wiener@arm.com#include "base/intmath.hh"
468999Suri.wiener@arm.com#include "base/random.hh"
478999Suri.wiener@arm.com#include "config/have_protobuf.hh"
488999Suri.wiener@arm.com#include "cpu/testers/traffic_gen/base_gen.hh"
498999Suri.wiener@arm.com#include "cpu/testers/traffic_gen/dram_gen.hh"
508999Suri.wiener@arm.com#include "cpu/testers/traffic_gen/dram_rot_gen.hh"
518999Suri.wiener@arm.com#include "cpu/testers/traffic_gen/exit_gen.hh"
528999Suri.wiener@arm.com#include "cpu/testers/traffic_gen/idle_gen.hh"
538999Suri.wiener@arm.com#include "cpu/testers/traffic_gen/linear_gen.hh"
548999Suri.wiener@arm.com#include "cpu/testers/traffic_gen/random_gen.hh"
558999Suri.wiener@arm.com#include "debug/Checkpoint.hh"
568999Suri.wiener@arm.com#include "debug/TrafficGen.hh"
578999Suri.wiener@arm.com#include "params/BaseTrafficGen.hh"
588999Suri.wiener@arm.com#include "sim/sim_exit.hh"
598999Suri.wiener@arm.com#include "sim/stats.hh"
609528Ssascha.bischoff@arm.com#include "sim/system.hh"
618999Suri.wiener@arm.com
628999Suri.wiener@arm.com#if HAVE_PROTOBUF
638999Suri.wiener@arm.com#include "cpu/testers/traffic_gen/trace_gen.hh"
648999Suri.wiener@arm.com#endif
658999Suri.wiener@arm.com
668999Suri.wiener@arm.com
678999Suri.wiener@arm.comusing namespace std;
688999Suri.wiener@arm.com
698999Suri.wiener@arm.comBaseTrafficGen::BaseTrafficGen(const BaseTrafficGenParams* p)
708999Suri.wiener@arm.com    : MemObject(p),
718999Suri.wiener@arm.com      system(p->system),
728999Suri.wiener@arm.com      elasticReq(p->elastic_req),
738999Suri.wiener@arm.com      progressCheck(p->progress_check),
748999Suri.wiener@arm.com      noProgressEvent([this]{ noProgress(); }, name()),
758999Suri.wiener@arm.com      nextTransitionTick(0),
768999Suri.wiener@arm.com      nextPacketTick(0),
778999Suri.wiener@arm.com      port(name() + ".port", *this),
788999Suri.wiener@arm.com      retryPkt(NULL),
798999Suri.wiener@arm.com      retryPktTick(0),
808999Suri.wiener@arm.com      updateEvent([this]{ update(); }, name()),
818999Suri.wiener@arm.com      numSuppressed(0),
828999Suri.wiener@arm.com      masterID(system->getMasterId(this))
838999Suri.wiener@arm.com{
848999Suri.wiener@arm.com}
858999Suri.wiener@arm.com
868999Suri.wiener@arm.comBaseMasterPort&
878999Suri.wiener@arm.comBaseTrafficGen::getMasterPort(const string& if_name, PortID idx)
888999Suri.wiener@arm.com{
898999Suri.wiener@arm.com    if (if_name == "port") {
908999Suri.wiener@arm.com        return port;
918999Suri.wiener@arm.com    } else {
928999Suri.wiener@arm.com        return MemObject::getMasterPort(if_name, idx);
938999Suri.wiener@arm.com    }
948999Suri.wiener@arm.com}
958999Suri.wiener@arm.com
968999Suri.wiener@arm.comvoid
978999Suri.wiener@arm.comBaseTrafficGen::init()
988999Suri.wiener@arm.com{
998999Suri.wiener@arm.com    MemObject::init();
1008999Suri.wiener@arm.com
1018999Suri.wiener@arm.com    if (!port.isConnected())
1028999Suri.wiener@arm.com        fatal("The port of %s is not connected!\n", name());
1038999Suri.wiener@arm.com}
1048999Suri.wiener@arm.com
1058999Suri.wiener@arm.comDrainState
1068999Suri.wiener@arm.comBaseTrafficGen::drain()
1078999Suri.wiener@arm.com{
1088999Suri.wiener@arm.com    if (!updateEvent.scheduled()) {
1098999Suri.wiener@arm.com        // no event has been scheduled yet (e.g. switched from atomic mode)
1108999Suri.wiener@arm.com        return DrainState::Drained;
1118999Suri.wiener@arm.com    }
1128999Suri.wiener@arm.com
1138999Suri.wiener@arm.com    if (retryPkt == NULL) {
1148999Suri.wiener@arm.com        // shut things down
1158999Suri.wiener@arm.com        nextPacketTick = MaxTick;
1168999Suri.wiener@arm.com        nextTransitionTick = MaxTick;
1178999Suri.wiener@arm.com        deschedule(updateEvent);
1188999Suri.wiener@arm.com        return DrainState::Drained;
1198999Suri.wiener@arm.com    } else {
1208999Suri.wiener@arm.com        return DrainState::Draining;
1218999Suri.wiener@arm.com    }
1228999Suri.wiener@arm.com}
1238999Suri.wiener@arm.com
1248999Suri.wiener@arm.comvoid
1258999Suri.wiener@arm.comBaseTrafficGen::serialize(CheckpointOut &cp) const
1268999Suri.wiener@arm.com{
1278999Suri.wiener@arm.com    DPRINTF(Checkpoint, "Serializing BaseTrafficGen\n");
1288999Suri.wiener@arm.com
1298999Suri.wiener@arm.com    // save ticks of the graph event if it is scheduled
1308999Suri.wiener@arm.com    Tick nextEvent = updateEvent.scheduled() ? updateEvent.when() : 0;
1318999Suri.wiener@arm.com
1328999Suri.wiener@arm.com    DPRINTF(TrafficGen, "Saving nextEvent=%llu\n", nextEvent);
1338999Suri.wiener@arm.com
1348999Suri.wiener@arm.com    SERIALIZE_SCALAR(nextEvent);
1358999Suri.wiener@arm.com
1368999Suri.wiener@arm.com    SERIALIZE_SCALAR(nextTransitionTick);
1378999Suri.wiener@arm.com
1388999Suri.wiener@arm.com    SERIALIZE_SCALAR(nextPacketTick);
1398999Suri.wiener@arm.com}
1408999Suri.wiener@arm.com
1418999Suri.wiener@arm.comvoid
1428999Suri.wiener@arm.comBaseTrafficGen::unserialize(CheckpointIn &cp)
1438999Suri.wiener@arm.com{
1448999Suri.wiener@arm.com    // restore scheduled events
1458999Suri.wiener@arm.com    Tick nextEvent;
1468999Suri.wiener@arm.com    UNSERIALIZE_SCALAR(nextEvent);
1478999Suri.wiener@arm.com    if (nextEvent != 0)
1488999Suri.wiener@arm.com        schedule(updateEvent, nextEvent);
1498999Suri.wiener@arm.com
1508999Suri.wiener@arm.com    UNSERIALIZE_SCALAR(nextTransitionTick);
1518999Suri.wiener@arm.com
1528999Suri.wiener@arm.com    UNSERIALIZE_SCALAR(nextPacketTick);
1538999Suri.wiener@arm.com}
1548999Suri.wiener@arm.com
1558999Suri.wiener@arm.comvoid
1568999Suri.wiener@arm.comBaseTrafficGen::update()
1578999Suri.wiener@arm.com{
1588999Suri.wiener@arm.com    // shift our progress-tracking event forward
1598999Suri.wiener@arm.com    reschedule(noProgressEvent, curTick() + progressCheck, true);
1608999Suri.wiener@arm.com
1618999Suri.wiener@arm.com    // if we have reached the time for the next state transition, then
1628999Suri.wiener@arm.com    // perform the transition
1638999Suri.wiener@arm.com    if (curTick() >= nextTransitionTick) {
1648999Suri.wiener@arm.com        transition();
1658999Suri.wiener@arm.com    } else {
1668999Suri.wiener@arm.com        assert(curTick() >= nextPacketTick);
1678999Suri.wiener@arm.com        // get the next packet and try to send it
1688999Suri.wiener@arm.com        PacketPtr pkt = activeGenerator->getNextPacket();
1698999Suri.wiener@arm.com
1708999Suri.wiener@arm.com        // suppress packets that are not destined for a memory, such as
1718999Suri.wiener@arm.com        // device accesses that could be part of a trace
1728999Suri.wiener@arm.com        if (pkt && system->isMemAddr(pkt->getAddr())) {
1738999Suri.wiener@arm.com            numPackets++;
1748999Suri.wiener@arm.com            if (!port.sendTimingReq(pkt)) {
1758999Suri.wiener@arm.com                retryPkt = pkt;
1768999Suri.wiener@arm.com                retryPktTick = curTick();
1778999Suri.wiener@arm.com            }
1788999Suri.wiener@arm.com        } else if (pkt) {
1798999Suri.wiener@arm.com            DPRINTF(TrafficGen, "Suppressed packet %s 0x%x\n",
1809528Ssascha.bischoff@arm.com                    pkt->cmdString(), pkt->getAddr());
181
182            ++numSuppressed;
183            if (numSuppressed % 10000)
184                warn("%s suppressed %d packets with non-memory addresses\n",
185                     name(), numSuppressed);
186
187            delete pkt;
188            pkt = nullptr;
189        }
190    }
191
192    // if we are waiting for a retry, do not schedule any further
193    // events, in the case of a transition or a successful send, go
194    // ahead and determine when the next update should take place
195    if (retryPkt == NULL) {
196        nextPacketTick = activeGenerator->nextPacketTick(elasticReq, 0);
197        scheduleUpdate();
198    }
199}
200
201void
202BaseTrafficGen::transition()
203{
204    if (activeGenerator)
205        activeGenerator->exit();
206
207    activeGenerator = nextGenerator();
208
209    if (activeGenerator) {
210        const Tick duration = activeGenerator->duration;
211        if (duration != MaxTick && duration != 0) {
212            // we could have been delayed and not transitioned on the
213            // exact tick when we were supposed to (due to back
214            // pressure when sending a packet)
215            nextTransitionTick = curTick() + duration;
216        } else {
217            nextTransitionTick = MaxTick;
218        }
219
220        activeGenerator->enter();
221        nextPacketTick = activeGenerator->nextPacketTick(elasticReq, 0);
222    } else {
223        nextPacketTick = MaxTick;
224        nextTransitionTick = MaxTick;
225        assert(!updateEvent.scheduled());
226    }
227}
228
229void
230BaseTrafficGen::scheduleUpdate()
231{
232    // Has the generator run out of work? In that case, force a
233    // transition if a transition period hasn't been configured.
234    while (activeGenerator &&
235           nextPacketTick == MaxTick && nextTransitionTick == MaxTick) {
236        transition();
237    }
238
239    if (!activeGenerator)
240        return;
241
242    // schedule next update event based on either the next execute
243    // tick or the next transition, which ever comes first
244    const Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
245
246    DPRINTF(TrafficGen, "Next event scheduled at %lld\n", nextEventTick);
247
248    // The next transition tick may be in the past if there was a
249    // retry, so ensure that we don't schedule anything in the past.
250    schedule(updateEvent, std::max(curTick(), nextEventTick));
251}
252
253void
254BaseTrafficGen::start()
255{
256    transition();
257    scheduleUpdate();
258}
259
260void
261BaseTrafficGen::recvReqRetry()
262{
263    assert(retryPkt != NULL);
264
265    DPRINTF(TrafficGen, "Received retry\n");
266    numRetries++;
267    // attempt to send the packet, and if we are successful start up
268    // the machinery again
269    if (port.sendTimingReq(retryPkt)) {
270        retryPkt = NULL;
271        // remember how much delay was incurred due to back-pressure
272        // when sending the request, we also use this to derive
273        // the tick for the next packet
274        Tick delay = curTick() - retryPktTick;
275        retryPktTick = 0;
276        retryTicks += delay;
277
278        if (drainState() != DrainState::Draining) {
279            // packet is sent, so find out when the next one is due
280            nextPacketTick = activeGenerator->nextPacketTick(elasticReq,
281                                                             delay);
282            scheduleUpdate();
283        } else {
284            // shut things down
285            nextPacketTick = MaxTick;
286            nextTransitionTick = MaxTick;
287            signalDrainDone();
288        }
289    }
290}
291
292void
293BaseTrafficGen::noProgress()
294{
295    fatal("BaseTrafficGen %s spent %llu ticks without making progress",
296          name(), progressCheck);
297}
298
299void
300BaseTrafficGen::regStats()
301{
302    ClockedObject::regStats();
303
304    // Initialise all the stats
305    using namespace Stats;
306
307    numPackets
308        .name(name() + ".numPackets")
309        .desc("Number of packets generated");
310
311    numRetries
312        .name(name() + ".numRetries")
313        .desc("Number of retries");
314
315    retryTicks
316        .name(name() + ".retryTicks")
317        .desc("Time spent waiting due to back-pressure (ticks)");
318}
319
320std::shared_ptr<BaseGen>
321BaseTrafficGen::createIdle(Tick duration)
322{
323    return std::shared_ptr<BaseGen>(new IdleGen(*this, duration));
324}
325
326std::shared_ptr<BaseGen>
327BaseTrafficGen::createExit(Tick duration)
328{
329    return std::shared_ptr<BaseGen>(new ExitGen(*this, duration));
330}
331
332std::shared_ptr<BaseGen>
333BaseTrafficGen::createLinear(Tick duration,
334                             Addr start_addr, Addr end_addr, Addr blocksize,
335                             Tick min_period, Tick max_period,
336                             uint8_t read_percent, Addr data_limit)
337{
338    return std::shared_ptr<BaseGen>(new LinearGen(*this,
339                                                  duration, start_addr,
340                                                  end_addr, blocksize,
341                                                  min_period, max_period,
342                                                  read_percent, data_limit));
343}
344
345std::shared_ptr<BaseGen>
346BaseTrafficGen::createRandom(Tick duration,
347                             Addr start_addr, Addr end_addr, Addr blocksize,
348                             Tick min_period, Tick max_period,
349                             uint8_t read_percent, Addr data_limit)
350{
351    return std::shared_ptr<BaseGen>(new RandomGen(*this,
352                                                  duration, start_addr,
353                                                  end_addr, blocksize,
354                                                  min_period, max_period,
355                                                  read_percent, data_limit));
356}
357
358std::shared_ptr<BaseGen>
359BaseTrafficGen::createDram(Tick duration,
360                           Addr start_addr, Addr end_addr, Addr blocksize,
361                           Tick min_period, Tick max_period,
362                           uint8_t read_percent, Addr data_limit,
363                           unsigned int num_seq_pkts, unsigned int page_size,
364                           unsigned int nbr_of_banks_DRAM,
365                           unsigned int nbr_of_banks_util,
366                           unsigned int addr_mapping,
367                           unsigned int nbr_of_ranks)
368{
369    return std::shared_ptr<BaseGen>(new DramGen(*this,
370                                                duration, start_addr,
371                                                end_addr, blocksize,
372                                                min_period, max_period,
373                                                read_percent, data_limit,
374                                                num_seq_pkts, page_size,
375                                                nbr_of_banks_DRAM,
376                                                nbr_of_banks_util,
377                                                addr_mapping,
378                                                nbr_of_ranks));
379}
380
381std::shared_ptr<BaseGen>
382BaseTrafficGen::createDramRot(Tick duration,
383                              Addr start_addr, Addr end_addr, Addr blocksize,
384                              Tick min_period, Tick max_period,
385                              uint8_t read_percent, Addr data_limit,
386                              unsigned int num_seq_pkts,
387                              unsigned int page_size,
388                              unsigned int nbr_of_banks_DRAM,
389                              unsigned int nbr_of_banks_util,
390                              unsigned int addr_mapping,
391                              unsigned int nbr_of_ranks,
392                              unsigned int max_seq_count_per_rank)
393{
394    return std::shared_ptr<BaseGen>(new DramRotGen(*this,
395                                                   duration, start_addr,
396                                                   end_addr, blocksize,
397                                                   min_period, max_period,
398                                                   read_percent, data_limit,
399                                                   num_seq_pkts, page_size,
400                                                   nbr_of_banks_DRAM,
401                                                   nbr_of_banks_util,
402                                                   addr_mapping,
403                                                   nbr_of_ranks,
404                                                   max_seq_count_per_rank));
405}
406
407std::shared_ptr<BaseGen>
408BaseTrafficGen::createTrace(Tick duration,
409                            const std::string& trace_file, Addr addr_offset)
410{
411#if HAVE_PROTOBUF
412    return std::shared_ptr<BaseGen>(
413        new TraceGen(*this, duration, trace_file, addr_offset));
414#else
415    panic("Can't instantiate trace generation without Protobuf support!\n");
416#endif
417}
418
419bool
420BaseTrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
421{
422    delete pkt;
423
424    return true;
425}
426