gem5  v21.1.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  * For use for simulation and test purposes only
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice,
11  * this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright notice,
14  * this list of conditions and the following disclaimer in the documentation
15  * and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the copyright holder nor the names of its
18  * contributors may be used to endorse or promote products derived from this
19  * software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
35 
36 #include <fstream>
37 
38 #include "debug/ProtocolTest.hh"
39 
40 namespace gem5
41 {
42 
44  : ClockedObject(p),
45  threadEvent(this, "TesterThread tick"),
46  deadlockCheckEvent(this),
47  threadId(p.thread_id),
48  numLanes(p.num_lanes),
49  tester(nullptr), addrManager(nullptr), port(nullptr),
50  scalarPort(nullptr), sqcPort(nullptr), curEpisode(nullptr),
51  curAction(nullptr), pendingLdStCount(0), pendingFenceCount(0),
52  pendingAtomicCount(0), lastActiveCycle(Cycles(0)),
53  deadlockThreshold(p.deadlock_threshold)
54 {
55 }
56 
58 {
59  for (auto ep : episodeHistory) {
60  assert(ep != nullptr);
61  delete ep;
62  }
63 }
64 
65 void
67 {
68  // this thread is waken up by one of the following events
69  // - hitCallback is called
70  // - a new episode is created
71 
72  // check if this is the first episode in this thread
73  if (curEpisode == nullptr) {
75  assert(curEpisode);
76  }
77 
78  if (isNextActionReady()) {
79  // isNextActionReady should check if the action list is empty
80  assert(curAction != nullptr);
81 
82  // issue the next action
84  } else {
85  // check for completion of the current episode
86  // completion = no outstanding requests + not having more actions
87  if (!curEpisode->hasMoreActions() &&
88  pendingLdStCount == 0 &&
89  pendingFenceCount == 0 &&
90  pendingAtomicCount == 0) {
91 
93 
94  // check if it's time to stop the tester
95  if (tester->checkExit()) {
96  // no more event is scheduled for this thread
97  return;
98  }
99 
100  // issue the next episode
101  issueNewEpisode();
102  assert(curEpisode);
103 
104  // now we get a new episode
105  // let's wake up the thread in the next cycle
106  if (!threadEvent.scheduled()) {
107  scheduleWakeup();
108  }
109  }
110  }
111 }
112 
113 void
115 {
116  assert(!threadEvent.scheduled());
118 }
119 
120 void
122 {
123  // after this first schedule, the deadlock event is scheduled by itself
124  assert(!deadlockCheckEvent.scheduled());
126 }
127 
128 void
131  ProtocolTester::GMTokenPort *_tokenPort,
132  ProtocolTester::SeqPort *_scalarPort,
133  ProtocolTester::SeqPort *_sqcPort)
134 {
135  tester = _tester;
136  port = _port;
137  tokenPort = _tokenPort;
138  scalarPort = _scalarPort;
139  sqcPort = _sqcPort;
140 
141  assert(tester && port);
143  assert(addrManager);
144 }
145 
146 void
148 {
149  int num_reg_loads = random() % 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 
157 bool
159 {
160  if (!curEpisode->hasMoreActions()) {
161  return false;
162  } else {
164 
165  // Only GPU wavefront threads have a token port. For all other types
166  // of threads evaluate to true.
167  bool haveTokens = tokenPort ? tokenPort->haveTokens(numLanes) : true;
168 
169  switch(curAction->getType()) {
171  // an atomic action must wait for all previous requests
172  // to complete
173  if (pendingLdStCount == 0 &&
174  pendingFenceCount == 0 &&
175  pendingAtomicCount == 0 &&
176  haveTokens) {
177  return true;
178  }
179 
180  return false;
182  // we should not see any outstanding ld_st or fence here
183  assert(pendingLdStCount == 0 &&
184  pendingFenceCount == 0);
185 
186  // an acquire action must wait for all previous atomic
187  // requests to complete
188  if (pendingAtomicCount == 0) {
189  return true;
190  }
191 
192  return false;
194  // we should not see any outstanding atomic or fence here
195  assert(pendingAtomicCount == 0 &&
196  pendingFenceCount == 0);
197 
198  // a release action must wait for all previous ld/st
199  // requests to complete
200  if (pendingLdStCount == 0) {
201  return true;
202  }
203 
204  return false;
207  // we should not see any outstanding atomic here
208  assert(pendingAtomicCount == 0);
209 
210  // can't issue if there is a pending fence
211  if (pendingFenceCount > 0 || !haveTokens) {
212  return false;
213  }
214 
215  // a Load or Store is ready if it doesn't overlap
216  // with any outstanding request
217  for (int lane = 0; lane < numLanes; ++lane) {
218  Location loc = curAction->getLocation(lane);
219 
222 
223  if (outstandingLoads.find(addr) !=
224  outstandingLoads.end()) {
225  return false;
226  }
227 
228  if (outstandingStores.find(addr) !=
229  outstandingStores.end()) {
230  return false;
231  }
232 
233  if (outstandingAtomics.find(addr) !=
234  outstandingAtomics.end()) {
235  // this is not an atomic action, so the address
236  // should not be in outstandingAtomics list
237  assert(false);
238  }
239  }
240  }
241 
242  return true;
243  default:
244  panic("The tester got an invalid action\n");
245  }
246  }
247 }
248 
249 void
251 {
252  switch(curAction->getType()) {
254  if (tokenPort) {
256  }
257  issueAtomicOps();
258  break;
260  issueAcquireOp();
261  break;
263  issueReleaseOp();
264  break;
266  if (tokenPort) {
268  }
269  issueLoadOps();
270  break;
272  if (tokenPort) {
274  }
275  issueStoreOps();
276  break;
277  default:
278  panic("The tester got an invalid action\n");
279  }
280 
281  // the current action has been issued, pop it from the action list
284 
285  // we may be able to schedule the next action
286  // just wake up this thread in the next cycle
287  if (!threadEvent.scheduled()) {
288  scheduleWakeup();
289  }
290 }
291 
292 void
294  int lane, Location loc, Value stored_val)
295 {
296  OutstandingReqTable::iterator it = req_table.find(address);
297  OutstandingReq req(lane, loc, stored_val, curCycle());
298 
299  if (it == req_table.end()) {
300  // insert a new list of requests for this address
301  req_table.insert(std::pair<Addr, OutstandingReqList>(address,
302  OutstandingReqList(1, req)));
303  } else {
304  // add a new request
305  (it->second).push_back(req);
306  }
307 }
308 
311 {
312  OutstandingReqTable::iterator it = req_table.find(addr);
313 
314  // there must be exactly one list of requests for this address in the table
315  assert(it != req_table.end());
316 
317  // get the request list
318  OutstandingReqList& req_list = it->second;
319  assert(!req_list.empty());
320 
321  // save a request
322  OutstandingReq ret_req = req_list.back();
323 
324  // remove the request from the list
325  req_list.pop_back();
326 
327  // if the list is now empty, remove it from req_table
328  if (req_list.empty()) {
329  req_table.erase(it);
330  }
331 
332  return ret_req;
333 }
334 
335 void
337 {
338  if (!addrManager->validateAtomicResp(loc, ret_val)) {
339  std::stringstream ss;
341 
342  // basic info
343  ss << threadName << ": Atomic Op returned unexpected value\n"
344  << "\tEpisode " << curEpisode->getEpisodeId() << "\n"
345  << "\tLane ID " << lane << "\n"
346  << "\tAddress " << ruby::printAddress(addr) << "\n"
347  << "\tAtomic Op's return value " << ret_val << "\n";
348 
349  // print out basic info
350  warn("%s\n", ss.str());
351 
352  // TODO add more detailed info
353 
354  // dump all error info and exit the simulation
356  }
357 }
358 
359 void
361 {
362  if (ret_val != addrManager->getLoggedValue(loc)) {
363  std::stringstream ss;
365 
366  // basic info
367  ss << threadName << ": Loaded value is not consistent with "
368  << "the last stored value\n"
369  << "\tTesterThread " << threadId << "\n"
370  << "\tEpisode " << curEpisode->getEpisodeId() << "\n"
371  << "\tLane ID " << lane << "\n"
372  << "\tAddress " << ruby::printAddress(addr) << "\n"
373  << "\tLoaded value " << ret_val << "\n"
374  << "\tLast writer " << addrManager->printLastWriter(loc) << "\n";
375 
376  // print out basic info
377  warn("%s\n", ss.str());
378 
379  // TODO add more detailed info
380 
381  // dump all error info and exit the simulation
383  }
384 }
385 
386 bool
387 TesterThread::checkDRF(Location atomic_loc, Location loc, bool isStore) const
388 {
389  if (curEpisode && curEpisode->isEpsActive()) {
390  // check against the current episode this thread is executing
391  return curEpisode->checkDRF(atomic_loc, loc, isStore, numLanes);
392  }
393 
394  return true;
395 }
396 
397 void
399 {
401  // deadlock detected
402  std::stringstream ss;
403 
404  ss << threadName << ": Deadlock detected\n"
405  << "\tLast active cycle: " << lastActiveCycle << "\n"
406  << "\tCurrent cycle: " << curCycle() << "\n"
407  << "\tDeadlock threshold: " << deadlockThreshold << "\n";
408 
409  // print out basic info
410  warn("%s\n", ss.str());
411 
412  // dump all error info and exit the simulation
414  } else if (!tester->checkExit()) {
415  // schedule a future deadlock check event
416  assert(!deadlockCheckEvent.scheduled());
419  }
420 }
421 
422 void
424  std::stringstream& ss) const
425 {
426  Cycles cur_cycle = curCycle();
427 
428  for (const auto& m : table) {
429  for (const auto& req : m.second) {
430  ss << "\t\t\tAddr " << ruby::printAddress(m.first)
431  << ": delta (curCycle - issueCycle) = "
432  << (cur_cycle - req.issueCycle) << std::endl;
433  }
434  }
435 }
436 
437 void
438 TesterThread::printAllOutstandingReqs(std::stringstream& ss) const
439 {
440  // dump all outstanding requests of this thread
441  ss << "\t\tOutstanding Loads:\n";
443  ss << "\t\tOutstanding Stores:\n";
445  ss << "\t\tOutstanding Atomics:\n";
447  ss << "\t\tNumber of outstanding acquires & releases: "
448  << pendingFenceCount << std::endl;
449 }
450 
451 } // namespace gem5
gem5::TesterThread::tokenPort
ProtocolTester::GMTokenPort * tokenPort
Definition: tester_thread.hh:149
gem5::TesterThread::Params
TesterThreadParams Params
Definition: tester_thread.hh:54
gem5::curTick
Tick curTick()
The universal simulation clock.
Definition: cur_tick.hh:46
gem5::TesterThread::deadlockCheckEvent
DeadlockCheckEvent deadlockCheckEvent
Definition: tester_thread.hh:120
warn
#define warn(...)
Definition: logging.hh:245
gem5::TesterThread::isNextActionReady
bool isNextActionReady()
Definition: tester_thread.cc:158
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:93
gem5::TesterThread::issueAtomicOps
virtual void issueAtomicOps()=0
gem5::TesterThread::checkDeadlock
void checkDeadlock()
Definition: tester_thread.cc:398
gem5::TesterThread::port
ProtocolTester::SeqPort * port
Definition: tester_thread.hh:148
gem5::TesterThread::issueReleaseOp
virtual void issueReleaseOp()=0
gem5::TesterThread::curAction
const Episode::Action * curAction
Definition: tester_thread.hh:160
gem5::Episode::Action::getType
Type getType() const
Definition: episode.hh:68
gem5::TesterThread::pendingAtomicCount
int pendingAtomicCount
Definition: tester_thread.hh:165
gem5::TesterThread::issueNextAction
void issueNextAction()
Definition: tester_thread.cc:250
gem5::TesterThread::pendingFenceCount
int pendingFenceCount
Definition: tester_thread.hh:164
gem5::TesterThread::outstandingAtomics
OutstandingReqTable outstandingAtomics
Definition: tester_thread.hh:176
gem5::MipsISA::random
random
Definition: pra_constants.hh:53
gem5::AddressManager::validateAtomicResp
bool validateAtomicResp(Location loc, Value ret_val)
Definition: address_manager.cc:430
gem5::TesterThread::threadEvent
TesterThreadEvent threadEvent
Definition: tester_thread.hh:100
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:168
gem5::ProtocolTester::SeqPort
Definition: protocol_tester.hh:74
gem5::TesterThread::pendingLdStCount
int pendingLdStCount
Definition: tester_thread.hh:163
gem5::TesterThread::issueStoreOps
virtual void issueStoreOps()=0
gem5::TesterThread::episodeHistory
EpisodeHistory episodeHistory
Definition: tester_thread.hh:156
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:202
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:129
gem5::MipsISA::ep
Bitfield< 1 > ep
Definition: pra_constants.hh:246
gem5::ProtocolTester::getEpisodeLength
int getEpisodeLength() const
Definition: protocol_tester.hh:128
gem5::TokenRequestPort::haveTokens
bool haveTokens(int num_tokens)
Query if there are at least num_tokens tokens available to acquire.
Definition: token_port.cc:58
gem5::TesterThread::outstandingStores
OutstandingReqTable outstandingStores
Definition: tester_thread.hh:175
gem5::TesterThread::popOutstandingReq
OutstandingReq popOutstandingReq(OutstandingReqTable &req_table, Addr address)
Definition: tester_thread.cc:310
gem5::Episode::peekCurAction
const Action * peekCurAction() const
Definition: episode.cc:79
gem5::TesterThread::threadId
int threadId
Definition: tester_thread.hh:138
gem5::TesterThread::numLanes
int numLanes
Definition: tester_thread.hh:140
gem5::MipsISA::p
Bitfield< 0 > p
Definition: pra_constants.hh:326
gem5::TesterThread::validateLoadResp
void validateLoadResp(Location loc, int lane, Value ret_val)
Definition: tester_thread.cc:360
gem5::ProtocolTester
Definition: protocol_tester.hh:71
gem5::TesterThread::issueAcquireOp
virtual void issueAcquireOp()=0
tester_thread.hh
gem5::TesterThread::sqcPort
ProtocolTester::SeqPort * sqcPort
Definition: tester_thread.hh:151
gem5::TokenRequestPort::acquireTokens
void acquireTokens(int num_tokens)
Acquire tokens by decrementing the number of available tokens across the port.
Definition: token_port.cc:66
gem5::ProtocolTester::checkExit
bool checkExit()
Definition: protocol_tester.cc:284
gem5::Episode::Action::Type::ATOMIC
@ ATOMIC
gem5::Episode::Action::Type::RELEASE
@ RELEASE
gem5::TesterThread::OutstandingReqList
std::vector< OutstandingReq > OutstandingReqList
Definition: tester_thread.hh:172
ss
std::stringstream ss
Definition: trace.test.cc:45
gem5::ProtocolTester::dumpErrorLog
void dumpErrorLog(std::stringstream &ss)
Definition: protocol_tester.cc:324
std::pair
STL pair class.
Definition: stl.hh:58
gem5::Episode::Action::getLocation
Location getLocation(int lane) const
Definition: episode.cc:291
gem5::TesterThread::printOutstandingReqs
void printOutstandingReqs(const OutstandingReqTable &table, std::stringstream &ss) const
Definition: tester_thread.cc:423
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:58
gem5::TesterThread::addrManager
AddressManager * addrManager
Definition: tester_thread.hh:146
gem5::TesterThread::scalarPort
ProtocolTester::SeqPort * scalarPort
Definition: tester_thread.hh:150
gem5::AddressManager::INVALID_LOCATION
static const int INVALID_LOCATION
Definition: address_manager.hh:154
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:293
gem5::TesterThread::outstandingLoads
OutstandingReqTable outstandingLoads
Definition: tester_thread.hh:174
gem5::TesterThread::wakeup
void wakeup()
Definition: tester_thread.cc:66
gem5::TesterThread::scheduleDeadlockCheckEvent
void scheduleDeadlockCheckEvent()
Definition: tester_thread.cc:121
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:97
gem5::TesterThread::~TesterThread
virtual ~TesterThread()
Definition: tester_thread.cc:57
gem5::ProtocolTester::GMTokenPort
Definition: protocol_tester.hh:88
gem5::ArmISA::m
Bitfield< 0 > m
Definition: misc_types.hh:394
gem5::Episode::Action::Type::ACQUIRE
@ ACQUIRE
gem5::TesterThread::curEpisode
Episode * curEpisode
Definition: tester_thread.hh:158
gem5::TesterThread::issueNewEpisode
void issueNewEpisode()
Definition: tester_thread.cc:147
gem5::TesterThread::printAllOutstandingReqs
void printAllOutstandingReqs(std::stringstream &ss) const
Definition: tester_thread.cc:438
gem5::Episode::checkDRF
bool checkDRF(Location atomic_loc, Location loc, bool isStore, int max_lane) const
Definition: episode.cc:242
gem5::Episode::getEpisodeId
int getEpisodeId() const
Definition: episode.hh:87
gem5::TesterThread::deadlockThreshold
Cycles deadlockThreshold
Definition: tester_thread.hh:169
gem5::TesterThread::checkDRF
bool checkDRF(Location atomic_loc, Location loc, bool isStore) const
Definition: tester_thread.cc:387
gem5::ProtocolTester::getAddressManager
AddressManager * getAddressManager() const
Definition: protocol_tester.hh:130
gem5::TesterThread::validateAtomicResp
void validateAtomicResp(Location loc, int lane, Value ret_val)
Definition: tester_thread.cc:336
gem5
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
Definition: decoder.cc:40
gem5::AddressManager::getLoggedValue
Value getLoggedValue(Location loc) const
Definition: address_manager.cc:423
gem5::TesterThread::OutstandingReqTable
std::unordered_map< Addr, OutstandingReqList > OutstandingReqTable
Definition: tester_thread.hh:173
gem5::Episode::popAction
void popAction()
Definition: episode.cc:88
gem5::TesterThread::OutstandingReq
Definition: tester_thread.hh:122
gem5::TesterThread::tester
ProtocolTester * tester
Definition: tester_thread.hh:144
gem5::TesterThread::TesterThread
TesterThread(const Params &p)
Definition: tester_thread.cc:43
gem5::TesterThread::threadName
std::string threadName
Definition: tester_thread.hh:142
gem5::TesterThread::scheduleWakeup
void scheduleWakeup()
Definition: tester_thread.cc:114
gem5::TesterThread::Value
AddressManager::Value Value
Definition: tester_thread.hh:59
gem5::Episode::Action::Type::LOAD
@ LOAD
gem5::Episode
Definition: episode.hh:47
gem5::AddressManager::printLastWriter
std::string printLastWriter(Location loc) const
Definition: address_manager.cc:133
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:177
gem5::AddressManager::getAddress
Addr getAddress(Location loc)
Definition: address_manager.cc:90
gem5::Clocked::clockPeriod
Tick clockPeriod() const
Definition: clocked_object.hh:217
gem5::X86ISA::addr
Bitfield< 3 > addr
Definition: types.hh:84

Generated on Tue Sep 21 2021 12:25:09 for gem5 by doxygen 1.8.17