gem5 v23.0.0.1
Loading...
Searching...
No Matches
protocol_tester.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 <algorithm>
35#include <ctime>
36#include <fstream>
37#include <random>
38
43#include "debug/ProtocolTest.hh"
44#include "mem/request.hh"
45#include "sim/sim_exit.hh"
46#include "sim/system.hh"
47
48namespace gem5
49{
50
53 _requestorId(p.system->getRequestorId(this)),
54 numCpuPorts(p.port_cpu_ports_connection_count),
55 numDmaPorts(p.port_dma_ports_connection_count),
56 numVectorPorts(p.port_cu_vector_ports_connection_count),
57 numSqcPorts(p.port_cu_sqc_ports_connection_count),
58 numScalarPorts(p.port_cu_scalar_ports_connection_count),
59 numTokenPorts(p.port_cu_token_ports_connection_count),
60 numCusPerSqc(p.cus_per_sqc),
61 numCusPerScalar(p.cus_per_scalar),
62 numWfsPerCu(p.wavefronts_per_cu),
63 numWisPerWf(p.workitems_per_wavefront),
64 numCuTokens(p.max_cu_tokens),
65 numAtomicLocs(p.num_atomic_locations),
66 numNormalLocsPerAtomic(p.num_normal_locs_per_atomic),
67 episodeLength(p.episode_length),
68 maxNumEpisodes(p.max_num_episodes),
69 debugTester(p.debug_tester),
70 cpuThreads(p.cpu_threads),
71 dmaThreads(p.dma_threads),
72 wfs(p.wavefronts)
73{
74 int idx = 0; // global port index
75
76 numCpus = numCpuPorts; // 1 cpu port per CPU
77 numDmas = numDmaPorts; // 1 dma port per DMA
78 numCus = numVectorPorts; // 1 vector port per CU
79
80 // create all physical cpu's data ports
81 for (int i = 0; i < numCpuPorts; ++i) {
82 DPRINTF(ProtocolTest, "Creating %s\n",
83 csprintf("%s-cpuPort%d", name(), i));
84 cpuPorts.push_back(new SeqPort(csprintf("%s-cpuPort%d", name(), i),
85 this, i, idx));
86 idx++;
87 }
88
89 // create all physical DMA data ports
90 for (int i = 0; i < numDmaPorts; ++i) {
91 DPRINTF(ProtocolTest, "Creating %s\n",
92 csprintf("%s-dmaPort%d", name(), i));
93 dmaPorts.push_back(new SeqPort(csprintf("%s-dmaPort%d", name(), i),
94 this, i, idx));
95 idx++;
96 }
97
98 // create all physical gpu's data ports
99 for (int i = 0; i < numVectorPorts; ++i) {
100 DPRINTF(ProtocolTest, "Creating %s\n",
101 csprintf("%s-cuVectorPort%d", name(), i));
102 cuVectorPorts.push_back(new SeqPort(csprintf("%s-cuVectorPort%d",
103 name(), i),
104 this, i, idx));
105 idx++;
106 }
107
108 for (int i = 0; i < numScalarPorts; ++i) {
109 DPRINTF(ProtocolTest, "Creating %s\n",
110 csprintf("%s-cuScalarPort%d", name(), i));
111 cuScalarPorts.push_back(new SeqPort(csprintf("%s-cuScalarPort%d",
112 name(), i),
113 this, i, idx));
114 idx++;
115 }
116
117 for (int i = 0; i < numSqcPorts; ++i) {
118 DPRINTF(ProtocolTest, "Creating %s\n",
119 csprintf("%s-cuSqcPort%d", name(), i));
120 cuSqcPorts.push_back(new SeqPort(csprintf("%s-cuSqcPort%d",
121 name(), i),
122 this, i, idx));
123 idx++;
124 }
125
126 for (int i = 0; i < numTokenPorts; ++i) {
127 cuTokenPorts.push_back(new GMTokenPort(csprintf("%s-cuTokenPort%d",
128 name(), i),
129 this, i));
131 cuTokenPorts[i]->setTokenManager(cuTokenManagers[i]);
132 }
133
134 // create an address manager
137 nextEpisodeId = 0;
138
139 if (!debugTester)
140 warn("Data race check is not enabled\n");
141
142 sentExitSignal = false;
143
144 // set random seed number
145 if (p.random_seed != 0) {
146 srand(p.random_seed);
147 } else {
148 srand(time(NULL));
149 }
150
151 actionCount = 0;
152
153 // create a new log file
154 logFile = simout.create(p.log_file);
155 assert(logFile);
156
157 // print test configs
158 std::stringstream ss;
159 ss << "GPU Ruby test's configurations" << std::endl
160 << "\tNumber of CPUs: " << numCpus << std::endl
161 << "\tNumber of DMAs: " << numDmas << std::endl
162 << "\tNumber of CUs: " << numCus << std::endl
163 << "\tNumber of wavefronts per CU: " << numWfsPerCu << std::endl
164 << "\tWavefront size: " << numWisPerWf << std::endl
165 << "\tNumber of atomic locations: " << numAtomicLocs << std::endl
166 << "\tNumber of non-atomic locations: "
167 << numNormalLocsPerAtomic * numAtomicLocs << std::endl
168 << "\tEpisode length: " << episodeLength << std::endl
169 << "\tTest length (max number of episodes): " << maxNumEpisodes
170 << std::endl
171 << "\tRandom seed: " << p.random_seed
172 << std::endl;
173
174 ccprintf(*(logFile->stream()), "%s", ss.str());
175 logFile->stream()->flush();
176}
177
179{
180 for (int i = 0; i < cpuPorts.size(); ++i)
181 delete cpuPorts[i];
182 for (int i = 0; i < dmaPorts.size(); ++i)
183 delete dmaPorts[i];
184 for (int i = 0; i < cuVectorPorts.size(); ++i)
185 delete cuVectorPorts[i];
186 for (int i = 0; i < cuScalarPorts.size(); ++i)
187 delete cuScalarPorts[i];
188 for (int i = 0; i < cuSqcPorts.size(); ++i)
189 delete cuSqcPorts[i];
190 delete addrManager;
191
192 // close the log file
194}
195
196void
198{
199 DPRINTF(ProtocolTest, "Attach threads to ports\n");
200
201 // connect cpu threads to cpu's ports
202 for (int cpu_id = 0; cpu_id < numCpus; ++cpu_id) {
203 cpuThreads[cpu_id]->attachTesterThreadToPorts(this,
204 static_cast<SeqPort*>(cpuPorts[cpu_id]));
205 cpuThreads[cpu_id]->scheduleWakeup();
206 cpuThreads[cpu_id]->scheduleDeadlockCheckEvent();
207 }
208
209 // connect dma threads to dma's ports
210 for (int dma_id = 0; dma_id < numDmas; ++dma_id) {
211 dmaThreads[dma_id]->attachTesterThreadToPorts(this,
212 static_cast<SeqPort*>(dmaPorts[dma_id]));
213 dmaThreads[dma_id]->scheduleWakeup();
214 dmaThreads[dma_id]->scheduleDeadlockCheckEvent();
215 }
216
217 // connect gpu wavefronts to gpu's ports
218 int wfId = 0;
219 int vectorPortId = 0;
220 int sqcPortId = 0;
221 int scalarPortId = 0;
222
223 for (int cu_id = 0; cu_id < numCus; ++cu_id) {
224 vectorPortId = cu_id;
225 sqcPortId = cu_id/numCusPerSqc;
226 scalarPortId = cu_id/numCusPerScalar;
227
228 for (int i = 0; i < numWfsPerCu; ++i) {
229 wfId = cu_id * numWfsPerCu + i;
230 wfs[wfId]->attachTesterThreadToPorts(this,
231 static_cast<SeqPort*>(cuVectorPorts[vectorPortId]),
232 cuTokenPorts[vectorPortId],
233 static_cast<SeqPort*>(cuSqcPorts[sqcPortId]),
234 static_cast<SeqPort*>(cuScalarPorts[scalarPortId]));
235 wfs[wfId]->scheduleWakeup();
236 wfs[wfId]->scheduleDeadlockCheckEvent();
237 }
238 }
239}
240
241Port&
242ProtocolTester::getPort(const std::string &if_name, PortID idx)
243{
244 if (if_name != "cpu_ports" && if_name != "dma_ports" &&
245 if_name != "cu_vector_ports" && if_name != "cu_sqc_ports" &&
246 if_name != "cu_scalar_ports" && if_name != "cu_token_ports") {
247 // pass along to super class
248 return ClockedObject::getPort(if_name, idx);
249 } else {
250 if (if_name == "cpu_ports") {
251 if (idx > numCpuPorts)
252 panic("ProtocolTester: unknown cpu port %d\n", idx);
253 return *cpuPorts[idx];
254 } else if (if_name == "dma_ports") {
255 if (idx > numDmaPorts)
256 panic("ProtocolTester: unknown dma port %d\n", idx);
257 return *dmaPorts[idx];
258 } else if (if_name == "cu_vector_ports") {
259 if (idx > numVectorPorts)
260 panic("ProtocolTester: unknown cu vect port %d\n", idx);
261 return *cuVectorPorts[idx];
262 } else if (if_name == "cu_sqc_ports") {
263 if (idx > numSqcPorts)
264 panic("ProtocolTester: unknown cu sqc port %d\n", idx);
265 return *cuSqcPorts[idx];
266 } else if (if_name == "cu_token_ports") {
267 if (idx > numTokenPorts)
268 panic("ProtocolTester: unknown cu token port %d\n", idx);
269 return *cuTokenPorts[idx];
270 } else {
271 assert(if_name == "cu_scalar_ports");
272 if (idx > numScalarPorts)
273 panic("ProtocolTester: unknown cu scal port %d\n", idx);
274 return *cuScalarPorts[idx];
275 }
276 }
277
278 assert(false);
279}
280
281bool
283{
285 if (!sentExitSignal) {
286 // all done
287 inform("Total completed episodes: %d\n", nextEpisodeId - 1);
288 exitSimLoop("GPU Ruby Tester: Passed!");
289 sentExitSignal = true;
290 }
291 return true;
292 }
293 return false;
294}
295
296bool
298 Location loc, bool isStore) const
299{
300 if (debugTester) {
301 // go through all active episodes in all threads
302 for (const TesterThread* th : wfs) {
303 if (!th->checkDRF(atomic_loc, loc, isStore))
304 return false;
305 }
306
307 for (const TesterThread* th : cpuThreads) {
308 if (!th->checkDRF(atomic_loc, loc, isStore))
309 return false;
310 }
311
312 for (const TesterThread* th : dmaThreads) {
313 if (!th->checkDRF(atomic_loc, loc, isStore))
314 return false;
315 }
316 }
317
318 return true;
319}
320
321void
323{
324 if (!sentExitSignal) {
325 // go through all threads and dump their outstanding requests
326 for (auto t : cpuThreads) {
327 t->printAllOutstandingReqs(ss);
328 }
329
330 for (auto t : dmaThreads) {
331 t->printAllOutstandingReqs(ss);
332 }
333
334 for (auto t : wfs) {
335 t->printAllOutstandingReqs(ss);
336 }
337
338 // dump error log into a file
339 assert(logFile);
340 ccprintf(*(logFile->stream()), "%s", ss.str());
341 logFile->stream()->flush();
342
343 sentExitSignal = true;
344 // terminate the simulation
345 panic("GPU Ruby Tester: Failed!\n");
346 }
347}
348
349bool
351{
352 // get the requesting thread from the original sender state
353 ProtocolTester::SenderState* senderState =
354 safe_cast<ProtocolTester::SenderState*>(pkt->senderState);
355 TesterThread *th = senderState->th;
356
357 th->hitCallback(pkt);
358
359 return true;
360}
361
362} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:210
The ClockedObject class extends the SimObject with a clock and accessor functions to relate ticks to ...
virtual std::string name() const
Definition named.hh:47
void close(OutputStream *file)
Closes an output file and free the corresponding OutputFile.
Definition output.cc:147
OutputStream * create(const std::string &name, bool binary=false, bool no_gz=false)
Creates a file in this directory (optionally compressed).
Definition output.cc:210
std::ostream * stream() const
Get the output underlying output stream.
Definition output.hh:62
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition packet.hh:295
SenderState * senderState
This packet's sender state.
Definition packet.hh:545
Ports are used to interface objects to each other.
Definition port.hh:62
virtual bool recvTimingResp(PacketPtr pkt)
Receive a timing response from the peer.
ProtocolTester(const Params &p)
std::vector< GpuWavefront * > wfs
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
std::vector< RequestPort * > cuVectorPorts
AddressManager * addrManager
AddressManager::Location Location
std::vector< RequestPort * > cuSqcPorts
ProtocolTesterParams Params
std::vector< DmaThread * > dmaThreads
bool checkDRF(Location atomic_loc, Location loc, bool isStore) const
std::vector< GMTokenPort * > cuTokenPorts
std::vector< CpuThread * > cpuThreads
std::vector< RequestPort * > cuScalarPorts
std::vector< RequestPort * > dmaPorts
Port & getPort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a port with a given name and index.
std::vector< TokenManager * > cuTokenManagers
std::vector< RequestPort * > cpuPorts
void dumpErrorLog(std::stringstream &ss)
virtual void hitCallback(PacketPtr pkt)=0
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:188
virtual Port & getPort(const std::string &if_name, PortID idx=InvalidPortID)
Get a port with a given name and index.
#define warn(...)
Definition logging.hh:256
#define inform(...)
Definition logging.hh:257
Bitfield< 5 > t
Definition misc_types.hh:71
Bitfield< 7 > i
Definition misc_types.hh:67
Bitfield< 21 > ss
Definition misc_types.hh:60
Bitfield< 0 > p
Bitfield< 15 > system
Definition misc.hh:1004
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
Definition types.hh:245
OutputDirectory simout
Definition output.cc:62
void exitSimLoop(const std::string &message, int exit_code, Tick when, Tick repeat, bool serialize)
Schedule an event to exit the simulation loop (returning to Python) at the end of the current cycle (...
Definition sim_events.cc:88
std::string csprintf(const char *format, const Args &...args)
Definition cprintf.hh:161
void ccprintf(cp::Print &print)
Definition cprintf.hh:130
Declaration of a request, the overall memory request consisting of the parts of the request that are ...

Generated on Mon Jul 10 2023 15:32:02 for gem5 by doxygen 1.9.7