LCOV - code coverage report
Current view: top level - adump - adx_dump_record.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 90.2 % 376 339
Test Date: 2026-08-31 10:09:28 Functions: 91.7 % 36 33

            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 "adx_dump_record.h"
      12              : #include <map>
      13              : #include <cinttypes>
      14              : #include <functional>
      15              : #include <pthread.h>
      16              : #include "mmpa_api.h"
      17              : #include "adx_log.h"
      18              : #include "file_utils.h"
      19              : #include "string_utils.h"
      20              : #include "memory_utils.h"
      21              : #include "common_utils.h"
      22              : #include "adx_dump_process.h"
      23              : #include "ide_os_type.h"
      24              : namespace Adx {
      25              : static const std::size_t MAX_IP_LENGTH = 16;
      26              : #if !defined(ADUMP_SOC_HOST) || ADUMP_SOC_HOST == 1
      27              : constexpr char STRING_BIN[] = ".bin";
      28              : constexpr char STRING_CSV[] = ".csv";
      29              : constexpr char CSV_HEADER[] = "Input/Output,Index,Data Size,Data Type,Format,Shape";
      30              : 
      31              : static const std::map<uint64_t, std::string> STATS_ITEM_MAP = {
      32              :     {DUMP_STATS_MAX, ",Max Value"},
      33              :     {DUMP_STATS_MIN, ",Min Value"},
      34              :     {DUMP_STATS_AVG, ",Avg Value"},
      35              :     {DUMP_STATS_NAN, ",Nan Count"},
      36              :     {DUMP_STATS_NEG_INF, ",Negative Inf Count"},
      37              :     {DUMP_STATS_POS_INF, ",Positive Inf Count"},
      38              :     {DUMP_STATS_L2NORM, ",l2norm"}};
      39              : 
      40              : static const std::map<toolkit::dump::OutputDataType, std::string> DT_STRING_MAP = {
      41              :     {toolkit::dump::DT_UNDEFINED, "DT_UNDEFINED"},
      42              :     {toolkit::dump::DT_FLOAT, "DT_FLOAT"},
      43              :     {toolkit::dump::DT_FLOAT16, "DT_FLOAT16"},
      44              :     {toolkit::dump::DT_INT8, "DT_INT8"},
      45              :     {toolkit::dump::DT_UINT8, "DT_UINT8"},
      46              :     {toolkit::dump::DT_INT16, "DT_INT16"},
      47              :     {toolkit::dump::DT_UINT16, "DT_UINT16"},
      48              :     {toolkit::dump::DT_INT32, "DT_INT32"},
      49              :     {toolkit::dump::DT_INT64, "DT_INT64"},
      50              :     {toolkit::dump::DT_UINT32, "DT_UINT32"},
      51              :     {toolkit::dump::DT_UINT64, "DT_UINT64"},
      52              :     {toolkit::dump::DT_BOOL, "DT_BOOL"},
      53              :     {toolkit::dump::DT_DOUBLE, "DT_DOUBLE"},
      54              :     {toolkit::dump::DT_STRING, "DT_STRING"},
      55              :     {toolkit::dump::DT_DUAL_SUB_INT8, "DT_DUAL_SUB_INT8"},
      56              :     {toolkit::dump::DT_DUAL_SUB_UINT8, "DT_DUAL_SUB_UINT8"},
      57              :     {toolkit::dump::DT_COMPLEX64, "DT_COMPLEX64"},
      58              :     {toolkit::dump::DT_COMPLEX128, "DT_COMPLEX128"},
      59              :     {toolkit::dump::DT_QINT8, "DT_QINT8"},
      60              :     {toolkit::dump::DT_QINT16, "DT_QINT16"},
      61              :     {toolkit::dump::DT_QINT32, "DT_QINT32"},
      62              :     {toolkit::dump::DT_QUINT8, "DT_QUINT8"},
      63              :     {toolkit::dump::DT_QUINT16, "DT_QUINT16"},
      64              :     {toolkit::dump::DT_RESOURCE, "DT_RESOURCE"},
      65              :     {toolkit::dump::DT_STRING_REF, "DT_STRING_REF"},
      66              :     {toolkit::dump::DT_DUAL, "DT_DUAL"},
      67              :     {toolkit::dump::DT_VARIANT, "DT_VARIANT"},
      68              :     {toolkit::dump::DT_BF16, "DT_BF16"},
      69              :     {toolkit::dump::DT_INT4, "DT_INT4"},
      70              :     {toolkit::dump::DT_UINT1, "DT_UINT1"},
      71              :     {toolkit::dump::DT_INT2, "DT_INT2"},
      72              :     {toolkit::dump::DT_UINT2, "DT_UINT2"},
      73              :     {toolkit::dump::DT_HIFLOAT8, "DT_HIFLOAT8"},
      74              :     {toolkit::dump::DT_FLOAT8_E5M2, "DT_FLOAT8_E5M2"},
      75              :     {toolkit::dump::DT_FLOAT8_E4M3FN, "DT_FLOAT8_E4M3FN"},
      76              :     {toolkit::dump::DT_FLOAT8_E8M0, "DT_FLOAT8_E8M0"},
      77              :     {toolkit::dump::DT_FLOAT6_E3M2, "DT_FLOAT6_E3M2"},
      78              :     {toolkit::dump::DT_FLOAT6_E2M3, "DT_FLOAT6_E2M3"},
      79              :     {toolkit::dump::DT_FLOAT4_E2M1, "DT_FLOAT4_E2M1"},
      80              :     {toolkit::dump::DT_FLOAT4_E1M2, "DT_FLOAT4_E1M2"},
      81              : };
      82              : 
      83              : static const std::map<toolkit::dump::OutputFormat, std::string> FORMAT_STRING_MAP = {
      84              :     {toolkit::dump::FORMAT_NCHW, "NCHW"},
      85              :     {toolkit::dump::FORMAT_NHWC, "NHWC"},
      86              :     {toolkit::dump::FORMAT_ND, "ND"},
      87              :     {toolkit::dump::FORMAT_NC1HWC0, "NC1HWC0"},
      88              :     {toolkit::dump::FORMAT_FRACTAL_Z, "FRACTAL_Z"},
      89              :     {toolkit::dump::FORMAT_NC1C0HWPAD, "NC1C0HWPAD"},
      90              :     {toolkit::dump::FORMAT_NHWC1C0, "NHWC1C0"},
      91              :     {toolkit::dump::FORMAT_FSR_NCHW, "FSR_NCHW"},
      92              :     {toolkit::dump::FORMAT_FRACTAL_DECONV, "FRACTAL_DECONV"},
      93              :     {toolkit::dump::FORMAT_C1HWNC0, "C1HWNC0"},
      94              :     {toolkit::dump::FORMAT_FRACTAL_DECONV_TRANSPOSE, "FRACTAL_DECONV_TRANSPOSE"},
      95              :     {toolkit::dump::FORMAT_FRACTAL_DECONV_SP_STRIDE_TRANS, "FRACTAL_DECONV_SP_STRIDE_TRANS"},
      96              :     {toolkit::dump::FORMAT_NC1HWC0_C04, "NC1HWC0_C04"},
      97              :     {toolkit::dump::FORMAT_FRACTAL_Z_C04, "FRACTAL_Z_C04"},
      98              :     {toolkit::dump::FORMAT_CHWN, "CHWN"},
      99              :     {toolkit::dump::FORMAT_FRACTAL_DECONV_SP_STRIDE8_TRANS, "FRACTAL_DECONV_SP_STRIDE8_TRANS"},
     100              :     {toolkit::dump::FORMAT_HWCN, "HWCN"},
     101              :     {toolkit::dump::FORMAT_NC1KHKWHWC0, "NC1KHKWHWC0"},
     102              :     {toolkit::dump::FORMAT_BN_WEIGHT, "BN_WEIGHT"},
     103              :     {toolkit::dump::FORMAT_FILTER_HWCK, "FILTER_HWCK"},
     104              :     {toolkit::dump::FORMAT_HASHTABLE_LOOKUP_LOOKUPS, "HASHTABLE_LOOKUP_LOOKUPS"},
     105              :     {toolkit::dump::FORMAT_HASHTABLE_LOOKUP_KEYS, "HASHTABLE_LOOKUP_KEYS"},
     106              :     {toolkit::dump::FORMAT_HASHTABLE_LOOKUP_VALUE, "HASHTABLE_LOOKUP_VALUE"},
     107              :     {toolkit::dump::FORMAT_HASHTABLE_LOOKUP_OUTPUT, "HASHTABLE_LOOKUP_OUTPUT"},
     108              :     {toolkit::dump::FORMAT_HASHTABLE_LOOKUP_HITS, "HASHTABLE_LOOKUP_HITS"},
     109              :     {toolkit::dump::FORMAT_C1HWNCoC0, "C1HWNCoC0"},
     110              :     {toolkit::dump::FORMAT_MD, "MD"},
     111              :     {toolkit::dump::FORMAT_NDHWC, "NDHWC"},
     112              :     {toolkit::dump::FORMAT_FRACTAL_ZZ, "FRACTAL_ZZ"},
     113              :     {toolkit::dump::FORMAT_FRACTAL_NZ, "FRACTAL_NZ"},
     114              :     {toolkit::dump::FORMAT_NCDHW, "NCDHW"},
     115              :     {toolkit::dump::FORMAT_DHWCH, "DHWCH"},
     116              :     {toolkit::dump::FORMAT_NDC1HWC0, "NDC1HWC0"},
     117              :     {toolkit::dump::FORMAT_FRACTAL_Z_3D, "FRACTAL_Z_3D"},
     118              :     {toolkit::dump::FORMAT_CN, "CN"},
     119              :     {toolkit::dump::FORMAT_NC, "NC"},
     120              :     {toolkit::dump::FORMAT_DHWNC, "DHWNC"},
     121              :     {toolkit::dump::FORMAT_FRACTAL_Z_3D_TRANSPOSE, "FRACTAL_Z_3D_TRANSPOSE"},
     122              :     {toolkit::dump::FORMAT_FRACTAL_ZN_LSTM, "FRACTAL_ZN_LSTM"},
     123              :     {toolkit::dump::FORMAT_FRACTAL_Z_G, "FRACTAL_Z_G"},
     124              :     {toolkit::dump::FORMAT_RESERVED, "RESERVED"},
     125              :     {toolkit::dump::FORMAT_ALL, "ALL"},
     126              :     {toolkit::dump::FORMAT_NULL, "NULL"},
     127              :     {toolkit::dump::FORMAT_ND_RNN_BIAS, "ND_RNN_BIAS"},
     128              :     {toolkit::dump::FORMAT_FRACTAL_ZN_RNN, "FRACTAL_ZN_RNN"},
     129              :     {toolkit::dump::FORMAT_NYUV, "NYUV"},
     130              :     {toolkit::dump::FORMAT_NYUV_A, "NYUV_A"},
     131              :     {toolkit::dump::FORMAT_NCL, "NCL"},
     132              :     {toolkit::dump::FORMAT_FRACTAL_Z_WINO, "FRACTAL_Z_WINO"},
     133              :     {toolkit::dump::FORMAT_C1HWC0, "C1HWC0"}};
     134              : #endif
     135              : 
     136            5 : AdxDumpRecord::AdxDumpRecord() : dumpRecordFlag_(true), dumpInitNum_(0)
     137              : {
     138              :     int32_t ret =
     139            5 :         pthread_atfork(AdxDumpRecord::PrepareFork, AdxDumpRecord::PostForkParent, AdxDumpRecord::PostForkChild);
     140            5 :     if (ret != 0) {
     141            0 :         IDE_LOGW("call pthread_atfork failed, ret: %d", ret);
     142              :     }
     143              : #if !defined(ADUMP_SOC_HOST) || ADUMP_SOC_HOST == 1
     144            5 :     fileNameStatus_.reserve(FILENAME_CHECK_SIZE_MAX);
     145           55 :     for (size_t idx = 0; idx < FILENAME_CHECK_SIZE_MAX; ++idx) {
     146          150 :         fileNameStatus_.push_back("");
     147              :     }
     148              :     funcMap_ = {
     149            0 :         {0, std::bind(&AdxDumpRecord::TypeDataHandle, this, std::placeholders::_1, std::placeholders::_2)}, // max
     150            0 :         {1, std::bind(&AdxDumpRecord::TypeDataHandle, this, std::placeholders::_1, std::placeholders::_2)}, // min
     151            0 :         {2, std::bind(&AdxDumpRecord::FloatDataHandle, this, std::placeholders::_1)},                       // avg
     152            0 :         {3, std::bind(&AdxDumpRecord::Int32DataHandle, this, std::placeholders::_1)},                       // nan
     153            0 :         {4, std::bind(&AdxDumpRecord::Int32DataHandle, this, std::placeholders::_1)},                       // neg inf
     154            0 :         {5, std::bind(&AdxDumpRecord::Int32DataHandle, this, std::placeholders::_1)},                       // pos inf
     155            0 :         {6, std::bind(&AdxDumpRecord::FloatDataHandle, this, std::placeholders::_1)},                       // l2norm
     156           40 :     };
     157              : #endif
     158           10 : }
     159              : 
     160            5 : AdxDumpRecord::~AdxDumpRecord() { UnInit(); }
     161              : 
     162          391 : int32_t AdxDumpRecord::GetDumpInitNum() const { return dumpInitNum_; }
     163              : 
     164          112 : void AdxDumpRecord::UpdateDumpInitNum(bool isPlus)
     165              : {
     166          112 :     if (isPlus) {
     167           52 :         dumpInitNum_++;
     168           60 :     } else if (dumpInitNum_ > 0) {
     169           52 :         dumpInitNum_--;
     170              :     }
     171          112 :     IDE_LOGI("dump init number: %d", dumpInitNum_);
     172          112 : }
     173              : 
     174           55 : bool AdxDumpRecord::HasStartedServer() const { return dumpInitNum_ > 0; }
     175              : 
     176           62 : bool AdxDumpRecord::CanShutdownServer() const { return dumpInitNum_ <= 1; }
     177              : 
     178           65 : int32_t AdxDumpRecord::Init(const std::string& hostPid)
     179              : {
     180              :     // non-soc case
     181           65 :     if (hostPid.empty()) {
     182           61 :         char dumpPath[MAX_FILE_PATH_LENGTH] = {0};
     183           61 :         if (mmGetCwd(dumpPath, sizeof(dumpPath)) != EN_OK) {
     184            1 :             IDE_LOGE("get current dir failed ");
     185            1 :             return IDE_DAEMON_ERROR;
     186              :         }
     187           60 :         dumpPath_ = dumpPath;
     188              :     } else {
     189              : #if (OS_TYPE == LINUX)
     190              :         // soc case
     191            4 :         std::string appBin = "/proc/" + hostPid + "/exe";
     192            4 :         errno = 0;
     193            4 :         if (!FileUtils::IsFileExist(appBin) && errno != EACCES) {
     194            0 :             appBin = "/local/proc/" + hostPid + "/exe"; // aoscore
     195              :         }
     196            4 :         uint32_t pathSize = MMPA_MAX_PATH + 1;
     197            4 :         IdeStringBuffer curPath = reinterpret_cast<IdeStringBuffer>(IdeXmalloc(pathSize));
     198            4 :         IDE_CTRL_VALUE_FAILED(curPath != nullptr, return IDE_DAEMON_ERROR, "malloc failed");
     199            4 :         errno = 0;
     200            4 :         int32_t len = readlink(appBin.c_str(), curPath, MMPA_MAX_PATH); // read self path of store
     201            4 :         if (len < 0 || len > MMPA_MAX_PATH) {
     202            2 :             IDE_LOGE(
     203              :                 "Can't get app bin directory, strerr: %s, length: %d bytes, path: %s", strerror(errno), len,
     204              :                 appBin.c_str());
     205            2 :             IDE_XFREE_AND_SET_NULL(curPath);
     206            2 :             return IDE_DAEMON_ERROR;
     207              :         }
     208            2 :         IDE_LOGI("get app bin path: %s", curPath);
     209            2 :         curPath[len] = '\0'; // add string end char
     210            2 :         dumpPath_ = curPath;
     211            2 :         std::string::size_type idx = dumpPath_.find_last_of(OS_SPLIT_STR);
     212            2 :         dumpPath_ = dumpPath_.substr(0, idx);
     213            2 :         IDE_XFREE_AND_SET_NULL(curPath);
     214              : #endif
     215            4 :     }
     216           62 :     IDE_LOGI("dumpPath prefix is %s", dumpPath_.c_str());
     217           62 :     if (!dumpPath_.empty() && dumpPath_.back() != OS_SPLIT_CHAR) {
     218           39 :         dumpPath_ += OS_SPLIT_CHAR;
     219              :     }
     220              : 
     221           62 :     std::lock_guard<std::mutex> lock(recordMutex_);
     222           62 :     if (hostDumpDataInfoQueue_ == nullptr) {
     223            6 :         hostDumpDataInfoQueue_.reset(new (std::nothrow) BoundQueueMemory<HostDumpDataInfo>());
     224            6 :         IDE_CTRL_VALUE_FAILED(
     225              :             hostDumpDataInfoQueue_ != nullptr, return IDE_DAEMON_ERROR, "Failed to new hostDumpDataInfoQueue");
     226              :     }
     227           62 :     hostDumpDataInfoQueue_->Init();
     228           62 :     IDE_LOGI("record remote dump temp path: %s", dumpPath_.c_str());
     229           62 :     hostDumpDataInfoQueue_->SetPath(dumpPath_);
     230           62 :     dumpRecordFlag_ = true;
     231           62 :     return IDE_DAEMON_OK;
     232           62 : }
     233              : 
     234           57 : int32_t AdxDumpRecord::StartRecord()
     235              : {
     236           57 :     std::lock_guard<std::mutex> lock(recordMutex_);
     237           57 :     if (recordThread_.joinable()) {
     238            4 :         IDE_LOGI("dump record thread has been started, no need to start again");
     239            4 :         return IDE_DAEMON_OK;
     240              :     }
     241           53 :     dumpRecordFlag_ = true;
     242              :     try {
     243           53 :         recordThread_ = std::thread(&AdxDumpRecord::RecordDumpInfo, this);
     244            0 :     } catch (const std::exception& ex) {
     245            0 :         dumpRecordFlag_ = false;
     246            0 :         IDE_LOGE("Create the dump record thread failed, message: %s", ex.what());
     247            0 :         return IDE_DAEMON_ERROR;
     248            0 :     }
     249           53 :     return IDE_DAEMON_OK;
     250           57 : }
     251              : 
     252              : /**
     253              :  * @brief initialize record file
     254              :  * @param [in] recordPath : record file Path
     255              :  * @return
     256              :  *      IDE_DAEMON_ERROR : falied
     257              :  *      IDE_DAEMON_OK : success
     258              :  */
     259           67 : int32_t AdxDumpRecord::UnInit()
     260              : {
     261           67 :     std::lock_guard<std::mutex> lock(recordMutex_);
     262           67 :     IDE_LOGI("start to dump uninit");
     263           67 :     dumpRecordFlag_ = false;
     264           67 :     if (hostDumpDataInfoQueue_ != nullptr) {
     265           64 :         hostDumpDataInfoQueue_->Quit();
     266              :     }
     267           67 :     if (recordThread_.joinable()) {
     268           52 :         recordThread_.join();
     269              :     }
     270           67 :     IDE_LOGI("dump uninit success");
     271           67 :     return IDE_DAEMON_OK;
     272           67 : }
     273              : 
     274            8 : void AdxDumpRecord::PrepareFork() { Instance().recordMutex_.lock(); }
     275              : 
     276            5 : void AdxDumpRecord::PostForkParent() { Instance().recordMutex_.unlock(); }
     277              : 
     278            3 : void AdxDumpRecord::PostForkChild()
     279              : {
     280            3 :     auto& instance = Instance();
     281            3 :     instance.dumpRecordFlag_ = false;
     282            3 :     if (instance.recordThread_.joinable()) {
     283            1 :         instance.recordThread_.detach();
     284              :     }
     285              : 
     286            3 :     (void)instance.hostDumpDataInfoQueue_.release();
     287            3 :     instance.recordMutex_.unlock();
     288            3 : }
     289              : 
     290              : /**
     291              :  * @brief record dump data to disk
     292              :  * @param [in] dumpChunk : dump chunk
     293              :  * @return
     294              :  *      true : record dump data to disk success
     295              :  *      false : record dump data to disk failed
     296              :  */
     297            8 : bool AdxDumpRecord::RecordDumpDataToDisk(const DumpChunk& dumpChunk) const
     298              : {
     299              :     // dump file aging
     300            8 :     std::string filePath = dumpChunk.fileName;
     301            8 :     if (filePath.empty()) {
     302            2 :         IDE_LOGE("filepath of received dump chunk is empty");
     303            2 :         return false;
     304              :     }
     305            6 :     if (JudgeRemoteFalg(filePath)) {
     306            0 :         auto pos = filePath.find_first_of(":");
     307            0 :         filePath = filePath.substr(pos + 1);
     308            0 :         filePath = dumpPath_ + filePath;
     309              :     } else {
     310            6 :         if (!FileUtils::IsAbsolutePath(filePath)) {
     311            6 :             filePath = dumpPath_ + filePath;
     312              :         }
     313              :     }
     314              : 
     315              : #if (OS_TYPE != LINUX)
     316              :     filePath = FileUtils::ReplaceAll(filePath, "/", "\\");
     317              : #endif
     318              : 
     319            6 :     IDE_LOGI("start to record dump data to disk path: %s", filePath.c_str());
     320              : 
     321            6 :     std::string saveDirName = FileUtils::GetFileDir(filePath);
     322            6 :     if (!FileUtils::IsFileExist(saveDirName)) {
     323            1 :         if (FileUtils::CreateDir(saveDirName) != IDE_DAEMON_NONE_ERROR) {
     324            1 :             IDE_LOGE("create dir failed path: %s", filePath.c_str());
     325            1 :             return false;
     326              :         }
     327              :     }
     328              : 
     329            5 :     while (FileUtils::IsDiskFull(saveDirName, dumpChunk.bufLen)) {
     330            1 :         IDE_LOGE("don't have enough free disk %u bytes", dumpChunk.bufLen);
     331            1 :         return false;
     332              :     }
     333              : 
     334            4 :     std::string realPath;
     335            4 :     if (FileUtils::FileNameIsReal(filePath, realPath) != IDE_DAEMON_OK) {
     336            1 :         IDE_LOGE("real path: %s", filePath.c_str());
     337            1 :         return false;
     338              :     }
     339              : 
     340            6 :     IdeErrorT err = FileUtils::WriteFile(realPath.c_str(), dumpChunk.dataBuf, dumpChunk.bufLen, dumpChunk.offset);
     341            3 :     if (err != IDE_DAEMON_NONE_ERROR) {
     342            1 :         (void)remove(realPath.c_str());
     343            1 :         IDE_LOGE("WriteFile failed, fileName: %s, err: %d", realPath.c_str(), err);
     344            1 :         return false;
     345              :     }
     346            2 :     IDE_LOGI("record dump data success: %s", realPath.c_str());
     347            2 :     return true;
     348            8 : }
     349              : 
     350              : /**
     351              :  * @brief judge if is remote case based on flag
     352              :  * @param [in] msg : flag msg
     353              :  * @return
     354              :  *      true : is remote case
     355              :  *      false : not remote case
     356              :  */
     357            6 : bool AdxDumpRecord::JudgeRemoteFalg(const std::string& msg) const
     358              : {
     359            6 :     std::size_t len = msg.find_first_of(":");
     360            6 :     if (len != std::string::npos && len < MAX_IP_LENGTH) {
     361            0 :         std::string ipStr = msg.substr(0, len);
     362            0 :         if (StringUtils::IpValid(ipStr)) {
     363            0 :             IDE_LOGD("remote ip info check pass: %s", ipStr.c_str());
     364            0 :             return true;
     365              :         }
     366            0 :     }
     367            6 :     IDE_LOGD("non remote ip case checked.");
     368              : 
     369            6 :     return false;
     370              : }
     371              : 
     372            0 : void AdxDumpRecord::SetWorkPath(const std::string& path) { workPath_ = path; }
     373              : 
     374              : #if !defined(ADUMP_SOC_HOST) || ADUMP_SOC_HOST == 1
     375           13 : void AdxDumpRecord::SetOptimizationMode(uint64_t statsItem)
     376              : {
     377           13 :     if (dumpStatsItem_ == statsItem) {
     378           10 :         return;
     379              :     }
     380            3 :     dumpStatsItem_ = statsItem;
     381            3 :     IDE_LOGI("SetOptimizationMode success with stats items:[0x%llx]", dumpStatsItem_);
     382            3 :     uint16_t statsNum = 0;
     383            3 :     statsHeader_ = CSV_HEADER;
     384            3 :     statsList_.clear();
     385              : 
     386            3 :     if (dumpStatsItem_ ==
     387              :         (DUMP_STATS_MAX | DUMP_STATS_MIN | DUMP_STATS_AVG | DUMP_STATS_NAN | DUMP_STATS_NEG_INF | DUMP_STATS_POS_INF)) {
     388            1 :         compatible_ = true;
     389              :     } else {
     390            2 :         statsHeader_ += ",Count";
     391              :     }
     392           24 :     for (auto it = STATS_ITEM_MAP.begin(); it != STATS_ITEM_MAP.cend(); ++it) {
     393           21 :         if ((dumpStatsItem_ & it->first) != 0) {
     394            9 :             if (compatible_ && statsNum == COUNT_HEADER_COMPATIBLE) {
     395            1 :                 statsHeader_ += ",Count";
     396              :             }
     397            9 :             statsHeader_ += it->second;
     398            9 :             statsList_.push_back(statsNum);
     399              :         }
     400           21 :         ++statsNum;
     401              :     }
     402            3 :     IDE_LOGI("SetOptimizationMode generate table header [%s].", statsHeader_.c_str());
     403              : }
     404              : 
     405           10 : std::string AdxDumpRecord::GetShapeString(const uint32_t shape[], int32_t shapeSize, int64_t& count) const
     406              : {
     407           10 :     IDE_CTRL_VALUE_FAILED(
     408              :         shapeSize <= MAX_SHAPE_SIZE, return "NA", "Shape size %d is out of range %d", shapeSize, MAX_SHAPE_SIZE);
     409           10 :     if (shapeSize == 0) { // 没有shape信息时,保持原有方式用-占位
     410            0 :         return "-";
     411              :     }
     412           10 :     std::ostringstream oss;
     413           40 :     for (int32_t idx = 0; idx < shapeSize; ++idx) {
     414           30 :         count *= shape[idx];
     415           30 :         oss << shape[idx];
     416           30 :         if (idx != shapeSize - 1) {
     417           20 :             oss << "x";
     418              :         }
     419              :     }
     420           10 :     return oss.str();
     421           10 : }
     422              : 
     423              : template <typename T>
     424           20 : std::string AdxDumpRecord::GetStringName(T key, const std::map<T, std::string>& stringMap) const
     425              : {
     426           20 :     auto it = stringMap.find(key);
     427           20 :     if (it != stringMap.cend()) {
     428           19 :         return it->second;
     429              :     }
     430            1 :     IDE_LOGW("Cannot find [%d] type name in string map.", key);
     431            2 :     return "UNKNOW";
     432              : }
     433              : 
     434           28 : std::string AdxDumpRecord::Int32DataHandle(const int64_t& data) const
     435              : {
     436              :     DataTypeUnion dtUnion;
     437           28 :     dtUnion.longIntValue = data;
     438           56 :     return std::to_string(dtUnion.intValue[0]);
     439              : }
     440              : 
     441           19 : std::string AdxDumpRecord::FloatDataHandle(const int64_t& data) const
     442              : {
     443              :     DataTypeUnion dtUnion;
     444           19 :     dtUnion.longIntValue = data;
     445           19 :     std::ostringstream oss;
     446           19 :     oss << dtUnion.floatValue;
     447           38 :     return oss.str();
     448           19 : }
     449              : 
     450           18 : std::string AdxDumpRecord::TypeDataHandle(const int64_t& data, toolkit::dump::OutputDataType dType) const
     451              : {
     452              :     // 如果dt是int64数据读取为int64;dt是非int64数据读取为int32,dt是float数据读取为float32
     453           18 :     if (dType == toolkit::dump::DT_FLOAT || dType == toolkit::dump::DT_FLOAT16 || dType == toolkit::dump::DT_BF16 ||
     454           12 :         dType == toolkit::dump::DT_HIFLOAT8 || dType == toolkit::dump::DT_FLOAT8_E5M2 ||
     455              :         dType == toolkit::dump::DT_FLOAT8_E4M3FN) {
     456           10 :         return FloatDataHandle(data);
     457            8 :     } else if (dType == toolkit::dump::DT_INT64) {
     458            4 :         return std::to_string(data);
     459              :     } else {
     460            4 :         return Int32DataHandle(data);
     461              :     }
     462              : }
     463              : 
     464           52 : std::string AdxDumpRecord::GetStatsString(toolkit::dump::OutputDataType dType, uint16_t pos, const int64_t& data)
     465              : {
     466           52 :     auto it = funcMap_.find(pos);
     467           52 :     if (it != funcMap_.cend()) {
     468           51 :         std::string result = it->second(data, dType);
     469           51 :         return result;
     470            0 :     } else {
     471            1 :         IDE_LOGW("Dump stats [%hu] is not supported.", pos);
     472            2 :         return "NA";
     473              :     }
     474              : }
     475              : 
     476            3 : bool AdxDumpRecord::CheckFileNameExist(const std::string& filename)
     477              : {
     478            3 :     auto it = std::find(fileNameStatus_.begin(), fileNameStatus_.end(), filename);
     479            6 :     if (it != fileNameStatus_.end()) {
     480            2 :         return true;
     481              :     }
     482            1 :     return false;
     483              : }
     484              : 
     485           14 : void AdxDumpRecord::AppendFileName(const std::string& filename)
     486              : {
     487              :     // Stores the names of processed files.
     488           14 :     fileNameStatus_[filenameIndex_] = filename;
     489           14 :     filenameIndex_ = (filenameIndex_ + 1) % fileNameStatus_.size();
     490           14 : }
     491              : 
     492           10 : void AdxDumpRecord::StatisticsData(
     493              :     std::stringstream& strStream, std::shared_ptr<OpStatsResult> statsResult, const int64_t& count, const int32_t& idx)
     494              : {
     495           10 :     if (statsResult->stat[idx].result != 0) {
     496            1 :         IDE_LOGW(
     497              :             "Stats data is unsupported, index is %d, size is %" PRId64 ", result is %u.", statsResult->stat[idx].index,
     498              :             statsResult->stat[idx].size, statsResult->stat[idx].result);
     499            7 :         for (size_t i = 0; i < statsList_.size(); ++i) {
     500            6 :             if (compatible_ && i == COUNT_HEADER_COMPATIBLE) {
     501            1 :                 strStream << "," << count;
     502              :             }
     503              :             strStream << ","
     504            6 :                       << "NA";
     505              :         }
     506              :     } else {
     507            9 :         size_t statsSize = sizeof(statsResult->stat[idx].stats) / sizeof(statsResult->stat[idx].stats[0]);
     508            9 :         if (!compatible_) {
     509            0 :             strStream << "," << count;
     510              :         }
     511           69 :         for (const uint16_t& pos : statsList_) {
     512           51 :             IDE_CTRL_VALUE_FAILED_NODO(
     513              :                 pos < statsSize, continue, "Index %hu is out of range %" PRIu64 ".", pos, statsSize);
     514           51 :             if (compatible_ && pos == COUNT_HEADER_COMPATIBLE) {
     515            8 :                 strStream << "," << count;
     516              :             }
     517              :             strStream << ","
     518           51 :                       << GetStatsString(
     519           51 :                              static_cast<toolkit::dump::OutputDataType>(statsResult->stat[idx].dType), pos,
     520          102 :                              statsResult->stat[idx].stats[pos]);
     521              :         }
     522              :     }
     523           10 : }
     524              : 
     525           10 : bool AdxDumpRecord::GenerateFileData(
     526              :     std::stringstream& strStream, const std::string& filename, std::shared_ptr<OpStatsResult> statsResult)
     527              : {
     528           10 :     IDE_CTRL_VALUE_FAILED(statsResult->statItem != 0, return false, "Dump stats is empty, nothing need to do.");
     529           10 :     IDE_CTRL_VALUE_FAILED(
     530              :         statsResult->tensorNum <= MAX_STATS_RESULT_NUM, return false, "Dump stats number %d is bigger than %d.",
     531              :         statsResult->tensorNum, MAX_STATS_RESULT_NUM);
     532           10 :     SetOptimizationMode(statsResult->statItem);
     533              :     // If the file name is processed for the first time, add the table header.
     534           10 :     if (!CheckFileNameExist(filename)) {
     535            9 :         strStream << statsHeader_;
     536            9 :         strStream << "\n";
     537              :     }
     538              : 
     539           20 :     for (int32_t idx = 0; idx < statsResult->tensorNum; ++idx) {
     540           10 :         IDE_LOGI("Process the data in file %s for the %d times.", filename.c_str(), idx);
     541           10 :         int64_t count = 1; // 默认count值为1
     542           10 :         std::string ioString = statsResult->stat[idx].io == 0 ? "Input" : "Output";
     543           10 :         strStream << ioString;
     544           10 :         strStream << "," << statsResult->stat[idx].index;
     545           10 :         strStream << "," << statsResult->stat[idx].size;
     546              :         strStream << ","
     547           10 :                   << GetStringName(
     548           10 :                          static_cast<toolkit::dump::OutputDataType>(statsResult->stat[idx].dType), DT_STRING_MAP);
     549              :         strStream << ","
     550           10 :                   << GetStringName(
     551           10 :                          static_cast<toolkit::dump::OutputFormat>(statsResult->stat[idx].format), FORMAT_STRING_MAP);
     552           10 :         strStream << "," << GetShapeString(statsResult->stat[idx].shape, statsResult->stat[idx].shapeSize, count);
     553           10 :         IDE_LOGD(
     554              :             "Process the data with index[%d], io[%d], statsLen[%u], result[%u], shapeSize[%d], size[%" PRId64 "].",
     555              :             statsResult->stat[idx].index, statsResult->stat[idx].io, statsResult->stat[idx].statsLen,
     556              :             statsResult->stat[idx].result, statsResult->stat[idx].shapeSize, statsResult->stat[idx].size);
     557              : 
     558           10 :         StatisticsData(strStream, statsResult, count, idx);
     559           10 :         strStream << "\n";
     560           10 :     }
     561           10 :     return true;
     562              : }
     563              : 
     564            1 : bool AdxDumpRecord::DumpDataToCallback(
     565              :     const std::string& filename, const std::string& dumpData, int64_t offSet, int32_t flag)
     566              : {
     567            1 :     IDE_LOGD("Ready to send file %s to mindspore session!", filename.c_str());
     568            1 :     IDE_CTRL_VALUE_FAILED(!dumpData.empty(), return false, "Dump data in DumpDataToCallback is empty.");
     569              : 
     570              :     std::function<int32_t(const struct DumpChunk*, int32_t)> messageCallback =
     571            1 :         AdxDumpProcess::Instance().GetCallbackFun();
     572            1 :     IDE_CTRL_VALUE_FAILED(
     573              :         messageCallback, return false, "Registered messageCallback function is not callable,\
     574              :             drop this data packet, filename:%s",
     575              :         filename.c_str());
     576              : 
     577            1 :     auto dumpChunkLen = sizeof(DumpChunk) + dumpData.size() + 1;
     578              :     std::unique_ptr<DumpChunk, void (*)(DumpChunk*)> dumpChunk(
     579            2 :         static_cast<DumpChunk*>(IdeXmalloc(dumpChunkLen)), [](DumpChunk* p) { IdeXfree(p); });
     580            1 :     IDE_CTRL_VALUE_FAILED(dumpChunk != nullptr, return IDE_DAEMON_ERROR, "Failed to malloc for dump chunk.");
     581              : 
     582            1 :     errno_t err = strncpy_s(dumpChunk->fileName, MAX_FILE_PATH_LENGTH, filename.c_str(), filename.size());
     583            1 :     IDE_CTRL_VALUE_FAILED(err == EOK, return false, "Filename string copy failed, err: %d", err);
     584            1 :     dumpChunk->bufLen = dumpData.size() + 1;
     585            1 :     dumpChunk->offset = offSet;
     586            1 :     dumpChunk->flag = flag;
     587            1 :     dumpChunk->isLastChunk = 1;
     588              : 
     589            1 :     err = strncpy_s(
     590            1 :         reinterpret_cast<AdxStringBuffer>(dumpChunk->dataBuf), dumpChunk->bufLen, dumpData.c_str(), dumpData.size());
     591            1 :     IDE_CTRL_VALUE_FAILED(err == EOK, return false, "DataBuf string copy failed, err: %d", err);
     592              : 
     593            1 :     int32_t ret = messageCallback(dumpChunk.get(), dumpChunkLen);
     594            1 :     IDE_CTRL_VALUE_FAILED(
     595              :         ret == IDE_DAEMON_NONE_ERROR, return false, "Failed to transmission dump data to mindspore. err = %d", ret);
     596            1 :     IDE_LOGI("Send dump data to mindspore success: %s", filename.c_str());
     597            1 :     AppendFileName(filename);
     598            1 :     return true;
     599            1 : }
     600              : 
     601            6 : bool AdxDumpRecord::FileNameCheck(const DumpChunk& dumpChunk) const
     602              : {
     603            6 :     size_t binSize = strlen(STRING_BIN);
     604            6 :     std::string filename = dumpChunk.fileName;
     605            6 :     size_t nameSize = filename.size();
     606            9 :     if (nameSize > binSize && filename.compare(nameSize - binSize, binSize, STRING_BIN) == 0 &&
     607            3 :         dumpChunk.bufLen == sizeof(OpStatsResult)) {
     608            1 :         IDE_LOGI("Received dump buffer length %u bytes, file name [%s].", dumpChunk.bufLen, dumpChunk.fileName);
     609            1 :         return true;
     610              :     }
     611            5 :     IDE_LOGD(
     612              :         "File name [%s] of dump chunk is not end with .bin, or data size %u bytes is different from %" PRIu64 ".",
     613              :         dumpChunk.fileName, dumpChunk.bufLen, sizeof(OpStatsResult));
     614            5 :     return false;
     615            6 : }
     616              : 
     617            7 : bool AdxDumpRecord::StatsDataParsing(const DumpChunk& dumpChunk)
     618              : {
     619            7 :     std::string filename = dumpChunk.fileName;
     620            7 :     filename.replace(filename.size() - strlen(STRING_BIN), strlen(STRING_BIN), STRING_CSV);
     621              : 
     622            7 :     std::shared_ptr<OpStatsResult> statsResult;
     623              :     try {
     624            7 :         statsResult = std::make_shared<OpStatsResult>();
     625            0 :     } catch (std::exception& ex) {
     626            0 :         IDE_LOGE("Make shared failed, message: %s", ex.what());
     627            0 :         return false;
     628            0 :     }
     629            7 :     auto err = memcpy_s(statsResult.get(), dumpChunk.bufLen, dumpChunk.dataBuf, dumpChunk.bufLen);
     630            7 :     IDE_CTRL_VALUE_FAILED(err == EOK, return false, "Filename string copy failed, err: %d", err);
     631              : 
     632            7 :     std::stringstream strStream;
     633            7 :     IDE_CTRL_VALUE_FAILED(GenerateFileData(strStream, filename, statsResult), return false, "Failed to export data.");
     634              : 
     635            7 :     if (AdxDumpProcess::Instance().IsRegistered()) { // dump data to mindspore and return
     636            1 :         return DumpDataToCallback(filename, strStream.str(), dumpChunk.offset, dumpChunk.flag);
     637              :     }
     638              : 
     639            6 :     if (JudgeRemoteFalg(filename)) {
     640            1 :         auto pos = filename.find_first_of(":");
     641            1 :         filename = filename.substr(pos + 1);
     642            1 :         filename = dumpPath_ + filename;
     643              :     } else {
     644            5 :         if (!FileUtils::IsAbsolutePath(filename)) {
     645            5 :             filename = dumpPath_ + filename;
     646              :         }
     647              :     }
     648              : 
     649              : #if (OS_TYPE != LINUX)
     650              :     filename = FileUtils::ReplaceAll(filename, "/", "\\");
     651              : #endif
     652              : 
     653            6 :     std::string dirName = FileUtils::GetFileDir(filename);
     654            6 :     if (!FileUtils::IsFileExist(dirName)) {
     655            1 :         IDE_CTRL_VALUE_FAILED(
     656              :             FileUtils::CreateDir(dirName) == IDE_DAEMON_NONE_ERROR, return false, "Create dir failed path: %s",
     657              :             dirName.c_str());
     658              :     }
     659            5 :     while (FileUtils::IsDiskFull(dirName, dumpChunk.bufLen)) {
     660            1 :         IDE_LOGE("Don't have enough free disk %u bytes", dumpChunk.bufLen);
     661            1 :         return false;
     662              :     }
     663              : 
     664            4 :     std::string realPath;
     665            4 :     IDE_CTRL_VALUE_FAILED(
     666              :         FileUtils::FileNameIsReal(filename, realPath) == IDE_DAEMON_OK, return false, "File name is not real: %s",
     667              :         filename.c_str());
     668              : 
     669            3 :     IDE_CTRL_VALUE_FAILED(
     670              :         FileUtils::WriteFile(filename, strStream.str().c_str(), strStream.str().size(), dumpChunk.offset) ==
     671              :             IDE_DAEMON_NONE_ERROR,
     672              :         return false, "Failed to dump file %s to path %s", filename.c_str(), dirName.c_str());
     673            2 :     IDE_LOGI("Record dump stats data success: %s", filename.c_str());
     674            2 :     AppendFileName(filename);
     675            2 :     return true;
     676            7 : }
     677              : #endif
     678              : 
     679              : /**
     680              :  * @brief record dump info to the file
     681              :  * @param [in] data : record data
     682              :  * @return
     683              :  *      IDE_DAEMON_ERROR : falied
     684              :  *      IDE_DAEMON_OK : success
     685              :  */
     686           58 : void AdxDumpRecord::RecordDumpInfo()
     687              : {
     688           58 :     IDE_RUN_LOGI("start dump thread, remote dump record temp path : %s.", dumpPath_.c_str());
     689           58 :     uint32_t chunkHeaderLen = static_cast<uint32_t>(sizeof(DumpChunk));
     690          111 :     while (hostDumpDataInfoQueue_ != nullptr && (dumpRecordFlag_ || !DumpDataQueueIsEmpty())) {
     691           53 :         HostDumpDataInfo data = {nullptr, 0};
     692           53 :         if (!hostDumpDataInfoQueue_->Pop(data)) {
     693           47 :             continue;
     694              :         }
     695              : 
     696            6 :         if (data.msg == nullptr) {
     697            0 :             continue;
     698              :         }
     699              : 
     700            6 :         SharedPtr<MsgProto> msgPtr = data.msg;
     701            6 :         IDE_CTRL_VALUE_FAILED_NODO(
     702              :             data.recvLen >= chunkHeaderLen, continue, "recvLen(%u) too small for DumpChunk header(%zu bytes)",
     703              :             data.recvLen, chunkHeaderLen);
     704              : 
     705            6 :         DumpChunk* dumpChunk = reinterpret_cast<DumpChunk*>(msgPtr->data);
     706              : 
     707            6 :         IDE_CTRL_VALUE_FAILED_NODO(
     708              :             dumpChunk->bufLen <= data.recvLen - chunkHeaderLen, continue,
     709              :             "bufLen(%u) exceeds actual data buffer size(%u bytes), fileName: %s", dumpChunk->bufLen,
     710              :             data.recvLen - chunkHeaderLen, dumpChunk->fileName);
     711              : 
     712            6 :         IDE_LOGI(
     713              :             "Queue pop data success! filename: %s, offset: %" PRId64 ", bufLen: %u bytes, "
     714              :             "isLast: %u, flag: %d, remaining queue size: %u.",
     715              :             dumpChunk->fileName, dumpChunk->offset, dumpChunk->bufLen, dumpChunk->isLastChunk, dumpChunk->flag,
     716              :             hostDumpDataInfoQueue_->Size());
     717              : #if !defined(ADUMP_SOC_HOST) || ADUMP_SOC_HOST == 1
     718            6 :         if (FileNameCheck(*dumpChunk)) {
     719            1 :             IDE_CTRL_VALUE_FAILED_NODO(
     720              :                 StatsDataParsing(*dumpChunk), continue, "Failed to parse dump data with file name %s",
     721              :                 dumpChunk->fileName);
     722            1 :             continue;
     723              :         }
     724              : #endif
     725            5 :         if (AdxDumpProcess::Instance().IsRegistered()) {
     726            3 :             IDE_LOGI("mindspore session!");
     727              :             std::function<int32_t(const struct DumpChunk*, int32_t)> messageCallback =
     728            3 :                 AdxDumpProcess::Instance().GetCallbackFun();
     729            3 :             if (!messageCallback) {
     730            0 :                 IDE_LOGE(
     731              :                     "Registered messageCallback function is not callable,\
     732              :                     drop this data packet, fileName:%s",
     733              :                     dumpChunk->fileName);
     734            0 :                 continue;
     735              :             }
     736            3 :             int32_t dumpChunkLen = sizeof(struct DumpChunk) + dumpChunk->bufLen;
     737            3 :             int32_t ret = messageCallback(dumpChunk, dumpChunkLen);
     738            3 :             if (ret != IDE_DAEMON_NONE_ERROR) {
     739            0 :                 IDE_LOGE("failed to transmission dump data to mindspore. err = %d", ret);
     740              :             }
     741            5 :         } else if (!RecordDumpDataToDisk(*dumpChunk)) {
     742            2 :             IDE_LOGE("failed to record dump data to disk.");
     743              :         }
     744           54 :     }
     745           58 :     IDE_LOGI("exit record file thread");
     746           58 : }
     747              : 
     748              : /**
     749              :  * @brief record dump info to the file
     750              :  * @param [in] data : record data
     751              :  * @return
     752              :  *      IDE_DAEMON_ERROR : falied
     753              :  *      IDE_DAEMON_OK : success
     754              :  */
     755            8 : bool AdxDumpRecord::RecordDumpDataToQueue(HostDumpDataInfo& info)
     756              : {
     757            8 :     if (hostDumpDataInfoQueue_ == nullptr) {
     758            1 :         IDE_LOGW("dump data queue is not initialized, drop this data packet.");
     759            1 :         return false;
     760              :     }
     761            7 :     if (hostDumpDataInfoQueue_->IsFull()) {
     762            2 :         const std::string tipFull = "Memory usage exceeds 85%, the dump data queue is full";
     763            2 :         const std::string tipReduce = "Please reduce model batches, images or dump layers";
     764            1 :         const std::string tipMemory = "Or clear the used memory or increase the maximum memory";
     765            1 :         IDE_LOGW("%s. %s. %s.", tipFull.c_str(), tipReduce.c_str(), tipMemory.c_str());
     766            1 :         return false;
     767            1 :     } else {
     768            6 :         if (!hostDumpDataInfoQueue_->Push(info)) {
     769            0 :             IDE_LOGW("dump data queue has quit, drop this data packet.");
     770            0 :             return false;
     771              :         }
     772            6 :         IDE_LOGI("Insert dump data to queue success, queue size: %u.", hostDumpDataInfoQueue_->Size());
     773              :     }
     774              : 
     775            6 :     return true;
     776              : }
     777              : 
     778              : /**
     779              :  * @brief get dump size from the record lists
     780              :  * @param [in] tag : tag of record lists
     781              :  * @return
     782              :  *      true : success
     783              :  *     false : false
     784              :  */
     785           62 : bool AdxDumpRecord::DumpDataQueueIsEmpty() const
     786              : {
     787           62 :     return hostDumpDataInfoQueue_ == nullptr || hostDumpDataInfoQueue_->IsEmpty();
     788              : }
     789              : 
     790            0 : void AdxDumpRecord::SetDumpPath(const std::string& dumpPath) { dumpPath_ = dumpPath; }
     791              : } // namespace Adx
        

Generated by: LCOV version 2.0-1