1 /*
2 * Copyright (C) 2018-2021 Intel Corporation
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 */
7
8 #include "shared/source/command_stream/preemption.h"
9 #include "shared/source/command_stream/stream_properties.h"
10 #include "shared/source/debug_settings/debug_settings_manager.h"
11 #include "shared/source/gen_common/reg_configs_common.h"
12 #include "shared/source/helpers/flat_batch_buffer_helper_hw.h"
13 #include "shared/source/helpers/preamble.h"
14 #include "shared/source/utilities/stackvec.h"
15 #include "shared/test/common/cmd_parse/hw_parse.h"
16 #include "shared/test/common/helpers/debug_manager_state_restore.h"
17 #include "shared/test/common/helpers/unit_test_helper.h"
18 #include "shared/test/common/mocks/mock_device.h"
19 #include "shared/test/common/mocks/mock_graphics_allocation.h"
20 #include "shared/test/common/test_macros/test.h"
21
22 #include "reg_configs_common.h"
23 #include <gtest/gtest.h>
24
25 #include <algorithm>
26
27 using PreambleTest = ::testing::Test;
28
29 using namespace NEO;
30
HWTEST_F(PreambleTest,givenDisabledPreemptioWhenPreambleAdditionalCommandsSizeIsQueriedThenZeroIsReturned)31 HWTEST_F(PreambleTest, givenDisabledPreemptioWhenPreambleAdditionalCommandsSizeIsQueriedThenZeroIsReturned) {
32 auto mockDevice = std::unique_ptr<MockDevice>(MockDevice::createWithNewExecutionEnvironment<MockDevice>(nullptr));
33 mockDevice->setPreemptionMode(PreemptionMode::Disabled);
34
35 auto cmdSize = PreambleHelper<FamilyType>::getAdditionalCommandsSize(*mockDevice);
36 EXPECT_EQ(PreemptionHelper::getRequiredPreambleSize<FamilyType>(*mockDevice), cmdSize);
37 EXPECT_EQ(0u, cmdSize);
38 }
39
HWCMDTEST_F(IGFX_GEN8_CORE,PreambleTest,givenMidthreadPreemptionWhenPreambleAdditionalCommandsSizeIsQueriedThenSizeForPreemptionPreambleIsReturned)40 HWCMDTEST_F(IGFX_GEN8_CORE, PreambleTest, givenMidthreadPreemptionWhenPreambleAdditionalCommandsSizeIsQueriedThenSizeForPreemptionPreambleIsReturned) {
41 using GPGPU_CSR_BASE_ADDRESS = typename FamilyType::GPGPU_CSR_BASE_ADDRESS;
42 auto mockDevice = std::unique_ptr<MockDevice>(MockDevice::createWithNewExecutionEnvironment<MockDevice>(nullptr));
43
44 if (mockDevice->getHardwareInfo().capabilityTable.defaultPreemptionMode == PreemptionMode::MidThread) {
45 mockDevice->setPreemptionMode(PreemptionMode::MidThread);
46
47 auto cmdSize = PreambleHelper<FamilyType>::getAdditionalCommandsSize(*mockDevice);
48 EXPECT_EQ(PreemptionHelper::getRequiredPreambleSize<FamilyType>(*mockDevice), cmdSize);
49 EXPECT_EQ(sizeof(GPGPU_CSR_BASE_ADDRESS), cmdSize);
50 }
51 }
52
HWCMDTEST_F(IGFX_GEN8_CORE,PreambleTest,givenMidThreadPreemptionWhenPreambleIsProgrammedThenStateSipAndCsrBaseAddressCmdsAreAdded)53 HWCMDTEST_F(IGFX_GEN8_CORE, PreambleTest, givenMidThreadPreemptionWhenPreambleIsProgrammedThenStateSipAndCsrBaseAddressCmdsAreAdded) {
54 using STATE_SIP = typename FamilyType::STATE_SIP;
55 using GPGPU_CSR_BASE_ADDRESS = typename FamilyType::GPGPU_CSR_BASE_ADDRESS;
56
57 auto mockDevice = std::unique_ptr<MockDevice>(MockDevice::createWithNewExecutionEnvironment<MockDevice>(nullptr));
58
59 mockDevice->setPreemptionMode(PreemptionMode::Disabled);
60 auto cmdSizePreemptionDisabled = PreemptionHelper::getRequiredStateSipCmdSize<FamilyType>(*mockDevice, false);
61 EXPECT_EQ(0u, cmdSizePreemptionDisabled);
62
63 if (mockDevice->getHardwareInfo().capabilityTable.defaultPreemptionMode == PreemptionMode::MidThread) {
64 mockDevice->setPreemptionMode(PreemptionMode::MidThread);
65 auto cmdSizePreemptionMidThread = PreemptionHelper::getRequiredStateSipCmdSize<FamilyType>(*mockDevice, false);
66 EXPECT_LT(cmdSizePreemptionDisabled, cmdSizePreemptionMidThread);
67
68 StackVec<char, 8192> preambleBuffer(8192);
69 LinearStream preambleStream(&*preambleBuffer.begin(), preambleBuffer.size());
70
71 StackVec<char, 4096> preemptionBuffer;
72 preemptionBuffer.resize(cmdSizePreemptionMidThread);
73 LinearStream preemptionStream(&*preemptionBuffer.begin(), preemptionBuffer.size());
74
75 uintptr_t minCsrAlignment = 2 * 256 * MemoryConstants::kiloByte;
76 MockGraphicsAllocation csrSurface(reinterpret_cast<void *>(minCsrAlignment), 1024);
77
78 PreambleHelper<FamilyType>::programPreamble(&preambleStream, *mockDevice, 0U,
79 ThreadArbitrationPolicy::RoundRobin, &csrSurface);
80
81 PreemptionHelper::programStateSip<FamilyType>(preemptionStream, *mockDevice);
82
83 HardwareParse hwParserPreamble;
84 hwParserPreamble.parseCommands<FamilyType>(preambleStream, 0);
85
86 auto csrCmd = hwParserPreamble.getCommand<GPGPU_CSR_BASE_ADDRESS>();
87 EXPECT_NE(nullptr, csrCmd);
88 EXPECT_EQ(csrSurface.getGpuAddress(), csrCmd->getGpgpuCsrBaseAddress());
89
90 HardwareParse hwParserPreemption;
91 hwParserPreemption.parseCommands<FamilyType>(preemptionStream, 0);
92
93 auto stateSipCmd = hwParserPreemption.getCommand<STATE_SIP>();
94 EXPECT_NE(nullptr, stateSipCmd);
95 }
96 }
97
HWTEST_F(PreambleTest,givenActiveKernelDebuggingWhenPreambleKernelDebuggingCommandsSizeIsQueriedThenCorrectSizeIsReturned)98 HWTEST_F(PreambleTest, givenActiveKernelDebuggingWhenPreambleKernelDebuggingCommandsSizeIsQueriedThenCorrectSizeIsReturned) {
99 typedef typename FamilyType::MI_LOAD_REGISTER_IMM MI_LOAD_REGISTER_IMM;
100 auto size = PreambleHelper<FamilyType>::getKernelDebuggingCommandsSize(true);
101 auto sizeExpected = 2 * sizeof(MI_LOAD_REGISTER_IMM);
102 EXPECT_EQ(sizeExpected, size);
103 }
104
HWTEST_F(PreambleTest,givenInactiveKernelDebuggingWhenPreambleKernelDebuggingCommandsSizeIsQueriedThenZeroIsReturned)105 HWTEST_F(PreambleTest, givenInactiveKernelDebuggingWhenPreambleKernelDebuggingCommandsSizeIsQueriedThenZeroIsReturned) {
106 auto size = PreambleHelper<FamilyType>::getKernelDebuggingCommandsSize(false);
107 EXPECT_EQ(0u, size);
108 }
109
HWTEST_F(PreambleTest,whenKernelDebuggingCommandsAreProgrammedThenCorrectCommandsArePlacedIntoStream)110 HWTEST_F(PreambleTest, whenKernelDebuggingCommandsAreProgrammedThenCorrectCommandsArePlacedIntoStream) {
111 typedef typename FamilyType::MI_LOAD_REGISTER_IMM MI_LOAD_REGISTER_IMM;
112
113 auto bufferSize = PreambleHelper<FamilyType>::getKernelDebuggingCommandsSize(true);
114 auto buffer = std::unique_ptr<char[]>(new char[bufferSize]);
115
116 LinearStream stream(buffer.get(), bufferSize);
117 PreambleHelper<FamilyType>::programKernelDebugging(&stream);
118
119 HardwareParse hwParser;
120 hwParser.parseCommands<FamilyType>(stream);
121 auto cmdList = hwParser.getCommandsList<MI_LOAD_REGISTER_IMM>();
122
123 ASSERT_EQ(2u, cmdList.size());
124
125 auto it = cmdList.begin();
126
127 MI_LOAD_REGISTER_IMM *pCmd = reinterpret_cast<MI_LOAD_REGISTER_IMM *>(*it);
128 EXPECT_EQ(UnitTestHelper<FamilyType>::getDebugModeRegisterOffset(), pCmd->getRegisterOffset());
129 EXPECT_EQ(UnitTestHelper<FamilyType>::getDebugModeRegisterValue(), pCmd->getDataDword());
130 it++;
131
132 pCmd = reinterpret_cast<MI_LOAD_REGISTER_IMM *>(*it);
133 EXPECT_EQ(UnitTestHelper<FamilyType>::getTdCtlRegisterOffset(), pCmd->getRegisterOffset());
134 EXPECT_EQ(UnitTestHelper<FamilyType>::getTdCtlRegisterValue(), pCmd->getDataDword());
135 }
136
HWTEST_F(PreambleTest,givenKernelDebuggingActiveWhenPreambleIsProgrammedThenProgramKernelDebuggingIsCalled)137 HWTEST_F(PreambleTest, givenKernelDebuggingActiveWhenPreambleIsProgrammedThenProgramKernelDebuggingIsCalled) {
138 typedef typename FamilyType::MI_LOAD_REGISTER_IMM MI_LOAD_REGISTER_IMM;
139
140 auto mockDevice = std::unique_ptr<MockDevice>(MockDevice::createWithNewExecutionEnvironment<MockDevice>(nullptr));
141
142 mockDevice->setPreemptionMode(PreemptionMode::Disabled);
143 mockDevice->setDebuggerActive(false);
144
145 StackVec<char, 8192> preambleBuffer(8192);
146 LinearStream preambleStream(&*preambleBuffer.begin(), preambleBuffer.size());
147
148 PreambleHelper<FamilyType>::programPreamble(&preambleStream, *mockDevice, 0U,
149 ThreadArbitrationPolicy::RoundRobin, nullptr);
150
151 HardwareParse hwParser;
152 hwParser.parseCommands<FamilyType>(preambleStream);
153 auto cmdList = hwParser.getCommandsList<MI_LOAD_REGISTER_IMM>();
154
155 auto miLoadRegImmCountWithoutDebugging = cmdList.size();
156
157 mockDevice->setDebuggerActive(true);
158 auto preemptionAllocation = mockDevice->getGpgpuCommandStreamReceiver().getPreemptionAllocation();
159
160 StackVec<char, 8192> preambleBuffer2(8192);
161 preambleStream.replaceBuffer(&*preambleBuffer2.begin(), preambleBuffer2.size());
162 PreambleHelper<FamilyType>::programPreamble(&preambleStream, *mockDevice, 0U,
163 ThreadArbitrationPolicy::RoundRobin, preemptionAllocation);
164 HardwareParse hwParser2;
165 hwParser2.parseCommands<FamilyType>(preambleStream);
166 cmdList = hwParser2.getCommandsList<MI_LOAD_REGISTER_IMM>();
167
168 auto miLoadRegImmCountWithDebugging = cmdList.size();
169 ASSERT_LT(miLoadRegImmCountWithoutDebugging, miLoadRegImmCountWithDebugging);
170 EXPECT_EQ(2u, miLoadRegImmCountWithDebugging - miLoadRegImmCountWithoutDebugging);
171 }
172
HWTEST_F(PreambleTest,givenKernelDebuggingActiveAndMidThreadPreemptionWhenGetAdditionalCommandsSizeIsCalledThen2MiLoadRegisterImmCmdsAreAdded)173 HWTEST_F(PreambleTest, givenKernelDebuggingActiveAndMidThreadPreemptionWhenGetAdditionalCommandsSizeIsCalledThen2MiLoadRegisterImmCmdsAreAdded) {
174 auto mockDevice = std::unique_ptr<MockDevice>(MockDevice::createWithNewExecutionEnvironment<MockDevice>(nullptr));
175 mockDevice->setPreemptionMode(PreemptionMode::MidThread);
176
177 mockDevice->setDebuggerActive(false);
178 size_t withoutDebugging = PreambleHelper<FamilyType>::getAdditionalCommandsSize(*mockDevice);
179 mockDevice->setDebuggerActive(true);
180 size_t withDebugging = PreambleHelper<FamilyType>::getAdditionalCommandsSize(*mockDevice);
181 EXPECT_LT(withoutDebugging, withDebugging);
182
183 size_t diff = withDebugging - withoutDebugging;
184 size_t sizeExpected = 2 * sizeof(typename FamilyType::MI_LOAD_REGISTER_IMM);
185 EXPECT_EQ(sizeExpected, diff);
186 }
187
HWTEST_F(PreambleTest,givenDefaultPreambleWhenGetThreadsMaxNumberIsCalledThenMaximumNumberOfThreadsIsReturned)188 HWTEST_F(PreambleTest, givenDefaultPreambleWhenGetThreadsMaxNumberIsCalledThenMaximumNumberOfThreadsIsReturned) {
189 const HardwareInfo &hwInfo = *defaultHwInfo;
190 uint32_t threadsPerEU = (hwInfo.gtSystemInfo.ThreadCount / hwInfo.gtSystemInfo.EUCount) + hwInfo.capabilityTable.extraQuantityThreadsPerEU;
191 uint32_t value = HwHelper::getMaxThreadsForVfe(hwInfo);
192
193 uint32_t expected = hwInfo.gtSystemInfo.EUCount * threadsPerEU;
194 EXPECT_EQ(expected, value);
195 }
196
HWTEST_F(PreambleTest,givenMaxHwThreadsPercentDebugVariableWhenGetThreadsMaxNumberIsCalledThenMaximumNumberOfThreadsIsCappedToRequestedNumber)197 HWTEST_F(PreambleTest, givenMaxHwThreadsPercentDebugVariableWhenGetThreadsMaxNumberIsCalledThenMaximumNumberOfThreadsIsCappedToRequestedNumber) {
198 const HardwareInfo &hwInfo = *defaultHwInfo;
199 uint32_t threadsPerEU = (hwInfo.gtSystemInfo.ThreadCount / hwInfo.gtSystemInfo.EUCount) + hwInfo.capabilityTable.extraQuantityThreadsPerEU;
200 DebugManagerStateRestore debugManagerStateRestore;
201 DebugManager.flags.MaxHwThreadsPercent.set(80);
202 uint32_t value = HwHelper::getMaxThreadsForVfe(hwInfo);
203
204 uint32_t expected = int(hwInfo.gtSystemInfo.EUCount * threadsPerEU * 80 / 100.0f);
205 EXPECT_EQ(expected, value);
206 }
207
HWTEST_F(PreambleTest,givenMinHwThreadsUnoccupiedDebugVariableWhenGetThreadsMaxNumberIsCalledThenMaximumNumberOfThreadsIsCappedToMatchRequestedNumber)208 HWTEST_F(PreambleTest, givenMinHwThreadsUnoccupiedDebugVariableWhenGetThreadsMaxNumberIsCalledThenMaximumNumberOfThreadsIsCappedToMatchRequestedNumber) {
209 const HardwareInfo &hwInfo = *defaultHwInfo;
210 uint32_t threadsPerEU = (hwInfo.gtSystemInfo.ThreadCount / hwInfo.gtSystemInfo.EUCount) + hwInfo.capabilityTable.extraQuantityThreadsPerEU;
211 DebugManagerStateRestore debugManagerStateRestore;
212 DebugManager.flags.MinHwThreadsUnoccupied.set(2);
213 uint32_t value = HwHelper::getMaxThreadsForVfe(hwInfo);
214
215 uint32_t expected = hwInfo.gtSystemInfo.EUCount * threadsPerEU - 2;
216 EXPECT_EQ(expected, value);
217 }
218
HWCMDTEST_F(IGFX_GEN8_CORE,PreambleTest,WhenProgramVFEStateIsCalledThenCorrectVfeStateAddressIsReturned)219 HWCMDTEST_F(IGFX_GEN8_CORE, PreambleTest, WhenProgramVFEStateIsCalledThenCorrectVfeStateAddressIsReturned) {
220 using MEDIA_VFE_STATE = typename FamilyType::MEDIA_VFE_STATE;
221
222 char buffer[64];
223 MockGraphicsAllocation graphicsAllocation(buffer, sizeof(buffer));
224 LinearStream preambleStream(&graphicsAllocation, graphicsAllocation.getUnderlyingBuffer(), graphicsAllocation.getUnderlyingBufferSize());
225 uint64_t addressToPatch = 0xC0DEC0DE;
226 uint64_t expectedAddress = 0xC0DEC000;
227
228 auto pVfeCmd = PreambleHelper<FamilyType>::getSpaceForVfeState(&preambleStream, *defaultHwInfo, EngineGroupType::RenderCompute);
229 StreamProperties emptyProperties{};
230 PreambleHelper<FamilyType>::programVfeState(pVfeCmd, *defaultHwInfo, 1024u, addressToPatch, 10u, emptyProperties);
231 EXPECT_GE(reinterpret_cast<uintptr_t>(pVfeCmd), reinterpret_cast<uintptr_t>(preambleStream.getCpuBase()));
232 EXPECT_LT(reinterpret_cast<uintptr_t>(pVfeCmd), reinterpret_cast<uintptr_t>(preambleStream.getCpuBase()) + preambleStream.getUsed());
233
234 auto &vfeCmd = *reinterpret_cast<MEDIA_VFE_STATE *>(pVfeCmd);
235 EXPECT_EQ(10u, vfeCmd.getMaximumNumberOfThreads());
236 EXPECT_EQ(1u, vfeCmd.getNumberOfUrbEntries());
237 EXPECT_EQ(expectedAddress, vfeCmd.getScratchSpaceBasePointer());
238 EXPECT_EQ(0u, vfeCmd.getScratchSpaceBasePointerHigh());
239 }
240
HWCMDTEST_F(IGFX_GEN8_CORE,PreambleTest,WhenGetScratchSpaceAddressOffsetForVfeStateIsCalledThenCorrectOffsetIsReturned)241 HWCMDTEST_F(IGFX_GEN8_CORE, PreambleTest, WhenGetScratchSpaceAddressOffsetForVfeStateIsCalledThenCorrectOffsetIsReturned) {
242 using MEDIA_VFE_STATE = typename FamilyType::MEDIA_VFE_STATE;
243
244 char buffer[64];
245 MockGraphicsAllocation graphicsAllocation(buffer, sizeof(buffer));
246 LinearStream preambleStream(&graphicsAllocation, graphicsAllocation.getUnderlyingBuffer(), graphicsAllocation.getUnderlyingBufferSize());
247 auto mockDevice = std::unique_ptr<MockDevice>(MockDevice::createWithNewExecutionEnvironment<MockDevice>(nullptr));
248 FlatBatchBufferHelperHw<FamilyType> helper(*mockDevice->getExecutionEnvironment());
249 uint64_t addressToPatch = 0xC0DEC0DE;
250
251 auto pVfeCmd = PreambleHelper<FamilyType>::getSpaceForVfeState(&preambleStream, mockDevice->getHardwareInfo(), EngineGroupType::RenderCompute);
252 StreamProperties emptyProperties{};
253 PreambleHelper<FamilyType>::programVfeState(pVfeCmd, mockDevice->getHardwareInfo(), 1024u, addressToPatch, 10u, emptyProperties);
254
255 auto offset = PreambleHelper<FamilyType>::getScratchSpaceAddressOffsetForVfeState(&preambleStream, pVfeCmd);
256 EXPECT_NE(0u, offset);
257 EXPECT_EQ(MEDIA_VFE_STATE::PATCH_CONSTANTS::SCRATCHSPACEBASEPOINTER_BYTEOFFSET + reinterpret_cast<uintptr_t>(pVfeCmd),
258 offset + reinterpret_cast<uintptr_t>(preambleStream.getCpuBase()));
259 }
260
HWCMDTEST_F(IGFX_GEN8_CORE,PreambleTest,WhenIsSystolicModeConfigurableThenReturnFalse)261 HWCMDTEST_F(IGFX_GEN8_CORE, PreambleTest, WhenIsSystolicModeConfigurableThenReturnFalse) {
262 auto result = PreambleHelper<FamilyType>::isSystolicModeConfigurable(*defaultHwInfo);
263 EXPECT_FALSE(result);
264 }
265
HWCMDTEST_F(IGFX_GEN8_CORE,PreambleTest,WhenAppendProgramPipelineSelectThenNothingChanged)266 HWCMDTEST_F(IGFX_GEN8_CORE, PreambleTest, WhenAppendProgramPipelineSelectThenNothingChanged) {
267 using PIPELINE_SELECT = typename FamilyType::PIPELINE_SELECT;
268 PIPELINE_SELECT cmd = FamilyType::cmdInitPipelineSelect;
269 cmd.setMaskBits(pipelineSelectEnablePipelineSelectMaskBits);
270 PreambleHelper<FamilyType>::appendProgramPipelineSelect(&cmd, true, *defaultHwInfo);
271 EXPECT_EQ(pipelineSelectEnablePipelineSelectMaskBits, cmd.getMaskBits());
272 }
273
HWTEST_F(PreambleTest,givenSetForceSemaphoreDelayBetweenWaitsWhenProgramSemaphoreDelayThenSemaWaitPollRegisterIsProgrammed)274 HWTEST_F(PreambleTest, givenSetForceSemaphoreDelayBetweenWaitsWhenProgramSemaphoreDelayThenSemaWaitPollRegisterIsProgrammed) {
275 using MI_LOAD_REGISTER_IMM = typename FamilyType::MI_LOAD_REGISTER_IMM;
276 DebugManagerStateRestore debugManagerStateRestore;
277 uint32_t newDelay = 10u;
278 DebugManager.flags.ForceSemaphoreDelayBetweenWaits.set(newDelay);
279
280 auto bufferSize = PreambleHelper<FamilyType>::getSemaphoreDelayCommandSize();
281 EXPECT_EQ(sizeof(MI_LOAD_REGISTER_IMM), bufferSize);
282 auto buffer = std::unique_ptr<char[]>(new char[bufferSize]);
283
284 LinearStream stream(buffer.get(), bufferSize);
285 PreambleHelper<FamilyType>::programSemaphoreDelay(&stream);
286
287 HardwareParse hwParser;
288 hwParser.parseCommands<FamilyType>(stream);
289 auto cmdList = hwParser.getCommandsList<MI_LOAD_REGISTER_IMM>();
290 ASSERT_EQ(1u, cmdList.size());
291
292 auto it = cmdList.begin();
293
294 MI_LOAD_REGISTER_IMM *pCmd = reinterpret_cast<MI_LOAD_REGISTER_IMM *>(*it);
295 EXPECT_EQ(static_cast<uint32_t>(0x224c), pCmd->getRegisterOffset());
296 EXPECT_EQ(newDelay, pCmd->getDataDword());
297 }
298
HWTEST_F(PreambleTest,givenNotSetForceSemaphoreDelayBetweenWaitsWhenProgramSemaphoreDelayThenSemaWaitPollRegisterIsNotProgrammed)299 HWTEST_F(PreambleTest, givenNotSetForceSemaphoreDelayBetweenWaitsWhenProgramSemaphoreDelayThenSemaWaitPollRegisterIsNotProgrammed) {
300 using MI_LOAD_REGISTER_IMM = typename FamilyType::MI_LOAD_REGISTER_IMM;
301 DebugManagerStateRestore debugManagerStateRestore;
302 DebugManager.flags.ForceSemaphoreDelayBetweenWaits.set(-1);
303
304 auto bufferSize = PreambleHelper<FamilyType>::getSemaphoreDelayCommandSize();
305 EXPECT_EQ(sizeof(MI_LOAD_REGISTER_IMM), bufferSize);
306 auto buffer = std::unique_ptr<char[]>(new char[bufferSize]);
307
308 LinearStream stream(buffer.get(), bufferSize);
309 PreambleHelper<FamilyType>::programSemaphoreDelay(&stream);
310
311 HardwareParse hwParser;
312 hwParser.parseCommands<FamilyType>(stream);
313 auto cmdList = hwParser.getCommandsList<MI_LOAD_REGISTER_IMM>();
314 ASSERT_EQ(0u, cmdList.size());
315 }
316