gem5  v22.0.0.2
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 
38 namespace gem5
39 {
40 
42  : ClockedObject(p),
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 
63 void
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()) {
105  scheduleWakeup();
106  }
107  }
108  }
109 }
110 
111 void
113 {
114  assert(!threadEvent.scheduled());
116 }
117 
118 void
120 {
121  // after this first schedule, the deadlock event is scheduled by itself
122  assert(!deadlockCheckEvent.scheduled());
124 }
125 
126 void
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 
144 void
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 
155 int
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 
186 bool
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 
287 void
289 {
290  switch(curAction->getType()) {
292  if (tokenPort) {
294  }
295  issueAtomicOps();
296  break;
298  issueAcquireOp();
299  break;
301  issueReleaseOp();
302  break;
304  if (tokenPort) {
306  }
307  issueLoadOps();
308  break;
310  if (tokenPort) {
312  }
313  issueStoreOps();
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()) {
326  scheduleWakeup();
327  }
328 }
329 
330 void
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 
373 void
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 
397 void
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 
424 bool
425 TesterThread::checkDRF(Location atomic_loc, Location loc, bool isStore) const
426 {
427  if (curEpisode && curEpisode->isEpsActive()) {
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 
435 void
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 
460 void
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 
475 void
476 TesterThread::printAllOutstandingReqs(std::stringstream& ss) const
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
gem5::TesterThread::tokenPort
ProtocolTester::GMTokenPort * tokenPort
Definition: tester_thread.hh:147
gem5::TesterThread::Params
TesterThreadParams Params
Definition: tester_thread.hh:52
gem5::curTick
Tick curTick()
The universal simulation clock.
Definition: cur_tick.hh:46
gem5::TesterThread::deadlockCheckEvent
DeadlockCheckEvent deadlockCheckEvent
Definition: tester_thread.hh:118
warn
#define warn(...)
Definition: logging.hh:246
gem5::TesterThread::isNextActionReady
bool isNextActionReady()
Definition: tester_thread.cc:187
gem5::VegaISA::m
m
Definition: pagetable.hh:52
gem5::Clocked::curCycle
Cycles curCycle() const
Determine the current cycle, corresponding to a tick aligned to a clock edge.
Definition: clocked_object.hh:195
gem5::TesterThread::issueLoadOps
virtual void issueLoadOps()=0
gem5::ruby::printAddress
std::string printAddress(Addr addr)
Definition: Address.cc:80
gem5::Episode::Action::Type::STORE
@ STORE
gem5::Episode::hasMoreActions
bool hasMoreActions() const
Definition: episode.hh:91
gem5::TesterThread::issueAtomicOps
virtual void issueAtomicOps()=0
gem5::TesterThread::checkDeadlock
void checkDeadlock()
Definition: tester_thread.cc:436
gem5::TesterThread::port
ProtocolTester::SeqPort * port
Definition: tester_thread.hh:146
gem5::TesterThread::issueReleaseOp
virtual void issueReleaseOp()=0
gem5::TesterThread::curAction
const Episode::Action * curAction
Definition: tester_thread.hh:158
gem5::Episode::Action::getType
Type getType() const
Definition: episode.hh:66
gem5::TesterThread::pendingAtomicCount
int pendingAtomicCount
Definition: tester_thread.hh:163
gem5::TesterThread::issueNextAction
void issueNextAction()
Definition: tester_thread.cc:288
gem5::TesterThread::pendingFenceCount
int pendingFenceCount
Definition: tester_thread.hh:162
gem5::TesterThread::outstandingAtomics
OutstandingReqTable outstandingAtomics
Definition: tester_thread.hh:174
gem5::MipsISA::random
random
Definition: pra_constants.hh:53
gem5::AddressManager::validateAtomicResp
bool validateAtomicResp(Location loc, Value ret_val)
Definition: address_manager.cc:428
gem5::TesterThread::threadEvent
TesterThreadEvent threadEvent
Definition: tester_thread.hh:98
gem5::EventManager::schedule
void schedule(Event &event, Tick when)
Definition: eventq.hh:1019
std::vector
STL vector class.
Definition: stl.hh:37
gem5::TesterThread::lastActiveCycle
Cycles lastActiveCycle
Definition: tester_thread.hh:166
gem5::ProtocolTester::SeqPort
Definition: protocol_tester.hh:72
gem5::TesterThread::pendingLdStCount
int pendingLdStCount
Definition: tester_thread.hh:161
gem5::TesterThread::issueStoreOps
virtual void issueStoreOps()=0
gem5::TesterThread::episodeHistory
EpisodeHistory episodeHistory
Definition: tester_thread.hh:154
gem5::Cycles
Cycles is a wrapper class for representing cycle counts, i.e.
Definition: types.hh:78
gem5::Episode::completeEpisode
void completeEpisode()
Definition: episode.cc:200
gem5::TesterThread::attachTesterThreadToPorts
void attachTesterThreadToPorts(ProtocolTester *_tester, ProtocolTester::SeqPort *_port, ProtocolTester::GMTokenPort *_tokenPort=nullptr, ProtocolTester::SeqPort *_sqcPort=nullptr, ProtocolTester::SeqPort *_scalarPort=nullptr)
Definition: tester_thread.cc:127
gem5::MipsISA::ep
Bitfield< 1 > ep
Definition: pra_constants.hh:246
gem5::ProtocolTester::getEpisodeLength
int getEpisodeLength() const
Definition: protocol_tester.hh:126
gem5::TokenRequestPort::haveTokens
bool haveTokens(int num_tokens)
Query if there are at least num_tokens tokens available to acquire.
Definition: token_port.cc:56
gem5::TesterThread::outstandingStores
OutstandingReqTable outstandingStores
Definition: tester_thread.hh:173
gem5::TesterThread::popOutstandingReq
OutstandingReq popOutstandingReq(OutstandingReqTable &req_table, Addr address)
Definition: tester_thread.cc:348
gem5::Episode::peekCurAction
const Action * peekCurAction() const
Definition: episode.cc:77
gem5::VegaISA::p
Bitfield< 54 > p
Definition: pagetable.hh:70
gem5::TesterThread::threadId
int threadId
Definition: tester_thread.hh:136
gem5::TesterThread::numLanes
int numLanes
Definition: tester_thread.hh:138
gem5::TesterThread::validateLoadResp
void validateLoadResp(Location loc, int lane, Value ret_val)
Definition: tester_thread.cc:398
gem5::ProtocolTester
Definition: protocol_tester.hh:69
gem5::TesterThread::issueAcquireOp
virtual void issueAcquireOp()=0
tester_thread.hh
gem5::TesterThread::sqcPort
ProtocolTester::SeqPort * sqcPort
Definition: tester_thread.hh:149
gem5::TokenRequestPort::acquireTokens
void acquireTokens(int num_tokens)
Acquire tokens by decrementing the number of available tokens across the port.
Definition: token_port.cc:64
gem5::ProtocolTester::checkExit
bool checkExit()
Definition: protocol_tester.cc:282
gem5::Episode::Action::Type::ATOMIC
@ ATOMIC
gem5::Episode::Action::Type::RELEASE
@ RELEASE
gem5::TesterThread::OutstandingReqList
std::vector< OutstandingReq > OutstandingReqList
Definition: tester_thread.hh:170
ss
std::stringstream ss
Definition: trace.test.cc:45
gem5::ProtocolTester::dumpErrorLog
void dumpErrorLog(std::stringstream &ss)
Definition: protocol_tester.cc:322
std::pair
STL pair class.
Definition: stl.hh:58
gem5::Episode::Action::getLocation
Location getLocation(int lane) const
Definition: episode.cc:289
gem5::TesterThread::printOutstandingReqs
void printOutstandingReqs(const OutstandingReqTable &table, std::stringstream &ss) const
Definition: tester_thread.cc:461
gem5::Addr
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:147
gem5::TesterThread::Location
AddressManager::Location Location
Definition: tester_thread.hh:56
gem5::TesterThread::addrManager
AddressManager * addrManager
Definition: tester_thread.hh:144
gem5::TesterThread::scalarPort
ProtocolTester::SeqPort * scalarPort
Definition: tester_thread.hh:148
gem5::AddressManager::INVALID_LOCATION
static const int INVALID_LOCATION
Definition: address_manager.hh:152
gem5::ClockedObject
The ClockedObject class extends the SimObject with a clock and accessor functions to relate ticks to ...
Definition: clocked_object.hh:234
gem5::TesterThread::addOutstandingReqs
void addOutstandingReqs(OutstandingReqTable &req_table, Addr addr, int lane, Location loc, Value stored_val=AddressManager::INVALID_VALUE)
Definition: tester_thread.cc:331
gem5::TesterThread::outstandingLoads
OutstandingReqTable outstandingLoads
Definition: tester_thread.hh:172
gem5::TesterThread::wakeup
void wakeup()
Definition: tester_thread.cc:64
gem5::TesterThread::scheduleDeadlockCheckEvent
void scheduleDeadlockCheckEvent()
Definition: tester_thread.cc:119
gem5::Clocked::nextCycle
Tick nextCycle() const
Based on the clock of the object, determine the start tick of the first cycle that is at least one cy...
Definition: clocked_object.hh:213
gem5::Episode::isEpsActive
bool isEpsActive() const
Definition: episode.hh:95
gem5::TesterThread::~TesterThread
virtual ~TesterThread()
Definition: tester_thread.cc:55
gem5::ProtocolTester::GMTokenPort
Definition: protocol_tester.hh:86
gem5::TesterThread::getTokensNeeded
int getTokensNeeded()
Definition: tester_thread.cc:156
gem5::Episode::Action::Type::ACQUIRE
@ ACQUIRE
gem5::TesterThread::curEpisode
Episode * curEpisode
Definition: tester_thread.hh:156
gem5::TesterThread::issueNewEpisode
void issueNewEpisode()
Definition: tester_thread.cc:145
gem5::TesterThread::printAllOutstandingReqs
void printAllOutstandingReqs(std::stringstream &ss) const
Definition: tester_thread.cc:476
gem5::Episode::checkDRF
bool checkDRF(Location atomic_loc, Location loc, bool isStore, int max_lane) const
Definition: episode.cc:240
gem5::Episode::getEpisodeId
int getEpisodeId() const
Definition: episode.hh:85
gem5::TesterThread::deadlockThreshold
Cycles deadlockThreshold
Definition: tester_thread.hh:167
gem5::TesterThread::checkDRF
bool checkDRF(Location atomic_loc, Location loc, bool isStore) const
Definition: tester_thread.cc:425
gem5::ProtocolTester::getAddressManager
AddressManager * getAddressManager() const
Definition: protocol_tester.hh:128
gem5::TesterThread::validateAtomicResp
void validateAtomicResp(Location loc, int lane, Value ret_val)
Definition: tester_thread.cc:374
gem5
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
Definition: gpu_translation_state.hh:37
gem5::AddressManager::getLoggedValue
Value getLoggedValue(Location loc) const
Definition: address_manager.cc:421
gem5::TesterThread::OutstandingReqTable
std::unordered_map< Addr, OutstandingReqList > OutstandingReqTable
Definition: tester_thread.hh:171
gem5::Episode::popAction
void popAction()
Definition: episode.cc:86
gem5::TesterThread::OutstandingReq
Definition: tester_thread.hh:120
gem5::TesterThread::tester
ProtocolTester * tester
Definition: tester_thread.hh:142
gem5::TesterThread::TesterThread
TesterThread(const Params &p)
Definition: tester_thread.cc:41
gem5::TesterThread::threadName
std::string threadName
Definition: tester_thread.hh:140
gem5::TesterThread::scheduleWakeup
void scheduleWakeup()
Definition: tester_thread.cc:112
gem5::TesterThread::Value
AddressManager::Value Value
Definition: tester_thread.hh:57
gem5::Episode::Action::Type::LOAD
@ LOAD
gem5::Episode
Definition: episode.hh:45
gem5::AddressManager::printLastWriter
std::string printLastWriter(Location loc) const
Definition: address_manager.cc:131
gem5::Event::scheduled
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:465
panic
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:178
gem5::AddressManager::getAddress
Addr getAddress(Location loc)
Definition: address_manager.cc:88
gem5::Clocked::clockPeriod
Tick clockPeriod() const
Definition: clocked_object.hh:217
gem5::X86ISA::addr
Bitfield< 3 > addr
Definition: types.hh:84

Generated on Thu Jul 28 2022 13:32:29 for gem5 by doxygen 1.8.17