base.cc revision 12810
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 "cpu/testers/traffic_gen/base_gen.hh"
48#include "debug/Checkpoint.hh"
49#include "debug/TrafficGen.hh"
50#include "params/BaseTrafficGen.hh"
51#include "sim/sim_exit.hh"
52#include "sim/stats.hh"
53#include "sim/system.hh"
54
55using namespace std;
56
57BaseTrafficGen::BaseTrafficGen(const BaseTrafficGenParams* p)
58    : MemObject(p),
59      system(p->system),
60      elasticReq(p->elastic_req),
61      progressCheck(p->progress_check),
62      noProgressEvent([this]{ noProgress(); }, name()),
63      nextTransitionTick(0),
64      nextPacketTick(0),
65      port(name() + ".port", *this),
66      retryPkt(NULL),
67      retryPktTick(0),
68      updateEvent([this]{ update(); }, name()),
69      numSuppressed(0),
70      masterID(system->getMasterId(this))
71{
72}
73
74BaseMasterPort&
75BaseTrafficGen::getMasterPort(const string& if_name, PortID idx)
76{
77    if (if_name == "port") {
78        return port;
79    } else {
80        return MemObject::getMasterPort(if_name, idx);
81    }
82}
83
84void
85BaseTrafficGen::init()
86{
87    MemObject::init();
88
89    if (!port.isConnected())
90        fatal("The port of %s is not connected!\n", name());
91}
92
93DrainState
94BaseTrafficGen::drain()
95{
96    if (!updateEvent.scheduled()) {
97        // no event has been scheduled yet (e.g. switched from atomic mode)
98        return DrainState::Drained;
99    }
100
101    if (retryPkt == NULL) {
102        // shut things down
103        nextPacketTick = MaxTick;
104        nextTransitionTick = MaxTick;
105        deschedule(updateEvent);
106        return DrainState::Drained;
107    } else {
108        return DrainState::Draining;
109    }
110}
111
112void
113BaseTrafficGen::serialize(CheckpointOut &cp) const
114{
115    DPRINTF(Checkpoint, "Serializing BaseTrafficGen\n");
116
117    // save ticks of the graph event if it is scheduled
118    Tick nextEvent = updateEvent.scheduled() ? updateEvent.when() : 0;
119
120    DPRINTF(TrafficGen, "Saving nextEvent=%llu\n", nextEvent);
121
122    SERIALIZE_SCALAR(nextEvent);
123
124    SERIALIZE_SCALAR(nextTransitionTick);
125
126    SERIALIZE_SCALAR(nextPacketTick);
127}
128
129void
130BaseTrafficGen::unserialize(CheckpointIn &cp)
131{
132    // restore scheduled events
133    Tick nextEvent;
134    UNSERIALIZE_SCALAR(nextEvent);
135    if (nextEvent != 0)
136        schedule(updateEvent, nextEvent);
137
138    UNSERIALIZE_SCALAR(nextTransitionTick);
139
140    UNSERIALIZE_SCALAR(nextPacketTick);
141}
142
143void
144BaseTrafficGen::update()
145{
146    // shift our progress-tracking event forward
147    reschedule(noProgressEvent, curTick() + progressCheck, true);
148
149    // if we have reached the time for the next state transition, then
150    // perform the transition
151    if (curTick() >= nextTransitionTick) {
152        transition();
153    } else {
154        assert(curTick() >= nextPacketTick);
155        // get the next packet and try to send it
156        PacketPtr pkt = activeGenerator->getNextPacket();
157
158        // suppress packets that are not destined for a memory, such as
159        // device accesses that could be part of a trace
160        if (system->isMemAddr(pkt->getAddr())) {
161            numPackets++;
162            if (!port.sendTimingReq(pkt)) {
163                retryPkt = pkt;
164                retryPktTick = curTick();
165            }
166        } else {
167            DPRINTF(TrafficGen, "Suppressed packet %s 0x%x\n",
168                    pkt->cmdString(), pkt->getAddr());
169
170            ++numSuppressed;
171            if (numSuppressed % 10000)
172                warn("%s suppressed %d packets with non-memory addresses\n",
173                     name(), numSuppressed);
174
175            delete pkt;
176            pkt = nullptr;
177        }
178    }
179
180    // if we are waiting for a retry, do not schedule any further
181    // events, in the case of a transition or a successful send, go
182    // ahead and determine when the next update should take place
183    if (retryPkt == NULL) {
184        nextPacketTick = activeGenerator->nextPacketTick(elasticReq, 0);
185        scheduleUpdate();
186    }
187}
188
189void
190BaseTrafficGen::transition()
191{
192    if (activeGenerator)
193        activeGenerator->exit();
194
195    activeGenerator = nextGenerator();
196
197    if (activeGenerator) {
198        const Tick duration = activeGenerator->duration;
199        if (duration != MaxTick && duration != 0) {
200            // we could have been delayed and not transitioned on the
201            // exact tick when we were supposed to (due to back
202            // pressure when sending a packet)
203            nextTransitionTick = curTick() + duration;
204        } else {
205            nextTransitionTick = MaxTick;
206        }
207
208        activeGenerator->enter();
209        nextPacketTick = activeGenerator->nextPacketTick(elasticReq, 0);
210    } else {
211        nextPacketTick = MaxTick;
212        nextTransitionTick = MaxTick;
213        assert(!updateEvent.scheduled());
214    }
215}
216
217void
218BaseTrafficGen::scheduleUpdate()
219{
220    // schedule next update event based on either the next execute
221    // tick or the next transition, which ever comes first
222    const Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
223    if (nextEventTick == MaxTick)
224        return;
225
226    DPRINTF(TrafficGen, "Next event scheduled at %lld\n", nextEventTick);
227
228    // The next transition tick may be in the past if there was a
229    // retry, so ensure that we don't schedule anything in the past.
230    schedule(updateEvent, std::max(curTick(), nextEventTick));
231}
232
233void
234BaseTrafficGen::start()
235{
236    transition();
237    scheduleUpdate();
238}
239
240void
241BaseTrafficGen::recvReqRetry()
242{
243    assert(retryPkt != NULL);
244
245    DPRINTF(TrafficGen, "Received retry\n");
246    numRetries++;
247    // attempt to send the packet, and if we are successful start up
248    // the machinery again
249    if (port.sendTimingReq(retryPkt)) {
250        retryPkt = NULL;
251        // remember how much delay was incurred due to back-pressure
252        // when sending the request, we also use this to derive
253        // the tick for the next packet
254        Tick delay = curTick() - retryPktTick;
255        retryPktTick = 0;
256        retryTicks += delay;
257
258        if (drainState() != DrainState::Draining) {
259            // packet is sent, so find out when the next one is due
260            nextPacketTick = activeGenerator->nextPacketTick(elasticReq,
261                                                             delay);
262            scheduleUpdate();
263        } else {
264            // shut things down
265            nextPacketTick = MaxTick;
266            nextTransitionTick = MaxTick;
267            signalDrainDone();
268        }
269    }
270}
271
272void
273BaseTrafficGen::noProgress()
274{
275    fatal("BaseTrafficGen %s spent %llu ticks without making progress",
276          name(), progressCheck);
277}
278
279void
280BaseTrafficGen::regStats()
281{
282    ClockedObject::regStats();
283
284    // Initialise all the stats
285    using namespace Stats;
286
287    numPackets
288        .name(name() + ".numPackets")
289        .desc("Number of packets generated");
290
291    numRetries
292        .name(name() + ".numRetries")
293        .desc("Number of retries");
294
295    retryTicks
296        .name(name() + ".retryTicks")
297        .desc("Time spent waiting due to back-pressure (ticks)");
298}
299
300bool
301BaseTrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
302{
303    delete pkt;
304
305    return true;
306}
307