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 : #include "dump_task.h"
11 :
12 : #include <algorithm>
13 : #include <regex>
14 : #include <sstream>
15 : #include <vector>
16 : #include <sys/time.h>
17 :
18 : #include "aicpusd_drv_manager.h"
19 : #include "aicpusd_status.h"
20 : #include "common/aicpusd_util.h"
21 : #include "securec.h"
22 : #include "metadef_types.h"
23 :
24 : namespace AicpuSchedule {
25 : // slice size for dump file, 128MByes
26 : const uint64_t DUMP_SLICE_SIZE = 128UL << 20U;
27 : const size_t INTERNAL_STEP_SIZE = 2U;
28 :
29 2 : static inline uint64_t GetCurrentTime()
30 : {
31 2 : uint64_t ret = 0U;
32 : struct timeval tv;
33 2 : if (gettimeofday(&tv, nullptr) == 0) {
34 2 : ret = (static_cast<uint64_t>(tv.tv_sec) * 1000000UL) + static_cast<uint64_t>(tv.tv_usec);
35 : }
36 :
37 2 : return ret;
38 : }
39 :
40 17 : OpDumpTask::OpDumpTask(const int32_t hostPid, const uint32_t deviceId)
41 17 : : taskDumpNum_(0U),
42 17 : endGraph_(false),
43 17 : inputTotalSize_(0U),
44 17 : outputTotalSize_(0U),
45 17 : opBufferTotalSize_(0U),
46 17 : opWorkspaceTotalSize_(0U),
47 17 : buff_(nullptr),
48 17 : buffSize_(0U),
49 17 : offset_(0U),
50 17 : skipAddressConversion_(false),
51 17 : hostPid_(hostPid),
52 17 : deviceId_(deviceId) { }
53 :
54 12 : static inline void ReplaceStringElem(std::string &str)
55 : {
56 12 : (void)for_each(str.begin(), str.end(),
57 162 : [](char_t &ch) {
58 162 : if ((ch == ' ') ||
59 142 : (ch == '.') ||
60 132 : (ch == '/') ||
61 162 : (ch == '\\')) { ch = '_'; }
62 162 : });
63 12 : }
64 :
65 6 : StatusCode OpDumpTask::GetDumpNumber(uint64_t &dumpNum)
66 : {
67 6 : if (optionalParam_.hasStepId) {
68 5 : if (optionalParam_.stepIdAddr == nullptr) {
69 1 : aicpusd_err("op name[%s], step id addr is null", opName_.c_str());
70 1 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
71 : }
72 :
73 4 : const uint64_t stepId = *(optionalParam_.stepIdAddr);
74 4 : aicpusd_info("op name[%s], step id is[%llu]", opName_.c_str(), stepId);
75 4 : uint64_t iterationsPerLoop = 0U;
76 4 : uint64_t loopCond = 0U;
77 4 : if (optionalParam_.hasIterationsPerLoop) {
78 3 : if (optionalParam_.iterationsPerLoopAddr == nullptr) {
79 1 : aicpusd_err("op name[%s], iterations per loop addr is null", opName_.c_str());
80 1 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
81 : }
82 2 : iterationsPerLoop = *(optionalParam_.iterationsPerLoopAddr);
83 2 : aicpusd_info("op name[%s], iterations per loop is[%llu]", opName_.c_str(), iterationsPerLoop);
84 : }
85 3 : if (optionalParam_.hasLoopCond) {
86 1 : if (optionalParam_.loopCondAddr == nullptr) {
87 1 : aicpusd_err("op name[%s], loop cond addr is null", opName_.c_str());
88 1 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
89 : }
90 0 : loopCond = *(optionalParam_.loopCondAddr);
91 0 : aicpusd_info("op name[%s], loop cond is[%llu]", opName_.c_str(), loopCond);
92 : }
93 2 : aicpusd_info("op name[%s], step id[%llu], iterations per loop[%llu], loop cond[%llu]",
94 : opName_.c_str(), stepId, iterationsPerLoop, loopCond);
95 : // overflow does not matter
96 2 : dumpNum = (stepId * (iterationsPerLoop + 1U)) + loopCond;
97 : } else {
98 1 : dumpNum = taskDumpNum_;
99 : }
100 :
101 3 : return AICPU_SCHEDULE_OK;
102 : }
103 :
104 7 : StatusCode OpDumpTask::PreProcessOutput(const aicpu::dump::Task &task,
105 : ::toolkit::dumpdata::DumpData &dumpData)
106 : {
107 7 : const auto &outputsFromMapInfo = task.output();
108 17 : for (int32_t index = 0; index < outputsFromMapInfo.size(); ++index) {
109 10 : const auto &item = outputsFromMapInfo.at(index);
110 10 : ::toolkit::dumpdata::OpOutput * const opOutput = dumpData.add_output();
111 10 : if (opOutput == nullptr) {
112 0 : aicpusd_err("op name[%s], call protobuf function to add output elem failed", opName_.c_str());
113 0 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
114 : }
115 10 : opOutput->set_data_type(static_cast<::toolkit::dumpdata::OutputDataType>(item.data_type()));
116 10 : const auto format = item.format();
117 10 : opOutput->set_format(static_cast<::toolkit::dumpdata::OutputFormat>(ge::GetPrimaryFormat(format)));
118 10 : opOutput->set_sub_format(ge::GetSubFormat(format));
119 10 : const auto dims = item.shape().dim();
120 10 : ::toolkit::dumpdata::Shape * const outShape = opOutput->mutable_shape();
121 30 : for (const auto dim : dims) {
122 20 : outShape->add_dim(dim);
123 : }
124 10 : const auto originalDims = item.origin_shape().dim();
125 10 : ::toolkit::dumpdata::Shape * const outOriginalShape = opOutput->mutable_original_shape();
126 15 : for (const auto dim : originalDims) {
127 5 : outOriginalShape->add_dim(dim);
128 : }
129 10 : if (!item.original_name().empty()) {
130 7 : ::toolkit::dumpdata::OriginalOp * const orgOp = opOutput->mutable_original_op();
131 7 : orgOp->set_name(item.original_name());
132 7 : orgOp->set_output_index(static_cast<uint32_t>(item.original_output_index()));
133 7 : orgOp->set_data_type(static_cast<::toolkit::dumpdata::OutputDataType>(item.original_output_data_type()));
134 7 : orgOp->set_format(static_cast<::toolkit::dumpdata::OutputFormat>(item.original_output_format()));
135 : }
136 10 : const auto &dim_rangeFromOutput = item.dim_range();
137 14 : for (int32_t i = 0; i < dim_rangeFromOutput.size(); ++i) {
138 4 : const auto &item = dim_rangeFromOutput.at(i);
139 4 : ::toolkit::dumpdata::DimRange * const dimRange = opOutput->add_dim_range();
140 4 : if (dimRange == nullptr) {
141 0 : aicpusd_err("op name[%s], call protobuf function to add dim_range elem failed, i[%d],"
142 : " dim_range_size[%zu]", opName_.c_str(), i, dim_rangeFromOutput.size());
143 0 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
144 : }
145 4 : dimRange->set_dim_start(item.dim_start());
146 4 : dimRange->set_dim_end(item.dim_end());
147 : }
148 10 : opOutput->set_size(item.size());
149 10 : outputTotalSize_ += item.size();
150 10 : outputsBaseAddr_.push_back(item.address());
151 10 : }
152 7 : return AICPU_SCHEDULE_OK;
153 : }
154 :
155 6 : StatusCode OpDumpTask::PreProcessInput(const aicpu::dump::Task &task,
156 : ::toolkit::dumpdata::DumpData &dumpData)
157 : {
158 6 : const auto &inputsFromMapInfo = task.input();
159 12 : for (int32_t i = 0; i < inputsFromMapInfo.size(); ++i) {
160 6 : const auto &item = inputsFromMapInfo.at(i);
161 6 : ::toolkit::dumpdata::OpInput * const opInput = dumpData.add_input();
162 6 : if (opInput == nullptr) {
163 0 : aicpusd_err("op name[%s], call protobuf function to add input elem failed", opName_.c_str());
164 0 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
165 : }
166 6 : opInput->set_data_type(static_cast<::toolkit::dumpdata::OutputDataType>(item.data_type()));
167 6 : const auto format = item.format();
168 6 : opInput->set_format(static_cast<::toolkit::dumpdata::OutputFormat>(ge::GetPrimaryFormat(format)));
169 6 : opInput->set_sub_format(ge::GetSubFormat(format));
170 6 : const auto dims = item.shape().dim();
171 6 : ::toolkit::dumpdata::Shape * const inShape = opInput->mutable_shape();
172 18 : for (const auto dim : dims) {
173 12 : inShape->add_dim(dim);
174 : }
175 6 : const auto originalDims = item.origin_shape().dim();
176 6 : ::toolkit::dumpdata::Shape * const inOriginalShape = opInput->mutable_original_shape();
177 10 : for (const auto dim : originalDims) {
178 4 : inOriginalShape->add_dim(dim);
179 : }
180 :
181 6 : opInput->set_size(item.size());
182 6 : inputTotalSize_ += item.size();
183 6 : inputsBaseAddr_.push_back(item.address());
184 6 : }
185 6 : return AICPU_SCHEDULE_OK;
186 : }
187 :
188 6 : StatusCode OpDumpTask::PreProcessOpBuffer(const aicpu::dump::Task &task,
189 : ::toolkit::dumpdata::DumpData &dumpData)
190 : {
191 6 : const auto &opsBufferFromMapInfo = task.buffer();
192 9 : for (int32_t i = 0; i < opsBufferFromMapInfo.size(); ++i) {
193 3 : const auto &item = opsBufferFromMapInfo.at(i);
194 3 : ::toolkit::dumpdata::OpBuffer * const opBuffer = dumpData.add_buffer();
195 3 : if (opBuffer == nullptr) {
196 0 : aicpusd_err("op name[%s], call protobuf function to add op buffer elem failed", opName_.c_str());
197 0 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
198 : }
199 :
200 3 : opBuffer->set_buffer_type(static_cast<::toolkit::dumpdata::BufferType>(item.buffer_type()));
201 3 : opBuffer->set_size(item.size());
202 3 : opBufferTotalSize_ += item.size();
203 3 : opBufferAddr_.push_back(item.address());
204 : }
205 6 : return AICPU_SCHEDULE_OK;
206 : }
207 :
208 7 : StatusCode OpDumpTask::PreProcessWorkspace(const aicpu::dump::Task &task,
209 : ::toolkit::dumpdata::DumpData &dumpData)
210 : {
211 7 : const auto &opsWorkspaceFromMapInfo = task.space();
212 8 : for (int64_t i = 0; i < opsWorkspaceFromMapInfo.size(); ++i) {
213 1 : const auto &item = opsWorkspaceFromMapInfo.at(i);
214 1 : ::toolkit::dumpdata::Workspace * const opWorkspace = dumpData.add_space();
215 1 : if (opWorkspace == nullptr) {
216 0 : aicpusd_err("op name[%s], call protobuf function to add op Workspace elem failed", opName_.c_str());
217 0 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
218 : }
219 :
220 1 : opWorkspace->set_type(static_cast<::toolkit::dumpdata::Workspace::SpaceType>(item.type()));
221 1 : opWorkspace->set_size(item.size());
222 1 : opWorkspaceTotalSize_ += item.size();
223 1 : opWorkspaceAddr_.push_back(item.data_addr());
224 : }
225 7 : return AICPU_SCHEDULE_OK;
226 : }
227 :
228 6 : StatusCode OpDumpTask::PreProcessOpMappingInfo(const aicpu::dump::Task &task,
229 : const std::string &basePath,
230 : const MappingInfoOptionalParam ¶m,
231 : const DumpStep &dumpStep,
232 : const bool skipAddressConversion)
233 : {
234 6 : aicpusd_info("Base path[%s], has model name[%d], model name[%s], has model id[%d], model id[%u].",
235 : basePath.c_str(), static_cast<int32_t>(param.hasModelName), param.modelName.c_str(),
236 : static_cast<int32_t>(param.hasModelId), param.modelId);
237 6 : aicpusd_debug("task info[%s].", task.DebugString().c_str());
238 6 : const std::lock_guard<std::mutex> queLock(dumpMtx_);
239 6 : baseDumpPath_ = basePath;
240 6 : optionalParam_ = param;
241 6 : dumpStep_ = dumpStep;
242 6 : skipAddressConversion_ = skipAddressConversion;
243 : // single op no task id and stream id
244 6 : taskInfo_.taskId_ = (skipAddressConversion_ && optionalParam_.hasStepId)? 0U : task.task_id();
245 6 : taskInfo_.streamId_ = (skipAddressConversion_ && optionalParam_.hasStepId)? 0U : task.stream_id();
246 6 : endGraph_ = task.end_graph();
247 :
248 6 : ::toolkit::dumpdata::DumpData dumpData;
249 : // version 2.0
250 : dumpData.set_version("2.0");
251 6 : StatusCode ret = PreProcessInput(task, dumpData);
252 6 : if (ret != AICPU_SCHEDULE_OK) {
253 0 : return ret;
254 : }
255 6 : ret = PreProcessOutput(task, dumpData);
256 6 : if (ret != AICPU_SCHEDULE_OK) {
257 0 : return ret;
258 : }
259 6 : ret = PreProcessOpBuffer(task, dumpData);
260 6 : if (ret != AICPU_SCHEDULE_OK) {
261 0 : return ret;
262 : }
263 6 : ret = PreProcessWorkspace(task, dumpData);
264 6 : if (ret != AICPU_SCHEDULE_OK) {
265 0 : return ret;
266 : }
267 6 : opName_ = task.op().op_name();
268 6 : opType_ = task.op().op_type();
269 6 : dumpData.set_op_name(opName_);
270 6 : aicpusd_info("[stream id:%u, task id:%u], op name[%s], op type[%s]",
271 : taskInfo_.streamId_, taskInfo_.taskId_, opName_.c_str(), opType_.c_str());
272 6 : baseDumpData_ = std::move(dumpData);
273 6 : taskDumpNum_ = 0U;
274 :
275 6 : return AICPU_SCHEDULE_OK;
276 6 : }
277 :
278 6 : StatusCode OpDumpTask::ProcessInputDump(const ::toolkit::dumpdata::DumpData &dumpData,
279 : const std::string &path,
280 : const IDE_SESSION ideSession)
281 : {
282 6 : uint64_t dumpedSize = 0U;
283 11 : for (int32_t i = 0; i < dumpData.input_size(); ++i) {
284 6 : auto &input = dumpData.input(i);
285 6 : const uint64_t len = input.size();
286 6 : if (len == 0U) {
287 1 : aicpusd_info("op name[%s], input[%d] data size is zero", opName_.c_str(), i);
288 1 : continue;
289 : }
290 5 : const uint64_t baseAddr = inputsBaseAddr_.at(static_cast<size_t>(i));
291 5 : uint64_t dataAddr = baseAddr;
292 5 : if (!skipAddressConversion_) {
293 3 : if (baseAddr == 0U) {
294 1 : aicpusd_info("op name[%s], input[%d] base addr is null", opName_.c_str(), i);
295 1 : continue;
296 : }
297 : // baseAddr is a pointer point to data addr
298 2 : dataAddr = *(PtrToPtr<void ,uint64_t>(ValueToPtr(baseAddr)));
299 : }
300 4 : aicpusd_info("op name[%s], input[%d] size[%llu]", opName_.c_str(), i, len);
301 4 : if (dataAddr == 0U) {
302 1 : aicpusd_info("op name[%s], input[%d] addr is null", opName_.c_str(), i);
303 1 : continue;
304 : }
305 3 : uint64_t innerOffset = 0U;
306 5 : while (innerOffset < len) {
307 3 : const uint64_t emptyBufferSize = buffSize_ - offset_;
308 3 : const uint64_t actSize = std::min(emptyBufferSize, len - innerOffset);
309 3 : const uint64_t srcAddr = dataAddr + innerOffset;
310 3 : aicpusd_info("op name[%s], begin to copy data from HBM to DDR for input[%d], size[%llu]",
311 : opName_.c_str(), i, actSize);
312 3 : const errno_t eRet = memcpy_s(buff_.get() + offset_,
313 : emptyBufferSize,
314 3 : ValueToPtr(srcAddr),
315 : actSize);
316 3 : if (eRet != EOK) {
317 0 : aicpusd_err("op name[%s], input[%d] memcpy failed, desSize[%llu], srcSize[%llu]", opName_.c_str(), i,
318 : emptyBufferSize, actSize);
319 1 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
320 : }
321 3 : aicpusd_info("op name[%s], end of copy data from HBM to DDR for input[%d], size[%llu]",
322 : opName_.c_str(), i, actSize);
323 3 : offset_ += actSize;
324 3 : innerOffset += actSize;
325 3 : dumpedSize += actSize;
326 2 : const bool isLastSilce = (dumpedSize == inputTotalSize_) && (outputTotalSize_ == 0U) &&
327 5 : (opBufferTotalSize_ == 0U) && (opWorkspaceTotalSize_ == 0U);
328 3 : if ((offset_ >= buffSize_) || isLastSilce) {
329 1 : const StatusCode ret = Dump(path, buff_.get(), offset_, ideSession, isLastSilce);
330 1 : if (ret != AICPU_SCHEDULE_OK) {
331 1 : aicpusd_err("op name[%s], dump input failed", opName_.c_str());
332 1 : return ret;
333 : }
334 0 : offset_ = 0U;
335 : }
336 : }
337 2 : aicpusd_info("op name[%s], process input[%d] data dump success.", opName_.c_str(), i);
338 : }
339 5 : return AICPU_SCHEDULE_OK;
340 : }
341 :
342 2 : StatusCode OpDumpTask::ProcessOutputDump(const ::toolkit::dumpdata::DumpData &dumpData,
343 : const std::string &path,
344 : const IDE_SESSION ideSession)
345 : {
346 2 : uint64_t dumpedSize = 0U;
347 4 : for (int32_t i = 0; i < dumpData.output_size(); ++i) {
348 2 : auto &output = dumpData.output(i);
349 2 : const uint64_t len = output.size();
350 2 : if (len == 0U) {
351 0 : aicpusd_info("op name[%s], output[%d] data size is zero", opName_.c_str(), i);
352 0 : continue;
353 : }
354 2 : const uint64_t baseAddr = outputsBaseAddr_.at(static_cast<size_t>(i));
355 2 : uint64_t dataAddr = baseAddr;
356 2 : if (!skipAddressConversion_) {
357 1 : if (baseAddr == 0U) {
358 0 : aicpusd_info("op name[%s], output[%d] base addr is null.", opName_.c_str(), i);
359 0 : continue;
360 : }
361 : // baseAddr is a pointer point to data addr
362 1 : dataAddr = *(PtrToPtr<void, uint64_t>(ValueToPtr(baseAddr)));
363 1 : aicpusd_info("op name[%s], output[%d].", opName_.c_str(), i);
364 : }
365 2 : aicpusd_info("op name[%s], output[%d] size[%llu].", opName_.c_str(), i, len);
366 :
367 2 : if (dataAddr == 0U) {
368 0 : aicpusd_info("op name[%s], output[%d] addr is null", opName_.c_str(), i);
369 0 : continue;
370 : }
371 2 : uint64_t innerOffset = 0U;
372 4 : while (innerOffset < len) {
373 2 : const uint64_t emptyBufferSize = buffSize_ - offset_;
374 2 : const uint64_t actSize = std::min(emptyBufferSize, len - innerOffset);
375 2 : const uint64_t srcAddr = dataAddr + innerOffset;
376 2 : aicpusd_info("op name[%s], begin to copy data from HBM to DDR for output[%d], size[%llu]",
377 : opName_.c_str(), i, actSize);
378 2 : const errno_t eRet = memcpy_s(buff_.get() + offset_,
379 : emptyBufferSize,
380 2 : ValueToPtr(srcAddr),
381 : actSize);
382 2 : if (eRet != EOK) {
383 0 : aicpusd_err("op name[%s], output[%d] memcpy failed, des[%llu], src[%llu]", opName_.c_str(), i,
384 : PtrToValue(buff_.get() + offset_), srcAddr);
385 0 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
386 : }
387 2 : aicpusd_info("op name[%s], end of copy data from HBM to DDR for output[%d], size[%llu]",
388 : opName_.c_str(), i, actSize);
389 2 : offset_ += actSize;
390 2 : innerOffset += actSize;
391 2 : dumpedSize += actSize;
392 2 : const bool isLastSilce = (offset_ >= buffSize_) ||
393 0 : ((dumpedSize == outputTotalSize_) && (opBufferTotalSize_ == 0U) && (opWorkspaceTotalSize_ == 0U));
394 2 : if (isLastSilce) {
395 2 : const StatusCode ret = Dump(path, buff_.get(), offset_, ideSession, isLastSilce);
396 2 : if (ret != AICPU_SCHEDULE_OK) {
397 0 : aicpusd_err("op name[%s], dump output failed", opName_.c_str());
398 0 : return ret;
399 : }
400 2 : offset_ = 0U;
401 : }
402 : }
403 :
404 2 : aicpusd_info("op name[%s], process output[%d] data dump success.", opName_.c_str(), i);
405 : }
406 2 : return AICPU_SCHEDULE_OK;
407 : }
408 :
409 4 : StatusCode OpDumpTask::ProcessOpBufferDump(const ::toolkit::dumpdata::DumpData &dumpData,
410 : const std::string &path,
411 : const IDE_SESSION ideSession)
412 : {
413 4 : uint64_t dumpedSize = 0U;
414 5 : for (int32_t i = 0; i < dumpData.buffer_size(); ++i) {
415 2 : auto &buffer = dumpData.buffer(i);
416 2 : if (buffer.size() == 0U) {
417 0 : aicpusd_info("op name[%s], op buffer[%d] data size is zero", opName_.c_str(), i);
418 0 : continue;
419 : }
420 2 : const size_t opBufferAddrIndex = static_cast<size_t>(i);
421 2 : if (opBufferAddr_[opBufferAddrIndex] == 0U) {
422 1 : aicpusd_info("op name[%s], op buffer[%d] addr is null", opName_.c_str(), i);
423 1 : continue;
424 : }
425 1 : uint64_t innerOffset = 0U;
426 1 : while (innerOffset < buffer.size()) {
427 1 : const uint64_t emptyBufferSize = buffSize_ - offset_;
428 1 : const uint64_t actSize = std::min(emptyBufferSize, buffer.size() - innerOffset);
429 1 : const uint64_t srcAddr = opBufferAddr_[opBufferAddrIndex] + innerOffset;
430 1 : aicpusd_info("op name[%s], begin to copy data from HBM to DDR for op buffer[%d], size[%llu]",
431 : opName_.c_str(), i, actSize);
432 1 : const errno_t eRet = memcpy_s(buff_.get() + offset_,
433 : emptyBufferSize,
434 1 : ValueToPtr(srcAddr),
435 : actSize);
436 1 : if (eRet != EOK) {
437 1 : aicpusd_err("op name[%s], op buffer[%d] memcpy failed, desSize[%llu], srcSize[%llu]",
438 : opName_.c_str(), i, emptyBufferSize, actSize);
439 1 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
440 : }
441 0 : aicpusd_info("op name[%s], end of copy data from HBM to DDR for op buffer[%d], size[%llu]",
442 : opName_.c_str(), i, actSize);
443 0 : offset_ += actSize;
444 0 : innerOffset += actSize;
445 0 : dumpedSize += actSize;
446 0 : const bool isLastSilce = (offset_ >= buffSize_) ||
447 0 : ((dumpedSize == opBufferTotalSize_) && (opWorkspaceTotalSize_ == 0U));
448 0 : if (isLastSilce) {
449 0 : const StatusCode ret = Dump(path, buff_.get(), offset_, ideSession, isLastSilce);
450 0 : if (ret != AICPU_SCHEDULE_OK) {
451 0 : aicpusd_err("op name[%s], dump op buffer failed", opName_.c_str());
452 0 : return ret;
453 : }
454 0 : offset_ = 0U;
455 : }
456 : }
457 0 : aicpusd_info("op name[%s], process op buffer[%d] data success.", opName_.c_str(), i);
458 : }
459 3 : return AICPU_SCHEDULE_OK;
460 : }
461 :
462 8 : StatusCode OpDumpTask::ProcessOpWorkspaceDump(const ::toolkit::dumpdata::DumpData &dumpData,
463 : const std::string &path,
464 : const IDE_SESSION ideSession)
465 : {
466 8 : uint64_t dumpedSize = 0U;
467 12 : for (int64_t i = 0; i < dumpData.space_size(); ++i) {
468 6 : auto &space = dumpData.space(i);
469 6 : if (space.size() == 0U) {
470 1 : aicpusd_err("op name[%s], op space[%d] data size is zero", opName_.c_str(), i);
471 1 : continue;
472 : }
473 5 : const size_t opWorkspaceAddrIndex = static_cast<size_t>(i);
474 5 : if (opWorkspaceAddr_[opWorkspaceAddrIndex] == 0U) {
475 1 : aicpusd_err("op name[%s], op space[%d] workspace is null", opName_.c_str(), i);
476 1 : continue;
477 : }
478 4 : uint64_t innerOffset = 0U;
479 6 : while (innerOffset < space.size()) {
480 4 : const uint64_t emptyWorkspaceSize = buffSize_ - offset_;
481 4 : const uint64_t actSize = std::min(emptyWorkspaceSize, space.size() - innerOffset);
482 4 : const uint64_t srcAddr = opWorkspaceAddr_[opWorkspaceAddrIndex] + innerOffset;
483 4 : aicpusd_info("op name[%s], begin to copy data from HBM to DDR for spaceIndex[%d]," \
484 : " srcSize[%llu], innerOffset[%llu], offset[%llu], dstSize[%llu]",
485 : opName_.c_str(), i, actSize, innerOffset, offset_, emptyWorkspaceSize);
486 4 : const errno_t eRet = memcpy_s(buff_.get() + offset_,
487 : emptyWorkspaceSize,
488 4 : PtrToPtr<void, char_t>(ValueToPtr(srcAddr)),
489 : actSize);
490 4 : if (eRet != EOK) {
491 1 : aicpusd_err("op name[%s], op spaceIndex[%d] memcpy failed, dstSize[%llu], srcSize[%llu]",
492 : opName_.c_str(), i, emptyWorkspaceSize, actSize);
493 2 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
494 : }
495 3 : aicpusd_info("op name[%s], op spaceIndex[%d] end copy, dstSize[%llu], srcSize[%llu]",
496 : opName_.c_str(), i, emptyWorkspaceSize, actSize);
497 3 : offset_ += actSize;
498 3 : innerOffset += actSize;
499 3 : dumpedSize += actSize;
500 3 : const bool isLastSilce = (dumpedSize == opWorkspaceTotalSize_);
501 3 : if (!((offset_ >= buffSize_) || isLastSilce)) {
502 0 : continue;
503 : }
504 3 : const StatusCode ret = Dump(path, buff_.get(), offset_, ideSession, isLastSilce);
505 3 : if (ret != AICPU_SCHEDULE_OK) {
506 1 : aicpusd_err("op name[%s], dump op space failed", opName_.c_str());
507 1 : return ret;
508 : }
509 2 : offset_ = 0U;
510 : }
511 2 : aicpusd_info("op name[%s], process op space[%d] data success.", opName_.c_str(), i);
512 : }
513 6 : return AICPU_SCHEDULE_OK;
514 : }
515 :
516 6 : StatusCode OpDumpTask::Dump(const std::string &path,
517 : char_t * const data,
518 : const uint64_t len,
519 : const IDE_SESSION ideSession,
520 : const bool isLastSlice) const
521 : {
522 6 : if (ideSession != nullptr) {
523 6 : IdeDumpChunk ideDumpChunk = {};
524 6 : ideDumpChunk.fileName = const_cast<char_t *>(path.c_str());
525 6 : ideDumpChunk.dataBuf = reinterpret_cast<uint8_t *>(data);
526 6 : ideDumpChunk.bufLen = static_cast<uint32_t>(len);
527 6 : ideDumpChunk.isLastChunk = isLastSlice ? 1U : 0U;
528 6 : ideDumpChunk.offset = -1; // append
529 6 : ideDumpChunk.flag = IDE_DUMP_NONE_FLAG;
530 6 : aicpusd_info("op name[%s], start to call IdeDumpData, size[%u], isLastChunk[%u]",
531 : opName_.c_str(), len, ideDumpChunk.isLastChunk);
532 6 : const IdeErrorT ideState = IdeDumpData(ideSession, &ideDumpChunk);
533 6 : if (ideState != IDE_DAEMON_NONE_ERROR) {
534 2 : aicpusd_err("op name[%s], call IdeDumpData failed, size[%u].", opName_.c_str(), len);
535 2 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
536 : }
537 4 : aicpusd_info("op name[%s], end of call IdeDumpData, size[%u]", opName_.c_str(), len);
538 : } else {
539 0 : aicpusd_err("op name[%s], ide session is null, size[%u].", opName_.c_str(), len);
540 0 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
541 : }
542 4 : return AICPU_SCHEDULE_OK;
543 : }
544 :
545 3 : StatusCode OpDumpTask::DumpOpInfo(const uint32_t streamId, const uint32_t taskId,
546 : const std::string &dumpDebugInfo)
547 : {
548 3 : const std::lock_guard<std::mutex> queLock(dumpMtx_);
549 3 : uint64_t dumpNumber = 0U;
550 3 : if (GetDumpNumber(dumpNumber) != AICPU_SCHEDULE_OK) {
551 1 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
552 : }
553 2 : if (!NeedDump(dumpNumber)) {
554 0 : return AICPU_SCHEDULE_OK;
555 : }
556 :
557 2 : const uint64_t nowTime = GetCurrentTime();
558 2 : baseDumpData_.set_dump_time(nowTime);
559 :
560 2 : if ((baseDumpData_.ByteSizeLong() > static_cast<uint64_t>(INT_MAX)) || (baseDumpData_.ByteSizeLong() == 0U)) {
561 0 : aicpusd_err("op name[%s], dump data size[%zuB] should be in [1B, 2GB)].",
562 : opName_.c_str(), baseDumpData_.ByteSizeLong());
563 0 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
564 : }
565 2 : aicpusd_info("op name[%s], proto buffer total bytes[%llu]", opName_.c_str(), baseDumpData_.ByteSizeLong());
566 2 : buffSize_ = baseDumpData_.ByteSizeLong() + sizeof(uint64_t) +
567 2 : inputTotalSize_ + outputTotalSize_ + opBufferTotalSize_ + opWorkspaceTotalSize_;
568 2 : buffSize_ = std::min(buffSize_, DUMP_SLICE_SIZE);
569 2 : buffSize_ = std::max(buffSize_, baseDumpData_.ByteSizeLong() + sizeof(uint64_t));
570 2 : buff_.reset(new (std::nothrow) char_t[buffSize_]);
571 2 : if (buff_ == nullptr) {
572 0 : aicpusd_err("op name[%s], malloc buffer for data dump failed, size[%llu]", opName_.c_str(), buffSize_);
573 0 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
574 : }
575 : // for memory statistic
576 2 : aicpusd_memory_log("op name[%s], MallocMemory, func=new, size=%llu, purpose=data dump buffer",
577 : opName_.c_str(), buffSize_);
578 2 : uint64_t * const sizePtr = PtrToPtr<char_t, uint64_t>(buff_.get());
579 2 : *sizePtr = baseDumpData_.ByteSizeLong();
580 2 : offset_ = sizeof(uint64_t);
581 2 : if (!baseDumpData_.SerializeToArray(buff_.get() + sizeof(uint64_t),
582 2 : static_cast<int32_t>(baseDumpData_.ByteSizeLong()))) {
583 0 : aicpusd_err("op name[%s], serialize dump data to string failed, data size[%zuB].",
584 : opName_.c_str(), baseDumpData_.ByteSizeLong());
585 0 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
586 : }
587 2 : offset_ += baseDumpData_.ByteSizeLong();
588 : // dump file path name
589 2 : const std::string dumpFilePath = DumpPath(nowTime, dumpNumber, streamId, taskId);
590 2 : std::string dumpDebugFilePath;
591 2 : if (!(dumpDebugInfo.empty())) {
592 0 : dumpDebugFilePath = DumpPath(nowTime, dumpNumber, streamId, taskId, true);
593 : }
594 2 : return DoDump(dumpFilePath, dumpDebugFilePath, dumpDebugInfo);
595 3 : }
596 :
597 2 : StatusCode OpDumpTask::DoDump(const std::string &dumpFilePath, const std::string &dumpDebugFilePath,
598 : const std::string &dumpDebugInfo)
599 : {
600 2 : aicpusd_info("op name[%s], start to dump data, path[%s]", opName_.c_str(), dumpFilePath.c_str());
601 : // the port is not used in ide module, just for privateInfo format check
602 2 : const std::string privateInfo = "127.0.0.1:22118;" + std::to_string(deviceId_) + ";" + std::to_string(hostPid_);
603 2 : aicpusd_info("op name[%s], ide dump start private info[%s]", opName_.c_str(), privateInfo.c_str());
604 2 : const IDE_SESSION ideSession = IdeDumpStart(privateInfo.c_str());
605 2 : if (ideSession == nullptr) {
606 0 : aicpusd_err("op name[%s], call IdeDumpStart failed, path[%s].", opName_.c_str(), dumpFilePath.c_str());
607 0 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
608 : }
609 0 : const ScopeGuard ideSessGuard([&ideSession]() {
610 2 : IdeDumpEnd(ideSession);
611 2 : });
612 2 : StatusCode ret = AICPU_SCHEDULE_OK;
613 2 : if (offset_ == buffSize_) {
614 0 : ret = Dump(dumpFilePath, buff_.get(), buffSize_, ideSession, false);
615 0 : if (ret != AICPU_SCHEDULE_OK) {
616 0 : aicpusd_err("op name[%s], dump proto failed, path[%s].", opName_.c_str(), dumpFilePath.c_str());
617 0 : return ret;
618 : }
619 0 : offset_ = 0U;
620 : }
621 :
622 2 : ret = ProcessInputDump(baseDumpData_, dumpFilePath, ideSession);
623 2 : if (ret != AICPU_SCHEDULE_OK) {
624 0 : return ret;
625 : }
626 2 : ret = ProcessOutputDump(baseDumpData_, dumpFilePath, ideSession);
627 2 : if (ret != AICPU_SCHEDULE_OK) {
628 0 : return ret;
629 : }
630 2 : ret = ProcessOpBufferDump(baseDumpData_, dumpFilePath, ideSession);
631 2 : if (ret != AICPU_SCHEDULE_OK) {
632 0 : return ret;
633 : }
634 2 : ret = ProcessOpWorkspaceDump(baseDumpData_, dumpFilePath, ideSession);
635 2 : if (ret != AICPU_SCHEDULE_OK) {
636 0 : return ret;
637 : }
638 : // release buffer
639 2 : buff_.reset(nullptr);
640 :
641 2 : if (!(dumpDebugInfo.empty())) {
642 0 : ret = Dump(dumpDebugFilePath, const_cast<char_t *>(dumpDebugInfo.c_str()),
643 : dumpDebugInfo.size(), ideSession, true);
644 0 : if (ret != AICPU_SCHEDULE_OK) {
645 0 : aicpusd_err("op name[%s], dump debug info failed, path[%s].", opName_.c_str(),
646 : dumpDebugFilePath.c_str());
647 0 : return ret;
648 : }
649 : }
650 2 : aicpusd_info("op name[%s], dump data success, path[%s]", opName_.c_str(), dumpFilePath.c_str());
651 2 : return AICPU_SCHEDULE_OK;
652 2 : }
653 :
654 1 : void OpDumpTask::UpdateDumpNum()
655 : {
656 1 : const std::lock_guard<std::mutex> queLock(dumpMtx_);
657 1 : taskDumpNum_++;
658 1 : aicpusd_info("op name[%s], dump number is updated, dump number[%llu].", opName_.c_str(), taskDumpNum_);
659 1 : }
660 :
661 1 : bool OpDumpTask::IsEndGraph() const
662 : {
663 1 : return endGraph_;
664 : }
665 :
666 1 : bool OpDumpTask::GetModelId(uint32_t &modelId) const
667 : {
668 1 : if (optionalParam_.hasModelId) {
669 1 : modelId = optionalParam_.modelId;
670 1 : return true;
671 : }
672 0 : return false;
673 : }
674 :
675 0 : std::string OpDumpTask::GetOpName() const
676 : {
677 0 : return opName_;
678 : }
679 :
680 2 : bool OpDumpTask::NeedDump(const uint64_t step)
681 : {
682 2 : if (endGraph_) {
683 0 : aicpusd_run_info("op name[%s], end graph dump task.", opName_.c_str());
684 0 : return false;
685 : }
686 :
687 2 : bool stepNeedDump = false;
688 2 : if (dumpStep_.singleStep.empty() && dumpStep_.intervalStep.empty()) {
689 2 : stepNeedDump = true;
690 : }
691 2 : if (dumpStep_.singleStep.find(step) != dumpStep_.singleStep.end()) {
692 0 : stepNeedDump = true;
693 : }
694 2 : for (const auto item : dumpStep_.intervalStep) {
695 0 : if ((step >= item.start) && (step <= item.end)) {
696 0 : stepNeedDump = true;
697 0 : break;
698 : }
699 : }
700 2 : if (!stepNeedDump) {
701 0 : aicpusd_run_info("op name[%s], the step[%llu] is not in dump list %s.",
702 : opName_.c_str(), step, dumpStep_.DebugString().c_str());
703 0 : return false;
704 : }
705 :
706 2 : if ((inputTotalSize_ == 0U) &&
707 0 : (outputTotalSize_ == 0U) &&
708 0 : (opBufferTotalSize_ == 0U) && (opWorkspaceTotalSize_ == 0U)) {
709 0 : aicpusd_run_info("op name[%s], no data need to dump.", opName_.c_str());
710 0 : return false;
711 : }
712 :
713 2 : return true;
714 : }
715 :
716 2 : std::string OpDumpTask::DumpPath(const uint64_t nowTime, const uint64_t dumpNumber,
717 : const uint32_t streamId, const uint32_t taskId, const bool debugFlag)
718 : {
719 2 : std::ostringstream oss;
720 2 : oss << baseDumpPath_;
721 2 : if (optionalParam_.hasModelName) {
722 1 : oss << "/" << optionalParam_.modelName;
723 : }
724 2 : if (optionalParam_.hasModelId) {
725 1 : oss << "/" << optionalParam_.modelId;
726 : }
727 : // single op dump
728 2 : if (!((skipAddressConversion_) && (!optionalParam_.hasStepId))) {
729 2 : oss << "/" << dumpNumber;
730 : }
731 :
732 2 : std::string opName = opName_;
733 2 : std::string opType = opType_;
734 2 : ReplaceStringElem(opName);
735 2 : ReplaceStringElem(opType);
736 2 : if (debugFlag) {
737 0 : opName += "Debug";
738 : }
739 2 : if ((streamId != INVALID_VAL) && (taskId != INVALID_VAL)) {
740 0 : oss << "/" << opType << "." << opName << "." << taskId << "." << streamId << "." << nowTime;
741 : } else {
742 2 : oss << "/" << opType << "." << opName << "." << taskInfo_.taskId_ << "."
743 2 : << taskInfo_.streamId_ << "." << nowTime;
744 : }
745 4 : return oss.str();
746 2 : }
747 :
748 2 : void OpDumpTask::ClearBaseDumpData()
749 : {
750 2 : baseDumpData_.Clear();
751 2 : return;
752 : }
753 :
754 1 : std::string DumpStep::DebugString()
755 : {
756 1 : std::ostringstream oss;
757 1 : for (const auto step : singleStep) {
758 0 : oss << "[" << step << "] ";
759 : }
760 1 : for (const auto step : intervalStep) {
761 0 : oss << "[" << step.start << ", " << step.end << "] ";
762 : }
763 :
764 2 : return oss.str();
765 1 : }
766 :
767 7 : OpDumpTaskManager &OpDumpTaskManager::GetInstance()
768 : {
769 7 : static OpDumpTaskManager instance;
770 7 : return instance;
771 : }
772 :
773 9 : void OpDumpTaskManager::GetOptionalParam(const aicpu::dump::OpMappingInfo &opMappingInfo,
774 : MappingInfoOptionalParam &optionalParam) const
775 : {
776 9 : if (opMappingInfo.model_name_param_case() == aicpu::dump::OpMappingInfo::kModelName) {
777 8 : optionalParam.modelName = opMappingInfo.model_name();
778 8 : ReplaceStringElem(optionalParam.modelName);
779 8 : optionalParam.hasModelName = true;
780 : }
781 9 : if (opMappingInfo.model_id_param_case() == aicpu::dump::OpMappingInfo::kModelId) {
782 8 : optionalParam.modelId = opMappingInfo.model_id();
783 8 : optionalParam.hasModelId = true;
784 : }
785 9 : if (opMappingInfo.step_id_case() == aicpu::dump::OpMappingInfo::kStepIdAddr) {
786 8 : optionalParam.stepIdAddr =
787 8 : PtrToPtr<void, uint64_t>(ValueToPtr(opMappingInfo.step_id_addr()));
788 8 : optionalParam.hasStepId = true;
789 : }
790 9 : if (opMappingInfo.iterations_per_loop_case() == aicpu::dump::OpMappingInfo::kIterationsPerLoopAddr) {
791 7 : optionalParam.iterationsPerLoopAddr =
792 7 : PtrToPtr<void, uint64_t>(ValueToPtr(opMappingInfo.iterations_per_loop_addr()));
793 7 : optionalParam.hasIterationsPerLoop = true;
794 : }
795 9 : if (opMappingInfo.loop_cond_case() == aicpu::dump::OpMappingInfo::kLoopCondAddr) {
796 7 : optionalParam.loopCondAddr =
797 7 : PtrToPtr<void, uint64_t>(ValueToPtr(opMappingInfo.loop_cond_addr()));
798 7 : optionalParam.hasLoopCond = true;
799 : }
800 9 : }
801 :
802 6 : int32_t OpDumpTaskManager::Load(const aicpu::dump::OpMappingInfo &opMappingInfo)
803 : {
804 6 : const std::string dumpPath = opMappingInfo.dump_path();
805 6 : MappingInfoOptionalParam optionalParam;
806 6 : GetOptionalParam(opMappingInfo, optionalParam);
807 6 : const std::string dumpStepStr = opMappingInfo.dump_step();
808 6 : DumpStep dumpStep;
809 6 : if (!GetDumpStepFromString(dumpStepStr, dumpStep)) {
810 1 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
811 : }
812 5 : const int32_t hostPid = static_cast<int32_t>(AicpuSchedule::AicpuDrvManager::GetInstance().GetHostPid());
813 5 : const uint32_t deviceId = AicpuSchedule::AicpuDrvManager::GetInstance().GetDeviceId();
814 5 : std::set<TaskInfo> tasksInfo;
815 : {
816 5 : const std::lock_guard<std::mutex> mapLock(dumpTaskMapMtx_);
817 10 : for (int32_t i = 0; i < opMappingInfo.task_size(); ++i) {
818 5 : const aicpu::dump::Task task = opMappingInfo.task(i);
819 5 : const uint32_t taskId = task.task_id() & 0xFFFF;
820 5 : const uint32_t streamId = task.stream_id();
821 5 : std::shared_ptr<OpDumpTask> opDumpTaskPtr = nullptr;
822 : try {
823 5 : opDumpTaskPtr = std::make_shared<OpDumpTask>(hostPid, deviceId);
824 0 : } catch (...) {
825 0 : aicpusd_err("make shared for OpDumpTask failed.");
826 0 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
827 0 : }
828 5 : aicpusd_memory_log("MallocMemory, func=new, size=%zu, purpose=data dumper", sizeof(OpDumpTask));
829 5 : if (opDumpTaskPtr == nullptr) {
830 0 : aicpusd_err("malloc memory for OpDumpTask object failed");
831 0 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
832 : }
833 5 : const int32_t ret = opDumpTaskPtr->PreProcessOpMappingInfo(task, dumpPath, optionalParam, dumpStep);
834 5 : if (ret != AICPU_SCHEDULE_OK) {
835 : // when error occur, ge call unload op mapping info
836 0 : aicpusd_err("pre process op mapping info failed");
837 0 : return ret;
838 : }
839 5 : TaskInfo taskInfo(streamId, taskId);
840 5 : (void)dumpTaskMap_.insert(std::make_pair(taskInfo, std::move(opDumpTaskPtr)));
841 5 : (void)tasksInfo.insert(taskInfo);
842 5 : }
843 5 : if (optionalParam.hasModelId) {
844 5 : const auto iter = modelIdToTask_.find(optionalParam.modelId);
845 5 : if (iter == modelIdToTask_.end()) {
846 2 : (void)modelIdToTask_.insert(std::make_pair(optionalParam.modelId, std::move(tasksInfo)));
847 : } else {
848 6 : for (const auto item : tasksInfo) {
849 3 : (void)iter->second.insert(item);
850 : }
851 : }
852 : }
853 5 : }
854 5 : return AICPU_SCHEDULE_OK;
855 6 : }
856 :
857 3 : void OpDumpTaskManager::UnloadClearTaskInfo(const TaskInfo &taskInfo)
858 : {
859 3 : const auto range = dumpTaskMap_.equal_range(taskInfo);
860 3 : if (range.first != range.second) {
861 3 : for (auto item = range.first; item != range.second; ++item) {
862 2 : item->second->ClearBaseDumpData();
863 : }
864 : }
865 3 : (void)dumpTaskMap_.erase(taskInfo);
866 6 : return;
867 : }
868 :
869 2 : int32_t OpDumpTaskManager::Unload(const aicpu::dump::OpMappingInfo &opMappingInfo)
870 : {
871 2 : const std::lock_guard<std::mutex> mapLock(dumpTaskMapMtx_);
872 4 : for (int32_t i = 0; i < opMappingInfo.task_size(); ++i) {
873 2 : const aicpu::dump::Task task = opMappingInfo.task(i);
874 2 : const uint32_t taskId = task.task_id();
875 2 : const uint32_t streamId = task.stream_id();
876 2 : const TaskInfo taskInfo(streamId, taskId);
877 2 : UnloadClearTaskInfo(taskInfo);
878 2 : aicpusd_info("Unload op mapping info, stream id[%u], task id[%u].",
879 : streamId, taskId);
880 2 : }
881 2 : MappingInfoOptionalParam optionalParam;
882 2 : GetOptionalParam(opMappingInfo, optionalParam);
883 2 : if (optionalParam.hasModelId) {
884 2 : const auto iter = modelIdToTask_.find(optionalParam.modelId);
885 2 : if (iter == modelIdToTask_.end()) {
886 1 : aicpusd_warn("no model id[%u], unload dump model failed", optionalParam.modelId);
887 1 : return AICPU_SCHEDULE_OK;
888 : }
889 2 : for (const auto taskInfo : iter->second) {
890 1 : UnloadClearTaskInfo(taskInfo);
891 1 : aicpusd_info("Check and clean data dump task resource, stream id[%u], task id[%u].",
892 : taskInfo.streamId_, taskInfo.taskId_);
893 : }
894 1 : (void)modelIdToTask_.erase(iter);
895 1 : aicpusd_info("Unloaded model id[%u] successfully", optionalParam.modelId);
896 : }
897 1 : return AICPU_SCHEDULE_OK;
898 2 : }
899 :
900 10 : int32_t OpDumpTaskManager::LoadOpMappingInfo(const char_t * const infoAddr, const uint32_t len)
901 : {
902 10 : aicpusd_info("Load op mapping info, size[%u].", len);
903 10 : if (infoAddr == nullptr) {
904 1 : aicpusd_err("op mapping info addr is null");
905 1 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
906 : }
907 9 : aicpu::dump::OpMappingInfo opMappingInfo;
908 9 : const std::string protoInfo(infoAddr, static_cast<unsigned long>(len));
909 9 : const bool parseRet = opMappingInfo.ParseFromString(protoInfo);
910 9 : if (!parseRet) {
911 1 : aicpusd_err("parse op mapping info failed");
912 1 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
913 : }
914 8 : if (opMappingInfo.flag() == 0x01U) {
915 6 : return Load(opMappingInfo);
916 2 : } else if (opMappingInfo.flag() == 0x00U) {
917 2 : return Unload(opMappingInfo);
918 : } else {
919 0 : aicpusd_info("Flag [%d] invalid, allow [0x00, 0x01]", opMappingInfo.flag());
920 0 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
921 : }
922 : return AICPU_SCHEDULE_OK;
923 9 : }
924 :
925 2 : int32_t OpDumpTaskManager::DumpOpInfo(const uint32_t streamId, const uint32_t taskId,
926 : const uint32_t streamId1, const uint32_t taskId1,
927 : const std::string &dumpDebugInfo)
928 : {
929 2 : const TaskInfo taskInfo(streamId, taskId);
930 2 : dumpTaskMapMtx_.lock();
931 2 : const auto range = dumpTaskMap_.equal_range(taskInfo);
932 2 : if (range.first == range.second) {
933 1 : dumpTaskMapMtx_.unlock();
934 1 : aicpusd_run_info("task required to dump does not exist, stream id[%u], task id[%u].", streamId, taskId);
935 1 : return AICPU_SCHEDULE_OK;
936 : } else {
937 1 : std::vector<std::shared_ptr<OpDumpTask>> opDumptasks;
938 3 : for (auto item = range.first; item != range.second; ++item) {
939 2 : std::shared_ptr<OpDumpTask> opDumpTask = item->second;
940 2 : opDumptasks.push_back(std::move(opDumpTask));
941 2 : }
942 1 : int32_t ret = AICPU_SCHEDULE_OK;
943 1 : dumpTaskMapMtx_.unlock();
944 1 : aicpusd_run_info("require to dump op info, stream id=%u, task id=%u, task number=%zu",
945 : streamId, taskId, opDumptasks.size());
946 2 : for (auto item : opDumptasks) {
947 2 : aicpusd_run_info("start to dump op info, stream id=%u, task id=%u, op name=%s",
948 : streamId, taskId, item->GetOpName().c_str());
949 2 : ret = item->DumpOpInfo(streamId1, taskId1, dumpDebugInfo);
950 2 : aicpusd_run_info("end of dump op info, result=%d, stream id=%u, task id=%u, op name=%s",
951 : ret, streamId, taskId, item->GetOpName().c_str());
952 2 : if (ret != AICPU_SCHEDULE_OK) {
953 1 : return ret;
954 : }
955 2 : }
956 : // process if task is end graph
957 0 : ProcessEndGraph(opDumptasks);
958 1 : }
959 0 : return AICPU_SCHEDULE_OK;
960 : }
961 :
962 2 : int32_t OpDumpTaskManager::DumpOpInfoForUnknowShape(const uint64_t opMappingInfoAddr,
963 : const uint64_t opMappingInfoLen) const
964 : {
965 2 : aicpusd_info("load op mapping info for single op or unknown shape op, size[%llu]", opMappingInfoLen);
966 2 : if (opMappingInfoAddr == 0U) {
967 1 : aicpusd_err("op mapping info addr is null");
968 1 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
969 : }
970 1 : aicpu::dump::OpMappingInfo opMappingInfo;
971 1 : const std::string protoInfo(PtrToPtr<const void, const char_t>(ValueToPtr(opMappingInfoAddr)),
972 1 : opMappingInfoLen);
973 1 : const bool parseRet = opMappingInfo.ParseFromString(protoInfo);
974 1 : if (!parseRet) {
975 0 : aicpusd_err("parse op mapping info failed, size[%u]", opMappingInfoLen);
976 0 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
977 : }
978 1 : const int32_t taskSize = opMappingInfo.task_size();
979 1 : if (taskSize != 1) {
980 0 : aicpusd_err("task number[%d] should be only one, op mapping info: %s",
981 : opMappingInfo.task_size(), opMappingInfo.DebugString().c_str());
982 0 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
983 : }
984 1 : return DoDump(opMappingInfo);
985 1 : }
986 :
987 1 : int32_t OpDumpTaskManager::DoDump(const aicpu::dump::OpMappingInfo &opMappingInfo) const
988 : {
989 1 : const std::string dumpPath = opMappingInfo.dump_path();
990 1 : MappingInfoOptionalParam optionalParam;
991 1 : GetOptionalParam(opMappingInfo, optionalParam);
992 1 : const std::string dumpStepStr = opMappingInfo.dump_step();
993 :
994 1 : DumpStep dumpStep;
995 1 : if (!GetDumpStepFromString(dumpStepStr, dumpStep)) {
996 0 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
997 : }
998 1 : const int32_t hostPid = static_cast<int32_t>(AicpuSchedule::AicpuDrvManager::GetInstance().GetHostPid());
999 1 : const uint32_t deviceId = AicpuSchedule::AicpuDrvManager::GetInstance().GetDeviceId();
1000 1 : std::shared_ptr<OpDumpTask> opDumpTaskPtr = nullptr;
1001 : try {
1002 1 : opDumpTaskPtr = std::make_shared<OpDumpTask>(hostPid, deviceId);
1003 0 : } catch (const std::bad_alloc &err) {
1004 0 : aicpusd_err("malloc memory for OpDumpTask object failed, reason is [%s]", err.what());
1005 0 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
1006 0 : } catch (...) {
1007 0 : aicpusd_err("malloc memory for OpDumpTask object failed");
1008 0 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
1009 0 : }
1010 1 : aicpusd_memory_log("MallocMemory, func=new, size=%zu, purpose=data dumper", sizeof(OpDumpTask));
1011 1 : if (opDumpTaskPtr == nullptr) {
1012 0 : aicpusd_err("malloc memory for OpDumpTask object failed");
1013 0 : return AICPU_SCHEDULE_ERROR_DUMP_FAILED;
1014 : }
1015 1 : int32_t ret = AICPU_SCHEDULE_OK;
1016 1 : const aicpu::dump::Task task = opMappingInfo.task(0);
1017 1 : ret = opDumpTaskPtr->PreProcessOpMappingInfo(task,
1018 : dumpPath,
1019 : optionalParam,
1020 : dumpStep,
1021 : true);
1022 1 : if (ret != AICPU_SCHEDULE_OK) {
1023 0 : aicpusd_err("pre process op mapping info failed, op mapping info: %s",
1024 : opMappingInfo.DebugString().c_str());
1025 0 : return ret;
1026 : }
1027 1 : auto startTime = std::chrono::steady_clock::now();
1028 1 : aicpusd_run_info("start to dump op info, op name=%s", opDumpTaskPtr->GetOpName().c_str());
1029 2 : ret = opDumpTaskPtr->DumpOpInfo();
1030 1 : auto endTime = std::chrono::steady_clock::now();
1031 1 : double drUs = std::chrono::duration<double, std::micro>(endTime - startTime).count();
1032 1 : aicpusd_run_info("end of dump op info, result=%d, op name=%s, cost time is [%.2lf]us",
1033 : ret, opDumpTaskPtr->GetOpName().c_str(), drUs);
1034 : UNUSED(drUs);
1035 1 : return ret;
1036 1 : }
1037 :
1038 1 : void OpDumpTaskManager::ProcessEndGraph(const std::vector<std::shared_ptr<OpDumpTask>> &opDumptasks)
1039 : {
1040 2 : for (const auto &item : opDumptasks) {
1041 1 : if (item->IsEndGraph()) {
1042 : uint32_t modelId;
1043 0 : if (item->GetModelId(modelId)) {
1044 0 : UpdateDumpNumByModelId(modelId);
1045 : } else {
1046 0 : item->UpdateDumpNum();
1047 : }
1048 : }
1049 : }
1050 1 : }
1051 :
1052 1 : void OpDumpTaskManager::UpdateDumpNumByModelId(const uint32_t modelId)
1053 : {
1054 1 : std::vector<std::shared_ptr<OpDumpTask>> opDumptasks;
1055 : {
1056 1 : const std::lock_guard<std::mutex> mapLock(dumpTaskMapMtx_);
1057 1 : const auto iter = modelIdToTask_.find(modelId);
1058 1 : if (iter != modelIdToTask_.end()) {
1059 0 : for (auto &taskInfo : iter->second) {
1060 0 : const auto range = dumpTaskMap_.equal_range(taskInfo);
1061 0 : for (auto item = range.first; item != range.second; ++item) {
1062 0 : std::shared_ptr<OpDumpTask> opDumpTask = item->second;
1063 0 : opDumptasks.push_back(std::move(opDumpTask));
1064 0 : }
1065 : }
1066 : }
1067 1 : }
1068 :
1069 1 : for (auto &dumpTask : opDumptasks) {
1070 0 : dumpTask->UpdateDumpNum();
1071 : }
1072 1 : }
1073 :
1074 1 : static void DoSplit(const std::string &externStr, std::vector<std::string> &ret, const std::string &delim)
1075 : {
1076 1 : size_t i = 0UL;
1077 2 : while (i < externStr.size()) {
1078 1 : const size_t pos = externStr.find(delim, i);
1079 1 : if (pos != std::string::npos) {
1080 1 : std::string s = externStr.substr(i, pos - i);
1081 1 : if (!s.empty()) {
1082 1 : ret.push_back(std::move(s));
1083 : }
1084 1 : i = pos + delim.size() - 1UL;
1085 1 : }
1086 1 : ++i;
1087 : }
1088 1 : }
1089 :
1090 7 : static std::vector<std::string> Split(const std::string &str, const std::string &delim)
1091 : {
1092 7 : std::vector<std::string> ret;
1093 7 : if (!str.empty()) {
1094 1 : const std::string externStr = str + delim;
1095 1 : DoSplit(externStr, ret, delim);
1096 1 : }
1097 7 : return ret;
1098 0 : }
1099 :
1100 1 : bool OpDumpTaskManager::MatchAndInsert(const std::string &step, DumpStep &tmpDumpStep) const
1101 : {
1102 : // smatch result
1103 1 : const std::regex singleStepPatten("(\\s*)(\\d+)(\\s*)");
1104 1 : const std::regex intervalStepPatten("((\\s*)(\\d+)(\\s*)){1}(-(\\s*)(\\d+)(\\s*))");
1105 1 : if (std::regex_match(step, singleStepPatten)) {
1106 1 : (void)tmpDumpStep.singleStep.insert(static_cast<uint64_t>(std::stoull(step)));
1107 0 : } else if (std::regex_match(step, intervalStepPatten)) {
1108 0 : const std::vector<std::string> intervalStepStr = Split(step, "-");
1109 0 : if (intervalStepStr.size() == INTERNAL_STEP_SIZE) {
1110 : IntervalStep intervalStep;
1111 0 : intervalStep.start = static_cast<uint64_t>(std::stoull(intervalStepStr[0U]));
1112 0 : intervalStep.end = static_cast<uint64_t>(std::stoull(intervalStepStr[1U]));
1113 0 : if (intervalStep.start > intervalStep.end) {
1114 0 : std::swap(intervalStep.start, intervalStep.end);
1115 : }
1116 0 : tmpDumpStep.intervalStep.push_back(std::move(intervalStep));
1117 : }
1118 0 : } else {
1119 0 : aicpusd_err("invalid step[%s], please check.", step.c_str());
1120 0 : return false;
1121 : }
1122 0 : return true;
1123 2 : }
1124 :
1125 7 : bool OpDumpTaskManager::GetDumpStepFromString(const std::string &str, DumpStep &dumpStep) const
1126 : {
1127 : // split by |, such as "0|5-10"
1128 7 : aicpusd_info("Step need to dump[%s].", str.c_str());
1129 7 : const std::vector<std::string> steps = Split(str, "|");
1130 7 : DumpStep tmpDumpStep;
1131 7 : for (const auto &step : steps) {
1132 : try {
1133 1 : if (!MatchAndInsert(step, tmpDumpStep)) {
1134 1 : return false;
1135 : }
1136 1 : } catch (std::out_of_range &e) {
1137 1 : aicpusd_err("out of range of uint64_max[%llu], invalid step[%s], msg[%s], please check.",
1138 : UINT64_MAX, step.c_str(), e.what());
1139 1 : return false;
1140 1 : } catch (...) {
1141 0 : aicpusd_err("invalid step[%s], please check.", step.c_str());
1142 0 : return false;
1143 0 : }
1144 : }
1145 6 : dumpStep = std::move(tmpDumpStep);
1146 6 : return true;
1147 7 : }
1148 :
1149 1 : void OpDumpTaskManager::ClearResource()
1150 : {
1151 1 : const std::lock_guard<std::mutex> mapLock(dumpTaskMapMtx_);
1152 1 : aicpusd_run_info("clear all resource of data dump");
1153 1 : dumpTaskMap_.clear();
1154 1 : modelIdToTask_.clear();
1155 1 : }
1156 : } // namespace aicpu
|