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