base.cc revision 12811:269967d5b4e4
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      numSuppressed(0),
82      masterID(system->getMasterId(this))
83{
84}
85
86BaseMasterPort&
87BaseTrafficGen::getMasterPort(const string& if_name, PortID idx)
88{
89    if (if_name == "port") {
90        return port;
91    } else {
92        return MemObject::getMasterPort(if_name, idx);
93    }
94}
95
96void
97BaseTrafficGen::init()
98{
99    MemObject::init();
100
101    if (!port.isConnected())
102        fatal("The port of %s is not connected!\n", name());
103}
104
105DrainState
106BaseTrafficGen::drain()
107{
108    if (!updateEvent.scheduled()) {
109        // no event has been scheduled yet (e.g. switched from atomic mode)
110        return DrainState::Drained;
111    }
112
113    if (retryPkt == NULL) {
114        // shut things down
115        nextPacketTick = MaxTick;
116        nextTransitionTick = MaxTick;
117        deschedule(updateEvent);
118        return DrainState::Drained;
119    } else {
120        return DrainState::Draining;
121    }
122}
123
124void
125BaseTrafficGen::serialize(CheckpointOut &cp) const
126{
127    DPRINTF(Checkpoint, "Serializing BaseTrafficGen\n");
128
129    // save ticks of the graph event if it is scheduled
130    Tick nextEvent = updateEvent.scheduled() ? updateEvent.when() : 0;
131
132    DPRINTF(TrafficGen, "Saving nextEvent=%llu\n", nextEvent);
133
134    SERIALIZE_SCALAR(nextEvent);
135
136    SERIALIZE_SCALAR(nextTransitionTick);
137
138    SERIALIZE_SCALAR(nextPacketTick);
139}
140
141void
142BaseTrafficGen::unserialize(CheckpointIn &cp)
143{
144    // restore scheduled events
145    Tick nextEvent;
146    UNSERIALIZE_SCALAR(nextEvent);
147    if (nextEvent != 0)
148        schedule(updateEvent, nextEvent);
149
150    UNSERIALIZE_SCALAR(nextTransitionTick);
151
152    UNSERIALIZE_SCALAR(nextPacketTick);
153}
154
155void
156BaseTrafficGen::update()
157{
158    // shift our progress-tracking event forward
159    reschedule(noProgressEvent, curTick() + progressCheck, true);
160
161    // if we have reached the time for the next state transition, then
162    // perform the transition
163    if (curTick() >= nextTransitionTick) {
164        transition();
165    } else {
166        assert(curTick() >= nextPacketTick);
167        // get the next packet and try to send it
168        PacketPtr pkt = activeGenerator->getNextPacket();
169
170        // suppress packets that are not destined for a memory, such as
171        // device accesses that could be part of a trace
172        if (system->isMemAddr(pkt->getAddr())) {
173            numPackets++;
174            if (!port.sendTimingReq(pkt)) {
175                retryPkt = pkt;
176                retryPktTick = curTick();
177            }
178        } else {
179            DPRINTF(TrafficGen, "Suppressed packet %s 0x%x\n",
180                    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    // schedule next update event based on either the next execute
233    // tick or the next transition, which ever comes first
234    const Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
235    if (nextEventTick == MaxTick)
236        return;
237
238    DPRINTF(TrafficGen, "Next event scheduled at %lld\n", nextEventTick);
239
240    // The next transition tick may be in the past if there was a
241    // retry, so ensure that we don't schedule anything in the past.
242    schedule(updateEvent, std::max(curTick(), nextEventTick));
243}
244
245void
246BaseTrafficGen::start()
247{
248    transition();
249    scheduleUpdate();
250}
251
252void
253BaseTrafficGen::recvReqRetry()
254{
255    assert(retryPkt != NULL);
256
257    DPRINTF(TrafficGen, "Received retry\n");
258    numRetries++;
259    // attempt to send the packet, and if we are successful start up
260    // the machinery again
261    if (port.sendTimingReq(retryPkt)) {
262        retryPkt = NULL;
263        // remember how much delay was incurred due to back-pressure
264        // when sending the request, we also use this to derive
265        // the tick for the next packet
266        Tick delay = curTick() - retryPktTick;
267        retryPktTick = 0;
268        retryTicks += delay;
269
270        if (drainState() != DrainState::Draining) {
271            // packet is sent, so find out when the next one is due
272            nextPacketTick = activeGenerator->nextPacketTick(elasticReq,
273                                                             delay);
274            scheduleUpdate();
275        } else {
276            // shut things down
277            nextPacketTick = MaxTick;
278            nextTransitionTick = MaxTick;
279            signalDrainDone();
280        }
281    }
282}
283
284void
285BaseTrafficGen::noProgress()
286{
287    fatal("BaseTrafficGen %s spent %llu ticks without making progress",
288          name(), progressCheck);
289}
290
291void
292BaseTrafficGen::regStats()
293{
294    ClockedObject::regStats();
295
296    // Initialise all the stats
297    using namespace Stats;
298
299    numPackets
300        .name(name() + ".numPackets")
301        .desc("Number of packets generated");
302
303    numRetries
304        .name(name() + ".numRetries")
305        .desc("Number of retries");
306
307    retryTicks
308        .name(name() + ".retryTicks")
309        .desc("Time spent waiting due to back-pressure (ticks)");
310}
311
312std::shared_ptr<BaseGen>
313BaseTrafficGen::createIdle(Tick duration)
314{
315    return std::shared_ptr<BaseGen>(new IdleGen(*this, duration));
316}
317
318std::shared_ptr<BaseGen>
319BaseTrafficGen::createExit(Tick duration)
320{
321    return std::shared_ptr<BaseGen>(new ExitGen(*this, duration));
322}
323
324std::shared_ptr<BaseGen>
325BaseTrafficGen::createLinear(Tick duration,
326                             Addr start_addr, Addr end_addr, Addr blocksize,
327                             Tick min_period, Tick max_period,
328                             uint8_t read_percent, Addr data_limit)
329{
330    return std::shared_ptr<BaseGen>(new LinearGen(*this,
331                                                  duration, start_addr,
332                                                  end_addr, blocksize,
333                                                  min_period, max_period,
334                                                  read_percent, data_limit));
335}
336
337std::shared_ptr<BaseGen>
338BaseTrafficGen::createRandom(Tick duration,
339                             Addr start_addr, Addr end_addr, Addr blocksize,
340                             Tick min_period, Tick max_period,
341                             uint8_t read_percent, Addr data_limit)
342{
343    return std::shared_ptr<BaseGen>(new RandomGen(*this,
344                                                  duration, start_addr,
345                                                  end_addr, blocksize,
346                                                  min_period, max_period,
347                                                  read_percent, data_limit));
348}
349
350std::shared_ptr<BaseGen>
351BaseTrafficGen::createDram(Tick duration,
352                           Addr start_addr, Addr end_addr, Addr blocksize,
353                           Tick min_period, Tick max_period,
354                           uint8_t read_percent, Addr data_limit,
355                           unsigned int num_seq_pkts, unsigned int page_size,
356                           unsigned int nbr_of_banks_DRAM,
357                           unsigned int nbr_of_banks_util,
358                           unsigned int addr_mapping,
359                           unsigned int nbr_of_ranks)
360{
361    return std::shared_ptr<BaseGen>(new DramGen(*this,
362                                                duration, start_addr,
363                                                end_addr, blocksize,
364                                                min_period, max_period,
365                                                read_percent, data_limit,
366                                                num_seq_pkts, page_size,
367                                                nbr_of_banks_DRAM,
368                                                nbr_of_banks_util,
369                                                addr_mapping,
370                                                nbr_of_ranks));
371}
372
373std::shared_ptr<BaseGen>
374BaseTrafficGen::createDramRot(Tick duration,
375                              Addr start_addr, Addr end_addr, Addr blocksize,
376                              Tick min_period, Tick max_period,
377                              uint8_t read_percent, Addr data_limit,
378                              unsigned int num_seq_pkts,
379                              unsigned int page_size,
380                              unsigned int nbr_of_banks_DRAM,
381                              unsigned int nbr_of_banks_util,
382                              unsigned int addr_mapping,
383                              unsigned int nbr_of_ranks,
384                              unsigned int max_seq_count_per_rank)
385{
386    return std::shared_ptr<BaseGen>(new DramRotGen(*this,
387                                                   duration, start_addr,
388                                                   end_addr, blocksize,
389                                                   min_period, max_period,
390                                                   read_percent, data_limit,
391                                                   num_seq_pkts, page_size,
392                                                   nbr_of_banks_DRAM,
393                                                   nbr_of_banks_util,
394                                                   addr_mapping,
395                                                   nbr_of_ranks,
396                                                   max_seq_count_per_rank));
397}
398
399std::shared_ptr<BaseGen>
400BaseTrafficGen::createTrace(Tick duration,
401                            const std::string& trace_file, Addr addr_offset)
402{
403#if HAVE_PROTOBUF
404    return std::shared_ptr<BaseGen>(
405        new TraceGen(*this, duration, trace_file, addr_offset));
406#else
407    panic("Can't instantiate trace generation without Protobuf support!\n");
408#endif
409}
410
411bool
412BaseTrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
413{
414    delete pkt;
415
416    return true;
417}
418