3 * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met: redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer;
10 * redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution;
13 * neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * Description: See System.hh
40 #include "mem/ruby/system/System.hh"
41 #include "mem/ruby/common/Address.hh"
42 #include "mem/ruby/profiler/Profiler.hh"
43 #include "mem/ruby/network/Network.hh"
44 #include "mem/ruby/recorder/Tracer.hh"
45 #include "mem/protocol/Protocol.hh"
46 #include "mem/ruby/buffers/MessageBuffer.hh"
47 #include "mem/ruby/system/Sequencer.hh"
48 #include "mem/ruby/system/DMASequencer.hh"
49 #include "mem/ruby/system/MemoryVector.hh"
50 #include "mem/protocol/ControllerFactory.hh"
51 #include "mem/ruby/slicc_interface/AbstractController.hh"
52 #include "mem/ruby/system/CacheMemory.hh"
53 #include "mem/ruby/system/DirectoryMemory.hh"
54 #include "mem/ruby/network/simple/Topology.hh"
55 #include "mem/ruby/network/simple/SimpleNetwork.hh"
56 #include "mem/ruby/system/RubyPort.hh"
57 #include "mem/ruby/network/garnet-flexible-pipeline/GarnetNetwork.hh"
58 #include "mem/ruby/network/garnet-fixed-pipeline/GarnetNetwork_d.hh"
59 #include "mem/ruby/system/MemoryControl.hh"
61 int RubySystem::m_random_seed
;
62 bool RubySystem::m_randomization
;
63 int RubySystem::m_tech_nm
;
64 int RubySystem::m_freq_mhz
;
65 int RubySystem::m_block_size_bytes
;
66 int RubySystem::m_block_size_bits
;
67 uint64
RubySystem::m_memory_size_bytes
;
68 int RubySystem::m_memory_size_bits
;
70 map
< string
, RubyPort
* > RubySystem::m_ports
;
71 map
< string
, CacheMemory
* > RubySystem::m_caches
;
72 map
< string
, DirectoryMemory
* > RubySystem::m_directories
;
73 map
< string
, Sequencer
* > RubySystem::m_sequencers
;
74 map
< string
, DMASequencer
* > RubySystem::m_dma_sequencers
;
75 map
< string
, AbstractController
* > RubySystem::m_controllers
;
76 map
< string
, MemoryControl
* > RubySystem::m_memorycontrols
;
79 Network
* RubySystem::m_network_ptr
;
80 map
< string
, Topology
*> RubySystem::m_topologies
;
81 Profiler
* RubySystem::m_profiler_ptr
;
82 Tracer
* RubySystem::m_tracer_ptr
;
84 MemoryVector
* RubySystem::m_mem_vec_ptr
;
87 RubySystem
* RubySystem::create(const vector
<RubyObjConf
> & sys_conf
)
89 if (g_system_ptr
== NULL
)
90 return new RubySystem(sys_conf
);
94 void RubySystem::init(const vector
<string
> & argv
)
96 for (size_t i
=0; i
< argv
.size(); i
+=2) {
97 if (argv
[i
] == "random_seed") {
98 m_random_seed
= atoi(argv
[i
+1].c_str());
99 srandom(m_random_seed
);
100 } else if (argv
[i
] == "randomization") {
101 m_randomization
= string_to_bool(argv
[i
+1]);
102 } else if (argv
[i
] == "tech_nm") {
103 m_tech_nm
= atoi(argv
[i
+1].c_str());
104 } else if (argv
[i
] == "freq_mhz") {
105 m_freq_mhz
= atoi(argv
[i
+1].c_str());
106 } else if (argv
[i
] == "block_size_bytes") {
107 m_block_size_bytes
= atoi(argv
[i
+1].c_str());
108 assert(is_power_of_2(m_block_size_bytes
));
109 m_block_size_bits
= log_int(m_block_size_bytes
);
110 } else if (argv
[i
] == "debug") {
112 } else if (argv
[i
] == "tracer") {
114 } else if (argv
[i
] == "profiler") {
116 // } else if (argv[i] == "MI_example") {
119 cerr
<< "Error: Unknown RubySystem config parameter -- " << argv
[i
] << endl
;
125 RubySystem::RubySystem(const vector
<RubyObjConf
> & sys_conf
)
127 // DEBUG_MSG(SYSTEM_COMP, MedPrio,"initializing");
129 for (size_t i
=0;i
<sys_conf
.size(); i
++) {
130 const string
& type
= sys_conf
[i
].type
;
131 const string
& name
= sys_conf
[i
].name
;
132 const vector
<string
> & argv
= sys_conf
[i
].argv
;
133 if (type
== "System") {
134 init(argv
); // initialize system-wide variables before doing anything else!
135 } else if (type
== "Debug") {
136 g_debug_ptr
= new Debug(name
, argv
);
140 assert( g_debug_ptr
!= NULL
);
141 g_eventQueue_ptr
= new RubyEventQueue
;
143 m_mem_vec_ptr
= new MemoryVector
;
145 /* object contruction is broken into two steps (Constructor and init) to avoid cyclic dependencies
146 * e.g. a sequencer needs a pointer to a controller and a controller needs a pointer to a sequencer
149 vector
<string
> memory_control_names
;
151 for (size_t i
=0;i
<sys_conf
.size(); i
++) {
152 const string
& type
= sys_conf
[i
].type
;
153 const string
& name
= sys_conf
[i
].name
;
154 if (type
== "System" || type
== "Debug")
156 else if (type
== "SetAssociativeCache")
157 m_caches
[name
] = new CacheMemory(name
);
158 else if (type
== "DirectoryMemory")
159 m_directories
[name
] = new DirectoryMemory(name
);
160 else if (type
== "Sequencer") {
161 m_sequencers
[name
] = new Sequencer(name
);
162 m_ports
[name
] = m_sequencers
[name
];
163 } else if (type
== "DMASequencer") {
164 m_dma_sequencers
[name
] = new DMASequencer(name
);
165 m_ports
[name
] = m_dma_sequencers
[name
];
166 } else if (type
== "Topology") {
167 assert(m_topologies
.size() == 0); // only one toplogy at a time is supported right now
168 m_topologies
[name
] = new Topology(name
);
169 } else if (type
== "SimpleNetwork") {
170 assert(m_network_ptr
== NULL
); // only one network at a time is supported right now
171 m_network_ptr
= new SimpleNetwork(name
);
172 } else if (type
.find("generated") == 0) {
173 string controller_type
= type
.substr(10);
174 m_controllers
[name
] = ControllerFactory::createController(controller_type
, name
);
175 // printf ("ss: generated %s \n", controller_type);
177 } else if (type
== "Tracer") {
178 //m_tracers[name] = new Tracer(name);
179 m_tracer_ptr
= new Tracer(name
);
180 } else if (type
== "Profiler") {
181 m_profiler_ptr
= new Profiler(name
);
182 } else if (type
== "GarnetNetwork") {
183 assert(m_network_ptr
== NULL
); // only one network at a time is supported right now
184 m_network_ptr
= new GarnetNetwork(name
);
185 } else if (type
== "GarnetNetwork_d") {
186 assert(m_network_ptr
== NULL
); // only one network at a time is supported right now
187 m_network_ptr
= new GarnetNetwork_d(name
);
188 } else if (type
== "MemoryControl") {
189 m_memorycontrols
[name
] = new MemoryControl(name
);
190 memory_control_names
.push_back (name
);
192 cerr
<< "Error: Unknown object type -- " << type
<< endl
;
197 for (size_t i
=0;i
<sys_conf
.size(); i
++) {
198 string type
= sys_conf
[i
].type
;
199 string name
= sys_conf
[i
].name
;
200 const vector
<string
> & argv
= sys_conf
[i
].argv
;
201 if (type
== "Topology")
202 m_topologies
[name
]->init(argv
);
205 for (size_t i
=0;i
<sys_conf
.size(); i
++) {
206 string type
= sys_conf
[i
].type
;
207 string name
= sys_conf
[i
].name
;
208 const vector
<string
> & argv
= sys_conf
[i
].argv
;
209 if (type
== "SimpleNetwork" || type
== "GarnetNetwork" || type
== "GarnetNetwork_d"){
210 m_network_ptr
->init(argv
);
214 for (size_t i
=0;i
<sys_conf
.size(); i
++) {
215 string type
= sys_conf
[i
].type
;
216 string name
= sys_conf
[i
].name
;
217 const vector
<string
> & argv
= sys_conf
[i
].argv
;
218 if (type
== "MemoryControl" ){
219 m_memorycontrols
[name
]->init(argv
);
223 for (size_t i
=0;i
<sys_conf
.size(); i
++) {
224 string type
= sys_conf
[i
].type
;
225 string name
= sys_conf
[i
].name
;
226 const vector
<string
> & argv
= sys_conf
[i
].argv
;
227 if (type
== "System" || type
== "Debug")
229 else if (type
== "SetAssociativeCache")
230 m_caches
[name
]->init(argv
);
231 else if (type
== "DirectoryMemory")
232 m_directories
[name
]->init(argv
);
233 else if (type
== "MemoryControl")
235 else if (type
== "Sequencer")
236 m_sequencers
[name
]->init(argv
);
237 else if (type
== "DMASequencer")
238 m_dma_sequencers
[name
]->init(argv
);
239 else if (type
== "Topology")
241 else if (type
== "SimpleNetwork" || type
== "GarnetNetwork" || type
== "GarnetNetwork_d")
243 else if (type
.find("generated") == 0) {
244 string controller_type
= type
.substr(11);
245 m_controllers
[name
]->init(m_network_ptr
, argv
);
248 else if (type
== "Tracer")
249 //m_tracers[name]->init(argv);
250 m_tracer_ptr
->init(argv
);
251 else if (type
== "Profiler")
252 m_profiler_ptr
->init(argv
, memory_control_names
);
253 // else if (type == "MI_example"){
259 // m_profiler_ptr = new Profiler;
261 // calculate system-wide parameters
262 m_memory_size_bytes
= 0;
263 DirectoryMemory
* prev
= NULL
;
264 for (map
< string
, DirectoryMemory
*>::const_iterator it
= m_directories
.begin();
265 it
!= m_directories
.end(); it
++) {
267 assert((*it
).second
->getSize() == prev
->getSize()); // must be equal for proper address mapping
268 m_memory_size_bytes
+= (*it
).second
->getSize();
271 m_mem_vec_ptr
->setSize(m_memory_size_bytes
);
272 m_memory_size_bits
= log_int(m_memory_size_bytes
);
274 // m_tracer_ptr = new Tracer;
275 DEBUG_MSG(SYSTEM_COMP
, MedPrio
,"finished initializing");
276 DEBUG_NEWLINE(SYSTEM_COMP
, MedPrio
);
279 RubySystem::~RubySystem()
284 void RubySystem::printSystemConfig(ostream
& out
)
286 out
<< "RubySystem config:" << endl
;
287 out
<< " random_seed: " << m_random_seed
<< endl
;
288 out
<< " randomization: " << m_randomization
<< endl
;
289 out
<< " tech_nm: " << m_tech_nm
<< endl
;
290 out
<< " freq_mhz: " << m_freq_mhz
<< endl
;
291 out
<< " block_size_bytes: " << m_block_size_bytes
<< endl
;
292 out
<< " block_size_bits: " << m_block_size_bits
<< endl
;
293 out
<< " memory_size_bytes: " << m_memory_size_bytes
<< endl
;
294 out
<< " memory_size_bits: " << m_memory_size_bits
<< endl
;
298 void RubySystem::printConfig(ostream
& out
)
300 out
<< "\n================ Begin RubySystem Configuration Print ================\n\n";
301 printSystemConfig(out
);
302 for (map
<string
, AbstractController
*>::const_iterator it
= m_controllers
.begin();
303 it
!= m_controllers
.end(); it
++) {
304 (*it
).second
->printConfig(out
);
306 for (map
<string
, CacheMemory
*>::const_iterator it
= m_caches
.begin();
307 it
!= m_caches
.end(); it
++) {
308 (*it
).second
->printConfig(out
);
310 DirectoryMemory::printGlobalConfig(out
);
311 for (map
<string
, DirectoryMemory
*>::const_iterator it
= m_directories
.begin();
312 it
!= m_directories
.end(); it
++) {
313 (*it
).second
->printConfig(out
);
315 for (map
<string
, Sequencer
*>::const_iterator it
= m_sequencers
.begin();
316 it
!= m_sequencers
.end(); it
++) {
317 (*it
).second
->printConfig(out
);
320 m_network_ptr
->printConfig(out
);
321 m_profiler_ptr
->printConfig(out
);
323 out
<< "\n================ End RubySystem Configuration Print ================\n\n";
326 void RubySystem::printStats(ostream
& out
)
329 const time_t T
= time(NULL
);
330 tm
*localTime
= localtime(&T
);
332 strftime(buf
, 100, "%b/%d/%Y %H:%M:%S", localTime
);
334 out
<< "Real time: " << buf
<< endl
;
336 m_profiler_ptr
->printStats(out
);
337 m_network_ptr
->printStats(out
);
338 for (map
<string
, CacheMemory
*>::const_iterator it
= m_caches
.begin();
339 it
!= m_caches
.end(); it
++) {
340 (*it
).second
->printStats(out
);
342 for (map
<string
, AbstractController
*>::const_iterator it
= m_controllers
.begin();
343 it
!= m_controllers
.end(); it
++) {
344 (*it
).second
->printStats(out
);
348 void RubySystem::clearStats() const
351 m_profiler_ptr->clearStats();
352 for (int i=0; i<m_rubyRequestQueues.size(); i++)
353 for (int j=0;j<m_rubyRequestQueues[i].size(); j++)
354 m_rubyRequestQueues[i][j]->clearStats();
355 m_network_ptr->clearStats();
356 for (int i=0; i < MachineType_base_level(MachineType_NUM); i++)
357 m_controllers[i][0]->clearStats();
361 void RubySystem::recordCacheContents(CacheRecorder
& tr
) const
366 #ifdef CHECK_COHERENCE
367 // This code will check for cases if the given cache block is exclusive in
368 // one node and shared in another-- a coherence violation
370 // To use, the SLICC specification must call sequencer.checkCoherence(address)
371 // when the controller changes to a state with new permissions. Do this
372 // in setState. The SLICC spec must also define methods "isBlockShared"
373 // and "isBlockExclusive" that are specific to that protocol
375 void RubySystem::checkGlobalCoherenceInvariant(const Address
& addr
) {
377 NodeID exclusive = -1;
378 bool sharedDetected = false;
379 NodeID lastShared = -1;
381 for (int i = 0; i < m_chip_vector.size(); i++) {
383 if (m_chip_vector[i]->isBlockExclusive(addr)) {
384 if (exclusive != -1) {
385 // coherence violation
386 WARN_EXPR(exclusive);
387 WARN_EXPR(m_chip_vector[i]->getID());
389 WARN_EXPR(g_eventQueue_ptr->getTime());
390 ERROR_MSG("Coherence Violation Detected -- 2 exclusive chips");
392 else if (sharedDetected) {
393 WARN_EXPR(lastShared);
394 WARN_EXPR(m_chip_vector[i]->getID());
396 WARN_EXPR(g_eventQueue_ptr->getTime());
397 ERROR_MSG("Coherence Violation Detected -- exclusive chip with >=1 shared");
400 exclusive = m_chip_vector[i]->getID();
403 else if (m_chip_vector[i]->isBlockShared(addr)) {
404 sharedDetected = true;
405 lastShared = m_chip_vector[i]->getID();
407 if (exclusive != -1) {
408 WARN_EXPR(lastShared);
409 WARN_EXPR(exclusive);
411 WARN_EXPR(g_eventQueue_ptr->getTime());
412 ERROR_MSG("Coherence Violation Detected -- exclusive chip with >=1 shared");