gem5  v21.0.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  * 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 
41  : ClockedObject(p),
42  threadEvent(this, "TesterThread tick"),
43  deadlockCheckEvent(this),
44  threadId(p.thread_id),
45  numLanes(p.num_lanes),
46  tester(nullptr), addrManager(nullptr), port(nullptr),
47  scalarPort(nullptr), sqcPort(nullptr), curEpisode(nullptr),
48  curAction(nullptr), pendingLdStCount(0), pendingFenceCount(0),
49  pendingAtomicCount(0), lastActiveCycle(Cycles(0)),
50  deadlockThreshold(p.deadlock_threshold)
51 {
52 }
53 
55 {
56  for (auto ep : episodeHistory) {
57  assert(ep != nullptr);
58  delete ep;
59  }
60 }
61 
62 void
64 {
65  // this thread is waken up by one of the following events
66  // - hitCallback is called
67  // - a new episode is created
68 
69  // check if this is the first episode in this thread
70  if (curEpisode == nullptr) {
72  assert(curEpisode);
73  }
74 
75  if (isNextActionReady()) {
76  // isNextActionReady should check if the action list is empty
77  assert(curAction != nullptr);
78 
79  // issue the next action
81  } else {
82  // check for completion of the current episode
83  // completion = no outstanding requests + not having more actions
84  if (!curEpisode->hasMoreActions() &&
85  pendingLdStCount == 0 &&
86  pendingFenceCount == 0 &&
87  pendingAtomicCount == 0) {
88 
90 
91  // check if it's time to stop the tester
92  if (tester->checkExit()) {
93  // no more event is scheduled for this thread
94  return;
95  }
96 
97  // issue the next episode
99  assert(curEpisode);
100 
101  // now we get a new episode
102  // let's wake up the thread in the next cycle
103  if (!threadEvent.scheduled()) {
104  scheduleWakeup();
105  }
106  }
107  }
108 }
109 
110 void
112 {
113  assert(!threadEvent.scheduled());
115 }
116 
117 void
119 {
120  // after this first schedule, the deadlock event is scheduled by itself
121  assert(!deadlockCheckEvent.scheduled());
123 }
124 
125 void
128  ProtocolTester::GMTokenPort *_tokenPort,
129  ProtocolTester::SeqPort *_scalarPort,
130  ProtocolTester::SeqPort *_sqcPort)
131 {
132  tester = _tester;
133  port = _port;
134  tokenPort = _tokenPort;
135  scalarPort = _scalarPort;
136  sqcPort = _sqcPort;
137 
138  assert(tester && port);
140  assert(addrManager);
141 }
142 
143 void
145 {
146  int num_reg_loads = random() % tester->getEpisodeLength();
147  int num_reg_stores = tester->getEpisodeLength() - num_reg_loads;
148 
149  // create a new episode
150  curEpisode = new Episode(tester, this, num_reg_loads, num_reg_stores);
151  episodeHistory.push_back(curEpisode);
152 }
153 
154 bool
156 {
157  if (!curEpisode->hasMoreActions()) {
158  return false;
159  } else {
161 
162  // Only GPU wavefront threads have a token port. For all other types
163  // of threads evaluate to true.
164  bool haveTokens = tokenPort ? tokenPort->haveTokens(numLanes) : true;
165 
166  switch(curAction->getType()) {
168  // an atomic action must wait for all previous requests
169  // to complete
170  if (pendingLdStCount == 0 &&
171  pendingFenceCount == 0 &&
172  pendingAtomicCount == 0 &&
173  haveTokens) {
174  return true;
175  }
176 
177  return false;
179  // we should not see any outstanding ld_st or fence here
180  assert(pendingLdStCount == 0 &&
181  pendingFenceCount == 0);
182 
183  // an acquire action must wait for all previous atomic
184  // requests to complete
185  if (pendingAtomicCount == 0) {
186  return true;
187  }
188 
189  return false;
191  // we should not see any outstanding atomic or fence here
192  assert(pendingAtomicCount == 0 &&
193  pendingFenceCount == 0);
194 
195  // a release action must wait for all previous ld/st
196  // requests to complete
197  if (pendingLdStCount == 0) {
198  return true;
199  }
200 
201  return false;
204  // we should not see any outstanding atomic here
205  assert(pendingAtomicCount == 0);
206 
207  // can't issue if there is a pending fence
208  if (pendingFenceCount > 0 || !haveTokens) {
209  return false;
210  }
211 
212  // a Load or Store is ready if it doesn't overlap
213  // with any outstanding request
214  for (int lane = 0; lane < numLanes; ++lane) {
215  Location loc = curAction->getLocation(lane);
216 
219 
220  if (outstandingLoads.find(addr) !=
221  outstandingLoads.end()) {
222  return false;
223  }
224 
225  if (outstandingStores.find(addr) !=
226  outstandingStores.end()) {
227  return false;
228  }
229 
230  if (outstandingAtomics.find(addr) !=
231  outstandingAtomics.end()) {
232  // this is not an atomic action, so the address
233  // should not be in outstandingAtomics list
234  assert(false);
235  }
236  }
237  }
238 
239  return true;
240  default:
241  panic("The tester got an invalid action\n");
242  }
243  }
244 }
245 
246 void
248 {
249  switch(curAction->getType()) {
251  if (tokenPort) {
253  }
254  issueAtomicOps();
255  break;
257  issueAcquireOp();
258  break;
260  issueReleaseOp();
261  break;
263  if (tokenPort) {
265  }
266  issueLoadOps();
267  break;
269  if (tokenPort) {
271  }
272  issueStoreOps();
273  break;
274  default:
275  panic("The tester got an invalid action\n");
276  }
277 
278  // the current action has been issued, pop it from the action list
281 
282  // we may be able to schedule the next action
283  // just wake up this thread in the next cycle
284  if (!threadEvent.scheduled()) {
285  scheduleWakeup();
286  }
287 }
288 
289 void
291  int lane, Location loc, Value stored_val)
292 {
293  OutstandingReqTable::iterator it = req_table.find(address);
294  OutstandingReq req(lane, loc, stored_val, curCycle());
295 
296  if (it == req_table.end()) {
297  // insert a new list of requests for this address
298  req_table.insert(std::pair<Addr, OutstandingReqList>(address,
299  OutstandingReqList(1, req)));
300  } else {
301  // add a new request
302  (it->second).push_back(req);
303  }
304 }
305 
308 {
309  OutstandingReqTable::iterator it = req_table.find(addr);
310 
311  // there must be exactly one list of requests for this address in the table
312  assert(it != req_table.end());
313 
314  // get the request list
315  OutstandingReqList& req_list = it->second;
316  assert(!req_list.empty());
317 
318  // save a request
319  OutstandingReq ret_req = req_list.back();
320 
321  // remove the request from the list
322  req_list.pop_back();
323 
324  // if the list is now empty, remove it from req_table
325  if (req_list.empty()) {
326  req_table.erase(it);
327  }
328 
329  return ret_req;
330 }
331 
332 void
334 {
335  if (!addrManager->validateAtomicResp(loc, ret_val)) {
336  std::stringstream ss;
338 
339  // basic info
340  ss << threadName << ": Atomic Op returned unexpected value\n"
341  << "\tEpisode " << curEpisode->getEpisodeId() << "\n"
342  << "\tLane ID " << lane << "\n"
343  << "\tAddress " << printAddress(addr) << "\n"
344  << "\tAtomic Op's return value " << ret_val << "\n";
345 
346  // print out basic info
347  warn("%s\n", ss.str());
348 
349  // TODO add more detailed info
350 
351  // dump all error info and exit the simulation
353  }
354 }
355 
356 void
358 {
359  if (ret_val != addrManager->getLoggedValue(loc)) {
360  std::stringstream ss;
362 
363  // basic info
364  ss << threadName << ": Loaded value is not consistent with "
365  << "the last stored value\n"
366  << "\tTesterThread " << threadId << "\n"
367  << "\tEpisode " << curEpisode->getEpisodeId() << "\n"
368  << "\tLane ID " << lane << "\n"
369  << "\tAddress " << printAddress(addr) << "\n"
370  << "\tLoaded value " << ret_val << "\n"
371  << "\tLast writer " << addrManager->printLastWriter(loc) << "\n";
372 
373  // print out basic info
374  warn("%s\n", ss.str());
375 
376  // TODO add more detailed info
377 
378  // dump all error info and exit the simulation
380  }
381 }
382 
383 bool
384 TesterThread::checkDRF(Location atomic_loc, Location loc, bool isStore) const
385 {
386  if (curEpisode && curEpisode->isEpsActive()) {
387  // check against the current episode this thread is executing
388  return curEpisode->checkDRF(atomic_loc, loc, isStore, numLanes);
389  }
390 
391  return true;
392 }
393 
394 void
396 {
398  // deadlock detected
399  std::stringstream ss;
400 
401  ss << threadName << ": Deadlock detected\n"
402  << "\tLast active cycle: " << lastActiveCycle << "\n"
403  << "\tCurrent cycle: " << curCycle() << "\n"
404  << "\tDeadlock threshold: " << deadlockThreshold << "\n";
405 
406  // print out basic info
407  warn("%s\n", ss.str());
408 
409  // dump all error info and exit the simulation
411  } else if (!tester->checkExit()) {
412  // schedule a future deadlock check event
413  assert(!deadlockCheckEvent.scheduled());
416  }
417 }
418 
419 void
421  std::stringstream& ss) const
422 {
423  Cycles cur_cycle = curCycle();
424 
425  for (const auto& m : table) {
426  for (const auto& req : m.second) {
427  ss << "\t\t\tAddr " << printAddress(m.first)
428  << ": delta (curCycle - issueCycle) = "
429  << (cur_cycle - req.issueCycle) << std::endl;
430  }
431  }
432 }
433 
434 void
435 TesterThread::printAllOutstandingReqs(std::stringstream& ss) const
436 {
437  // dump all outstanding requests of this thread
438  ss << "\t\tOutstanding Loads:\n";
440  ss << "\t\tOutstanding Stores:\n";
442  ss << "\t\tOutstanding Atomics:\n";
444  ss << "\t\tNumber of outstanding acquires & releases: "
445  << pendingFenceCount << std::endl;
446 }
AddressManager::validateAtomicResp
bool validateAtomicResp(Location loc, Value ret_val)
Definition: address_manager.cc:427
Episode::Action::getLocation
Location getLocation(int lane) const
Definition: episode.cc:288
TesterThread::outstandingStores
OutstandingReqTable outstandingStores
Definition: tester_thread.hh:172
Event::scheduled
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:462
MipsISA::ep
Bitfield< 1 > ep
Definition: pra_constants.hh:243
TesterThread::Value
AddressManager::Value Value
Definition: tester_thread.hh:56
warn
#define warn(...)
Definition: logging.hh:239
TesterThread::pendingFenceCount
int pendingFenceCount
Definition: tester_thread.hh:161
TesterThread::issueStoreOps
virtual void issueStoreOps()=0
TesterThread::wakeup
void wakeup()
Definition: tester_thread.cc:63
TesterThread::scalarPort
ProtocolTester::SeqPort * scalarPort
Definition: tester_thread.hh:147
AddressManager::getAddress
Addr getAddress(Location loc)
Definition: address_manager.cc:87
TesterThread::printAllOutstandingReqs
void printAllOutstandingReqs(std::stringstream &ss) const
Definition: tester_thread.cc:435
TesterThread::issueReleaseOp
virtual void issueReleaseOp()=0
TesterThread::numLanes
int numLanes
Definition: tester_thread.hh:137
Episode::Action::Type::LOAD
@ LOAD
ProtocolTester::SeqPort
Definition: protocol_tester.hh:71
TesterThread::pendingAtomicCount
int pendingAtomicCount
Definition: tester_thread.hh:162
TesterThread::OutstandingReqTable
std::unordered_map< Addr, OutstandingReqList > OutstandingReqTable
Definition: tester_thread.hh:170
std::vector
STL vector class.
Definition: stl.hh:37
TesterThread::issueNewEpisode
void issueNewEpisode()
Definition: tester_thread.cc:144
TesterThread::addrManager
AddressManager * addrManager
Definition: tester_thread.hh:143
Episode::Action::getType
Type getType() const
Definition: episode.hh:63
TesterThread::~TesterThread
virtual ~TesterThread()
Definition: tester_thread.cc:54
TesterThread::issueNextAction
void issueNextAction()
Definition: tester_thread.cc:247
TesterThread::scheduleDeadlockCheckEvent
void scheduleDeadlockCheckEvent()
Definition: tester_thread.cc:118
TesterThread::OutstandingReqList
std::vector< OutstandingReq > OutstandingReqList
Definition: tester_thread.hh:169
TesterThread::checkDeadlock
void checkDeadlock()
Definition: tester_thread.cc:395
ClockedObject
The ClockedObject class extends the SimObject with a clock and accessor functions to relate ticks to ...
Definition: clocked_object.hh:231
TesterThread::outstandingLoads
OutstandingReqTable outstandingLoads
Definition: tester_thread.hh:171
TesterThread::issueAtomicOps
virtual void issueAtomicOps()=0
TesterThread::OutstandingReq
Definition: tester_thread.hh:119
TesterThread::threadName
std::string threadName
Definition: tester_thread.hh:139
EventManager::schedule
void schedule(Event &event, Tick when)
Definition: eventq.hh:1016
TesterThread::checkDRF
bool checkDRF(Location atomic_loc, Location loc, bool isStore) const
Definition: tester_thread.cc:384
AddressManager::getLoggedValue
Value getLoggedValue(Location loc) const
Definition: address_manager.cc:420
ArmISA::ss
Bitfield< 21 > ss
Definition: miscregs_types.hh:56
ProtocolTester::checkExit
bool checkExit()
Definition: protocol_tester.cc:281
TokenRequestPort::acquireTokens
void acquireTokens(int num_tokens)
Acquire tokens by decrementing the number of available tokens across the port.
Definition: token_port.cc:63
TesterThread::issueAcquireOp
virtual void issueAcquireOp()=0
Episode::checkDRF
bool checkDRF(Location atomic_loc, Location loc, bool isStore, int max_lane) const
Definition: episode.cc:239
ProtocolTester::getAddressManager
AddressManager * getAddressManager() const
Definition: protocol_tester.hh:127
tester_thread.hh
TesterThread::curEpisode
Episode * curEpisode
Definition: tester_thread.hh:155
Episode::Action::Type::RELEASE
@ RELEASE
Clocked::curCycle
Cycles curCycle() const
Determine the current cycle, corresponding to a tick aligned to a clock edge.
Definition: clocked_object.hh:192
Episode::Action::Type::ACQUIRE
@ ACQUIRE
Episode::isEpsActive
bool isEpsActive() const
Definition: episode.hh:92
TesterThread::lastActiveCycle
Cycles lastActiveCycle
Definition: tester_thread.hh:165
Episode
Definition: episode.hh:44
TesterThread::deadlockCheckEvent
DeadlockCheckEvent deadlockCheckEvent
Definition: tester_thread.hh:117
TesterThread::deadlockThreshold
Cycles deadlockThreshold
Definition: tester_thread.hh:166
TesterThread::curAction
const Episode::Action * curAction
Definition: tester_thread.hh:157
TesterThread::popOutstandingReq
OutstandingReq popOutstandingReq(OutstandingReqTable &req_table, Addr address)
Definition: tester_thread.cc:307
std::pair
STL pair class.
Definition: stl.hh:58
TesterThread::sqcPort
ProtocolTester::SeqPort * sqcPort
Definition: tester_thread.hh:148
Addr
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:148
TesterThread::validateAtomicResp
void validateAtomicResp(Location loc, int lane, Value ret_val)
Definition: tester_thread.cc:333
TesterThread::printOutstandingReqs
void printOutstandingReqs(const OutstandingReqTable &table, std::stringstream &ss) const
Definition: tester_thread.cc:420
ProtocolTester
Definition: protocol_tester.hh:68
Clocked::clockPeriod
Tick clockPeriod() const
Definition: clocked_object.hh:214
Episode::popAction
void popAction()
Definition: episode.cc:85
TesterThread::issueLoadOps
virtual void issueLoadOps()=0
TesterThread::Params
TesterThreadParams Params
Definition: tester_thread.hh:51
Episode::hasMoreActions
bool hasMoreActions() const
Definition: episode.hh:88
X86ISA::addr
Bitfield< 3 > addr
Definition: types.hh:80
TesterThread::threadId
int threadId
Definition: tester_thread.hh:135
Episode::completeEpisode
void completeEpisode()
Definition: episode.cc:199
TesterThread::TesterThread
TesterThread(const Params &p)
Definition: tester_thread.cc:40
TesterThread::outstandingAtomics
OutstandingReqTable outstandingAtomics
Definition: tester_thread.hh:173
Episode::Action::Type::STORE
@ STORE
ProtocolTester::dumpErrorLog
void dumpErrorLog(std::stringstream &ss)
Definition: protocol_tester.cc:321
TokenRequestPort::haveTokens
bool haveTokens(int num_tokens)
Query if there are at least num_tokens tokens available to acquire.
Definition: token_port.cc:55
TesterThread::scheduleWakeup
void scheduleWakeup()
Definition: tester_thread.cc:111
ProtocolTester::getEpisodeLength
int getEpisodeLength() const
Definition: protocol_tester.hh:125
AddressManager::printLastWriter
std::string printLastWriter(Location loc) const
Definition: address_manager.cc:130
TesterThread::isNextActionReady
bool isNextActionReady()
Definition: tester_thread.cc:155
TesterThread::episodeHistory
EpisodeHistory episodeHistory
Definition: tester_thread.hh:153
Cycles
Cycles is a wrapper class for representing cycle counts, i.e.
Definition: types.hh:79
TesterThread::threadEvent
TesterThreadEvent threadEvent
Definition: tester_thread.hh:97
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:210
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:126
MipsISA::random
random
Definition: pra_constants.hh:50
curTick
Tick curTick()
The universal simulation clock.
Definition: cur_tick.hh:43
TesterThread::pendingLdStCount
int pendingLdStCount
Definition: tester_thread.hh:160
TesterThread::Location
AddressManager::Location Location
Definition: tester_thread.hh:55
MipsISA::p
Bitfield< 0 > p
Definition: pra_constants.hh:323
TesterThread::addOutstandingReqs
void addOutstandingReqs(OutstandingReqTable &req_table, Addr addr, int lane, Location loc, Value stored_val=AddressManager::INVALID_VALUE)
Definition: tester_thread.cc:290
ProtocolTester::GMTokenPort
Definition: protocol_tester.hh:85
TesterThread::tokenPort
ProtocolTester::GMTokenPort * tokenPort
Definition: tester_thread.hh:146
Episode::peekCurAction
const Action * peekCurAction() const
Definition: episode.cc:76
AddressManager::INVALID_LOCATION
static const int INVALID_LOCATION
Definition: address_manager.hh:151
TesterThread::tester
ProtocolTester * tester
Definition: tester_thread.hh:141
Episode::getEpisodeId
int getEpisodeId() const
Definition: episode.hh:82
printAddress
std::string printAddress(Addr addr)
Definition: Address.cc:74
TesterThread::port
ProtocolTester::SeqPort * port
Definition: tester_thread.hh:145
TesterThread::validateLoadResp
void validateLoadResp(Location loc, int lane, Value ret_val)
Definition: tester_thread.cc:357
ArmISA::m
Bitfield< 0 > m
Definition: miscregs_types.hh:389
panic
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:171
Episode::Action::Type::ATOMIC
@ ATOMIC

Generated on Tue Mar 23 2021 19:41:25 for gem5 by doxygen 1.8.17