1 /*
2 * Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 */
23
24 #include <math.h>
25 #include <limits.h>
26
27 #include "KFDEventTest.hpp"
28 #include "PM4Queue.hpp"
29 #include "PM4Packet.hpp"
30
31
SetUp()32 void KFDEventTest::SetUp() {
33 ROUTINE_START
34
35 KFDBaseComponentTest::SetUp();
36 m_pHsaEvent = NULL;
37
38 ROUTINE_END
39 }
40
TearDown()41 void KFDEventTest::TearDown() {
42 ROUTINE_START
43
44 // not all tests create event, destroy only if there is one
45 if (m_pHsaEvent != NULL) {
46 // hsaKmtDestroyEvent moved to TearDown to make sure it is being called
47 EXPECT_SUCCESS(hsaKmtDestroyEvent(m_pHsaEvent));
48 }
49
50 KFDBaseComponentTest::TearDown();
51
52 ROUTINE_END
53 }
54
TEST_F(KFDEventTest,CreateDestroyEvent)55 TEST_F(KFDEventTest, CreateDestroyEvent) {
56 TEST_START(TESTPROFILE_RUNALL);
57
58 ASSERT_SUCCESS(CreateQueueTypeEvent(false, false, m_NodeInfo.HsaDefaultGPUNode(), &m_pHsaEvent));
59 EXPECT_NE(0, m_pHsaEvent->EventData.HWData2);
60
61 // destroy event is being called in test TearDown
62 TEST_END;
63 }
64
TEST_F(KFDEventTest,CreateMaxEvents)65 TEST_F(KFDEventTest, CreateMaxEvents) {
66 TEST_START(TESTPROFILE_RUNALL);
67
68 static const unsigned int MAX_EVENT_NUMBER = 256;
69
70 HsaEvent* pHsaEvent[MAX_EVENT_NUMBER];
71
72 unsigned int i = 0;
73
74 for (i = 0; i < MAX_EVENT_NUMBER; i++) {
75 pHsaEvent[i] = NULL;
76 ASSERT_SUCCESS(CreateQueueTypeEvent(false, false, m_NodeInfo.HsaDefaultGPUNode(), &pHsaEvent[i]));
77 }
78
79 for (i = 0; i < MAX_EVENT_NUMBER; i++) {
80 EXPECT_SUCCESS(hsaKmtDestroyEvent(pHsaEvent[i]));
81 }
82
83 TEST_END;
84 }
85
TEST_F(KFDEventTest,SignalEvent)86 TEST_F(KFDEventTest, SignalEvent) {
87 TEST_START(TESTPROFILE_RUNALL);
88
89 ASSERT_SUCCESS(CreateQueueTypeEvent(false, false, m_NodeInfo.HsaDefaultGPUNode(), &m_pHsaEvent));
90 ASSERT_NE(0, m_pHsaEvent->EventData.HWData2);
91
92 PM4Queue queue;
93 int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
94 ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node";
95
96 ASSERT_SUCCESS(queue.Create(defaultGPUNode));
97
98 queue.PlaceAndSubmitPacket(PM4ReleaseMemoryPacket(false, m_pHsaEvent->EventData.HWData2, m_pHsaEvent->EventId));
99
100 queue.Wait4PacketConsumption();
101
102 ASSERT_SUCCESS(hsaKmtWaitOnEvent(m_pHsaEvent, g_TestTimeOut));
103
104 ASSERT_SUCCESS(queue.Destroy());
105
106 TEST_END;
107 }
108
gettime()109 static uint64_t gettime() {
110 struct timespec ts;
111 clock_gettime(CLOCK_MONOTONIC, &ts);
112 return ((int64_t)ts.tv_sec) * 1000 * 1000 * 1000 + ts.tv_nsec;
113 }
114
pow2_round_up(int num)115 static inline double pow2_round_up(int num) {
116 return pow(2, ceil(log(num)/log(2)));
117 }
118
119 class QueueAndSignalBenchmark {
120 private:
121 static const int HISTORY_SIZE = 100;
122
123 int mNumEvents;
124 int mHistorySlot;
125 uint64_t mTimeHistory[HISTORY_SIZE];
126 uint64_t mLatHistory[HISTORY_SIZE];
127
128 public:
QueueAndSignalBenchmark(int events)129 QueueAndSignalBenchmark(int events) : mNumEvents(events), mHistorySlot(0) {
130 memset(mTimeHistory, 0, sizeof(mTimeHistory));
131 memset(mLatHistory, 0, sizeof(mLatHistory));
132 }
133
queueAndSignalEvents(int node,int eventCount,uint64_t & time,uint64_t & latency)134 int queueAndSignalEvents(int node, int eventCount, uint64_t &time, uint64_t &latency) {
135 int r;
136 uint64_t startTime;
137 PM4Queue queue;
138
139 HsaEvent** pHsaEvent = (HsaEvent**) calloc(eventCount, sizeof(HsaEvent*));
140 size_t packetSize = PM4ReleaseMemoryPacket(false, 0, 0).SizeInBytes();
141 int qSize = fmax(PAGE_SIZE, pow2_round_up(packetSize*eventCount + 1));
142
143 time = 0;
144
145 r = queue.Create(node, qSize);
146 if (r != HSAKMT_STATUS_SUCCESS)
147 goto exit;
148
149 for (int i = 0; i < eventCount; i++) {
150 r = CreateQueueTypeEvent(false, false, node, &pHsaEvent[i]);
151 if (r != HSAKMT_STATUS_SUCCESS)
152 goto exit;
153
154 queue.PlacePacket(PM4ReleaseMemoryPacket(false, pHsaEvent[i]->EventData.HWData2, pHsaEvent[i]->EventId));
155 }
156
157 startTime = gettime();
158 queue.SubmitPacket();
159 for (int i = 0; i < eventCount; i++) {
160 r = hsaKmtWaitOnEvent(pHsaEvent[i], g_TestTimeOut);
161
162 if (r != HSAKMT_STATUS_SUCCESS)
163 goto exit;
164
165 if (i == 0)
166 latency = gettime() - startTime;
167 }
168 time = gettime() - startTime;
169
170 exit:
171 for (int i = 0; i < eventCount; i++) {
172 if (pHsaEvent[i])
173 hsaKmtDestroyEvent(pHsaEvent[i]);
174 }
175 queue.Destroy();
176
177 return r;
178 }
179
run(int node)180 void run(int node) {
181 int r = 0;
182 uint64_t time = 0, latency = 0;
183 uint64_t avgLat = 0, avgTime = 0;
184 uint64_t minTime = ULONG_MAX, maxTime = 0;
185 uint64_t minLat = ULONG_MAX, maxLat = 0;
186
187 r = queueAndSignalEvents(node, mNumEvents, time, latency);
188 ASSERT_EQ(r, HSAKMT_STATUS_SUCCESS);
189
190 mTimeHistory[mHistorySlot%HISTORY_SIZE] = time;
191 mLatHistory[mHistorySlot%HISTORY_SIZE] = latency;
192
193 for (int i = 0; i < HISTORY_SIZE; i++) {
194 minTime = mTimeHistory[i] < minTime ? mTimeHistory[i] : minTime;
195 maxTime = mTimeHistory[i] > maxTime ? mTimeHistory[i] : maxTime;
196 avgTime += mTimeHistory[i];
197
198 minLat = mLatHistory[i] < minLat ? mLatHistory[i] : minLat;
199 maxLat = mLatHistory[i] > maxLat ? mLatHistory[i] : maxLat;
200 avgLat += mLatHistory[i];
201 }
202
203 avgTime /= HISTORY_SIZE;
204 avgLat /= HISTORY_SIZE;
205 mHistorySlot++;
206
207 printf("\033[KEvents: %d History: %d/%d\n", mNumEvents, mHistorySlot, HISTORY_SIZE);
208 printf("\033[KMin Latency: %f ms\n", (float)minLat/1000000);
209 printf("\033[KMax Latency: %f ms\n", (float)maxLat/1000000);
210 printf("\033[KAvg Latency: %f ms\n", (float)avgLat/1000000);
211 printf("\033[K Min Rate: %f IH/ms\n", ((float)mNumEvents)/maxTime*1000000);
212 printf("\033[K Max Rate: %f IH/ms\n", ((float)mNumEvents)/minTime*1000000);
213 printf("\033[K Avg Rate: %f IH/ms\n", ((float)mNumEvents)/avgTime*1000000);
214 }
215 };
216
TEST_F(KFDEventTest,MeasureInterruptConsumption)217 TEST_F(KFDEventTest, MeasureInterruptConsumption) {
218 TEST_START(TESTPROFILE_RUNALL);
219 QueueAndSignalBenchmark latencyBench(128);
220 QueueAndSignalBenchmark sustainedBench(4096);
221
222 printf("\033[2J");
223 while (true) {
224 printf("\033[H");
225 printf("--------------------------\n");
226 latencyBench.run(m_NodeInfo.HsaDefaultGPUNode());
227 printf("--------------------------\n");
228 sustainedBench.run(m_NodeInfo.HsaDefaultGPUNode());
229 printf("--------------------------\n");
230 }
231
232 TEST_END;
233 }
234
TEST_F(KFDEventTest,SignalMaxEvents)235 TEST_F(KFDEventTest, SignalMaxEvents) {
236 TEST_START(TESTPROFILE_RUNALL);
237
238 static const unsigned int MAX_EVENT_NUMBER = 4096;
239 uint64_t time, latency;
240
241 QueueAndSignalBenchmark maxEventTest(MAX_EVENT_NUMBER);
242 maxEventTest.queueAndSignalEvents(m_NodeInfo.HsaDefaultGPUNode(), MAX_EVENT_NUMBER,
243 time, latency);
244
245 TEST_END;
246 }
247
TEST_F(KFDEventTest,SignalMultipleEventsWaitForAll)248 TEST_F(KFDEventTest, SignalMultipleEventsWaitForAll) {
249 TEST_START(TESTPROFILE_RUNALL);
250
251 static const unsigned int EVENT_NUMBER = 64; // 64 is the maximum for hsaKmtWaitOnMultipleEvents
252 static const unsigned int WAIT_BETWEEN_SUBMISSIONS_MS = 50;
253
254 HsaEvent* pHsaEvent[EVENT_NUMBER];
255 unsigned int i = 0;
256
257 int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
258 ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node";
259
260 for (i = 0; i < EVENT_NUMBER; i++) {
261 pHsaEvent[i] = NULL;
262 ASSERT_SUCCESS(CreateQueueTypeEvent(false, false, defaultGPUNode, &pHsaEvent[i]));
263 }
264
265 PM4Queue queue;
266
267 ASSERT_SUCCESS(queue.Create(defaultGPUNode));
268
269 unsigned int pktSizeDwords = 0;
270 for (i = 0; i < EVENT_NUMBER; i++) {
271 queue.PlaceAndSubmitPacket(PM4ReleaseMemoryPacket(false, pHsaEvent[i]->EventData.HWData2, pHsaEvent[i]->EventId));
272 queue.Wait4PacketConsumption();
273
274 Delay(WAIT_BETWEEN_SUBMISSIONS_MS);
275 }
276
277 ASSERT_SUCCESS(hsaKmtWaitOnMultipleEvents(pHsaEvent, EVENT_NUMBER, true, g_TestTimeOut));
278
279 ASSERT_SUCCESS(queue.Destroy());
280
281 for (i = 0; i < EVENT_NUMBER; i++)
282 EXPECT_SUCCESS(hsaKmtDestroyEvent(pHsaEvent[i]));
283
284 TEST_END;
285 }
286