traffic_gen.hh revision 9403:af9066bc088c
1/*
2 * Copyright (c) 2012 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#ifndef __MEM_TRAFFIC_GEN_HH__
42#define __MEM_TRAFFIC_GEN_HH__
43
44#include "base/hashmap.hh"
45#include "mem/mem_object.hh"
46#include "mem/qport.hh"
47#include "params/TrafficGen.hh"
48#include "proto/protoio.hh"
49
50/**
51 * The traffic generator is a master module that generates stimuli for
52 * the memory system, based on a collection of simple behaviours that
53 * are either probabilistic or based on traces. It can be used stand
54 * alone for creating test cases for interconnect and memory
55 * controllers, or function as a black box replacement for system
56 * components that are not yet modelled in detail, e.g. a video engine
57 * or baseband subsystem.
58 */
59class TrafficGen : public MemObject
60{
61
62  private:
63
64    /**
65     * The system used to determine which mode we are currently operating
66     * in.
67     */
68    System* system;
69
70    /**
71     * MasterID used in generated requests.
72     */
73    MasterID masterID;
74
75  protected:
76
77    /**
78     * The state graph is responsible for instantiating and keeping
79     * track of the various generator states and also perform the
80     * transitions and call the appropriate functions when entering,
81     * executing and exiting a state.
82     */
83    class StateGraph
84    {
85
86      public:
87
88        /**
89         * Create a state graph from an input file.
90         *
91         * @param _owner used solely for the name
92         * @param _port port used to send requests
93         * @param file_name configuration description to read in
94         * @param master_id the unique id used for all requests
95         */
96        StateGraph(TrafficGen& _owner, QueuedMasterPort& _port,
97                   const std::string& file_name, MasterID master_id)
98            : nextTransitionTick(0), owner(_owner), port(_port)
99        {
100            parseConfig(file_name, master_id);
101        }
102
103        /**
104         * Get the name, used for DPRINTFs.
105         *
106         * @return the owner's name
107         */
108        std::string name() const { return owner.name(); }
109
110        /**
111         * Either perform a state transition or execute the current
112         * state, depending on the current time.
113         */
114        void update();
115
116        /**
117         * Determine next state and perform the transition.
118         */
119        void transition();
120
121        /**
122         * Enter a new state.
123         *
124         * @param newState identifier of state to enter
125         */
126        void enterState(uint32_t newState);
127
128        /**
129         * Get the tick of the next event, either an execution or a
130         * transition.
131         *
132         * @return tick of the next state graph event
133         */
134        Tick nextEventTick()
135        {
136            return std::min(states[currState]->nextExecuteTick(),
137                            nextTransitionTick);
138
139        }
140
141        /** Time of next transition */
142        Tick nextTransitionTick;
143
144      private:
145
146        /**
147         * Parse the config file and build the state map and
148         * transition matrix.
149         *
150         * @param file_name Config file name to parse
151         * @param master_id MasterID to use for generated requests
152         */
153        void parseConfig(const std::string& file_name, MasterID master_id);
154
155        /** Struct to represent a probabilistic transition during parsing. */
156        struct Transition {
157            uint32_t from;
158            uint32_t to;
159            double p;
160        };
161
162        /** Base class for all generator states */
163        class BaseGen
164        {
165
166          protected:
167
168            /** Port used to send requests */
169            QueuedMasterPort& port;
170
171            /** The MasterID used for generating requests */
172            const MasterID masterID;
173
174            /**
175             * Create a new request and associated packet and schedule
176             * it to be sent in the current tick.
177             *
178             * @param addr Physical address to use
179             * @param size Size of the request
180             * @param cmd Memory command to send
181             */
182            void send(Addr addr, unsigned size, const MemCmd& cmd);
183
184          public:
185
186            /** Time to spend in this state */
187            const Tick duration;
188
189            /**
190             * Create a base generator.
191             *
192             * @param _port port used to send requests
193             * @param master_id MasterID set on each request
194             * @param _duration duration of this state before transitioning
195             */
196            BaseGen(QueuedMasterPort& _port, MasterID master_id,
197                    Tick _duration);
198
199            virtual ~BaseGen() { }
200
201            /**
202             * Get the name, useful for DPRINTFs.
203             *
204             * @return the port name
205             */
206            std::string name() const { return port.name(); }
207
208            /**
209             * Enter this generator state.
210             */
211            virtual void enter() = 0;
212
213            /**
214             * Execute this generator state.
215             */
216            virtual void execute() = 0;
217
218            /**
219             * Exit this generator state. By default do nothing.
220             */
221            virtual void exit() { };
222
223            /**
224             * Determine the next execute tick. MaxTick means that
225             * there will not be any further event in the current
226             * activation cycle of the state.
227             *
228             * @return next tick when the state should be executed
229             */
230            virtual Tick nextExecuteTick() = 0;
231
232        };
233
234        /**
235         * The idle generator does nothing.
236         */
237        class IdleGen : public BaseGen
238        {
239
240          public:
241
242            IdleGen(QueuedMasterPort& _port, MasterID master_id,
243                    Tick _duration)
244                : BaseGen(_port, master_id, _duration)
245            { }
246
247            void enter() { }
248
249            void execute() { }
250
251            Tick nextExecuteTick() { return MaxTick; }
252        };
253
254        /**
255         * The linear generator generates sequential requests from a
256         * start to an end address, with a fixed block size. A
257         * fraction of the requests are reads, as determined by the
258         * read percent. There is an optional data limit for when to
259         * stop generating new requests.
260         */
261        class LinearGen : public BaseGen
262        {
263
264          public:
265
266            /**
267             * Create a linear address sequence generator. Set
268             * min_period == max_period for a fixed inter-transaction
269             * time.
270             *
271             * @param _port port used to send requests
272             * @param master_id MasterID set on each request
273             * @param _duration duration of this state before transitioning
274             * @param start_addr Start address
275             * @param end_addr End address
276             * @param _blocksize Size used for transactions injected
277             * @param min_period Lower limit of random inter-transaction time
278             * @param max_period Upper limit of random inter-transaction time
279             * @param read_percent Percent of transactions that are reads
280             * @param data_limit Upper limit on how much data to read/write
281             */
282            LinearGen(QueuedMasterPort& _port, MasterID master_id,
283                      Tick _duration, Addr start_addr, Addr end_addr,
284                      Addr _blocksize, Tick min_period, Tick max_period,
285                      uint8_t read_percent, Addr data_limit)
286                : BaseGen(_port, master_id, _duration),
287                  startAddr(start_addr), endAddr(end_addr),
288                  blocksize(_blocksize), minPeriod(min_period),
289                  maxPeriod(max_period), readPercent(read_percent),
290                  dataLimit(data_limit)
291            { }
292
293            void enter();
294
295            void execute();
296
297            Tick nextExecuteTick();
298
299          private:
300
301            /** Start of address range */
302            const Addr startAddr;
303
304            /** End of address range */
305            const Addr endAddr;
306
307            /** Blocksize and address increment */
308            const Addr blocksize;
309
310            /** Request generation period */
311            const Tick minPeriod;
312            const Tick maxPeriod;
313
314            /**
315             * Percent of generated transactions that should be reads
316             */
317            const uint8_t readPercent;
318
319            /** Maximum amount of data to manipulate */
320            const Addr dataLimit;
321
322            /** Address of next request */
323            Addr nextAddr;
324
325            /**
326             * Counter to determine the amount of data
327             * manipulated. Used to determine if we should continue
328             * generating requests.
329             */
330            Addr dataManipulated;
331        };
332
333        /**
334         * The random generator is similar to the linear one, but does
335         * not generate sequential addresses. Instead it randomly
336         * picks an address in the range, aligned to the block size.
337         */
338        class RandomGen : public BaseGen
339        {
340
341          public:
342
343            /**
344             * Create a random address sequence generator. Set
345             * min_period == max_period for a fixed inter-transaction
346             * time.
347             *
348             * @param _port port used to send requests
349             * @param master_id MasterID set on each request
350             * @param _duration duration of this state before transitioning
351             * @param start_addr Start address
352             * @param end_addr End address
353             * @param _blocksize Size used for transactions injected
354             * @param min_period Lower limit of random inter-transaction time
355             * @param max_period Upper limit of random inter-transaction time
356             * @param read_percent Percent of transactions that are reads
357             * @param data_limit Upper limit on how much data to read/write
358             */
359            RandomGen(QueuedMasterPort& _port, MasterID master_id,
360                      Tick _duration, Addr start_addr, Addr end_addr,
361                      Addr _blocksize, Tick min_period, Tick max_period,
362                      uint8_t read_percent, Addr data_limit)
363                : BaseGen(_port, master_id, _duration),
364                  startAddr(start_addr), endAddr(end_addr),
365                  blocksize(_blocksize), minPeriod(min_period),
366                  maxPeriod(max_period), readPercent(read_percent),
367                  dataLimit(data_limit)
368            { }
369
370            void enter();
371
372            void execute();
373
374            Tick nextExecuteTick();
375
376          private:
377
378            /** Start of address range */
379            const Addr startAddr;
380
381            /** End of address range */
382            const Addr endAddr;
383
384            /** Block size */
385            const Addr blocksize;
386
387            /** Request generation period */
388            const Tick minPeriod;
389            const Tick maxPeriod;
390
391            /**
392             * Percent of generated transactions that should be reads
393             */
394            const uint8_t readPercent;
395
396            /** Maximum amount of data to manipulate */
397            const Addr dataLimit;
398
399            /**
400             * Counter to determine the amount of data
401             * manipulated. Used to determine if we should continue
402             * generating requests.
403             */
404            Addr dataManipulated;
405        };
406
407        /**
408         * The trace replay generator reads a trace file and plays
409         * back the transactions. The trace is offset with respect to
410         * the time when the state was entered.
411         */
412        class TraceGen : public BaseGen
413        {
414
415          private:
416
417            /**
418             * This struct stores a line in the trace file.
419             */
420            struct TraceElement {
421
422                /** Specifies if the request is to be a read or a write */
423                MemCmd cmd;
424
425                /** The address for the request */
426                Addr addr;
427
428                /** The size of the access for the request */
429                Addr blocksize;
430
431                /** The time at which the request should be sent */
432                Tick tick;
433
434                /**
435                 * Check validity of this element.
436                 *
437                 * @return if this element is valid
438                 */
439                bool isValid() const {
440                    return cmd != MemCmd::InvalidCmd;
441                }
442
443                /**
444                 * Make this element invalid.
445                 */
446                void clear() {
447                    cmd = MemCmd::InvalidCmd;
448                }
449            };
450
451            /**
452             * The InputStream encapsulates a trace file and the
453             * internal buffers and populates TraceElements based on
454             * the input.
455             */
456            class InputStream
457            {
458
459              private:
460
461                /// Input file stream for the protobuf trace
462                ProtoInputStream trace;
463
464              public:
465
466                /**
467                 * Create a trace input stream for a given file name.
468                 *
469                 * @param filename Path to the file to read from
470                 */
471                InputStream(const std::string& filename);
472
473                /**
474                 * Reset the stream such that it can be played once
475                 * again.
476                 */
477                void reset();
478
479                /**
480                 * Attempt to read a trace element from the stream,
481                 * and also notify the caller if the end of the file
482                 * was reached.
483                 *
484                 * @param element Trace element to populate
485                 * @return True if an element could be read successfully
486                 */
487                bool read(TraceElement& element);
488            };
489
490          public:
491
492           /**
493             * Create a trace generator.
494             *
495             * @param _port port used to send requests
496             * @param master_id MasterID set on each request
497             * @param _duration duration of this state before transitioning
498             * @param trace_file File to read the transactions from
499             * @param addr_offset Positive offset to add to trace address
500             */
501            TraceGen(QueuedMasterPort& _port, MasterID master_id,
502                     Tick _duration, const std::string& trace_file,
503                     Addr addr_offset)
504                : BaseGen(_port, master_id, _duration),
505                  trace(trace_file),
506                  addrOffset(addr_offset),
507                  traceComplete(false)
508            {
509            }
510
511            void enter();
512
513            void execute();
514
515            void exit();
516
517            /**
518             * Read a line of the trace file. Returns the raw tick
519             * when the next request should be generated. If the end
520             * of the file has been reached, it returns MaxTick to
521             * indicate that there will be no more requests.
522             */
523            Tick nextExecuteTick();
524
525          private:
526
527            /** Input stream used for reading the input trace file */
528            InputStream trace;
529
530            /** Store the current and next element in the trace */
531            TraceElement currElement;
532            TraceElement nextElement;
533
534            /**
535             * Stores the time when the state was entered. This is to add an
536             * offset to the times stored in the trace file.
537             */
538            Tick tickOffset;
539
540            /**
541             * Offset for memory requests. Used to shift the trace
542             * away from the CPU address space.
543             */
544            Addr addrOffset;
545
546            /**
547             * Set to true when the trace replay for one instance of
548             * state is complete.
549             */
550            bool traceComplete;
551
552            /**
553             * Used to store the Tick when the next generate should
554             * occur. It is to remove a transaction as soon as we
555             * enter the state.
556             */
557            Tick oldEmitTime;
558        };
559
560        /** Pointer to owner of request handler */
561        TrafficGen& owner;
562
563        /** Pointer to request handler */
564        QueuedMasterPort& port;
565
566        /** State transition matrix */
567        std::vector<std::vector<double> > transitionMatrix;
568
569      public:
570
571        /** Index of the current state */
572        uint32_t currState;
573
574        /** Map of states */
575        m5::hash_map<uint32_t, BaseGen*> states;
576    };
577
578
579    /** Queued handler */
580    class TrafficGenPort : public QueuedMasterPort
581    {
582      public:
583
584        TrafficGenPort(const std::string& name, TrafficGen& _owner)
585            : QueuedMasterPort(name, &_owner, queue), queue(_owner, *this),
586              owner(_owner)
587        { }
588
589      protected:
590
591        bool recvTimingResp(PacketPtr pkt);
592
593      private:
594
595        MasterPacketQueue queue;
596
597        // Owner of the port
598        TrafficGen& owner;
599
600    };
601
602    TrafficGenPort port;
603
604    /** Request generator state graph */
605    StateGraph stateGraph;
606
607    /**
608     * Schedules event for next update and executes an update on the
609     * state graph.
610     */
611    void updateStateGraph();
612
613    /** Event for updating the state graph */
614    EventWrapper<TrafficGen,
615                 &TrafficGen::updateStateGraph> updateStateGraphEvent;
616
617
618  public:
619
620    TrafficGen(const TrafficGenParams* p);
621
622    ~TrafficGen() {}
623
624    virtual BaseMasterPort& getMasterPort(const std::string &if_name,
625                                          PortID idx = InvalidPortID);
626
627    void init();
628
629    void initState();
630
631    unsigned int drain(DrainManager *dm);
632
633    void serialize(std::ostream &os);
634
635    void unserialize(Checkpoint* cp, const std::string& section);
636
637};
638
639#endif //__MEM_TRAFFIC_GEN_HH__
640