LCOV - code coverage report
Current view: top level - adump/dump_statistics/dump_stat_op - kfc_dump_max_or_min.h (source / functions) Coverage Total Hit
Test: coverage.info Lines: 94.9 % 99 94
Test Date: 2026-08-31 10:09:28 Functions: 100.0 % 66 66

            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              : #ifndef __KFC_DUMP_MAX_OR_MIN_H__
      12              : #define __KFC_DUMP_MAX_OR_MIN_H__
      13              : 
      14              : #include "kfc_dump_base.h"
      15              : 
      16              : namespace KfcDumpStat {
      17              : 
      18              : // max/min 统计共用模板,isStatMax 为编译期常量,由编译器完成分支裁剪
      19              : template <typename InputT, bool isStatMax>
      20          383 : __aicore__ inline void ComputeMaxOrMinSingleType(
      21              :     TQue<QuePosition::VECOUT, BUFFER_NUM>& workQueue, LocalTensor<InputT>& inputLocal, LocalTensor<uint8_t>& calMidAddr,
      22              :     int64_t curLoop, int64_t curProcessCount)
      23              : {
      24          383 :     LocalTensor<uint8_t> curMaxOrMinAddr = calMidAddr[sizeof(float)];
      25          383 :     LocalTensor<InputT> workLocal = workQueue.AllocTensor<InputT>();
      26          383 :     LocalTensor<InputT> calMiddleResult = calMidAddr.ReinterpretCast<InputT>();
      27              : 
      28              :     if constexpr (isStatMax) {
      29          192 :         ReduceMax<InputT>(calMiddleResult, inputLocal, workLocal, curProcessCount, false);
      30              :     } else {
      31          191 :         ReduceMin<InputT>(calMiddleResult, inputLocal, workLocal, curProcessCount, false);
      32              :     }
      33          383 :     pipe_barrier(PIPE_ALL);
      34              : 
      35              :     // 更新最终结果
      36          383 :     LocalTensor<InputT> curMaxOrMin = curMaxOrMinAddr.ReinterpretCast<InputT>();
      37          383 :     bool needUpdate = curLoop == 0;
      38          383 :     if (!needUpdate) {
      39              :         if constexpr (isStatMax) {
      40           10 :             needUpdate = static_cast<float>(calMiddleResult.GetValue(0)) > static_cast<float>(curMaxOrMin.GetValue(0));
      41              :         } else {
      42           10 :             needUpdate = static_cast<float>(calMiddleResult.GetValue(0)) < static_cast<float>(curMaxOrMin.GetValue(0));
      43              :         }
      44              :     }
      45          383 :     if (needUpdate) {
      46          363 :         curMaxOrMin.SetValue(0, calMiddleResult.GetValue(0));
      47              :     }
      48          383 :     pipe_barrier(PIPE_ALL);
      49              : 
      50          383 :     workQueue.FreeTensor(workLocal);
      51          383 : }
      52              : 
      53              : // int32 走 Max/Min 向量指令,不复用 ReduceMax/ReduceMin 路径
      54              : template <bool isStatMax>
      55           16 : __aicore__ inline void ComputeInt32MaxOrMin(
      56              :     LocalTensor<int32_t>& int32X, LocalTensor<int32_t>& x, int64_t curLoop, int64_t curProcessCount,
      57              :     int64_t tileLengthMean)
      58              : {
      59           16 :     if (curLoop == 0) {
      60           14 :         int32_t inputVal = x.GetValue(0);
      61           14 :         Duplicate<int32_t>(int32X, inputVal, tileLengthMean);
      62           14 :         pipe_barrier(PIPE_ALL);
      63              :     }
      64              : 
      65              :     if constexpr (isStatMax) {
      66            8 :         Max(int32X, x, int32X, curProcessCount);
      67              :     } else {
      68            8 :         Min(int32X, x, int32X, curProcessCount);
      69              :     }
      70           16 : }
      71              : 
      72              : template <typename T, bool isStatMax>
      73          399 : __aicore__ inline bool ComputeMaxOrMinMultiDataType(
      74              :     TQue<QuePosition::VECIN, BUFFER_NUM>& xQue, TBuf<TPosition::VECCALC>& castXBuf,
      75              :     TQue<QuePosition::VECOUT, BUFFER_NUM>& workQueue, LocalTensor<uint8_t>& calMidAddr, int64_t curLoop,
      76              :     int64_t curProcessCount, int64_t appendNum, int64_t tileLengthMean)
      77              : {
      78          399 :     LocalTensor<T> x = xQue.DeQue<T>();
      79              : 
      80              :     // 32B 对齐,max/min 尾块以首元素填充(不改变最值);fp8 类型延后到 cast 完成后填充
      81          399 :     if (appendNum > 0) {
      82              :         if constexpr (!IsFp8Type<T>::value) {
      83          300 :             T appendValue = x.GetValue(0);
      84         1084 :             for (int64_t i = curProcessCount - appendNum; i < curProcessCount; ++i) {
      85          784 :                 x.SetValue(i, appendValue);
      86              :             }
      87              :         }
      88          306 :         pipe_barrier(PIPE_ALL);
      89              :     }
      90              : 
      91          399 :     bool isProcessFloat32 = true;
      92              :     if constexpr (std::is_same_v<T, uint8_t> || std::is_same_v<T, int8_t>) {
      93              :         // b8 转 half 后统计
      94           26 :         LocalTensor<half> float16X = castXBuf.Get<half>();
      95           26 :         Cast(float16X, x, RoundMode::CAST_NONE, curProcessCount);
      96           26 :         pipe_barrier(PIPE_ALL);
      97           26 :         ComputeMaxOrMinSingleType<half, isStatMax>(workQueue, float16X, calMidAddr, curLoop, curProcessCount);
      98           26 :         isProcessFloat32 = false;
      99              :     } else if constexpr (std::is_same_v<T, int32_t>) {
     100           16 :         LocalTensor<int32_t> int32X = castXBuf.Get<int32_t>();
     101           16 :         ComputeInt32MaxOrMin<isStatMax>(int32X, x, curLoop, curProcessCount, tileLengthMean);
     102           16 :         isProcessFloat32 = false;
     103              :     } else if constexpr (std::is_same_v<T, half>) {
     104            8 :         ComputeMaxOrMinSingleType<half, isStatMax>(workQueue, x, calMidAddr, curLoop, curProcessCount);
     105            8 :         isProcessFloat32 = false;
     106              :     } else {
     107              :         // int16/bfloat16 及支持的 fp8 类型统一 cast 到 float32 后统计
     108          349 :         LocalTensor<float> float32X = CastXToFloat32<T>(x, castXBuf, curProcessCount);
     109              :         // int16/bfloat16 在 cast 前已按首元素填充(首元素已随 cast 携带),仅 fp8 需在 cast 后补填;
     110              :         // 同样以首元素填充保证不改变最值,否则全负数据的 max / 全正数据的 min 会被错误统计为 0
     111              :         if constexpr (IsFp8Type<T>::value) {
     112           18 :             AppendTailPaddingFp32(float32X, curProcessCount, appendNum, float32X.GetValue(0));
     113              :         }
     114          349 :         pipe_barrier(PIPE_ALL);
     115          349 :         ComputeMaxOrMinSingleType<float, isStatMax>(workQueue, float32X, calMidAddr, curLoop, curProcessCount);
     116              :     }
     117              : 
     118          399 :     xQue.FreeTensor(x);
     119          399 :     return isProcessFloat32;
     120              : }
     121              : 
     122              : // 将 curMaxOrMinValueAddr 中的最值搬到 calMidAddr 首地址,不同输入类型的目标读取类型不同
     123              : template <typename T, bool isStatMax>
     124          377 : __aicore__ inline void WriteMaxOrMinOutput(
     125              :     LocalTensor<uint8_t>& calMidAddr, LocalTensor<uint8_t>& curMaxOrMinValueAddr, TBuf<TPosition::VECCALC>& castXBuf,
     126              :     bool isProcessFloat32, int64_t tileLengthMean)
     127              : {
     128              :     if constexpr (std::is_same_v<T, uint8_t> || std::is_same_v<T, int8_t>) {
     129           14 :         LocalTensor<half> tmpValue = curMaxOrMinValueAddr.ReinterpretCast<half>();
     130           14 :         int32_t outputValue = static_cast<int32_t>(tmpValue.GetValue(0));
     131           14 :         LocalTensor<int32_t> localOutput = calMidAddr.ReinterpretCast<int32_t>();
     132           14 :         localOutput.SetValue(0, outputValue);
     133              :     } else if constexpr (std::is_same_v<T, int16_t>) {
     134            8 :         LocalTensor<float> tmpValue = curMaxOrMinValueAddr.ReinterpretCast<float>();
     135            8 :         int32_t outputValue = static_cast<int32_t>(tmpValue.GetValue(0));
     136            8 :         LocalTensor<int32_t> localOutput = calMidAddr.ReinterpretCast<int32_t>();
     137            8 :         localOutput.SetValue(0, outputValue);
     138              :     } else if constexpr (std::is_same_v<T, int32_t>) {
     139              :         // int32 结果保留在 castXBuf 中,按标量逐个收尾取最值
     140           14 :         LocalTensor<int32_t> int32X = castXBuf.Get<int32_t>();
     141           14 :         int32_t outputValue = int32X.GetValue(0);
     142        67584 :         for (int32_t i = 1; i < tileLengthMean; ++i) {
     143        67570 :             int32_t curValue = int32X.GetValue(i);
     144        33785 :             if (isStatMax && outputValue < curValue) {
     145         4704 :                 outputValue = curValue;
     146        33785 :             } else if (!isStatMax && outputValue > curValue) {
     147            0 :                 outputValue = curValue;
     148              :             }
     149              :         }
     150           14 :         LocalTensor<int32_t> localOutput = calMidAddr.ReinterpretCast<int32_t>();
     151           14 :         localOutput.SetValue(0, outputValue);
     152              :     } else if constexpr (std::is_same_v<T, half>) {
     153            8 :         if (isProcessFloat32) {
     154            0 :             LocalTensor<float> tmpValue = curMaxOrMinValueAddr.ReinterpretCast<float>();
     155            0 :             float outputValue = tmpValue.GetValue(0);
     156            0 :             LocalTensor<float> localOutput = calMidAddr.ReinterpretCast<float>();
     157            0 :             localOutput.SetValue(0, outputValue);
     158              :         } else {
     159            8 :             LocalTensor<half> tmpValue = curMaxOrMinValueAddr.ReinterpretCast<half>();
     160            8 :             float outputValue = static_cast<float>(tmpValue.GetValue(0));
     161            8 :             LocalTensor<float> localOutput = calMidAddr.ReinterpretCast<float>();
     162            8 :             localOutput.SetValue(0, outputValue);
     163              :         }
     164              :     } else {
     165              :         // float/bfloat16 及支持的 fp8 类型:结果以 float32 存放
     166          333 :         LocalTensor<float> tmpValue = curMaxOrMinValueAddr.ReinterpretCast<float>();
     167          333 :         auto outputValue = tmpValue.GetValue(0);
     168          333 :         LocalTensor<float> localOutput = calMidAddr.ReinterpretCast<float>();
     169          333 :         localOutput.SetValue(0, outputValue);
     170              :     }
     171          377 : }
     172              : 
     173              : template <typename T, bool isStatMax>
     174          377 : __aicore__ inline void ProcessMaxOrMin(
     175              :     TQue<QuePosition::VECIN, BUFFER_NUM>& xQue, TBuf<TPosition::VECCALC>& calMiddleBuf,
     176              :     TBuf<TPosition::VECCALC>& castXBuf, TQue<QuePosition::VECOUT, BUFFER_NUM>& workQueue, GlobalTensor<T>& xGm,
     177              :     int64_t innerLoopTime, int64_t tileLengthMean, int64_t tileLengthEnd, int64_t perBlockCount, int64_t blockOffset,
     178              :     int64_t tileNumEnd)
     179              : {
     180          377 :     StatClass statClass = isStatMax ? StatClass::STAT_MAX : StatClass::STAT_MIN;
     181          377 :     LocalTensor<uint8_t> calMidAddr = calMiddleBuf.Get<uint8_t>()[static_cast<int64_t>(statClass) * BLOCK_SIZE];
     182          377 :     LocalTensor<uint8_t> curMaxOrMinValueAddr = calMidAddr[sizeof(float)];
     183          377 :     bool isProcessFloat32 = true;
     184              : 
     185          401 :     for (int64_t curLoopTime = 0; curLoopTime < innerLoopTime; ++curLoopTime) {
     186           24 :         CopyInX(
     187           24 :             xQue, xGm, blockOffset + curLoopTime * tileLengthMean, tileLengthMean,
     188              :             perBlockCount); // tileLengthMean 满足 32B 对齐
     189           24 :         int64_t appendNum = 0;
     190           24 :         isProcessFloat32 = ComputeMaxOrMinMultiDataType<T, isStatMax>(
     191              :             xQue, castXBuf, workQueue, calMidAddr, curLoopTime, tileLengthMean, appendNum, tileLengthMean);
     192              :     }
     193              : 
     194          377 :     if (tileNumEnd) {
     195          375 :         CopyInX(xQue, xGm, blockOffset + innerLoopTime * tileLengthMean, tileLengthEnd, perBlockCount); // 处理尾块
     196          375 :         auto appendNum = CeilAlign(tileLengthEnd, perBlockCount) - tileLengthEnd;
     197          375 :         isProcessFloat32 = ComputeMaxOrMinMultiDataType<T, isStatMax>(
     198              :             xQue, castXBuf, workQueue, calMidAddr, innerLoopTime, tileLengthEnd + appendNum, appendNum, tileLengthMean);
     199              :     }
     200              : 
     201          377 :     WriteMaxOrMinOutput<T, isStatMax>(calMidAddr, curMaxOrMinValueAddr, castXBuf, isProcessFloat32, tileLengthMean);
     202          377 :     pipe_barrier(PIPE_ALL);
     203          377 : }
     204              : 
     205              : } // namespace KfcDumpStat
     206              : 
     207              : #endif // __KFC_DUMP_MAX_OR_MIN_H__
        

Generated by: LCOV version 2.0-1