base.cc revision 13784:1941dc118243
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/base.hh"
42
43#include <sstream>
44
45#include "base/intmath.hh"
46#include "base/random.hh"
47#include "config/have_protobuf.hh"
48#include "cpu/testers/traffic_gen/base_gen.hh"
49#include "cpu/testers/traffic_gen/dram_gen.hh"
50#include "cpu/testers/traffic_gen/dram_rot_gen.hh"
51#include "cpu/testers/traffic_gen/exit_gen.hh"
52#include "cpu/testers/traffic_gen/idle_gen.hh"
53#include "cpu/testers/traffic_gen/linear_gen.hh"
54#include "cpu/testers/traffic_gen/random_gen.hh"
55#include "cpu/testers/traffic_gen/stream_gen.hh"
56#include "debug/Checkpoint.hh"
57#include "debug/TrafficGen.hh"
58#include "params/BaseTrafficGen.hh"
59#include "sim/sim_exit.hh"
60#include "sim/stats.hh"
61#include "sim/system.hh"
62
63#if HAVE_PROTOBUF
64#include "cpu/testers/traffic_gen/trace_gen.hh"
65#endif
66
67
68using namespace std;
69
70BaseTrafficGen::BaseTrafficGen(const BaseTrafficGenParams* p)
71    : MemObject(p),
72      system(p->system),
73      elasticReq(p->elastic_req),
74      progressCheck(p->progress_check),
75      noProgressEvent([this]{ noProgress(); }, name()),
76      nextTransitionTick(0),
77      nextPacketTick(0),
78      port(name() + ".port", *this),
79      retryPkt(NULL),
80      retryPktTick(0),
81      updateEvent([this]{ update(); }, name()),
82      masterID(system->getMasterId(this)),
83      streamGenerator(StreamGen::create(p))
84{
85}
86
87BaseTrafficGen::~BaseTrafficGen()
88{
89}
90
91Port &
92BaseTrafficGen::getPort(const string &if_name, PortID idx)
93{
94    if (if_name == "port") {
95        return port;
96    } else {
97        return MemObject::getPort(if_name, idx);
98    }
99}
100
101void
102BaseTrafficGen::init()
103{
104    MemObject::init();
105
106    if (!port.isConnected())
107        fatal("The port of %s is not connected!\n", name());
108}
109
110DrainState
111BaseTrafficGen::drain()
112{
113    if (!updateEvent.scheduled()) {
114        // no event has been scheduled yet (e.g. switched from atomic mode)
115        return DrainState::Drained;
116    }
117
118    if (retryPkt == NULL) {
119        // shut things down
120        nextPacketTick = MaxTick;
121        nextTransitionTick = MaxTick;
122        deschedule(updateEvent);
123        return DrainState::Drained;
124    } else {
125        return DrainState::Draining;
126    }
127}
128
129void
130BaseTrafficGen::serialize(CheckpointOut &cp) const
131{
132    warn("%s serialization does not keep all traffic generator"
133         " internal state\n", name());
134
135    DPRINTF(Checkpoint, "Serializing BaseTrafficGen\n");
136
137    // save ticks of the graph event if it is scheduled
138    Tick nextEvent = updateEvent.scheduled() ? updateEvent.when() : 0;
139
140    DPRINTF(TrafficGen, "Saving nextEvent=%llu\n", nextEvent);
141
142    SERIALIZE_SCALAR(nextEvent);
143
144    SERIALIZE_SCALAR(nextTransitionTick);
145
146    SERIALIZE_SCALAR(nextPacketTick);
147}
148
149void
150BaseTrafficGen::unserialize(CheckpointIn &cp)
151{
152    warn("%s serialization does not restore all traffic generator"
153         " internal state\n", name());
154
155    // restore scheduled events
156    Tick nextEvent;
157    UNSERIALIZE_SCALAR(nextEvent);
158    if (nextEvent != 0)
159        schedule(updateEvent, nextEvent);
160
161    UNSERIALIZE_SCALAR(nextTransitionTick);
162
163    UNSERIALIZE_SCALAR(nextPacketTick);
164}
165
166void
167BaseTrafficGen::update()
168{
169    // shift our progress-tracking event forward
170    reschedule(noProgressEvent, curTick() + progressCheck, true);
171
172    // if we have reached the time for the next state transition, then
173    // perform the transition
174    if (curTick() >= nextTransitionTick) {
175        transition();
176    } else {
177        assert(curTick() >= nextPacketTick);
178        // get the next packet and try to send it
179        PacketPtr pkt = activeGenerator->getNextPacket();
180
181        // If generating stream/substream IDs are enabled,
182        // try to pick and assign them to the new packet
183        if (streamGenerator) {
184            auto sid = streamGenerator->pickStreamID();
185            auto ssid = streamGenerator->pickSubStreamID();
186
187            pkt->req->setStreamId(sid);
188
189            if (streamGenerator->ssidValid()) {
190                pkt->req->setSubStreamId(ssid);
191            }
192        }
193
194        // suppress packets that are not destined for a memory, such as
195        // device accesses that could be part of a trace
196        if (pkt && system->isMemAddr(pkt->getAddr())) {
197            numPackets++;
198            if (!port.sendTimingReq(pkt)) {
199                retryPkt = pkt;
200                retryPktTick = curTick();
201            }
202        } else if (pkt) {
203            DPRINTF(TrafficGen, "Suppressed packet %s 0x%x\n",
204                    pkt->cmdString(), pkt->getAddr());
205
206            ++numSuppressed;
207            if (!(static_cast<int>(numSuppressed.value()) % 10000))
208                warn("%s suppressed %d packets with non-memory addresses\n",
209                     name(), numSuppressed.value());
210
211            delete pkt;
212            pkt = nullptr;
213        }
214    }
215
216    // if we are waiting for a retry, do not schedule any further
217    // events, in the case of a transition or a successful send, go
218    // ahead and determine when the next update should take place
219    if (retryPkt == NULL) {
220        nextPacketTick = activeGenerator->nextPacketTick(elasticReq, 0);
221        scheduleUpdate();
222    }
223}
224
225void
226BaseTrafficGen::transition()
227{
228    if (activeGenerator)
229        activeGenerator->exit();
230
231    activeGenerator = nextGenerator();
232
233    if (activeGenerator) {
234        const Tick duration = activeGenerator->duration;
235        if (duration != MaxTick && duration != 0) {
236            // we could have been delayed and not transitioned on the
237            // exact tick when we were supposed to (due to back
238            // pressure when sending a packet)
239            nextTransitionTick = curTick() + duration;
240        } else {
241            nextTransitionTick = MaxTick;
242        }
243
244        activeGenerator->enter();
245        nextPacketTick = activeGenerator->nextPacketTick(elasticReq, 0);
246    } else {
247        nextPacketTick = MaxTick;
248        nextTransitionTick = MaxTick;
249        assert(!updateEvent.scheduled());
250    }
251}
252
253void
254BaseTrafficGen::scheduleUpdate()
255{
256    // Has the generator run out of work? In that case, force a
257    // transition if a transition period hasn't been configured.
258    while (activeGenerator &&
259           nextPacketTick == MaxTick && nextTransitionTick == MaxTick) {
260        transition();
261    }
262
263    if (!activeGenerator)
264        return;
265
266    // schedule next update event based on either the next execute
267    // tick or the next transition, which ever comes first
268    const Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
269
270    DPRINTF(TrafficGen, "Next event scheduled at %lld\n", nextEventTick);
271
272    // The next transition tick may be in the past if there was a
273    // retry, so ensure that we don't schedule anything in the past.
274    schedule(updateEvent, std::max(curTick(), nextEventTick));
275}
276
277void
278BaseTrafficGen::start()
279{
280    transition();
281    scheduleUpdate();
282}
283
284void
285BaseTrafficGen::recvReqRetry()
286{
287    assert(retryPkt != NULL);
288
289    DPRINTF(TrafficGen, "Received retry\n");
290    numRetries++;
291    // attempt to send the packet, and if we are successful start up
292    // the machinery again
293    if (port.sendTimingReq(retryPkt)) {
294        retryPkt = NULL;
295        // remember how much delay was incurred due to back-pressure
296        // when sending the request, we also use this to derive
297        // the tick for the next packet
298        Tick delay = curTick() - retryPktTick;
299        retryPktTick = 0;
300        retryTicks += delay;
301
302        if (drainState() != DrainState::Draining) {
303            // packet is sent, so find out when the next one is due
304            nextPacketTick = activeGenerator->nextPacketTick(elasticReq,
305                                                             delay);
306            scheduleUpdate();
307        } else {
308            // shut things down
309            nextPacketTick = MaxTick;
310            nextTransitionTick = MaxTick;
311            signalDrainDone();
312        }
313    }
314}
315
316void
317BaseTrafficGen::noProgress()
318{
319    fatal("BaseTrafficGen %s spent %llu ticks without making progress",
320          name(), progressCheck);
321}
322
323void
324BaseTrafficGen::regStats()
325{
326    ClockedObject::regStats();
327
328    // Initialise all the stats
329    using namespace Stats;
330
331    numPackets
332        .name(name() + ".numPackets")
333        .desc("Number of packets generated");
334
335    numSuppressed
336        .name(name() + ".numSuppressed")
337        .desc("Number of suppressed packets to non-memory space");
338
339    numRetries
340        .name(name() + ".numRetries")
341        .desc("Number of retries");
342
343    retryTicks
344        .name(name() + ".retryTicks")
345        .desc("Time spent waiting due to back-pressure (ticks)");
346}
347
348std::shared_ptr<BaseGen>
349BaseTrafficGen::createIdle(Tick duration)
350{
351    return std::shared_ptr<BaseGen>(new IdleGen(*this, masterID, duration));
352}
353
354std::shared_ptr<BaseGen>
355BaseTrafficGen::createExit(Tick duration)
356{
357    return std::shared_ptr<BaseGen>(new ExitGen(*this, masterID, duration));
358}
359
360std::shared_ptr<BaseGen>
361BaseTrafficGen::createLinear(Tick duration,
362                             Addr start_addr, Addr end_addr, Addr blocksize,
363                             Tick min_period, Tick max_period,
364                             uint8_t read_percent, Addr data_limit)
365{
366    return std::shared_ptr<BaseGen>(new LinearGen(*this, masterID,
367                                                  duration, start_addr,
368                                                  end_addr, blocksize,
369                                                  system->cacheLineSize(),
370                                                  min_period, max_period,
371                                                  read_percent, data_limit));
372}
373
374std::shared_ptr<BaseGen>
375BaseTrafficGen::createRandom(Tick duration,
376                             Addr start_addr, Addr end_addr, Addr blocksize,
377                             Tick min_period, Tick max_period,
378                             uint8_t read_percent, Addr data_limit)
379{
380    return std::shared_ptr<BaseGen>(new RandomGen(*this, masterID,
381                                                  duration, start_addr,
382                                                  end_addr, blocksize,
383                                                  system->cacheLineSize(),
384                                                  min_period, max_period,
385                                                  read_percent, data_limit));
386}
387
388std::shared_ptr<BaseGen>
389BaseTrafficGen::createDram(Tick duration,
390                           Addr start_addr, Addr end_addr, Addr blocksize,
391                           Tick min_period, Tick max_period,
392                           uint8_t read_percent, Addr data_limit,
393                           unsigned int num_seq_pkts, unsigned int page_size,
394                           unsigned int nbr_of_banks_DRAM,
395                           unsigned int nbr_of_banks_util,
396                           unsigned int addr_mapping,
397                           unsigned int nbr_of_ranks)
398{
399    return std::shared_ptr<BaseGen>(new DramGen(*this, masterID,
400                                                duration, start_addr,
401                                                end_addr, blocksize,
402                                                system->cacheLineSize(),
403                                                min_period, max_period,
404                                                read_percent, data_limit,
405                                                num_seq_pkts, page_size,
406                                                nbr_of_banks_DRAM,
407                                                nbr_of_banks_util,
408                                                addr_mapping,
409                                                nbr_of_ranks));
410}
411
412std::shared_ptr<BaseGen>
413BaseTrafficGen::createDramRot(Tick duration,
414                              Addr start_addr, Addr end_addr, Addr blocksize,
415                              Tick min_period, Tick max_period,
416                              uint8_t read_percent, Addr data_limit,
417                              unsigned int num_seq_pkts,
418                              unsigned int page_size,
419                              unsigned int nbr_of_banks_DRAM,
420                              unsigned int nbr_of_banks_util,
421                              unsigned int addr_mapping,
422                              unsigned int nbr_of_ranks,
423                              unsigned int max_seq_count_per_rank)
424{
425    return std::shared_ptr<BaseGen>(new DramRotGen(*this, masterID,
426                                                   duration, start_addr,
427                                                   end_addr, blocksize,
428                                                   system->cacheLineSize(),
429                                                   min_period, max_period,
430                                                   read_percent, data_limit,
431                                                   num_seq_pkts, page_size,
432                                                   nbr_of_banks_DRAM,
433                                                   nbr_of_banks_util,
434                                                   addr_mapping,
435                                                   nbr_of_ranks,
436                                                   max_seq_count_per_rank));
437}
438
439std::shared_ptr<BaseGen>
440BaseTrafficGen::createTrace(Tick duration,
441                            const std::string& trace_file, Addr addr_offset)
442{
443#if HAVE_PROTOBUF
444    return std::shared_ptr<BaseGen>(
445        new TraceGen(*this, masterID, duration, trace_file, addr_offset));
446#else
447    panic("Can't instantiate trace generation without Protobuf support!\n");
448#endif
449}
450
451bool
452BaseTrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
453{
454    delete pkt;
455
456    return true;
457}
458