traffic_gen.hh revision 9402:f6e3c60f04e5
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          public:
175
176            /** Time to spend in this state */
177            const Tick duration;
178
179            /**
180             * Create a base generator.
181             *
182             * @param _port port used to send requests
183             * @param master_id MasterID set on each request
184             * @param _duration duration of this state before transitioning
185             */
186            BaseGen(QueuedMasterPort& _port, MasterID master_id,
187                    Tick _duration);
188
189            virtual ~BaseGen() { }
190
191            /**
192             * Get the name, useful for DPRINTFs.
193             *
194             * @return the port name
195             */
196            std::string name() const { return port.name(); }
197
198            /**
199             * Enter this generator state.
200             */
201            virtual void enter() = 0;
202
203            /**
204             * Execute this generator state.
205             */
206            virtual void execute() = 0;
207
208            /**
209             * Exit this generator state. By default do nothing.
210             */
211            virtual void exit() { };
212
213            /**
214             * Determine the next execute tick. MaxTick means that
215             * there will not be any further event in the current
216             * activation cycle of the state.
217             *
218             * @return next tick when the state should be executed
219             */
220            virtual Tick nextExecuteTick() = 0;
221
222        };
223
224        /**
225         * The idle generator does nothing.
226         */
227        class IdleGen : public BaseGen
228        {
229
230          public:
231
232            IdleGen(QueuedMasterPort& _port, MasterID master_id,
233                    Tick _duration)
234                : BaseGen(_port, master_id, _duration)
235            { }
236
237            void enter() { }
238
239            void execute() { }
240
241            Tick nextExecuteTick() { return MaxTick; }
242        };
243
244        /**
245         * The linear generator generates sequential requests from a
246         * start to an end address, with a fixed block size. A
247         * fraction of the requests are reads, as determined by the
248         * read percent. There is an optional data limit for when to
249         * stop generating new requests.
250         */
251        class LinearGen : public BaseGen
252        {
253
254          public:
255
256            /**
257             * Create a linear address sequence generator. Set
258             * min_period == max_period for a fixed inter-transaction
259             * time.
260             *
261             * @param _port port used to send requests
262             * @param master_id MasterID set on each request
263             * @param _duration duration of this state before transitioning
264             * @param start_addr Start address
265             * @param end_addr End address
266             * @param _blocksize Size used for transactions injected
267             * @param min_period Lower limit of random inter-transaction time
268             * @param max_period Upper limit of random inter-transaction time
269             * @param read_percent Percent of transactions that are reads
270             * @param data_limit Upper limit on how much data to read/write
271             */
272            LinearGen(QueuedMasterPort& _port, MasterID master_id,
273                      Tick _duration, Addr start_addr, Addr end_addr,
274                      Addr _blocksize, Tick min_period, Tick max_period,
275                      uint8_t read_percent, Addr data_limit)
276                : BaseGen(_port, master_id, _duration),
277                  startAddr(start_addr), endAddr(end_addr),
278                  blocksize(_blocksize), minPeriod(min_period),
279                  maxPeriod(max_period), readPercent(read_percent),
280                  dataLimit(data_limit)
281            { }
282
283            void enter();
284
285            void execute();
286
287            Tick nextExecuteTick();
288
289          private:
290
291            /** Start of address range */
292            const Addr startAddr;
293
294            /** End of address range */
295            const Addr endAddr;
296
297            /** Blocksize and address increment */
298            const Addr blocksize;
299
300            /** Request generation period */
301            const Tick minPeriod;
302            const Tick maxPeriod;
303
304            /**
305             * Percent of generated transactions that should be reads
306             */
307            const uint8_t readPercent;
308
309            /** Maximum amount of data to manipulate */
310            const Addr dataLimit;
311
312            /** Address of next request */
313            Addr nextAddr;
314
315            /**
316             * Counter to determine the amount of data
317             * manipulated. Used to determine if we should continue
318             * generating requests.
319             */
320            Addr dataManipulated;
321        };
322
323        /**
324         * The random generator is similar to the linear one, but does
325         * not generate sequential addresses. Instead it randomly
326         * picks an address in the range, aligned to the block size.
327         */
328        class RandomGen : public BaseGen
329        {
330
331          public:
332
333            /**
334             * Create a random address sequence generator. Set
335             * min_period == max_period for a fixed inter-transaction
336             * time.
337             *
338             * @param _port port used to send requests
339             * @param master_id MasterID set on each request
340             * @param _duration duration of this state before transitioning
341             * @param start_addr Start address
342             * @param end_addr End address
343             * @param _blocksize Size used for transactions injected
344             * @param min_period Lower limit of random inter-transaction time
345             * @param max_period Upper limit of random inter-transaction time
346             * @param read_percent Percent of transactions that are reads
347             * @param data_limit Upper limit on how much data to read/write
348             */
349            RandomGen(QueuedMasterPort& _port, MasterID master_id,
350                      Tick _duration, Addr start_addr, Addr end_addr,
351                      Addr _blocksize, Tick min_period, Tick max_period,
352                      uint8_t read_percent, Addr data_limit)
353                : BaseGen(_port, master_id, _duration),
354                  startAddr(start_addr), endAddr(end_addr),
355                  blocksize(_blocksize), minPeriod(min_period),
356                  maxPeriod(max_period), readPercent(read_percent),
357                  dataLimit(data_limit)
358            { }
359
360            void enter();
361
362            void execute();
363
364            Tick nextExecuteTick();
365
366          private:
367
368            /** Start of address range */
369            const Addr startAddr;
370
371            /** End of address range */
372            const Addr endAddr;
373
374            /** Block size */
375            const Addr blocksize;
376
377            /** Request generation period */
378            const Tick minPeriod;
379            const Tick maxPeriod;
380
381            /**
382             * Percent of generated transactions that should be reads
383             */
384            const uint8_t readPercent;
385
386            /** Maximum amount of data to manipulate */
387            const Addr dataLimit;
388
389            /**
390             * Counter to determine the amount of data
391             * manipulated. Used to determine if we should continue
392             * generating requests.
393             */
394            Addr dataManipulated;
395        };
396
397        /**
398         * The trace replay generator reads a trace file and plays
399         * back the transactions. The trace is offset with respect to
400         * the time when the state was entered.
401         */
402        class TraceGen : public BaseGen
403        {
404
405          private:
406
407            /**
408             * This struct stores a line in the trace file.
409             */
410            struct TraceElement {
411
412                /** Specifies if the request is to be a read or a write */
413                MemCmd cmd;
414
415                /** The address for the request */
416                Addr addr;
417
418                /** The size of the access for the request */
419                Addr blocksize;
420
421                /** The time at which the request should be sent */
422                Tick tick;
423
424                /**
425                 * Check validity of this element.
426                 *
427                 * @return if this element is valid
428                 */
429                bool isValid() const {
430                    return cmd != MemCmd::InvalidCmd;
431                }
432
433                /**
434                 * Make this element invalid.
435                 */
436                void clear() {
437                    cmd = MemCmd::InvalidCmd;
438                }
439            };
440
441            /**
442             * The InputStream encapsulates a trace file and the
443             * internal buffers and populates TraceElements based on
444             * the input.
445             */
446            class InputStream
447            {
448
449              private:
450
451                /// Input file stream for the protobuf trace
452                ProtoInputStream trace;
453
454              public:
455
456                /**
457                 * Create a trace input stream for a given file name.
458                 *
459                 * @param filename Path to the file to read from
460                 */
461                InputStream(const std::string& filename);
462
463                /**
464                 * Reset the stream such that it can be played once
465                 * again.
466                 */
467                void reset();
468
469                /**
470                 * Attempt to read a trace element from the stream,
471                 * and also notify the caller if the end of the file
472                 * was reached.
473                 *
474                 * @param element Trace element to populate
475                 * @return True if an element could be read successfully
476                 */
477                bool read(TraceElement& element);
478            };
479
480          public:
481
482           /**
483             * Create a trace generator.
484             *
485             * @param _port port used to send requests
486             * @param master_id MasterID set on each request
487             * @param _duration duration of this state before transitioning
488             * @param trace_file File to read the transactions from
489             * @param addr_offset Positive offset to add to trace address
490             */
491            TraceGen(QueuedMasterPort& _port, MasterID master_id,
492                     Tick _duration, const std::string& trace_file,
493                     Addr addr_offset)
494                : BaseGen(_port, master_id, _duration),
495                  trace(trace_file),
496                  addrOffset(addr_offset),
497                  traceComplete(false)
498            {
499            }
500
501            void enter();
502
503            void execute();
504
505            void exit();
506
507            /**
508             * Read a line of the trace file. Returns the raw tick
509             * when the next request should be generated. If the end
510             * of the file has been reached, it returns MaxTick to
511             * indicate that there will be no more requests.
512             */
513            Tick nextExecuteTick();
514
515          private:
516
517            /** Input stream used for reading the input trace file */
518            InputStream trace;
519
520            /** Store the current and next element in the trace */
521            TraceElement currElement;
522            TraceElement nextElement;
523
524            /**
525             * Stores the time when the state was entered. This is to add an
526             * offset to the times stored in the trace file.
527             */
528            Tick tickOffset;
529
530            /**
531             * Offset for memory requests. Used to shift the trace
532             * away from the CPU address space.
533             */
534            Addr addrOffset;
535
536            /**
537             * Set to true when the trace replay for one instance of
538             * state is complete.
539             */
540            bool traceComplete;
541
542            /**
543             * Used to store the Tick when the next generate should
544             * occur. It is to remove a transaction as soon as we
545             * enter the state.
546             */
547            Tick oldEmitTime;
548        };
549
550        /** Pointer to owner of request handler */
551        TrafficGen& owner;
552
553        /** Pointer to request handler */
554        QueuedMasterPort& port;
555
556        /** State transition matrix */
557        std::vector<std::vector<double> > transitionMatrix;
558
559      public:
560
561        /** Index of the current state */
562        uint32_t currState;
563
564        /** Map of states */
565        m5::hash_map<uint32_t, BaseGen*> states;
566    };
567
568
569    /** Queued handler */
570    class TrafficGenPort : public QueuedMasterPort
571    {
572      public:
573
574        TrafficGenPort(const std::string& name, TrafficGen& _owner)
575            : QueuedMasterPort(name, &_owner, queue), queue(_owner, *this),
576              owner(_owner)
577        { }
578
579      protected:
580
581        bool recvTimingResp(PacketPtr pkt);
582
583      private:
584
585        MasterPacketQueue queue;
586
587        // Owner of the port
588        TrafficGen& owner;
589
590    };
591
592    TrafficGenPort port;
593
594    /** Request generator state graph */
595    StateGraph stateGraph;
596
597    /**
598     * Schedules event for next update and executes an update on the
599     * state graph.
600     */
601    void updateStateGraph();
602
603    /** Event for updating the state graph */
604    EventWrapper<TrafficGen,
605                 &TrafficGen::updateStateGraph> updateStateGraphEvent;
606
607
608  public:
609
610    TrafficGen(const TrafficGenParams* p);
611
612    ~TrafficGen() {}
613
614    virtual BaseMasterPort& getMasterPort(const std::string &if_name,
615                                          PortID idx = InvalidPortID);
616
617    void init();
618
619    void initState();
620
621    unsigned int drain(DrainManager *dm);
622
623    void serialize(std::ostream &os);
624
625    void unserialize(Checkpoint* cp, const std::string& section);
626
627};
628
629#endif //__MEM_TRAFFIC_GEN_HH__
630