Line data Source code
1 : /**
2 : * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3 : * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4 : * CANN Open Software License Agreement Version 2.0 (the "License").
5 : * Please refer to the License for details. You may not use this file except in compliance with the License.
6 : * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7 : * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8 : * See LICENSE in the root of the software repository for the full text of the License.
9 : */
10 :
11 : #include "dump_args_callback.h"
12 : #include "dfx_args_parser.h"
13 : #include "dump_memory.h"
14 : #include "exception_info_common.h"
15 : #include "kernel_symbol_locator.h"
16 : #include "str_utils.h"
17 : #include "log/adx_log.h"
18 : #include "log/hdc_log.h"
19 :
20 : namespace Adx {
21 :
22 25 : DumpArgsCallback::DumpArgsCallback(const rtExceptionInfo &exception, const ExceptionDumpInfo &info,
23 25 : const std::string &dumpPath)
24 25 : : exception_(exception),
25 25 : info_(info),
26 25 : dumpPath_(dumpPath),
27 75 : dumpFilePath_(dumpPath + "/" +
28 100 : std::string(info.kernelDisplayName[0] != '\0' ? info.kernelDisplayName : "exception_info") + "." +
29 100 : std::to_string(exception.streamid) + "." + std::to_string(exception.taskid) + "." +
30 100 : std::to_string(info.coreType) + "." + std::to_string(info.coreId) + "." +
31 50 : SysUtils::GetCurrentTimeWithMillisecond()),
32 50 : dumpFile_(exception.deviceid, dumpFilePath_)
33 : {
34 25 : }
35 :
36 4 : int32_t DumpArgsCallback::DumpKernelBin()
37 : {
38 4 : std::string kernelName(info_.kernelName);
39 4 : if (info_.bin == nullptr || kernelName.empty()) {
40 3 : return ADUMP_SUCCESS;
41 : }
42 1 : IDE_LOGI("Dump kernel bin file. bin=%p, kernelName=%s", info_.bin, kernelName.c_str());
43 1 : KernelInfoCollector collector;
44 1 : int32_t ret = collector.InitFromBinHandle(info_.bin, kernelName);
45 1 : IDE_CTRL_VALUE_FAILED(ret == ADUMP_SUCCESS, return ADUMP_FAILED,
46 : "Init for dump kernel bin failed. ret=%d, bin=%p, kernelName=%s.", ret, info_.bin, kernelName.c_str());
47 :
48 1 : ret = collector.StartCollectKernel(dumpPath_);
49 1 : IDE_CTRL_VALUE_WARN(ret == ADUMP_SUCCESS, return ADUMP_FAILED,
50 : "StartCollectKernel failed, kernelName=%s.", kernelName.c_str());
51 :
52 1 : IDE_LOGI("DumpKernelBin success, kernelName=%s.", kernelName.c_str());
53 1 : return ADUMP_SUCCESS;
54 4 : }
55 :
56 6 : int32_t DumpArgsCallback::DumpKernelErrorSymbols()
57 : {
58 6 : if (info_.bin == nullptr) {
59 2 : return ADUMP_SUCCESS;
60 : }
61 4 : KernelSymbolLocator locator;
62 4 : int32_t ret = locator.InitFromBinHandle(info_.bin);
63 4 : IDE_CTRL_VALUE_FAILED(ret == ADUMP_SUCCESS, return ADUMP_FAILED,
64 : "KernelSymbolLocator InitFromBinHandle failed for callback exception. ret=%d", ret);
65 3 : locator.UpdateStartPCFromDeviceAddr(info_.bin);
66 :
67 3 : ExceptionRegInfo exceptionRegInfo{0, nullptr};
68 3 : ret = ExceptionInfoCommon::GetExceptionRegInfo(exception_, exceptionRegInfo);
69 3 : IDE_CTRL_VALUE_WARN(ret == ADUMP_SUCCESS, return ADUMP_FAILED,
70 : "Get exception register information failed for callback exception. ret=%d", ret);
71 :
72 2 : ret = locator.LocateAndPrintErrorSymbolsForCore(info_.coreId, info_.coreType, exceptionRegInfo);
73 2 : IDE_CTRL_VALUE_WARN(ret == ADUMP_SUCCESS, return ADUMP_FAILED,
74 : "LocateAndPrintErrorSymbolsForCore failed for callback exception. ret=%d, coreId=%u, coreType=%u.",
75 : ret, info_.coreId, info_.coreType);
76 :
77 1 : return ADUMP_SUCCESS;
78 4 : }
79 :
80 3 : int32_t DumpArgsCallback::QueryDfxIsTikInfo(rtFuncHandle funcHandle)
81 : {
82 3 : size_t isTikSize = 0;
83 3 : rtError_t rtRet = rtFunctionGetMetaInfoSize(funcHandle, RT_FUNCTION_TYPE_L0_EXCEPTION_DFX_IS_TIK, &isTikSize);
84 3 : if (rtRet != RT_ERROR_NONE || isTikSize == 0 || isTikSize < sizeof(uint32_t)) {
85 1 : IDE_LOGW("rtFunctionGetMetaInfoSize for dfxIsTik failed, will set dfxIsTik with false. "
86 : "rtRet=%d, kernelName=%s", rtRet, info_.kernelName);
87 1 : return ADUMP_FAILED;
88 : }
89 :
90 2 : std::vector<uint8_t> isTikBuffer(isTikSize);
91 2 : rtRet = rtFunctionGetMetaInfo(funcHandle, RT_FUNCTION_TYPE_L0_EXCEPTION_DFX_IS_TIK,
92 2 : isTikBuffer.data(), isTikSize);
93 2 : if (rtRet != RT_ERROR_NONE) {
94 1 : IDE_LOGW("rtFunctionGetMetaInfo for isTik failed, will set dfxIsTik with false. "
95 : "ret=%d, kernelName=%s, isTikSize=%zu.", rtRet, info_.kernelName, isTikSize);
96 1 : return ADUMP_FAILED;
97 : }
98 :
99 1 : uint32_t isTik = 0;
100 1 : isTik = *reinterpret_cast<uint32_t*>(isTikBuffer.data());
101 1 : isTik_ = (isTik == 1U) ? true : false;
102 1 : IDE_LOGI("Query dfxIsTik info success. kernelName=%s, dfxIsTik=%u", info_.kernelName, isTik);
103 1 : return ADUMP_SUCCESS;
104 2 : }
105 :
106 7 : int32_t DumpArgsCallback::QueryDfxInfo(std::vector<uint8_t> &dfxBuffer)
107 : {
108 7 : rtFuncHandle funcHandle = nullptr;
109 7 : rtError_t rtRet = rtBinaryGetFunctionByName(info_.bin, info_.kernelName, &funcHandle);
110 7 : IDE_CTRL_VALUE_FAILED(rtRet == RT_ERROR_NONE && funcHandle != nullptr, return ADUMP_FAILED,
111 : "rtBinaryGetFunctionByName failed, ret=%d, bin=%p, kernelName=%s.", rtRet, info_.bin, info_.kernelName);
112 :
113 6 : size_t dfxSize = 0;
114 6 : rtRet = rtFunctionGetMetaInfoSize(funcHandle, RT_FUNCTION_TYPE_DFX_TYPE, &dfxSize);
115 6 : IDE_CTRL_VALUE_FAILED(rtRet == RT_ERROR_NONE && dfxSize > 0, return ADUMP_FAILED,
116 : "rtFunctionGetMetaInfoSize failed, ret=%d, kernelName=%s, dfxSize=%zu.", rtRet, info_.kernelName, dfxSize);
117 5 : IDE_CTRL_VALUE_FAILED(dfxSize <= UINT16_MAX, return ADUMP_FAILED,
118 : "Dfx size exceeds uint16_t max, dfxSize=%zu", dfxSize);
119 :
120 4 : dfxBuffer.resize(dfxSize);
121 4 : rtRet = rtFunctionGetMetaInfo(funcHandle, RT_FUNCTION_TYPE_DFX_TYPE, dfxBuffer.data(), dfxSize);
122 4 : IDE_CTRL_VALUE_FAILED(rtRet == RT_ERROR_NONE, return ADUMP_FAILED,
123 : "rtFunctionGetMetaInfo failed, ret=%d, kernelName=%s, dfxSize=%zu.", rtRet, info_.kernelName, dfxSize);
124 :
125 3 : (void)QueryDfxIsTikInfo(funcHandle);
126 :
127 3 : IDE_LOGI("Query kernel dfx args info success. kernelName=%s, dfxSize=%zu, isTik=%d",
128 : info_.kernelName, dfxSize, isTik_);
129 3 : return ADUMP_SUCCESS;
130 : }
131 :
132 9 : int32_t DumpArgsCallback::DumpDfxArgs()
133 : {
134 9 : if (info_.argAddr == nullptr || info_.argSize == 0 || info_.bin == nullptr || info_.kernelName[0] == '\0') {
135 2 : return ADUMP_SUCCESS;
136 : }
137 :
138 7 : IDE_LOGI("Begin to dump dfx args tensors. argAddr=%p, argSize=%u, bin=%p, kernelName=%s",
139 : info_.argAddr, info_.argSize, info_.bin, info_.kernelName);
140 :
141 7 : int32_t ret = QueryDfxInfo(dfxBuffer_);
142 7 : IDE_CTRL_VALUE_FAILED(ret == ADUMP_SUCCESS, return ADUMP_FAILED, "Query kernel dfx info failed.");
143 :
144 3 : DfxArgsParser parser;
145 3 : ret = parser.Init(info_.argAddr, info_.argSize, dfxBuffer_.data(), static_cast<uint16_t>(dfxBuffer_.size()));
146 3 : IDE_CTRL_VALUE_FAILED(ret == ADUMP_SUCCESS, return ADUMP_FAILED, "Dfx args parser init failed.");
147 :
148 3 : parser.SetIsTik(isTik_);
149 3 : ret = parser.InitTensorModeInfo();
150 3 : IDE_CHECK_RET(ret, return ADUMP_FAILED);
151 :
152 0 : ret = parser.ParseAll();
153 0 : IDE_CHECK_RET(ret, return ADUMP_FAILED);
154 :
155 0 : tensorBuffer_ = parser.GetTensors();
156 0 : workspaces_ = parser.GetWorkspaces();
157 0 : logRecord_ = parser.GetLogRecords();
158 :
159 0 : IDE_LOGI("Dfx args tensors are parsed finished. tensor size=%zu, workspace size=%zu.",
160 : tensorBuffer_.size(), workspaces_.size());
161 :
162 0 : dumpFile_.SetTensorBuffer(tensorBuffer_);
163 0 : dumpFile_.SetWorkspaces(workspaces_);
164 :
165 0 : IDE_LOGI("End to dump dfx args tensors.");
166 0 : return ADUMP_SUCCESS;
167 3 : }
168 :
169 6 : int32_t DumpArgsCallback::DumpExtraTensors()
170 : {
171 6 : if (info_.extraTensorNum == 0) {
172 2 : return ADUMP_SUCCESS;
173 : }
174 4 : if (info_.extraTensorNum > EXCEPTION_DUMP_MAX_TENSOR_NUM) {
175 1 : IDE_LOGE("Extra tensor size exceeds the maximum limit. realSize=%u, maxSize=%u",
176 : info_.extraTensorNum, EXCEPTION_DUMP_MAX_TENSOR_NUM);
177 1 : return ADUMP_FAILED;
178 : }
179 :
180 3 : IDE_LOGI("Begin to dump extra tensors. extra tensor size=%u", info_.extraTensorNum);
181 :
182 3 : std::vector<DumpTensor> inputTensors;
183 3 : std::vector<DumpTensor> outputTensors;
184 3 : std::vector<DumpWorkspace> workspaces;
185 3 : uint32_t baseOffset = static_cast<uint32_t>(tensorBuffer_.size() + workspaces_.size());
186 :
187 9 : for (uint32_t i = 0; i < info_.extraTensorNum; ++i) {
188 6 : if (info_.extraTensor[i].tensorAddr == nullptr || info_.extraTensor[i].tensorSize == 0) {
189 1 : IDE_LOGW("Skip null extra tensor[%u], addr=%p, size=%zu.",
190 : i, info_.extraTensor[i].tensorAddr, info_.extraTensor[i].tensorSize);
191 1 : continue;
192 : }
193 : // tensor基于args偏移offset
194 5 : info_.extraTensor[i].argsOffSet = baseOffset + i;
195 :
196 5 : RecordDumpLog(StrUtils::Format("[Dump][Exception] exception info dump extra tensor data, "
197 : "addr:%p; size:%zu bytes; index:%u(origin:%u); type:%d",
198 : info_.extraTensor[i].tensorAddr, info_.extraTensor[i].tensorSize,
199 5 : info_.extraTensor[i].argsOffSet, i, static_cast<int>(info_.extraTensor[i].type)));
200 :
201 5 : if (info_.extraTensor[i].type == TensorType::INPUT) {
202 3 : inputTensors.emplace_back(info_.extraTensor[i]);
203 2 : } else if (info_.extraTensor[i].type == TensorType::OUTPUT) {
204 1 : outputTensors.emplace_back(info_.extraTensor[i]);
205 1 : } else if (info_.extraTensor[i].type == TensorType::WORKSPACE) {
206 : DumpWorkspace workspace;
207 1 : workspace.addr = info_.extraTensor[i].tensorAddr;
208 1 : workspace.bytes = info_.extraTensor[i].tensorSize;
209 1 : workspace.argsOffset = info_.extraTensor[i].argsOffSet;
210 1 : workspaces.push_back(workspace);
211 : }
212 : }
213 :
214 3 : dumpFile_.SetInputTensors(inputTensors);
215 3 : dumpFile_.SetOutputTensors(outputTensors);
216 3 : dumpFile_.SetWorkspaces(workspaces);
217 :
218 3 : IDE_LOGI("End to dump extra tensors.");
219 3 : return ADUMP_SUCCESS;
220 3 : }
221 :
222 6 : int32_t DumpArgsCallback::Dump()
223 : {
224 6 : int32_t ret = dumpFile_.Dump(logRecord_);
225 6 : IDE_CTRL_VALUE_FAILED(ret == ADUMP_SUCCESS, return ADUMP_FAILED,
226 : "[Dump][Exception] Write callback exception to file failed, file: %s", dumpFilePath_.c_str());
227 :
228 5 : (void)mmChmod(dumpFilePath_.c_str(), M_IRUSR); // readonly, 400
229 5 : IDE_LOGE("[Dump][Exception] dump exception to file, file: %s", dumpFilePath_.c_str());
230 5 : return ADUMP_SUCCESS;
231 : }
232 :
233 5 : void DumpArgsCallback::RecordDumpLog(const std::string &log)
234 : {
235 5 : IDE_LOGE("%s", log.c_str());
236 5 : logRecord_.emplace_back(log + "\n");
237 5 : }
238 :
239 : } // namespace Adx
|