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

Generated by: LCOV version 2.0-1