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

Generated by: LCOV version 2.0-1