Deleted Added
sdiff udiff text old ( 9241:6cfb9a7acb1b ) new ( 9294:8fb03b13de02 )
full compact
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(Event *drain_event);
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__