2ea82c77c60afb471796a37c505bd088f8e79dc5
[gem5.git] / src / mem / ruby / tester / DeterministicDriver.cc
1
2 /*
3 * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
4 * All rights reserved.
5 *
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.
16 *
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.
28 */
29
30 /*
31 * $Id$
32 *
33 */
34
35 #include "mem/ruby/common/Global.hh"
36 #include "mem/ruby/system/System.hh"
37 #include "mem/ruby/tester/DeterministicDriver.hh"
38 #include "mem/ruby/eventqueue/RubyEventQueue.hh"
39 #include "mem/ruby/tester/SpecifiedGenerator.hh"
40 #include "mem/ruby/tester/DetermGETXGenerator.hh"
41 #include "mem/ruby/tester/DetermInvGenerator.hh"
42 #include "mem/ruby/tester/DetermSeriesGETSGenerator.hh"
43 #include "mem/ruby/common/SubBlock.hh"
44 #include "mem/protocol/Chip.hh"
45
46 DeterministicDriver::DeterministicDriver(RubySystem* sys_ptr)
47 {
48 if (g_SIMULATING) {
49 ERROR_MSG("g_SIMULATING should not be defined.");
50 }
51
52 m_finish_time = 0;
53 m_last_issue = -11;
54 m_done_counter = 0;
55 m_loads_completed = 0;
56 m_stores_completed = 0;
57
58 m_numCompletionsPerNode = g_NUM_COMPLETIONS_BEFORE_PASS;
59
60 m_last_progress_vector.setSize(RubyConfig::numberOfProcessors());
61 for (int i=0; i<m_last_progress_vector.size(); i++) {
62 m_last_progress_vector[i] = 0;
63 }
64
65 m_load_vector.setSize(g_deterministic_addrs);
66 for (int i=0; i<m_load_vector.size(); i++) {
67 m_load_vector[i] = -1; // No processor last held it
68 }
69
70 m_store_vector.setSize(g_deterministic_addrs);
71 for (int i=0; i<m_store_vector.size(); i++) {
72 m_store_vector[i] = -1; // No processor last held it
73 }
74
75 m_generator_vector.setSize(RubyConfig::numberOfProcessors());
76
77 SpecifiedGeneratorType generator = string_to_SpecifiedGeneratorType(g_SpecifiedGenerator);
78
79 for (int i=0; i<m_generator_vector.size(); i++) {
80 switch (generator) {
81 case SpecifiedGeneratorType_DetermGETXGenerator:
82 m_generator_vector[i] = new DetermGETXGenerator(i, *this);
83 break;
84 case SpecifiedGeneratorType_DetermSeriesGETSGenerator:
85 m_generator_vector[i] = new DetermSeriesGETSGenerator(i, *this);
86 break;
87 case SpecifiedGeneratorType_DetermInvGenerator:
88 m_generator_vector[i] = new DetermInvGenerator(i, *this);
89 break;
90 default:
91 ERROR_MSG("Unexpected specified generator type");
92 }
93 }
94
95 // add the tester consumer to the global event queue
96 g_eventQueue_ptr->scheduleEvent(this, 1);
97 }
98
99 DeterministicDriver::~DeterministicDriver()
100 {
101 for (int i=0; i<m_last_progress_vector.size(); i++) {
102 delete m_generator_vector[i];
103 }
104 }
105
106 void DeterministicDriver::hitCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread)
107 {
108 DEBUG_EXPR(TESTER_COMP, MedPrio, data);
109
110 m_generator_vector[proc]->performCallback(proc, data);
111
112 // Mark that we made progress
113 m_last_progress_vector[proc] = g_eventQueue_ptr->getTime();
114 }
115
116 bool DeterministicDriver::isStoreReady(NodeID node)
117 {
118 return isAddrReady(node, m_store_vector);
119 }
120
121 bool DeterministicDriver::isStoreReady(NodeID node, Address addr)
122 {
123 return isAddrReady(node, m_store_vector, addr);
124 }
125
126 bool DeterministicDriver::isLoadReady(NodeID node)
127 {
128 return isAddrReady(node, m_load_vector);
129 }
130
131 bool DeterministicDriver::isLoadReady(NodeID node, Address addr)
132 {
133 return isAddrReady(node, m_load_vector, addr);
134 }
135
136 // searches for any address in the addr_vector
137 bool DeterministicDriver::isAddrReady(NodeID node, Vector<NodeID> addr_vector)
138 {
139 for (int i=0; i<addr_vector.size(); i++) {
140 if (((addr_vector[i]+1)%RubyConfig::numberOfProcessors() == node) &&
141 (m_loads_completed+m_stores_completed >= m_numCompletionsPerNode*node) && // is this node next
142 (g_eventQueue_ptr->getTime() >= m_last_issue + 10)) { // controll rate of requests
143 return true;
144 }
145 }
146 return false;
147 }
148
149 // test for a particular addr
150 bool DeterministicDriver::isAddrReady(NodeID node, Vector<NodeID> addr_vector, Address addr)
151 {
152 int addr_number = addr.getAddress()/RubyConfig::dataBlockBytes();
153
154 ASSERT ((addr_number >= 0) && (addr_number < addr_vector.size()));
155
156 if (((addr_vector[addr_number]+1)%RubyConfig::numberOfProcessors() == node) &&
157 (m_loads_completed+m_stores_completed >= m_numCompletionsPerNode*node) && // is this node next
158 (g_eventQueue_ptr->getTime() >= m_last_issue + 10)) { // controll rate of requests
159 return true;
160 } else {
161 return false;
162 }
163 }
164
165 void DeterministicDriver::loadCompleted(NodeID node, Address addr)
166 {
167 m_loads_completed++;
168 setNextAddr(node, addr, m_load_vector);
169 }
170
171 void DeterministicDriver::storeCompleted(NodeID node, Address addr)
172 {
173 m_stores_completed++;
174 setNextAddr(node, addr, m_store_vector);
175 }
176
177 void DeterministicDriver::setNextAddr(NodeID node, Address addr, Vector<NodeID>& addr_vector)
178 {
179 // mark the addr vector that this proc was the last to use the particular address
180 int addr_number = addr.getAddress()/RubyConfig::dataBlockBytes();
181 addr_vector[addr_number] = node;
182 }
183
184 Address DeterministicDriver::getNextLoadAddr(NodeID node)
185 {
186 return getNextAddr(node, m_load_vector);
187 }
188
189 Address DeterministicDriver::getNextStoreAddr(NodeID node)
190 {
191 return getNextAddr(node, m_store_vector);
192 }
193
194 Address DeterministicDriver::getNextAddr(NodeID node, Vector<NodeID> addr_vector)
195 {
196
197 // This method deterministically picks the next addr the node should acquirer
198 // The addrs cycle through according to NodeID 0->1->...->lastID->0...
199
200 Address addr;
201
202 // should only be called if we know a addr is ready for the node
203 ASSERT(isAddrReady(node, addr_vector));
204
205 for (int addr_number=0; addr_number<addr_vector.size(); addr_number++) {
206 //for (int addr_number=addr_vector.size()-1; addr_number>0; addr_number--) {
207
208 // is this node next in line for the addr
209 if (((addr_vector[addr_number]+1)%RubyConfig::numberOfProcessors()) == node) {
210
211 // One addr per cache line
212 addr.setAddress(addr_number * RubyConfig::dataBlockBytes());
213 }
214 }
215
216 m_last_issue = g_eventQueue_ptr->getTime();
217
218 return addr;
219 }
220
221
222 void DeterministicDriver::reportDone()
223 {
224 m_done_counter++;
225 if ((m_done_counter == RubyConfig::numberOfProcessors())) {
226 //|| (m_done_counter == g_tester_length)) {
227 m_finish_time = g_eventQueue_ptr->getTime();
228 }
229 }
230
231 void DeterministicDriver::recordLoadLatency(Time time)
232 {
233 m_load_latency.add(time);
234 }
235
236 void DeterministicDriver::recordStoreLatency(Time time)
237 {
238 m_store_latency.add(time);
239 }
240
241 void DeterministicDriver::wakeup()
242 {
243 // checkForDeadlock();
244 if (m_done_counter < RubyConfig::numberOfProcessors()) {
245 g_eventQueue_ptr->scheduleEvent(this, g_DEADLOCK_THRESHOLD);
246 }
247 }
248
249 void DeterministicDriver::checkForDeadlock()
250 {
251 int size = m_last_progress_vector.size();
252 Time current_time = g_eventQueue_ptr->getTime();
253 for (int processor=0; processor<size; processor++) {
254 if ((current_time - m_last_progress_vector[processor]) > g_DEADLOCK_THRESHOLD) {
255 WARN_EXPR(processor);
256 Sequencer* seq_ptr = g_system_ptr->getChip(processor/RubyConfig::numberOfProcsPerChip())->getSequencer(processor%RubyConfig::numberOfProcsPerChip());
257 assert(seq_ptr != NULL);
258 // if (seq_ptr->isRequestPending()) {
259 // WARN_EXPR(seq_ptr->pendingAddress());
260 // }
261 WARN_EXPR(current_time);
262 WARN_EXPR(m_last_progress_vector[processor]);
263 WARN_EXPR(current_time - m_last_progress_vector[processor]);
264 ERROR_MSG("Deadlock detected.");
265 }
266 }
267 }
268
269 void DeterministicDriver::printStats(ostream& out) const
270 {
271 out << endl;
272 out << "DeterministicDriver Stats" << endl;
273 out << "---------------------" << endl;
274
275 out << "finish_time: " << m_finish_time << endl;
276 out << "load_latency: " << m_load_latency << endl;
277 out << "store_latency: " << m_store_latency << endl;
278 }
279
280 void DeterministicDriver::print(ostream& out) const
281 {
282 }