gem5 v24.0.0.0
Loading...
Searching...
No Matches
tester_thread.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2017-2021 Advanced Micro Devices, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its
16 * contributors may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
33
34#include <fstream>
35
36#include "base/random.hh"
37#include "debug/ProtocolTest.hh"
38
39namespace gem5
40{
41
44 threadEvent(this, "TesterThread tick"),
45 deadlockCheckEvent(this),
46 threadId(p.thread_id),
47 numLanes(p.num_lanes),
48 tester(nullptr), addrManager(nullptr), port(nullptr),
49 scalarPort(nullptr), sqcPort(nullptr), curEpisode(nullptr),
50 curAction(nullptr), pendingLdStCount(0), pendingFenceCount(0),
51 pendingAtomicCount(0), lastActiveCycle(Cycles(0)),
52 deadlockThreshold(p.deadlock_threshold)
53{
54}
55
57{
58 for (auto ep : episodeHistory) {
59 assert(ep != nullptr);
60 delete ep;
61 }
62}
63
64void
66{
67 // this thread is waken up by one of the following events
68 // - hitCallback is called
69 // - a new episode is created
70
71 // check if this is the first episode in this thread
72 if (curEpisode == nullptr) {
74 assert(curEpisode);
75 }
76
77 if (isNextActionReady()) {
78 // isNextActionReady should check if the action list is empty
79 assert(curAction != nullptr);
80
81 // issue the next action
83 } else {
84 // check for completion of the current episode
85 // completion = no outstanding requests + not having more actions
86 if (!curEpisode->hasMoreActions() &&
87 pendingLdStCount == 0 &&
88 pendingFenceCount == 0 &&
89 pendingAtomicCount == 0) {
90
92
93 // check if it's time to stop the tester
94 if (tester->checkExit()) {
95 // no more event is scheduled for this thread
96 return;
97 }
98
99 // issue the next episode
101 assert(curEpisode);
102
103 // now we get a new episode
104 // let's wake up the thread in the next cycle
105 if (!threadEvent.scheduled()) {
107 }
108 }
109 }
110}
111
112void
118
119void
121{
122 // after this first schedule, the deadlock event is scheduled by itself
123 assert(!deadlockCheckEvent.scheduled());
125}
126
127void
130 ProtocolTester::GMTokenPort *_tokenPort,
131 ProtocolTester::SeqPort *_scalarPort,
132 ProtocolTester::SeqPort *_sqcPort)
133{
134 tester = _tester;
135 port = _port;
136 tokenPort = _tokenPort;
137 scalarPort = _scalarPort;
138 sqcPort = _sqcPort;
139
140 assert(tester && port);
142 assert(addrManager);
143}
144
145void
147{
148 int num_reg_loads = \
149 random_mt.random<unsigned int>() % tester->getEpisodeLength();
150 int num_reg_stores = tester->getEpisodeLength() - num_reg_loads;
151
152 // create a new episode
153 curEpisode = new Episode(tester, this, num_reg_loads, num_reg_stores);
154 episodeHistory.push_back(curEpisode);
155}
156
157int
159{
160 if (!tokenPort) {
161 return 0;
162 }
163
164 int tokens_needed = 0;
166
167 switch(curAction->getType()) {
169 tokens_needed = numLanes;
170 break;
173 for (int lane = 0; lane < numLanes; ++lane) {
174 Location loc = curAction->getLocation(lane);
175
176 if (loc != AddressManager::INVALID_LOCATION && loc >= 0) {
177 tokens_needed++;
178 }
179 }
180 break;
181 default:
182 tokens_needed = 0;
183 }
184
185 return tokens_needed;
186}
187
188bool
190{
191 if (!curEpisode->hasMoreActions()) {
192 return false;
193 } else {
195
196 // Only GPU wavefront threads have a token port. For all other types
197 // of threads evaluate to true.
198 bool haveTokens = true;
199
200 switch(curAction->getType()) {
202 haveTokens = tokenPort ?
204
205 // an atomic action must wait for all previous requests
206 // to complete
207 if (pendingLdStCount == 0 &&
208 pendingFenceCount == 0 &&
209 pendingAtomicCount == 0 &&
210 haveTokens) {
211 return true;
212 }
213
214 return false;
216 // we should not see any outstanding ld_st or fence here
217 assert(pendingLdStCount == 0 &&
218 pendingFenceCount == 0);
219
220 // an acquire action must wait for all previous atomic
221 // requests to complete
222 if (pendingAtomicCount == 0) {
223 return true;
224 }
225
226 return false;
228 // we should not see any outstanding atomic or fence here
229 assert(pendingAtomicCount == 0 &&
230 pendingFenceCount == 0);
231
232 // a release action must wait for all previous ld/st
233 // requests to complete
234 if (pendingLdStCount == 0) {
235 return true;
236 }
237
238 return false;
241 // we should not see any outstanding atomic here
242 assert(pendingAtomicCount == 0);
243
244 // can't issue if there is a pending fence
245 if (pendingFenceCount > 0) {
246 return false;
247 }
248
249 // a Load or Store is ready if it doesn't overlap
250 // with any outstanding request
251 for (int lane = 0; lane < numLanes; ++lane) {
252 Location loc = curAction->getLocation(lane);
253
254 if (loc != AddressManager::INVALID_LOCATION && loc >= 0) {
256
257 if (outstandingLoads.find(addr) !=
258 outstandingLoads.end()) {
259 return false;
260 }
261
262 if (outstandingStores.find(addr) !=
263 outstandingStores.end()) {
264 return false;
265 }
266
267 if (outstandingAtomics.find(addr) !=
268 outstandingAtomics.end()) {
269 // this is not an atomic action, so the address
270 // should not be in outstandingAtomics list
271 assert(false);
272 }
273 }
274 }
275
276 haveTokens = tokenPort ?
278 if (!haveTokens) {
279 return false;
280 }
281
282 return true;
283 default:
284 panic("The tester got an invalid action\n");
285 }
286 }
287}
288
289void
291{
292 switch(curAction->getType()) {
294 if (tokenPort) {
296 }
298 break;
301 break;
304 break;
306 if (tokenPort) {
308 }
309 issueLoadOps();
310 break;
312 if (tokenPort) {
314 }
316 break;
317 default:
318 panic("The tester got an invalid action\n");
319 }
320
321 // the current action has been issued, pop it from the action list
324
325 // we may be able to schedule the next action
326 // just wake up this thread in the next cycle
327 if (!threadEvent.scheduled()) {
329 }
330}
331
332void
334 int lane, Location loc, Value stored_val)
335{
336 OutstandingReqTable::iterator it = req_table.find(address);
337 OutstandingReq req(lane, loc, stored_val, curCycle());
338
339 if (it == req_table.end()) {
340 // insert a new list of requests for this address
341 req_table.insert(std::pair<Addr, OutstandingReqList>(address,
342 OutstandingReqList(1, req)));
343 } else {
344 // add a new request
345 (it->second).push_back(req);
346 }
347}
348
351{
352 OutstandingReqTable::iterator it = req_table.find(addr);
353
354 // there must be exactly one list of requests for this address in the table
355 assert(it != req_table.end());
356
357 // get the request list
358 OutstandingReqList& req_list = it->second;
359 assert(!req_list.empty());
360
361 // save a request
362 OutstandingReq ret_req = req_list.back();
363
364 // remove the request from the list
365 req_list.pop_back();
366
367 // if the list is now empty, remove it from req_table
368 if (req_list.empty()) {
369 req_table.erase(it);
370 }
371
372 return ret_req;
373}
374
375void
377{
378 if (!addrManager->validateAtomicResp(loc, ret_val)) {
379 std::stringstream ss;
381
382 // basic info
383 ss << threadName << ": Atomic Op returned unexpected value\n"
384 << "\tEpisode " << curEpisode->getEpisodeId() << "\n"
385 << "\tLane ID " << lane << "\n"
386 << "\tAddress " << ruby::printAddress(addr) << "\n"
387 << "\tAtomic Op's return value " << ret_val << "\n";
388
389 // print out basic info
390 warn("%s\n", ss.str());
391
392 // TODO add more detailed info
393
394 // dump all error info and exit the simulation
396 }
397}
398
399void
401{
402 if (ret_val != addrManager->getLoggedValue(loc)) {
403 std::stringstream ss;
405
406 // basic info
407 ss << threadName << ": Loaded value is not consistent with "
408 << "the last stored value\n"
409 << "\tTesterThread " << threadId << "\n"
410 << "\tEpisode " << curEpisode->getEpisodeId() << "\n"
411 << "\tLane ID " << lane << "\n"
412 << "\tAddress " << ruby::printAddress(addr) << "\n"
413 << "\tLoaded value " << ret_val << "\n"
414 << "\tLast writer " << addrManager->printLastWriter(loc) << "\n";
415
416 // print out basic info
417 warn("%s\n", ss.str());
418
419 // TODO add more detailed info
420
421 // dump all error info and exit the simulation
423 }
424}
425
426bool
427TesterThread::checkDRF(Location atomic_loc, Location loc, bool isStore) const
428{
430 // check against the current episode this thread is executing
431 return curEpisode->checkDRF(atomic_loc, loc, isStore, numLanes);
432 }
433
434 return true;
435}
436
437void
439{
441 // deadlock detected
442 std::stringstream ss;
443
444 ss << threadName << ": Deadlock detected\n"
445 << "\tLast active cycle: " << lastActiveCycle << "\n"
446 << "\tCurrent cycle: " << curCycle() << "\n"
447 << "\tDeadlock threshold: " << deadlockThreshold << "\n";
448
449 // print out basic info
450 warn("%s\n", ss.str());
451
452 // dump all error info and exit the simulation
454 } else if (!tester->checkExit()) {
455 // schedule a future deadlock check event
456 assert(!deadlockCheckEvent.scheduled());
459 }
460}
461
462void
464 std::stringstream& ss) const
465{
466 Cycles cur_cycle = curCycle();
467
468 for (const auto& m : table) {
469 for (const auto& req : m.second) {
470 ss << "\t\t\tAddr " << ruby::printAddress(m.first)
471 << ": delta (curCycle - issueCycle) = "
472 << (cur_cycle - req.issueCycle) << std::endl;
473 }
474 }
475}
476
477void
479{
480 // dump all outstanding requests of this thread
481 ss << "\t\tOutstanding Loads:\n";
483 ss << "\t\tOutstanding Stores:\n";
485 ss << "\t\tOutstanding Atomics:\n";
487 ss << "\t\tNumber of outstanding acquires & releases: "
488 << pendingFenceCount << std::endl;
489}
490
491} // namespace gem5
Addr getAddress(Location loc)
Value getLoggedValue(Location loc) const
std::string printLastWriter(Location loc) const
static const int INVALID_LOCATION
bool validateAtomicResp(Location loc, Value ret_val)
The ClockedObject class extends the SimObject with a clock and accessor functions to relate ticks to ...
Cycles curCycle() const
Determine the current cycle, corresponding to a tick aligned to a clock edge.
Tick nextCycle() const
Based on the clock of the object, determine the start tick of the first cycle that is at least one cy...
Tick clockPeriod() const
Cycles is a wrapper class for representing cycle counts, i.e.
Definition types.hh:79
Location getLocation(int lane) const
Definition episode.cc:290
Type getType() const
Definition episode.hh:66
int getEpisodeId() const
Definition episode.hh:85
void completeEpisode()
Definition episode.cc:201
bool checkDRF(Location atomic_loc, Location loc, bool isStore, int max_lane) const
Definition episode.cc:241
bool hasMoreActions() const
Definition episode.hh:91
bool isEpsActive() const
Definition episode.hh:95
void popAction()
Definition episode.cc:87
const Action * peekCurAction() const
Definition episode.cc:78
AddressManager * getAddressManager() const
void dumpErrorLog(std::stringstream &ss)
TesterThread(const Params &p)
AddressManager * addrManager
AddressManager::Value Value
void attachTesterThreadToPorts(ProtocolTester *_tester, ProtocolTester::SeqPort *_port, ProtocolTester::GMTokenPort *_tokenPort=nullptr, ProtocolTester::SeqPort *_sqcPort=nullptr, ProtocolTester::SeqPort *_scalarPort=nullptr)
virtual void issueReleaseOp()=0
OutstandingReqTable outstandingAtomics
AddressManager::Location Location
void scheduleDeadlockCheckEvent()
void validateAtomicResp(Location loc, int lane, Value ret_val)
ProtocolTester * tester
ProtocolTester::SeqPort * port
bool checkDRF(Location atomic_loc, Location loc, bool isStore) const
void printAllOutstandingReqs(std::stringstream &ss) const
DeadlockCheckEvent deadlockCheckEvent
virtual void issueAcquireOp()=0
ProtocolTester::SeqPort * scalarPort
OutstandingReqTable outstandingStores
void addOutstandingReqs(OutstandingReqTable &req_table, Addr addr, int lane, Location loc, Value stored_val=AddressManager::INVALID_VALUE)
virtual void issueStoreOps()=0
OutstandingReqTable outstandingLoads
ProtocolTester::GMTokenPort * tokenPort
EpisodeHistory episodeHistory
OutstandingReq popOutstandingReq(OutstandingReqTable &req_table, Addr address)
const Episode::Action * curAction
virtual void issueAtomicOps()=0
ProtocolTester::SeqPort * sqcPort
void printOutstandingReqs(const OutstandingReqTable &table, std::stringstream &ss) const
TesterThreadParams Params
virtual void issueLoadOps()=0
std::unordered_map< Addr, OutstandingReqList > OutstandingReqTable
TesterThreadEvent threadEvent
std::vector< OutstandingReq > OutstandingReqList
void validateLoadResp(Location loc, int lane, Value ret_val)
void acquireTokens(int num_tokens)
Acquire tokens by decrementing the number of available tokens across the port.
Definition token_port.cc:64
bool haveTokens(int num_tokens)
Query if there are at least num_tokens tokens available to acquire.
Definition token_port.cc:56
STL pair class.
Definition stl.hh:58
STL vector class.
Definition stl.hh:37
Random random_mt
Definition random.cc:99
std::enable_if_t< std::is_integral_v< T >, T > random()
Use the SFINAE idiom to choose an implementation based on whether the type is integral or floating po...
Definition random.hh:90
bool scheduled() const
Determine if the current event is scheduled.
Definition eventq.hh:458
void schedule(Event &event, Tick when)
Definition eventq.hh:1012
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:188
#define warn(...)
Definition logging.hh:256
Bitfield< 0 > m
Bitfield< 21 > ss
Definition misc_types.hh:60
Bitfield< 1 > ep
Bitfield< 0 > p
Bitfield< 3 > addr
Definition types.hh:84
std::string printAddress(Addr addr)
Definition Address.cc:80
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36
Tick curTick()
The universal simulation clock.
Definition cur_tick.hh:46
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition types.hh:147

Generated on Tue Jun 18 2024 16:24:02 for gem5 by doxygen 1.11.0