LCOV - code coverage report
Current view: top level - adump/exception - dump_operator.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 86.7 % 256 222
Test Date: 2026-08-31 10:09:28 Functions: 95.2 % 21 20

            Line data    Source code
       1              : /**
       2              :  * Copyright (c) 2025 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              : #include "dump_operator.h"
      12              : #include "runtime/rt.h"
      13              : #include "str_utils.h"
      14              : #include "sys_utils.h"
      15              : #include "file.h"
      16              : #include "path.h"
      17              : #include "dump_memory.h"
      18              : #include "dump_datatype.h"
      19              : #include "dump_file.h"
      20              : #include "log/hdc_log.h"
      21              : #include "dump_manager.h"
      22              : 
      23              : namespace Adx {
      24              : namespace {
      25              : const std::set<char> INVALID_FILE_NAME_CHAR = {' ', '.', '/', '\\'};
      26              : constexpr char REPLACE_FILE_NAME_CHAR = '_';
      27              : } // namespace
      28              : 
      29           10 : bool OpIdentity::operator==(const OpIdentity& rhs) const
      30              : {
      31           10 :     return rhs.deviceId == deviceId && rhs.taskId == taskId && rhs.streamId == streamId && rhs.contextId == contextId;
      32              : }
      33              : 
      34           10 : std::string OpIdentity::GetString() const
      35              : {
      36           10 :     std::stringstream ss;
      37           10 :     ss << "stream_id:" << streamId << ", task_id:" << taskId << ", context_id:" << contextId << ", thread_id:";
      38           20 :     return ss.str();
      39           10 : }
      40              : 
      41          147 : DumpOperator::DumpOperator(const OperatorInfoV2& opInfo) { Init(opInfo); }
      42              : 
      43          148 : void DumpOperator::Init(const OperatorInfoV2& opInfo)
      44              : {
      45              :     // init base info
      46          148 :     opName_ = opInfo.opName;
      47          148 :     opType_ = opInfo.opType;
      48              : 
      49          148 :     identity_.taskId = opInfo.taskId;
      50          148 :     identity_.streamId = opInfo.streamId;
      51          148 :     identity_.deviceId = opInfo.deviceId;
      52          148 :     identity_.contextId = opInfo.contextId;
      53              : 
      54              :     // init device info
      55          148 :     deviceInfos_ = opInfo.deviceInfos;
      56              : 
      57              :     // init additional info
      58          148 :     additions_ = opInfo.additionalInfo;
      59          296 :     auto item = additions_.find(DUMP_ADDITIONAL_IS_HOST_ARGS);
      60          148 :     if (item != additions_.end()) {
      61            4 :         isHostArgs_ = item->second;
      62              :     }
      63          148 :     InitDeviceArgs();
      64              : 
      65              :     // init tensor or workspace
      66          315 :     for (const auto& tensorInfo : opInfo.tensorInfos) {
      67           19 :         if (tensorInfo.tensorAddr == nullptr || tensorInfo.tensorSize == 0 ||
      68           17 :             tensorInfo.placement != TensorPlacement::kOnDeviceHbm) {
      69            9 :             continue;
      70              :         }
      71              : 
      72           10 :         if (tensorInfo.type == TensorType::INPUT) {
      73            4 :             inputTensors_.emplace_back(tensorInfo);
      74            6 :         } else if (tensorInfo.type == TensorType::OUTPUT) {
      75            4 :             outputTensors_.emplace_back(tensorInfo);
      76            2 :         } else if (tensorInfo.type == TensorType::WORKSPACE) {
      77            2 :             workspaces_.emplace_back(
      78            2 :                 tensorInfo.tensorAddr, static_cast<uint64_t>(tensorInfo.tensorSize), tensorInfo.argsOffSet);
      79              :         }
      80              :     }
      81          296 :     return;
      82              : }
      83              : 
      84          148 : void DumpOperator::InitDeviceArgs()
      85              : {
      86          297 :     for (const auto& deviceInfo : deviceInfos_) {
      87            4 :         if (deviceInfo.name == DEVICE_INFO_NAME_ARGS) {
      88            3 :             if (deviceInfo.addr == nullptr) {
      89            1 :                 IDE_LOGW("The args before execute is null.");
      90            3 :                 break;
      91              :             }
      92            2 :             void* argsAddr = nullptr;
      93            2 :             void* argsMem = nullptr;
      94            2 :             if (isHostArgs_ == "false") {
      95            0 :                 argsMem = DumpMemory::CopyDeviceToHost(deviceInfo.addr, deviceInfo.length);
      96            0 :                 if (argsMem == nullptr) {
      97            0 :                     IDE_LOGE("Copy device args to host failed.");
      98            0 :                     return;
      99              :                 }
     100            0 :                 argsAddr = argsMem;
     101              :             } else {
     102            2 :                 argsAddr = deviceInfo.addr;
     103              :             }
     104            4 :             HOST_RT_MEMORY_GUARD(argsMem);
     105              : 
     106            2 :             uint64_t maxArgNum = deviceInfo.length / sizeof(uint64_t);
     107           30 :             for (uint64_t i = 0; i < maxArgNum; ++i) {
     108           28 :                 hostArgs_.emplace_back(static_cast<void**>(argsAddr)[i]);
     109              :             }
     110            2 :             break;
     111            2 :         }
     112              :     }
     113              : }
     114              : 
     115            6 : bool DumpOperator::IsBelongTo(const OpIdentity& identity) const { return identity == identity_; }
     116              : 
     117           80 : void DumpOperator::PrintAdditionInfo(const char* flag) const
     118              : {
     119           80 :     std::string value;
     120          160 :     auto it = additions_.find(flag);
     121           80 :     if (it != additions_.end()) {
     122            8 :         value = it->second;
     123              :     }
     124           80 :     IDE_RUN_LOGI("[AIC_INFO] %s:%s", flag, value.c_str());
     125           80 : }
     126              : 
     127            8 : int32_t DumpOperator::LogExceptionInfo(const rtExceptionArgsInfo& argsInfo)
     128              : {
     129            8 :     kernelCollector_.LoadKernelInfo(argsInfo);
     130              : 
     131              :     // log op basic info
     132            8 :     std::ostringstream oss;
     133              :     oss << "[AIC_INFO] node_name:" << opName_.c_str() << ", node_type:" << opType_.c_str() << ", "
     134            8 :         << identity_.GetString().c_str();
     135            8 :     IDE_RUN_LOGI("%s", oss.str().c_str());
     136            8 :     logRecord_.emplace_back(oss.str() + "\n");
     137            8 :     oss.str("");
     138              :     // log tensor info
     139            9 :     for (size_t i = 0U; i < inputTensors_.size(); ++i) {
     140            1 :         oss << "[Dump][Exception] begin to load input tensor, index:" << inputTensors_[i].GetArgsOffSet();
     141            1 :         RecordCurrentLog(oss);
     142            1 :         IDE_RUN_LOGI("[AIC_INFO] input:%zu;%s", i, GetTensorString(inputTensors_[i]).c_str());
     143            1 :         oss << "[Dump][Exception] end to load input tensor, index:" << inputTensors_[i].GetArgsOffSet();
     144            1 :         RecordCurrentLog(oss);
     145              :     }
     146            9 :     for (size_t i = 0U; i < outputTensors_.size(); ++i) {
     147            1 :         oss << "[Dump][Exception] begin to load output tensor, index:" << outputTensors_[i].GetArgsOffSet();
     148            1 :         RecordCurrentLog(oss);
     149            1 :         IDE_RUN_LOGI("[AIC_INFO] output:%zu;%s", i, GetTensorString(outputTensors_[i]).c_str());
     150            1 :         oss << "[Dump][Exception] end to load output tensor, index:" << outputTensors_[i].GetArgsOffSet();
     151            1 :         RecordCurrentLog(oss);
     152              :     }
     153            9 :     for (size_t i = 0U; i < workspaces_.size(); ++i) {
     154            1 :         oss << "[Dump][Exception] begin to load workspace, index:" << workspaces_[i].argsOffset;
     155            1 :         RecordCurrentLog(oss);
     156            1 :         oss << "[Dump][Exception] exception info dump args data, addr:" << workspaces_[i].addr
     157            1 :             << "; size:" << workspaces_[i].bytes << " bytes";
     158            1 :         RecordCurrentLog(oss);
     159            1 :         IDE_RUN_LOGI("[AIC_INFO] workspace:%zu;addr:%p;size:%llu bytes", i, workspaces_[i].addr, workspaces_[i].bytes);
     160            1 :         oss << "[Dump][Exception] end to load workspace, index:" << workspaces_[i].argsOffset;
     161            1 :         RecordCurrentLog(oss);
     162              :     }
     163              : 
     164              :     // log additional info
     165            8 :     PrintAdditionInfo(DUMP_ADDITIONAL_BLOCK_DIM);
     166            8 :     PrintAdditionInfo(DUMP_ADDITIONAL_WORKSPACE_BYTES);
     167            8 :     PrintAdditionInfo(DUMP_ADDITIONAL_WORKSPACE_ADDRS);
     168            8 :     PrintAdditionInfo(DUMP_ADDITIONAL_ALL_ATTRS);
     169            8 :     PrintAdditionInfo(DUMP_ADDITIONAL_DEV_FUNC);
     170            8 :     PrintAdditionInfo(DUMP_ADDITIONAL_TVM_MAGIC);
     171            8 :     PrintAdditionInfo(DUMP_ADDITIONAL_KERNEL_INFO);
     172            8 :     PrintAdditionInfo(DUMP_ADDITIONAL_TILING_KEY);
     173            8 :     PrintAdditionInfo(DUMP_ADDITIONAL_TILING_DATA);
     174            8 :     PrintAdditionInfo(DUMP_ADDITIONAL_OP_FILE_PATH);
     175              : 
     176              :     // log args
     177           16 :     return LogExceptionArgs(argsInfo);
     178            8 : }
     179              : 
     180            3 : int32_t DumpOperator::CopyOpKernelFile() const
     181              : {
     182              :     // src file path
     183            6 :     auto it = additions_.find(DUMP_ADDITIONAL_OP_FILE_PATH);
     184            5 :     std::string opFilePath = it != additions_.cend() ? it->second : "./kernel_meta";
     185              : 
     186            6 :     it = additions_.find(DUMP_ADDITIONAL_DEV_FUNC);
     187            3 :     if (it == additions_.cend()) {
     188            2 :         IDE_LOGW("can't find [%s] in additional info.", DUMP_ADDITIONAL_DEV_FUNC);
     189            2 :         return ADUMP_FAILED;
     190              :     }
     191            1 :     std::string devFunc = it->second;
     192            1 :     std::string opFileName = devFunc.substr(0, devFunc.rfind("__"));
     193            3 :     Path srcFilePath = Path(opFilePath).Concat(opFileName).AddExtension(".o");
     194            1 :     if (!srcFilePath.RealPath()) {
     195            1 :         IDE_LOGW("Can not get realpath for src op file %s.", srcFilePath.GetCString());
     196            1 :         return ADUMP_FAILED;
     197              :     }
     198              : 
     199              :     // dst file path
     200            0 :     std::string currentDir = SysUtils::GetCurrentWorkDir();
     201            0 :     if (currentDir.empty()) {
     202            0 :         IDE_LOGE("Get current program work dir failed.");
     203            0 :         return ADUMP_FAILED;
     204              :     }
     205            0 :     Path dstFilePath = Path(currentDir).Concat(opFileName).AddExtension(".o");
     206              : 
     207              :     // copy file
     208            0 :     const auto ret = File::Copy(srcFilePath.GetString(), dstFilePath.GetString());
     209            0 :     if (ret != ADUMP_SUCCESS) {
     210            0 :         IDE_LOGE("Copy op kernel file from %s to %s failed.", srcFilePath.GetCString(), dstFilePath.GetCString());
     211            0 :         return ADUMP_FAILED;
     212              :     }
     213            0 :     return ADUMP_SUCCESS;
     214            3 : }
     215              : 
     216            4 : int32_t DumpOperator::RefreshAddrs(const rtExceptionArgsInfo& argsInfo)
     217              : {
     218            4 :     void* hostMem = DumpMemory::CopyDeviceToHost(argsInfo.argAddr, argsInfo.argsize);
     219            4 :     if (hostMem == nullptr) {
     220            1 :         IDE_LOGE("Copy device args to host failed, ptr: %p, size: %lu bytes.", argsInfo.argAddr, argsInfo.argsize);
     221            1 :         return ADUMP_FAILED;
     222              :     }
     223            6 :     HOST_RT_MEMORY_GUARD(hostMem);
     224              : 
     225            3 :     IDE_LOGI("Op %s type %s refresh addr.", opName_.c_str(), opType_.c_str());
     226            3 :     void** argsOnHost = static_cast<void**>(hostMem);
     227            3 :     size_t maxArgNum = argsInfo.argsize / sizeof(uint64_t);
     228            5 :     for (size_t i = 0U; i < inputTensors_.size(); i++) {
     229            2 :         const void* oriAddr = inputTensors_[i].GetAddress();
     230            2 :         if (maxArgNum <= inputTensors_[i].GetArgsOffSet()) {
     231            1 :             IDE_LOGW(
     232              :                 "Tensor args offset[%u] is larger than max arg num[%llu].", inputTensors_[i].GetArgsOffSet(),
     233              :                 maxArgNum);
     234            1 :             continue;
     235              :         }
     236            1 :         const void* refreshAddr = *(argsOnHost + inputTensors_[i].GetArgsOffSet());
     237            1 :         IDE_LOGI("Input.%zu addr refresh from %p to %p.", i, oriAddr, refreshAddr);
     238            1 :         inputTensors_[i].SetAddress(refreshAddr);
     239              :     }
     240              : 
     241            5 :     for (size_t i = 0U; i < outputTensors_.size(); i++) {
     242            2 :         const void* oriAddr = outputTensors_[i].GetAddress();
     243            2 :         if (maxArgNum <= outputTensors_[i].GetArgsOffSet()) {
     244            0 :             IDE_LOGW(
     245              :                 "Tensor args offset[%u] is larger than max arg num[%llu].", outputTensors_[i].GetArgsOffSet(),
     246              :                 maxArgNum);
     247            0 :             continue;
     248              :         }
     249            2 :         const void* refreshAddr = *(argsOnHost + outputTensors_[i].GetArgsOffSet());
     250            2 :         IDE_LOGI("Output.%zu addr refresh from %p to %p.", i, oriAddr, refreshAddr);
     251            2 :         outputTensors_[i].SetAddress(refreshAddr);
     252              :     }
     253            3 :     return ADUMP_SUCCESS;
     254            3 : }
     255              : 
     256            2 : int32_t DumpOperator::DumpExceptionFile(const uint32_t deviceId, const std::string& dumpPath)
     257              : {
     258            2 :     std::string dumpFilePath = GetDumpFilePath(dumpPath);
     259            2 :     IDE_LOGI("[Dump][Exception] The exception dump file path is %s", dumpFilePath.c_str());
     260              : 
     261            2 :     DumpFile dumpFile(deviceId, dumpFilePath);
     262            2 :     dumpFile.SetHeader(opName_);
     263            2 :     dumpFile.SetInputTensors(inputTensors_);
     264            2 :     dumpFile.SetOutputTensors(outputTensors_);
     265            2 :     dumpFile.SetWorkspaces(workspaces_);
     266              : 
     267            2 :     AdxLogFlush();
     268            2 :     const int32_t ret = dumpFile.Dump(logRecord_);
     269            2 :     if (ret != ADUMP_SUCCESS) {
     270            0 :         IDE_LOGE("[Dump][Exception] write exception to file failed, file: %s", dumpFilePath.c_str());
     271            0 :         return ADUMP_FAILED;
     272              :     }
     273            2 :     IDE_LOGE("[Dump][Exception] dump exception to file, file: %s", dumpFilePath.c_str());
     274            2 :     IDE_LOGI("[Dump][Exception] Dump exception info success.");
     275            2 :     return ADUMP_SUCCESS;
     276            2 : }
     277              : 
     278            2 : int32_t DumpOperator::DumpException(const uint32_t deviceId, const std::string& dumpPath)
     279              : {
     280            2 :     int32_t ret = ADUMP_SUCCESS;
     281            2 :     if (DumpExceptionFile(deviceId, dumpPath) != ADUMP_SUCCESS) {
     282            0 :         ret = ADUMP_FAILED;
     283              :     }
     284            2 :     if (kernelCollector_.LoadKernelBinBuffer() != ADUMP_SUCCESS) {
     285            0 :         ret = ADUMP_FAILED;
     286              :     }
     287              :     // 先同步落 _host.o,再做慢的 kernel_meta 搜索拷贝。落盘失败需传播,保持与拆分前一致的错误可观测性。
     288            2 :     std::string hostOPath;
     289            2 :     if (kernelCollector_.DumpHostKernelBin(dumpPath, hostOPath) != ADUMP_SUCCESS) {
     290            0 :         ret = ADUMP_FAILED;
     291              :     }
     292            2 :     if (kernelCollector_.StartCollectKernel(dumpPath) != ADUMP_SUCCESS) {
     293            0 :         ret = ADUMP_FAILED;
     294              :     }
     295            2 :     return ret;
     296            2 : }
     297              : 
     298            0 : bool DumpOperator::IsTvmOperator() const
     299              : {
     300            0 :     const auto it = additions_.find(DUMP_ADDITIONAL_IMPLY_TYPE);
     301            0 :     if (it == additions_.cend()) {
     302            0 :         return false;
     303              :     }
     304              : 
     305            0 :     int32_t implType = 0;
     306            0 :     if (!StrUtils::ToInteger(it->second, implType)) {
     307            0 :         IDE_LOGW("Convert imply_type string %s to int failed.", it->second.c_str());
     308            0 :         return false;
     309              :     }
     310            0 :     return static_cast<ImplyType>(implType) == ImplyType::TVM;
     311              : }
     312              : 
     313            2 : std::string DumpOperator::GetTensorString(const DumpTensor& tensor)
     314              : {
     315            2 :     std::stringstream content;
     316            4 :     content << "shape:" << StrUtils::ToString(tensor.GetShape()) << ";"
     317            4 :             << "format:" << DumpDataType::FormatToSerialString(static_cast<int32_t>(tensor.GetFormat())) << ";"
     318            4 :             << "dtype:" << DumpDataType::DataTypeToSerialString(static_cast<int32_t>(tensor.GetDataType())) << ";"
     319            8 :             << "addr:" << tensor.GetAddress() << ";"
     320            2 :             << "size:" << tensor.GetSize() << " bytes";
     321            2 :     std::ostringstream oss;
     322            2 :     oss << "[Dump][Exception] exception info dump args data, addr:" << tensor.GetAddress()
     323            2 :         << "; size:" << tensor.GetSize() << " bytes";
     324            2 :     RecordCurrentLog(oss);
     325            4 :     return content.str();
     326            2 : }
     327              : 
     328            8 : int32_t DumpOperator::LogExceptionArgs(const rtExceptionArgsInfo& argsInfo) const
     329              : {
     330            8 :     if (hostArgs_.size() == 0) {
     331            7 :         IDE_LOGI("Op %s args is empty, skip log args.", opName_.c_str());
     332              :     } else {
     333            1 :         void* const* argsMem = hostArgs_.data();
     334            2 :         PrintLog(argsMem, hostArgs_.size(), std::string(DEVICE_INFO_NAME_ARGS));
     335              :     }
     336              : 
     337            8 :     if (argsInfo.argAddr == nullptr) {
     338            7 :         IDE_LOGE("exception callback argAddr is null");
     339            7 :         return ADUMP_SUCCESS;
     340              :     }
     341            1 :     void* hostMem = DumpMemory::CopyDeviceToHost(argsInfo.argAddr, argsInfo.argsize);
     342            1 :     if (hostMem == nullptr) {
     343            0 :         IDE_LOGE("Copy device args to host failed, addr: %p, size: %u.", argsInfo.argAddr, argsInfo.argsize);
     344            0 :         return ADUMP_FAILED;
     345              :     }
     346            2 :     HOST_RT_MEMORY_GUARD(hostMem);
     347            1 :     void* const* argsOnHost = static_cast<void* const*>(hostMem);
     348            1 :     size_t argNum = argsInfo.argsize / sizeof(uint64_t);
     349            1 :     PrintLog(argsOnHost, argNum, "args after execute");
     350              : 
     351            1 :     return ADUMP_SUCCESS;
     352            1 : }
     353              : 
     354            2 : void DumpOperator::PrintLog(void* const* argsOnHost, size_t argNum, const std::string& tag) const
     355              : {
     356            2 :     std::stringstream strStream;
     357            2 :     const uint32_t printNumEachTime = 20;
     358            2 :     uint32_t count = argNum / printNumEachTime;
     359            2 :     uint32_t left = argNum % printNumEachTime;
     360              : 
     361            3 :     for (uint32_t i = 0; i < count; ++i) {
     362            1 :         uint32_t begin = printNumEachTime * i;
     363            1 :         uint32_t end = printNumEachTime * (i + 1);
     364           21 :         for (uint32_t j = begin; j < end; ++j) {
     365           20 :             strStream << *(argsOnHost + j) << " ";
     366              :         }
     367            1 :         IDE_RUN_LOGI("[AIC_INFO] %s(%u to %u): %s", tag.c_str(), begin, end - 1, strStream.str().c_str());
     368            2 :         strStream.str("");
     369              :     }
     370              : 
     371            2 :     if (left != 0 && argNum > 0) {
     372            2 :         uint32_t begin = printNumEachTime * count;
     373            2 :         uint32_t end = argNum;
     374           11 :         for (uint32_t j = begin; j < end; ++j) {
     375            9 :             strStream << *(argsOnHost + j) << " ";
     376              :         }
     377            2 :         IDE_RUN_LOGI("[AIC_INFO] %s(%u to %u): %s", tag.c_str(), begin, end - 1, strStream.str().c_str());
     378              :     }
     379            2 : }
     380              : 
     381            2 : std::string DumpOperator::GetDumpFilePath(const std::string& dumpPath) const
     382              : {
     383            2 :     std::string opType = StrUtils::Replace(opType_, INVALID_FILE_NAME_CHAR, REPLACE_FILE_NAME_CHAR);
     384            2 :     std::string opName = StrUtils::Replace(opName_, INVALID_FILE_NAME_CHAR, REPLACE_FILE_NAME_CHAR);
     385            2 :     uint32_t taskId = identity_.taskId;
     386              :     std::string dumpFileName =
     387            2 :         opType + "." + opName + "." + std::to_string(taskId) + "." + SysUtils::GetCurrentTimeWithMillisecond();
     388            2 :     Path dumpFilePath(dumpPath);
     389            2 :     dumpFilePath.Concat(dumpFileName);
     390            4 :     return dumpFilePath.GetString();
     391            2 : }
     392              : 
     393            9 : void DumpOperator::RecordCurrentLog(std::ostringstream& oss)
     394              : {
     395            9 :     IDE_LOGE("%s", oss.str().c_str());
     396            9 :     logRecord_.emplace_back(oss.str() + "\n");
     397            9 :     oss.str("");
     398            9 : }
     399              : } // namespace Adx
        

Generated by: LCOV version 2.0-1