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