traffic_gen.hh revision 9342:6fec8f26e56d
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          public:
443
444           /**
445             * Create a trace generator.
446             *
447             * @param _port port used to send requests
448             * @param master_id MasterID set on each request
449             * @param _duration duration of this state before transitioning
450             * @param trace_file File to read the transactions from
451             * @param addr_offset Positive offset to add to trace address
452             */
453            TraceGen(QueuedMasterPort& _port, MasterID master_id,
454                     Tick _duration, const std::string& trace_file,
455                     Addr addr_offset)
456                : BaseGen(_port, master_id, _duration),
457                  traceFile(trace_file),
458                  addrOffset(addr_offset),
459                  traceComplete(false)
460            {
461                /**
462                 * Create a 4MB read buffer for the input trace
463                 * file. This is to reduce the number of disk accesses
464                 * and thereby speed up the execution of the code.
465                 */
466                readBuffer = new char[4 * 1024 * 1024];
467                trace.rdbuf()->pubsetbuf(readBuffer, 4 * 1024 * 1024);
468                trace.open(traceFile.c_str(), std::ifstream::in);
469
470                if (!trace.is_open()) {
471                    fatal("Traffic generator %s trace file could not be"
472                          " opened: %s\n", name(), traceFile);
473                }
474            }
475
476            ~TraceGen() {
477                // free the memory used by the readBuffer
478                delete[] readBuffer;
479            }
480
481            void enter();
482
483            void execute();
484
485            void exit();
486
487            /**
488             * Read a line of the trace file. Returns the raw tick
489             * when the next request should be generated. If the end
490             * of the file has been reached, it returns MaxTick to
491             * indicate that there will be no more requests.
492             */
493            Tick nextExecuteTick();
494
495          private:
496
497            /** Path to the trace file */
498            std::string traceFile;
499
500            /** Input stream used for reading the input trace file */
501            std::ifstream trace;
502
503            /** Larger buffer used for reading from the stream */
504            char* readBuffer;
505
506            /** Store the current and next element in the trace */
507            TraceElement currElement;
508            TraceElement nextElement;
509
510            /**
511             * Stores the time when the state was entered. This is to add an
512             * offset to the times stored in the trace file.
513             */
514            Tick tickOffset;
515
516            /**
517             * Offset for memory requests. Used to shift the trace
518             * away from the CPU address space.
519             */
520            Addr addrOffset;
521
522            /**
523             * Set to true when the trace replay for one instance of
524             * state is complete.
525             */
526            bool traceComplete;
527
528            /**
529             * Used to store the Tick when the next generate should
530             * occur. It is to remove a transaction as soon as we
531             * enter the state.
532             */
533            Tick oldEmitTime;
534        };
535
536        /** Pointer to owner of request handler */
537        TrafficGen& owner;
538
539        /** Pointer to request handler */
540        QueuedMasterPort& port;
541
542        /** State transition matrix */
543        std::vector<std::vector<double> > transitionMatrix;
544
545      public:
546
547        /** Index of the current state */
548        uint32_t currState;
549
550        /** Map of states */
551        m5::hash_map<uint32_t, BaseGen*> states;
552    };
553
554
555    /** Queued handler */
556    class TrafficGenPort : public QueuedMasterPort
557    {
558      public:
559
560        TrafficGenPort(const std::string& name, TrafficGen& _owner)
561            : QueuedMasterPort(name, &_owner, queue), queue(_owner, *this),
562              owner(_owner)
563        { }
564
565      protected:
566
567        bool recvTimingResp(PacketPtr pkt);
568
569      private:
570
571        MasterPacketQueue queue;
572
573        // Owner of the port
574        TrafficGen& owner;
575
576    };
577
578    TrafficGenPort port;
579
580    /** Request generator state graph */
581    StateGraph stateGraph;
582
583    /**
584     * Schedules event for next update and executes an update on the
585     * state graph.
586     */
587    void updateStateGraph();
588
589    /** Event for updating the state graph */
590    EventWrapper<TrafficGen,
591                 &TrafficGen::updateStateGraph> updateStateGraphEvent;
592
593
594  public:
595
596    TrafficGen(const TrafficGenParams* p);
597
598    ~TrafficGen() {}
599
600    virtual BaseMasterPort& getMasterPort(const std::string &if_name,
601                                          PortID idx = InvalidPortID);
602
603    void init();
604
605    void initState();
606
607    unsigned int drain(DrainManager *dm);
608
609    void serialize(std::ostream &os);
610
611    void unserialize(Checkpoint* cp, const std::string& section);
612
613};
614
615#endif //__MEM_TRAFFIC_GEN_HH__
616