gem5  v21.2.0.0
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 
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 bool
157 {
158  if (!curEpisode->hasMoreActions()) {
159  return false;
160  } else {
162 
163  // Only GPU wavefront threads have a token port. For all other types
164  // of threads evaluate to true.
165  bool haveTokens = tokenPort ? tokenPort->haveTokens(numLanes) : true;
166 
167  switch(curAction->getType()) {
169  // an atomic action must wait for all previous requests
170  // to complete
171  if (pendingLdStCount == 0 &&
172  pendingFenceCount == 0 &&
173  pendingAtomicCount == 0 &&
174  haveTokens) {
175  return true;
176  }
177 
178  return false;
180  // we should not see any outstanding ld_st or fence here
181  assert(pendingLdStCount == 0 &&
182  pendingFenceCount == 0);
183 
184  // an acquire action must wait for all previous atomic
185  // requests to complete
186  if (pendingAtomicCount == 0) {
187  return true;
188  }
189 
190  return false;
192  // we should not see any outstanding atomic or fence here
193  assert(pendingAtomicCount == 0 &&
194  pendingFenceCount == 0);
195 
196  // a release action must wait for all previous ld/st
197  // requests to complete
198  if (pendingLdStCount == 0) {
199  return true;
200  }
201 
202  return false;
205  // we should not see any outstanding atomic here
206  assert(pendingAtomicCount == 0);
207 
208  // can't issue if there is a pending fence
209  if (pendingFenceCount > 0 || !haveTokens) {
210  return false;
211  }
212 
213  // a Load or Store is ready if it doesn't overlap
214  // with any outstanding request
215  for (int lane = 0; lane < numLanes; ++lane) {
216  Location loc = curAction->getLocation(lane);
217 
220 
221  if (outstandingLoads.find(addr) !=
222  outstandingLoads.end()) {
223  return false;
224  }
225 
226  if (outstandingStores.find(addr) !=
227  outstandingStores.end()) {
228  return false;
229  }
230 
231  if (outstandingAtomics.find(addr) !=
232  outstandingAtomics.end()) {
233  // this is not an atomic action, so the address
234  // should not be in outstandingAtomics list
235  assert(false);
236  }
237  }
238  }
239 
240  return true;
241  default:
242  panic("The tester got an invalid action\n");
243  }
244  }
245 }
246 
247 void
249 {
250  switch(curAction->getType()) {
252  if (tokenPort) {
254  }
255  issueAtomicOps();
256  break;
258  issueAcquireOp();
259  break;
261  issueReleaseOp();
262  break;
264  if (tokenPort) {
266  }
267  issueLoadOps();
268  break;
270  if (tokenPort) {
272  }
273  issueStoreOps();
274  break;
275  default:
276  panic("The tester got an invalid action\n");
277  }
278 
279  // the current action has been issued, pop it from the action list
282 
283  // we may be able to schedule the next action
284  // just wake up this thread in the next cycle
285  if (!threadEvent.scheduled()) {
286  scheduleWakeup();
287  }
288 }
289 
290 void
292  int lane, Location loc, Value stored_val)
293 {
294  OutstandingReqTable::iterator it = req_table.find(address);
295  OutstandingReq req(lane, loc, stored_val, curCycle());
296 
297  if (it == req_table.end()) {
298  // insert a new list of requests for this address
299  req_table.insert(std::pair<Addr, OutstandingReqList>(address,
300  OutstandingReqList(1, req)));
301  } else {
302  // add a new request
303  (it->second).push_back(req);
304  }
305 }
306 
309 {
310  OutstandingReqTable::iterator it = req_table.find(addr);
311 
312  // there must be exactly one list of requests for this address in the table
313  assert(it != req_table.end());
314 
315  // get the request list
316  OutstandingReqList& req_list = it->second;
317  assert(!req_list.empty());
318 
319  // save a request
320  OutstandingReq ret_req = req_list.back();
321 
322  // remove the request from the list
323  req_list.pop_back();
324 
325  // if the list is now empty, remove it from req_table
326  if (req_list.empty()) {
327  req_table.erase(it);
328  }
329 
330  return ret_req;
331 }
332 
333 void
335 {
336  if (!addrManager->validateAtomicResp(loc, ret_val)) {
337  std::stringstream ss;
339 
340  // basic info
341  ss << threadName << ": Atomic Op returned unexpected value\n"
342  << "\tEpisode " << curEpisode->getEpisodeId() << "\n"
343  << "\tLane ID " << lane << "\n"
344  << "\tAddress " << ruby::printAddress(addr) << "\n"
345  << "\tAtomic Op's return value " << ret_val << "\n";
346 
347  // print out basic info
348  warn("%s\n", ss.str());
349 
350  // TODO add more detailed info
351 
352  // dump all error info and exit the simulation
354  }
355 }
356 
357 void
359 {
360  if (ret_val != addrManager->getLoggedValue(loc)) {
361  std::stringstream ss;
363 
364  // basic info
365  ss << threadName << ": Loaded value is not consistent with "
366  << "the last stored value\n"
367  << "\tTesterThread " << threadId << "\n"
368  << "\tEpisode " << curEpisode->getEpisodeId() << "\n"
369  << "\tLane ID " << lane << "\n"
370  << "\tAddress " << ruby::printAddress(addr) << "\n"
371  << "\tLoaded value " << ret_val << "\n"
372  << "\tLast writer " << addrManager->printLastWriter(loc) << "\n";
373 
374  // print out basic info
375  warn("%s\n", ss.str());
376 
377  // TODO add more detailed info
378 
379  // dump all error info and exit the simulation
381  }
382 }
383 
384 bool
385 TesterThread::checkDRF(Location atomic_loc, Location loc, bool isStore) const
386 {
387  if (curEpisode && curEpisode->isEpsActive()) {
388  // check against the current episode this thread is executing
389  return curEpisode->checkDRF(atomic_loc, loc, isStore, numLanes);
390  }
391 
392  return true;
393 }
394 
395 void
397 {
399  // deadlock detected
400  std::stringstream ss;
401 
402  ss << threadName << ": Deadlock detected\n"
403  << "\tLast active cycle: " << lastActiveCycle << "\n"
404  << "\tCurrent cycle: " << curCycle() << "\n"
405  << "\tDeadlock threshold: " << deadlockThreshold << "\n";
406 
407  // print out basic info
408  warn("%s\n", ss.str());
409 
410  // dump all error info and exit the simulation
412  } else if (!tester->checkExit()) {
413  // schedule a future deadlock check event
414  assert(!deadlockCheckEvent.scheduled());
417  }
418 }
419 
420 void
422  std::stringstream& ss) const
423 {
424  Cycles cur_cycle = curCycle();
425 
426  for (const auto& m : table) {
427  for (const auto& req : m.second) {
428  ss << "\t\t\tAddr " << ruby::printAddress(m.first)
429  << ": delta (curCycle - issueCycle) = "
430  << (cur_cycle - req.issueCycle) << std::endl;
431  }
432  }
433 }
434 
435 void
436 TesterThread::printAllOutstandingReqs(std::stringstream& ss) const
437 {
438  // dump all outstanding requests of this thread
439  ss << "\t\tOutstanding Loads:\n";
441  ss << "\t\tOutstanding Stores:\n";
443  ss << "\t\tOutstanding Atomics:\n";
445  ss << "\t\tNumber of outstanding acquires & releases: "
446  << pendingFenceCount << std::endl;
447 }
448 
449 } // 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:156
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:396
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:248
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:308
gem5::Episode::peekCurAction
const Action * peekCurAction() const
Definition: episode.cc:77
gem5::TesterThread::threadId
int threadId
Definition: tester_thread.hh:136
gem5::TesterThread::numLanes
int numLanes
Definition: tester_thread.hh:138
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:358
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:421
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:291
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::ArmISA::m
Bitfield< 0 > m
Definition: misc_types.hh:395
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:436
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:385
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:334
gem5
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
Definition: tlb.cc:60
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 Tue Dec 21 2021 11:34:27 for gem5 by doxygen 1.8.17