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