gem5 v23.0.0.1
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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 "debug/ProtocolTest.hh"
37
38namespace gem5
39{
40
43 threadEvent(this, "TesterThread tick"),
44 deadlockCheckEvent(this),
45 threadId(p.thread_id),
46 numLanes(p.num_lanes),
47 tester(nullptr), addrManager(nullptr), port(nullptr),
48 scalarPort(nullptr), sqcPort(nullptr), curEpisode(nullptr),
49 curAction(nullptr), pendingLdStCount(0), pendingFenceCount(0),
50 pendingAtomicCount(0), lastActiveCycle(Cycles(0)),
51 deadlockThreshold(p.deadlock_threshold)
52{
53}
54
56{
57 for (auto ep : episodeHistory) {
58 assert(ep != nullptr);
59 delete ep;
60 }
61}
62
63void
65{
66 // this thread is waken up by one of the following events
67 // - hitCallback is called
68 // - a new episode is created
69
70 // check if this is the first episode in this thread
71 if (curEpisode == nullptr) {
73 assert(curEpisode);
74 }
75
76 if (isNextActionReady()) {
77 // isNextActionReady should check if the action list is empty
78 assert(curAction != nullptr);
79
80 // issue the next action
82 } else {
83 // check for completion of the current episode
84 // completion = no outstanding requests + not having more actions
85 if (!curEpisode->hasMoreActions() &&
86 pendingLdStCount == 0 &&
87 pendingFenceCount == 0 &&
88 pendingAtomicCount == 0) {
89
91
92 // check if it's time to stop the tester
93 if (tester->checkExit()) {
94 // no more event is scheduled for this thread
95 return;
96 }
97
98 // issue the next episode
100 assert(curEpisode);
101
102 // now we get a new episode
103 // let's wake up the thread in the next cycle
104 if (!threadEvent.scheduled()) {
106 }
107 }
108 }
109}
110
111void
113{
114 assert(!threadEvent.scheduled());
116}
117
118void
120{
121 // after this first schedule, the deadlock event is scheduled by itself
122 assert(!deadlockCheckEvent.scheduled());
124}
125
126void
129 ProtocolTester::GMTokenPort *_tokenPort,
130 ProtocolTester::SeqPort *_scalarPort,
131 ProtocolTester::SeqPort *_sqcPort)
132{
133 tester = _tester;
134 port = _port;
135 tokenPort = _tokenPort;
136 scalarPort = _scalarPort;
137 sqcPort = _sqcPort;
138
139 assert(tester && port);
141 assert(addrManager);
142}
143
144void
146{
147 int num_reg_loads = random() % tester->getEpisodeLength();
148 int num_reg_stores = tester->getEpisodeLength() - num_reg_loads;
149
150 // create a new episode
151 curEpisode = new Episode(tester, this, num_reg_loads, num_reg_stores);
152 episodeHistory.push_back(curEpisode);
153}
154
155int
157{
158 if (!tokenPort) {
159 return 0;
160 }
161
162 int tokens_needed = 0;
164
165 switch(curAction->getType()) {
167 tokens_needed = numLanes;
168 break;
171 for (int lane = 0; lane < numLanes; ++lane) {
172 Location loc = curAction->getLocation(lane);
173
174 if (loc != AddressManager::INVALID_LOCATION && loc >= 0) {
175 tokens_needed++;
176 }
177 }
178 break;
179 default:
180 tokens_needed = 0;
181 }
182
183 return tokens_needed;
184}
185
186bool
188{
189 if (!curEpisode->hasMoreActions()) {
190 return false;
191 } else {
193
194 // Only GPU wavefront threads have a token port. For all other types
195 // of threads evaluate to true.
196 bool haveTokens = true;
197
198 switch(curAction->getType()) {
200 haveTokens = tokenPort ?
202
203 // an atomic action must wait for all previous requests
204 // to complete
205 if (pendingLdStCount == 0 &&
206 pendingFenceCount == 0 &&
207 pendingAtomicCount == 0 &&
208 haveTokens) {
209 return true;
210 }
211
212 return false;
214 // we should not see any outstanding ld_st or fence here
215 assert(pendingLdStCount == 0 &&
216 pendingFenceCount == 0);
217
218 // an acquire action must wait for all previous atomic
219 // requests to complete
220 if (pendingAtomicCount == 0) {
221 return true;
222 }
223
224 return false;
226 // we should not see any outstanding atomic or fence here
227 assert(pendingAtomicCount == 0 &&
228 pendingFenceCount == 0);
229
230 // a release action must wait for all previous ld/st
231 // requests to complete
232 if (pendingLdStCount == 0) {
233 return true;
234 }
235
236 return false;
239 // we should not see any outstanding atomic here
240 assert(pendingAtomicCount == 0);
241
242 // can't issue if there is a pending fence
243 if (pendingFenceCount > 0) {
244 return false;
245 }
246
247 // a Load or Store is ready if it doesn't overlap
248 // with any outstanding request
249 for (int lane = 0; lane < numLanes; ++lane) {
250 Location loc = curAction->getLocation(lane);
251
252 if (loc != AddressManager::INVALID_LOCATION && loc >= 0) {
254
255 if (outstandingLoads.find(addr) !=
256 outstandingLoads.end()) {
257 return false;
258 }
259
260 if (outstandingStores.find(addr) !=
261 outstandingStores.end()) {
262 return false;
263 }
264
265 if (outstandingAtomics.find(addr) !=
266 outstandingAtomics.end()) {
267 // this is not an atomic action, so the address
268 // should not be in outstandingAtomics list
269 assert(false);
270 }
271 }
272 }
273
274 haveTokens = tokenPort ?
276 if (!haveTokens) {
277 return false;
278 }
279
280 return true;
281 default:
282 panic("The tester got an invalid action\n");
283 }
284 }
285}
286
287void
289{
290 switch(curAction->getType()) {
292 if (tokenPort) {
294 }
296 break;
299 break;
302 break;
304 if (tokenPort) {
306 }
307 issueLoadOps();
308 break;
310 if (tokenPort) {
312 }
314 break;
315 default:
316 panic("The tester got an invalid action\n");
317 }
318
319 // the current action has been issued, pop it from the action list
322
323 // we may be able to schedule the next action
324 // just wake up this thread in the next cycle
325 if (!threadEvent.scheduled()) {
327 }
328}
329
330void
332 int lane, Location loc, Value stored_val)
333{
334 OutstandingReqTable::iterator it = req_table.find(address);
335 OutstandingReq req(lane, loc, stored_val, curCycle());
336
337 if (it == req_table.end()) {
338 // insert a new list of requests for this address
339 req_table.insert(std::pair<Addr, OutstandingReqList>(address,
340 OutstandingReqList(1, req)));
341 } else {
342 // add a new request
343 (it->second).push_back(req);
344 }
345}
346
349{
350 OutstandingReqTable::iterator it = req_table.find(addr);
351
352 // there must be exactly one list of requests for this address in the table
353 assert(it != req_table.end());
354
355 // get the request list
356 OutstandingReqList& req_list = it->second;
357 assert(!req_list.empty());
358
359 // save a request
360 OutstandingReq ret_req = req_list.back();
361
362 // remove the request from the list
363 req_list.pop_back();
364
365 // if the list is now empty, remove it from req_table
366 if (req_list.empty()) {
367 req_table.erase(it);
368 }
369
370 return ret_req;
371}
372
373void
375{
376 if (!addrManager->validateAtomicResp(loc, ret_val)) {
377 std::stringstream ss;
379
380 // basic info
381 ss << threadName << ": Atomic Op returned unexpected value\n"
382 << "\tEpisode " << curEpisode->getEpisodeId() << "\n"
383 << "\tLane ID " << lane << "\n"
384 << "\tAddress " << ruby::printAddress(addr) << "\n"
385 << "\tAtomic Op's return value " << ret_val << "\n";
386
387 // print out basic info
388 warn("%s\n", ss.str());
389
390 // TODO add more detailed info
391
392 // dump all error info and exit the simulation
394 }
395}
396
397void
399{
400 if (ret_val != addrManager->getLoggedValue(loc)) {
401 std::stringstream ss;
403
404 // basic info
405 ss << threadName << ": Loaded value is not consistent with "
406 << "the last stored value\n"
407 << "\tTesterThread " << threadId << "\n"
408 << "\tEpisode " << curEpisode->getEpisodeId() << "\n"
409 << "\tLane ID " << lane << "\n"
410 << "\tAddress " << ruby::printAddress(addr) << "\n"
411 << "\tLoaded value " << ret_val << "\n"
412 << "\tLast writer " << addrManager->printLastWriter(loc) << "\n";
413
414 // print out basic info
415 warn("%s\n", ss.str());
416
417 // TODO add more detailed info
418
419 // dump all error info and exit the simulation
421 }
422}
423
424bool
425TesterThread::checkDRF(Location atomic_loc, Location loc, bool isStore) const
426{
428 // check against the current episode this thread is executing
429 return curEpisode->checkDRF(atomic_loc, loc, isStore, numLanes);
430 }
431
432 return true;
433}
434
435void
437{
439 // deadlock detected
440 std::stringstream ss;
441
442 ss << threadName << ": Deadlock detected\n"
443 << "\tLast active cycle: " << lastActiveCycle << "\n"
444 << "\tCurrent cycle: " << curCycle() << "\n"
445 << "\tDeadlock threshold: " << deadlockThreshold << "\n";
446
447 // print out basic info
448 warn("%s\n", ss.str());
449
450 // dump all error info and exit the simulation
452 } else if (!tester->checkExit()) {
453 // schedule a future deadlock check event
454 assert(!deadlockCheckEvent.scheduled());
457 }
458}
459
460void
462 std::stringstream& ss) const
463{
464 Cycles cur_cycle = curCycle();
465
466 for (const auto& m : table) {
467 for (const auto& req : m.second) {
468 ss << "\t\t\tAddr " << ruby::printAddress(m.first)
469 << ": delta (curCycle - issueCycle) = "
470 << (cur_cycle - req.issueCycle) << std::endl;
471 }
472 }
473}
474
475void
477{
478 // dump all outstanding requests of this thread
479 ss << "\t\tOutstanding Loads:\n";
481 ss << "\t\tOutstanding Stores:\n";
483 ss << "\t\tOutstanding Atomics:\n";
485 ss << "\t\tNumber of outstanding acquires & releases: "
486 << pendingFenceCount << std::endl;
487}
488
489} // 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:289
Type getType() const
Definition episode.hh:66
int getEpisodeId() const
Definition episode.hh:85
void completeEpisode()
Definition episode.cc:200
bool checkDRF(Location atomic_loc, Location loc, bool isStore, int max_lane) const
Definition episode.cc:240
bool hasMoreActions() const
Definition episode.hh:91
bool isEpsActive() const
Definition episode.hh:95
void popAction()
Definition episode.cc:86
const Action * peekCurAction() const
Definition episode.cc:77
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
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
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
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 Mon Jul 10 2023 15:32:02 for gem5 by doxygen 1.9.7