Line data Source code
1 : /**
2 : * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3 : * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4 : * CANN Open Software License Agreement Version 2.0 (the "License").
5 : * Please refer to the License for details. You may not use this file except in compliance with the License.
6 : * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7 : * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8 : * See LICENSE in the root of the software repository for the full text of the License.
9 : */
10 :
11 : /*!
12 : * \file conv3d_backprop_input_v2_small_kernel_tiling.cpp
13 : * \brief small kernel tiling template: N-axis full load, M-axis split, maximize core utilization
14 : */
15 :
16 : #include <map>
17 : #include <numeric>
18 : #include <log/log.h>
19 : #include "error_util.h"
20 : #include <util/math_util.h>
21 : #include <graph/utils/type_utils.h>
22 : #include <register/op_impl_registry.h>
23 : #include "op_host/tiling_templates_registry.h"
24 : #include "conv/common/op_host/op_tiling/conv_platform_util.h"
25 : #include "conv3d_backprop_input_v2_small_kernel_tiling.h"
26 :
27 : namespace {
28 : constexpr uint8_t ENABLE_SMALL_KERNEL = 4;
29 : constexpr uint8_t REVERSE_ONLY = 2;
30 : constexpr uint8_t NO_SPLIT_KERNEL = 0;
31 : constexpr uint64_t SMALL_KERNEL_COMPUTE_THRESHOLD = 144 * 2048 * 2048;
32 : constexpr uint64_t CORE_SCORE_TAIL_WEIGHT = 1000;
33 : constexpr uint64_t CORE_SCORE_IDLE_WEIGHT = 10;
34 : } // namespace
35 :
36 : namespace Ops {
37 : namespace NN {
38 : namespace Conv {
39 :
40 : bool Conv3DDXV2SmallKernelTiling::IsCapable()
41 : {
42 : if (!CheckSmallKernelEnable()) {
43 : return false;
44 : }
45 :
46 : uint64_t cinAlign = Ops::Base::CeilAlign(static_cast<uint64_t>(runInfo_.dedx_cin_g),
47 : static_cast<uint64_t>(tilingRunInfo_.n0));
48 : if (cinAlign > MAX_BASE_MN) {
49 : return false;
50 : }
51 :
52 : if (Conv3DDXV2InnerProductTiling::GetTilingFromRepo()) {
53 : isGetTilingFromRepo = true;
54 : }
55 : return true;
56 : }
57 :
58 : ge::graphStatus Conv3DDXV2SmallKernelTiling::DoLibApiTiling()
59 : {
60 : OP_LOGD(opName_, "Enable small kernel tiling");
61 : tilingRunInfo_.enableSmallKernel = true;
62 :
63 : if (isGetTilingFromRepo) {
64 : OP_LOGD(context_->GetNodeName(),
65 : "Conv3DBackpropInputV2 AscendC: SmallKernel get tiling from knowledge_tiling success.");
66 : PrintTilingSummary();
67 : return ge::GRAPH_SUCCESS;
68 : }
69 :
70 : CoreTilingParams coreParams;
71 : L0TilingParams l0Params;
72 : SetSmallKernelCoreInfo(coreParams, l0Params);
73 :
74 : InitBaseMNK(l0Params);
75 :
76 : L1TilingParams l1Params;
77 : Conv3DDXV2InnerProductTiling::InitL1Params(l1Params, l0Params);
78 :
79 : CalStepK(l1Params, l0Params);
80 :
81 : SetTilingCondition(coreParams, l1Params, l0Params);
82 : Conv3DDXV2InnerProductTiling::SetTilingData(coreParams, l1Params, l0Params);
83 : Conv3DDXV2InnerProductTiling::PrintTilingSummary();
84 : return ge::GRAPH_SUCCESS;
85 : }
86 :
87 : void Conv3DDXV2SmallKernelTiling::InitBaseMNK(L0TilingParams& l0Params)
88 : {
89 : l0Params.al0Pbuffer = DB_OFF;
90 : l0Params.bl0Pbuffer = DB_OFF;
91 : l0Params.cl0Pbuffer = DB_OFF;
92 :
93 : uint64_t coutAlign = Ops::Base::CeilAlign(static_cast<uint64_t>(runInfo_.dedy_cout_g),
94 : static_cast<uint64_t>(tilingRunInfo_.k0));
95 : uint64_t kTotal = coutAlign * runInfo_.kernel_h * runInfo_.kernel_w;
96 :
97 : auto calcMaxBaseK = [this, &l0Params, kTotal]() -> uint32_t {
98 : uint32_t maxBaseKByL0a = static_cast<uint32_t>(platformInfo_.l0_ab_size / l0Params.al0Pbuffer / dtypeByteL0a_ /
99 : l0Params.baseM);
100 : uint32_t maxBaseKByL0b = static_cast<uint32_t>(platformInfo_.l0_ab_size / l0Params.bl0Pbuffer / dtypeByteL0b_ /
101 : l0Params.baseN);
102 : uint32_t maxBaseK = std::min({maxBaseKByL0a, maxBaseKByL0b, static_cast<uint32_t>(kTotal)});
103 : maxBaseK = std::max(maxBaseK / tilingRunInfo_.k0, ONE_U32) * tilingRunInfo_.k0;
104 : maxBaseK = std::min(maxBaseK, static_cast<uint32_t>(kTotal));
105 : return maxBaseK == 0 ? tilingRunInfo_.k0 : maxBaseK;
106 : };
107 :
108 : l0Params.baseK = calcMaxBaseK();
109 :
110 : uint32_t kIter = static_cast<uint32_t>(Ops::Base::CeilDiv(kTotal, static_cast<uint64_t>(l0Params.baseK)));
111 : if (kIter >= TWO_U32) {
112 : // 开启DB前校验: DB后L0a/L0b至少需容纳k0, 否则calcMaxBaseK内强制对齐k0会导致L0溢出
113 7 : uint32_t maxBaseKByL0aDb = static_cast<uint32_t>(platformInfo_.l0_ab_size / DB_ON / dtypeByteL0a_ /
114 7 : l0Params.baseM);
115 7 : uint32_t maxBaseKByL0bDb = static_cast<uint32_t>(platformInfo_.l0_ab_size / DB_ON / dtypeByteL0b_ /
116 7 : l0Params.baseN);
117 7 : if (maxBaseKByL0aDb >= tilingRunInfo_.k0 && maxBaseKByL0bDb >= tilingRunInfo_.k0) {
118 7 : l0Params.al0Pbuffer = DB_ON;
119 7 : l0Params.bl0Pbuffer = DB_ON;
120 7 : l0Params.baseK = calcMaxBaseK();
121 : }
122 : }
123 : }
124 :
125 : void Conv3DDXV2SmallKernelTiling::SetSmallKernelCoreInfo(CoreTilingParams& coreParams, L0TilingParams& l0Params)
126 : {
127 : enableA1Db_ = false;
128 : coreParams.singleCoreDin = ONE_U32;
129 : coreParams.singleCoreCout = static_cast<uint32_t>(runInfo_.dedy_cout_g);
130 :
131 : uint64_t cinAlign = Ops::Base::CeilAlign(static_cast<uint64_t>(runInfo_.dedx_cin_g),
132 : static_cast<uint64_t>(tilingRunInfo_.n0));
133 : if (cinAlign == 0) {
134 : coreParams.singleCoreM = 0;
135 : l0Params.baseM = 0;
136 : return;
137 : }
138 : coreParams.singleCoreCin = cinAlign;
139 : l0Params.baseN = static_cast<uint32_t>(cinAlign);
140 :
141 : uint64_t hwI = static_cast<uint64_t>(runInfo_.dedx_h) * runInfo_.dedx_w;
142 : uint64_t batchDepth = static_cast<uint64_t>(runInfo_.batch_n) * runInfo_.dedx_d;
143 : uint64_t coreNum = static_cast<uint64_t>(coreNum_);
144 : uint64_t m0 = static_cast<uint64_t>(tilingRunInfo_.m0);
145 : if (batchDepth == 0 || coreNum == 0 || m0 == 0) {
146 : coreParams.singleCoreM = 0;
147 : l0Params.baseM = 0;
148 : return;
149 : }
150 :
151 : uint64_t maxSingleCoreMByL0C = CalcSmallKernelMaxMByL0C(cinAlign, l0Params.cl0Pbuffer);
152 : uint64_t maxM = std::min(hwI, static_cast<uint64_t>(MAX_BASE_MN));
153 : uint64_t maxSingleCoreM = std::min(
154 : {maxSingleCoreMByL0C, CalcSmallKernelMaxMByL0A(DB_OFF), CalcMaxSingleCoreMByL1(maxM, DB_OFF)});
155 : if (maxSingleCoreM < m0) {
156 : coreParams.singleCoreM = 0;
157 : l0Params.baseM = 0;
158 : return;
159 : }
160 :
161 : // 基本块分块决策: 负载均衡 > 核利用率 > 单轮核数
162 : // A1 DB 决策: A1 DB_OFF 优先,存在单核多轮次计算则 A1 DB_ON,若超出buffer约束则回退 A1 DB_OFF
163 : uint64_t bestSingleCoreM = SelectSmallKernelCoreMWithBuffering(hwI, batchDepth, coreNum, m0, maxM,
164 : maxSingleCoreMByL0C);
165 :
166 : coreParams.singleCoreM = bestSingleCoreM;
167 : l0Params.baseM = static_cast<uint32_t>(Ops::Base::CeilAlign(bestSingleCoreM, m0));
168 : }
169 :
170 : uint64_t Conv3DDXV2SmallKernelTiling::SelectSmallKernelCoreMWithBuffering(uint64_t hwI, uint64_t batchDepth,
171 : uint64_t coreNum, uint64_t m0, uint64_t maxM,
172 : uint64_t maxSingleCoreMByL0C)
173 : {
174 : uint64_t bestSingleCoreM = SelectSmallKernelCoreM(
175 : hwI, batchDepth, coreNum, m0,
176 : std::min({maxSingleCoreMByL0C, CalcSmallKernelMaxMByL0A(DB_OFF), CalcMaxSingleCoreMByL1(maxM, DB_OFF)}));
177 : uint64_t baseMCnt = Ops::Base::CeilDiv(hwI, bestSingleCoreM);
178 : uint64_t baseTotalCnt = batchDepth * baseMCnt;
179 : uint64_t baseUsedCoreNum = std::min(baseTotalCnt, coreNum);
180 : uint64_t baseCalRound = baseUsedCoreNum == 0 ? 0 : baseTotalCnt / baseUsedCoreNum;
181 : uint64_t baseTailCnt = baseUsedCoreNum == 0 ? 0 : baseTotalCnt - baseCalRound * baseUsedCoreNum;
182 : enableA1Db_ = baseCalRound > ONE_U64 || baseTailCnt > 0;
183 : if (!enableA1Db_) {
184 : return bestSingleCoreM;
185 : }
186 : uint64_t maxSingleCoreMByDb = std::min(
187 : {maxSingleCoreMByL0C, CalcSmallKernelMaxMByL0A(DB_ON), CalcMaxSingleCoreMByL1(maxM, DB_ON)});
188 : if (maxSingleCoreMByDb < m0) {
189 : enableA1Db_ = false;
190 : return bestSingleCoreM;
191 : }
192 : return SelectSmallKernelCoreM(hwI, batchDepth, coreNum, m0, maxSingleCoreMByDb);
193 : }
194 :
195 : uint64_t Conv3DDXV2SmallKernelTiling::CalcSmallKernelMaxMByL0C(uint64_t cinAlign, uint32_t cl0Pbuffer) const
196 : {
197 : const uint64_t m0 = tilingRunInfo_.m0;
198 : const uint64_t floatSize = ge::GetSizeByDataType(ge::DT_FLOAT);
199 : if (cinAlign == 0 || m0 == 0 || cl0Pbuffer == 0 || floatSize == 0) {
200 : return 0;
201 : }
202 : uint64_t l0cElementCount = platformInfo_.l0_c_size / cl0Pbuffer / floatSize;
203 : return (l0cElementCount / cinAlign / m0) * m0;
204 : }
205 :
206 : uint64_t Conv3DDXV2SmallKernelTiling::CalcSmallKernelMaxMByL0A(uint32_t al0Pbuffer) const
207 : {
208 : bool isA16W8 = static_cast<int32_t>(dtypeByteL0a_) == ge::GetSizeByDataType(ge::DT_FLOAT16) &&
209 : static_cast<int32_t>(dtypeByteL0b_) == ge::GetSizeByDataType(ge::DT_INT8);
210 : if (!isA16W8) {
211 : return UINT64_MAX;
212 : }
213 : const uint64_t k0 = tilingRunInfo_.k0;
214 : const uint64_t m0 = tilingRunInfo_.m0;
215 : if (k0 == 0 || m0 == 0 || al0Pbuffer == 0 || dtypeByteL0a_ == 0) {
216 : return 0;
217 : }
218 : uint64_t maxBaseM = platformInfo_.l0_ab_size / (k0 * dtypeByteL0a_ * al0Pbuffer);
219 : return maxBaseM / m0 * m0;
220 : }
221 :
222 : uint64_t Conv3DDXV2SmallKernelTiling::CalcSmallKernelCandidateM(uint64_t hwI, uint64_t mCnt, uint64_t maxMByBuffer,
223 : uint64_t m0) const
224 : {
225 : uint64_t candidate = Ops::Base::CeilAlign(Ops::Base::CeilDiv(hwI, mCnt), m0);
226 : candidate = std::min({candidate, hwI, static_cast<uint64_t>(MAX_BASE_MN), maxMByBuffer});
227 : uint64_t alignedWi = std::max(candidate / runInfo_.dedx_w, ONE_U64) * runInfo_.dedx_w;
228 : if (Ops::Base::CeilDiv(hwI, alignedWi) == Ops::Base::CeilDiv(hwI, candidate)) {
229 : candidate = alignedWi;
230 : }
231 : return Ops::Base::FloorAlign(std::min(candidate, maxMByBuffer), m0);
232 : }
233 :
234 : uint64_t Conv3DDXV2SmallKernelTiling::CalcSmallKernelCoreScore(uint64_t hwI, uint64_t batchDepth, uint64_t coreNum,
235 : uint64_t singleCoreM) const
236 : {
237 : uint64_t totalCnt = batchDepth * Ops::Base::CeilDiv(hwI, singleCoreM);
238 : uint64_t usedCoreNum = std::min(totalCnt, coreNum);
239 : if (usedCoreNum == 0) {
240 : return UINT64_MAX;
241 : }
242 : uint64_t calRound = totalCnt / usedCoreNum;
243 : uint64_t tailCnt = totalCnt - calRound * usedCoreNum;
244 : return tailCnt * CORE_SCORE_TAIL_WEIGHT + (coreNum - usedCoreNum) * CORE_SCORE_IDLE_WEIGHT + calRound;
245 : }
246 :
247 : uint64_t Conv3DDXV2SmallKernelTiling::SelectSmallKernelCoreM(uint64_t hwI, uint64_t batchDepth, uint64_t coreNum,
248 : uint64_t m0, uint64_t maxMByBuffer) const
249 : {
250 : uint64_t idealMCnt = std::max(coreNum / batchDepth, ONE_U64);
251 : uint64_t minMCnt = std::max(idealMCnt / 2, ONE_U64);
252 : uint64_t maxMCnt = std::min(Ops::Base::CeilDiv(hwI, static_cast<uint64_t>(BASIC_BLOCK_SIZE_64)), idealMCnt * 2);
253 : uint64_t bestSingleCoreM = CalcSmallKernelCandidateM(hwI, idealMCnt, maxMByBuffer, m0);
254 : uint64_t bestScore = CalcSmallKernelCoreScore(hwI, batchDepth, coreNum, bestSingleCoreM);
255 : for (uint64_t mCnt = minMCnt; mCnt <= maxMCnt; ++mCnt) {
256 : uint64_t singleCoreM = CalcSmallKernelCandidateM(hwI, mCnt, maxMByBuffer, m0);
257 : if (singleCoreM < BASIC_BLOCK_SIZE_64) {
258 : break;
259 : }
260 : uint64_t score = CalcSmallKernelCoreScore(hwI, batchDepth, coreNum, singleCoreM);
261 : if (score < bestScore) {
262 : bestScore = score;
263 : bestSingleCoreM = singleCoreM;
264 : }
265 : }
266 : return bestSingleCoreM;
267 : }
268 :
269 : void Conv3DDXV2SmallKernelTiling::CalStepK(L1TilingParams& l1Params, const L0TilingParams& l0Params)
270 : {
271 : (void)l0Params;
272 : l1Params.al1Pbuffer = enableA1Db_ ? DB_ON : DB_OFF;
273 : l1Params.bl1Pbuffer = DB_OFF;
274 : l1Params.stepKa = ONE_U32;
275 : l1Params.stepKb = ONE_U32;
276 : }
277 :
278 : void Conv3DDXV2SmallKernelTiling::SetTilingCondition(const CoreTilingParams& coreParams, const L1TilingParams& l1Params,
279 : const L0TilingParams& l0Params)
280 : {
281 : loadB1Condition_ = ENABLE_SMALL_KERNEL;
282 : loadB2Condition_ = (runInfo_.filterFormat == ge::FORMAT_FRACTAL_Z) ? B2_NO_TRANSPOSE_NO_REVERSE : REVERSE_ONLY;
283 : kernelSplitMode_ = NO_SPLIT_KERNEL;
284 : groupConvMode_ = TILING_GROUP_MODE_ORIGIN;
285 : tilingRunInfo_.enableVecTransFlag = false;
286 : }
287 :
288 : uint64_t Conv3DDXV2SmallKernelTiling::CalSmallKernelLocalHo(uint64_t maxM, uint64_t wi, uint64_t hk, uint64_t dilationH,
289 : uint64_t hoExpand)
290 : {
291 : uint64_t hiCount = Ops::Base::CeilDiv(maxM + wi - 1, wi);
292 : uint64_t receptiveHo = hiCount + (hk - 1) * dilationH;
293 : return std::min(receptiveHo, hoExpand);
294 : }
295 :
296 : uint64_t Conv3DDXV2SmallKernelTiling::CalcSmallKernelA1Size(uint64_t baseM) const
297 : {
298 : uint64_t hoExpand = (static_cast<uint64_t>(runInfo_.dedy_h) - 1) * runInfo_.stride_h + 1;
299 : uint64_t woExpand = (static_cast<uint64_t>(runInfo_.dedy_w) - 1) * runInfo_.stride_w + 1;
300 : uint64_t coutAlign = Ops::Base::CeilAlign(static_cast<uint64_t>(runInfo_.dedy_cout_g),
301 : static_cast<uint64_t>(tilingRunInfo_.k0));
302 : uint64_t localHo = Ops::Base::CeilDiv(baseM + runInfo_.dedx_w - 1, static_cast<uint64_t>(runInfo_.dedx_w)) +
303 : (runInfo_.kernel_h - 1) * runInfo_.dilation_h;
304 : localHo = std::min(localHo, hoExpand);
305 : return localHo * woExpand * coutAlign * dtypeByteL0a_;
306 : }
307 :
308 : uint64_t Conv3DDXV2SmallKernelTiling::CalcSmallKernelL1FixedSize() const
309 : {
310 : uint64_t coutAlign = Ops::Base::CeilAlign(static_cast<uint64_t>(runInfo_.dedy_cout_g),
311 : static_cast<uint64_t>(tilingRunInfo_.k0));
312 : uint64_t cinAlign = Ops::Base::CeilAlign(static_cast<uint64_t>(runInfo_.dedx_cin_g),
313 : static_cast<uint64_t>(tilingRunInfo_.n0));
314 : uint64_t b1Size = static_cast<uint64_t>(runInfo_.kernel_h) * runInfo_.kernel_w * coutAlign * cinAlign *
315 : dtypeByteL0b_;
316 : uint64_t biasSize = 0;
317 : if (hasBiasFlag_) {
318 : uint64_t dtypeByteBtBuffer = (runInfo_.a_dtype_bytes == ge::GetSizeByDataType(ge::DT_INT8)) ?
319 : ge::GetSizeByDataType(ge::DT_INT32) :
320 : ge::GetSizeByDataType(ge::DT_FLOAT);
321 : // bias L1 区按 64B 对齐,与 kernel 侧 GetBiasL1SizeBytes 保持一致(scale 起始地址需 64B 对齐,否则 AIC
322 : // error)。
323 : biasSize = Ops::Base::CeilAlign(cinAlign * dtypeByteBtBuffer, BYTE_64);
324 : }
325 : uint64_t scaleSize = 0;
326 : if (hasScaleFlag_ && runInfo_.quantMode == static_cast<uint8_t>(QuantMode::VECTOR_QUANT)) {
327 : scaleSize = cinAlign * ge::GetSizeByDataType(ge::DT_INT64);
328 : }
329 : return b1Size + biasSize + scaleSize;
330 : }
331 :
332 : uint64_t Conv3DDXV2SmallKernelTiling::CalcMaxSingleCoreMByL1(uint64_t maxM, uint32_t a1Pbuffer) const
333 : {
334 : const uint64_t m0 = tilingRunInfo_.m0;
335 : if (a1Pbuffer == 0 || m0 == 0 || maxM < m0 || platformInfo_.l1_size <= CalcSmallKernelL1FixedSize()) {
336 : return 0;
337 : }
338 : const uint64_t a1BankBudget = (platformInfo_.l1_size - CalcSmallKernelL1FixedSize()) / a1Pbuffer;
339 : uint64_t low = 1;
340 : uint64_t high = maxM / m0;
341 : uint64_t best = 0;
342 : while (low <= high) {
343 : uint64_t mid = low + (high - low) / 2;
344 : uint64_t candidateM = mid * m0;
345 : if (CalcSmallKernelA1Size(candidateM) <= a1BankBudget) {
346 : best = candidateM;
347 : low = mid + 1;
348 : } else {
349 : high = mid - 1;
350 : }
351 : }
352 : return best;
353 : }
354 :
355 : bool Conv3DDXV2SmallKernelTiling::HasSupportedSmallKernelDimensions() const
356 : {
357 : return runInfo_.kernel_d == 1 && runInfo_.dedx_d == 1 && runInfo_.dedy_d == 1 && runInfo_.groups == 1;
358 : }
359 :
360 : bool Conv3DDXV2SmallKernelTiling::HasSupportedSmallKernelFormats() const
361 : {
362 : return runInfo_.outBackpropFormat == ge::FORMAT_NCDHW && runInfo_.yFormat == ge::FORMAT_NCDHW &&
363 : (runInfo_.filterFormat == ge::FORMAT_NDHWC || runInfo_.filterFormat == ge::FORMAT_FRACTAL_Z);
364 : }
365 :
366 : bool Conv3DDXV2SmallKernelTiling::HasSupportedSmallKernelPadding() const
367 : {
368 : return runInfo_.backprop_pad_l >= 0 && runInfo_.backprop_pad_r >= 0 && runInfo_.backprop_pad_u >= 0 &&
369 : runInfo_.backprop_pad_d >= 0 && runInfo_.backprop_pad_l <= PAD_DIM_UP &&
370 : runInfo_.backprop_pad_r <= PAD_DIM_UP && runInfo_.backprop_pad_u <= PAD_DIM_UP &&
371 : runInfo_.backprop_pad_d <= PAD_DIM_UP;
372 : }
373 :
374 : bool Conv3DDXV2SmallKernelTiling::HasSmallKernelComputationBudget() const
375 : {
376 : uint64_t computation = static_cast<uint64_t>(runInfo_.dedx_h) * runInfo_.dedx_w * runInfo_.kernel_h *
377 : runInfo_.kernel_w * runInfo_.dedy_cout_g * runInfo_.dedx_cin_g;
378 : bool isFp16Fp16 = static_cast<int32_t>(dtypeByteL0a_) == ge::GetSizeByDataType(ge::DT_FLOAT16) &&
379 : static_cast<int32_t>(dtypeByteL0b_) == ge::GetSizeByDataType(ge::DT_FLOAT16);
380 : if (isFp16Fp16) {
381 : return computation < SMALL_KERNEL_COMPUTE_THRESHOLD;
382 : }
383 : bool isA16W8 = static_cast<int32_t>(dtypeByteL0a_) == ge::GetSizeByDataType(ge::DT_FLOAT16) &&
384 : static_cast<int32_t>(dtypeByteL0b_) == ge::GetSizeByDataType(ge::DT_INT8);
385 : if (isA16W8) {
386 : return computation < SMALL_KERNEL_COMPUTE_THRESHOLD * TWO;
387 : }
388 : return true;
389 : }
390 :
391 : bool Conv3DDXV2SmallKernelTiling::HasSmallKernelBufferBudget() const
392 : {
393 : if (tilingRunInfo_.n0 == 0 || tilingRunInfo_.m0 == 0) {
394 : return false;
395 : }
396 : // The scheduling overhead of small kernel causes a severe performance regression in single-core scenarios.
397 : if (coreNum_ == 1) {
398 : return false;
399 : }
400 : uint64_t cinAlign = Ops::Base::CeilAlign(static_cast<uint64_t>(runInfo_.dedx_cin_g),
401 : static_cast<uint64_t>(tilingRunInfo_.n0));
402 : uint64_t maxMByL0C = CalcSmallKernelMaxMByL0C(cinAlign, DB_OFF);
403 : uint64_t maxMByL0A = CalcSmallKernelMaxMByL0A(DB_OFF);
404 : uint64_t hwI = static_cast<uint64_t>(runInfo_.dedx_h) * runInfo_.dedx_w;
405 : uint64_t maxSingleCoreM = CalcMaxSingleCoreMByL1(std::min(hwI, static_cast<uint64_t>(MAX_BASE_MN)), DB_OFF);
406 : uint64_t l1UsedSize = CalcSmallKernelL1FixedSize() + CalcSmallKernelA1Size(maxSingleCoreM);
407 : return maxMByL0C >= tilingRunInfo_.m0 && maxMByL0A >= tilingRunInfo_.m0 && maxSingleCoreM >= tilingRunInfo_.m0 &&
408 : l1UsedSize <= platformInfo_.l1_size;
409 : }
410 :
411 : bool Conv3DDXV2SmallKernelTiling::CheckSmallKernelEnable()
412 : {
413 : if (!IsSocVersionFuse(context_)) {
414 : return false;
415 : }
416 : // 维度要求: D=1, group=1
417 : // format要求: outBackprop/y=NCDHW, filter=NDHWC
418 : if (!HasSupportedSmallKernelDimensions() || !HasSupportedSmallKernelFormats() ||
419 : !HasSupportedSmallKernelPadding() || !HasSmallKernelComputationBudget()) {
420 : return false;
421 : }
422 : return HasSmallKernelBufferBudget();
423 : }
424 :
425 : REGISTER_TILING_TEMPLATE("Conv3DBackpropInputV2", Conv3DDXV2SmallKernelTiling, 96);
426 :
427 : } // namespace Conv
428 : } // namespace NN
429 : } // namespace Ops
|