已关闭
[feat] arch5162 support datadump #5290
FengHaozhan创建于 12 天前关闭于 10 天前
[feat] arch5162 support datadump #5290
已关闭
FengHaozhan创建于 12 天前关闭于 10 天前
共 24 个文件变更+3477-60
@@ -23,10 +23,18 @@ enum class RuntimeThreadAicpuStatus : uint32_t {
23 SYMBOL_NOT_FOUND,23 SYMBOL_NOT_FOUND,
24 KERNEL_FAILED,24 KERNEL_FAILED,
25 INTERNAL_ERROR,25 INTERNAL_ERROR,
26+ DATADUMP_PARSE_FAILED,
27+ DATADUMP_OP_NOT_FOUND,
28+ DATADUMP_ADDRESS_INVALID,
29+ DATADUMP_TENSOR_INVALID,
30+ DATADUMP_CREATE_DIR_FAILED,
31+ DATADUMP_OPEN_FILE_FAILED,
32+ DATADUMP_WRITE_FILE_FAILED,
26};33};
27 34 
28enum class RuntimeThreadAicpuSqeSubtype : uint32_t {35enum class RuntimeThreadAicpuSqeSubtype : uint32_t {
29 AICPU = 22U,36 AICPU = 22U,
37+ DATADUMP = 23U,
30};38};
31 39 
32struct RuntimeThreadAicpuRuntimeHooks {40struct RuntimeThreadAicpuRuntimeHooks {
@@ -73,12 +81,28 @@ struct RuntimeThreadAicpuPreparedKernel {
73 uint64_t fnData;81 uint64_t fnData;
74};82};
75 83 
84+struct RuntimeThreadAicpuStartRequest {
85+ uint32_t structSize;
86+ uint32_t deviceId;
87+ uint32_t tsId;
88+};
89+ 
90+struct RuntimeThreadAicpuDumpInfoRequest {
91+ uint32_t structSize;
92+ uint32_t deviceId;
93+ uint32_t tsId;
94+ const void* dumpInfo;
95+ uint32_t length;
96+};
97+ 
76struct RuntimeThreadAicpuPluginApi {98struct RuntimeThreadAicpuPluginApi {
77 uint32_t structSize;99 uint32_t structSize;
78 RuntimeThreadAicpuStatus (*prepareKernel)(100 RuntimeThreadAicpuStatus (*prepareKernel)(
79 const RuntimeThreadAicpuKernelRequest* request, RuntimeThreadAicpuPreparedKernel* preparedKernel);101 const RuntimeThreadAicpuKernelRequest* request, RuntimeThreadAicpuPreparedKernel* preparedKernel);
80 void (*releasePreparedKernel)(uint64_t taskCookie);102 void (*releasePreparedKernel)(uint64_t taskCookie);
81 void (*streamDestroyed)(void* streamHandle);103 void (*streamDestroyed)(void* streamHandle);
104+ RuntimeThreadAicpuStatus (*startWorker)(const RuntimeThreadAicpuStartRequest* request);
105+ RuntimeThreadAicpuStatus (*loadDumpInfo)(const RuntimeThreadAicpuDumpInfoRequest* request);
82};106};
83 107 
84using RuntimeThreadAicpuGetPluginApiFunc = RuntimeThreadAicpuStatus (*)(108using RuntimeThreadAicpuGetPluginApiFunc = RuntimeThreadAicpuStatus (*)(
@@ -12,6 +12,9 @@ set(RUNTIME_THREAD_AICPU_RUNTIME_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
12set(RUNTIME_THREAD_AICPU_CONTEXT_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/../aicpu_sharder/aicpu_context.cc)12set(RUNTIME_THREAD_AICPU_CONTEXT_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/../aicpu_sharder/aicpu_context.cc)
13 13 
14add_library(runtime_thread_aicpu SHARED14add_library(runtime_thread_aicpu SHARED
15+ datadump/data_dump_manager.cc
16+ datadump/data_dump_parser.cc
17+ datadump/data_dump_writer.cc
15 runtime_thread_aicpu_plugin.cc18 runtime_thread_aicpu_plugin.cc
16 runtime_thread_aicpu_service.cc19 runtime_thread_aicpu_service.cc
17 runtime_thread_aicpu_so_manager.cc20 runtime_thread_aicpu_so_manager.cc
@@ -0,0 +1,94 @@
1+/**
2+ * Copyright (c) 2026 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 "data_dump_manager.hpp"
12+ 
13+#include <new>
14+ 
15+#include "aicpu_sched/aicpu_schedule/common/aicpusd_status.h"
16+ 
17+namespace cce {
18+namespace runtime_thread_aicpu {
19+namespace datadump {
20+namespace {
21+ 
22+void EraseModelTasks(const ModelDumpInfo& model, std::unordered_map<TaskKey, OpDumpInfoPtr, TaskKeyHash>& taskMap)
23+{
24+ for (const auto& item : model.ops) {
25+ const auto taskIt = taskMap.find(item.first);
26+ if ((taskIt != taskMap.end()) && (taskIt->second == item.second)) {
27+ taskMap.erase(taskIt);
28+ }
29+ }
30+}
31+ 
32+} // namespace
33+ 
34+RuntimeThreadAicpuStatus DataDumpManager::Load(const ModelDumpInfoPtr& model)
35+{
36+ if ((model == nullptr) || (model->config == nullptr)) {
37+ return RuntimeThreadAicpuStatus::INVALID_PARAM;
38+ }
39+ try {
40+ std::lock_guard<std::mutex> lock(mutex_);
41+ auto newModelMap = modelMap_;
42+ auto newTaskMap = taskMap_;
43+ const uint32_t modelId = model->config->modelId;
44+ const auto oldModel = newModelMap.find(modelId);
45+ if (oldModel != newModelMap.end()) {
46+ EraseModelTasks(*oldModel->second, newTaskMap);
47+ }
48+ newModelMap[modelId] = model;
49+ for (const auto& item : model->ops) {
50+ const auto oldTask = newTaskMap.find(item.first);
51+ if ((oldTask != newTaskMap.end()) && (oldTask->second != item.second)) {
52+ aicpusd_warn(
53+ "DataDump task key is rebound to the later model, model_id=%u, stream_id=%u, task_id=%u.", modelId,
54+ static_cast<uint32_t>(item.first.streamId), static_cast<uint32_t>(item.first.taskId));
55+ }
56+ newTaskMap[item.first] = item.second;
57+ }
58+ modelMap_.swap(newModelMap);
59+ taskMap_.swap(newTaskMap);
60+ aicpusd_info("Load DataDump model success, model_id=%u, op_count=%zu.", modelId, model->ops.size());
61+ } catch (const std::bad_alloc&) {
62+ aicpusd_err("Load DataDump model failed because memory allocation failed.");
63+ return RuntimeThreadAicpuStatus::NO_MEMORY;
64+ } catch (...) {
65+ aicpusd_err("Load DataDump model failed because updating indexes threw an exception.");
66+ return RuntimeThreadAicpuStatus::INTERNAL_ERROR;
67+ }
68+ return RuntimeThreadAicpuStatus::OK;
69+}
70+ 
71+RuntimeThreadAicpuStatus DataDumpManager::Unload(const uint32_t modelId)
72+{
73+ std::lock_guard<std::mutex> lock(mutex_);
74+ const auto modelIt = modelMap_.find(modelId);
75+ if (modelIt == modelMap_.end()) {
76+ aicpusd_warn("Unload DataDump model ignored because it is not loaded, model_id=%u.", modelId);
77+ return RuntimeThreadAicpuStatus::OK;
78+ }
79+ EraseModelTasks(*modelIt->second, taskMap_);
80+ modelMap_.erase(modelIt);
81+ aicpusd_info("Unload DataDump model success, model_id=%u.", modelId);
82+ return RuntimeThreadAicpuStatus::OK;
83+}
84+ 
85+ConstOpDumpInfoPtr DataDumpManager::SearchOp(const TaskKey& key) const
86+{
87+ std::lock_guard<std::mutex> lock(mutex_);
88+ const auto taskIt = taskMap_.find(key);
89+ return (taskIt == taskMap_.end()) ? ConstOpDumpInfoPtr() : taskIt->second;
90+}
91+ 
92+} // namespace datadump
93+} // namespace runtime_thread_aicpu
94+} // namespace cce
@@ -0,0 +1,41 @@
1+/**
2+ * Copyright (c) 2026 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+#ifndef RUNTIME_THREAD_AICPU_DATA_DUMP_MANAGER_HPP
12+#define RUNTIME_THREAD_AICPU_DATA_DUMP_MANAGER_HPP
13+ 
14+#include <cstdint>
15+#include <mutex>
16+#include <unordered_map>
17+ 
18+#include "aicpu_sched/runtime_thread_aicpu_plugin.h"
19+#include "data_dump_types.hpp"
20+ 
21+namespace cce {
22+namespace runtime_thread_aicpu {
23+namespace datadump {
24+ 
25+class DataDumpManager final {
26+public:
27+ RuntimeThreadAicpuStatus Load(const ModelDumpInfoPtr& model);
28+ RuntimeThreadAicpuStatus Unload(const uint32_t modelId);
29+ ConstOpDumpInfoPtr SearchOp(const TaskKey& key) const;
30+ 
31+private:
32+ mutable std::mutex mutex_;
33+ std::unordered_map<uint32_t, ModelDumpInfoPtr> modelMap_;
34+ std::unordered_map<TaskKey, OpDumpInfoPtr, TaskKeyHash> taskMap_;
35+};
36+ 
37+} // namespace datadump
38+} // namespace runtime_thread_aicpu
39+} // namespace cce
40+ 
41+#endif
@@ -0,0 +1,647 @@
1+/**
2+ * Copyright (c) 2026 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 "data_dump_parser.hpp"
12+ 
13+#include <array>
14+#include <limits>
15+#include <memory>
16+#include <new>
17+#include <utility>
18+#include <vector>
19+ 
20+#include "securec.h"
21+#include "aicpu_sched/aicpu_schedule/common/aicpusd_status.h"
22+#include "aicpu_sched/common/type_def.h"
23+#include "data_dump_tlv.hpp"
24+ 
25+namespace cce {
26+namespace runtime_thread_aicpu {
27+namespace datadump {
28+namespace {
29+ 
30+class Cursor final {
31+public:
32+ Cursor(const uint8_t* const data, const size_t size) : data_(data), size_(size) {}
33+ 
34+ template <typename T>
35+ bool Read(T& value)
36+ {
37+ if (sizeof(T) > Remaining()) {
38+ return false;
39+ }
40+ if (memcpy_s(&value, sizeof(T), data_ + offset_, sizeof(T)) != EOK) {
41+ return false;
42+ }
43+ offset_ += sizeof(T);
44+ return true;
45+ }
46+ 
47+ bool Take(const size_t length, Cursor& subCursor)
48+ {
49+ if (length > Remaining()) {
50+ return false;
51+ }
52+ subCursor = Cursor(data_ + offset_, length);
53+ offset_ += length;
54+ return true;
55+ }
56+ 
57+ void ReadString(std::string& value)
58+ {
59+ value.assign(PtrToPtr<uint8_t, const char>(data_ + offset_), Remaining());
60+ offset_ = size_;
61+ }
62+ 
63+ const uint8_t* Current() const { return data_ + offset_; }
64+ size_t Remaining() const { return size_ - offset_; }
65+ bool Empty() const { return offset_ == size_; }
66+ 
67+private:
68+ const uint8_t* data_ = nullptr;
69+ size_t size_ = 0U;
70+ size_t offset_ = 0U;
71+};
72+ 
73+bool Fail(std::string& errorDetail, const char* const detail)
74+{
75+ errorDetail = detail;
76+ return false;
77+}
78+ 
79+bool ReadTlv(Cursor& cursor, tlv::TlvHeader& header, Cursor& value, std::string& errorDetail)
80+{
81+ if (!cursor.Read(header)) {
82+ return Fail(errorDetail, "truncated TLV header");
83+ }
84+ if (!cursor.Take(header.length, value)) {
85+ return Fail(errorDetail, "TLV value exceeds its enclosing buffer");
86+ }
87+ return true;
88+}
89+ 
90+bool ParseStringList(Cursor& cursor, std::vector<std::string>& values, std::string& errorDetail)
91+{
92+ while (!cursor.Empty()) {
93+ uint32_t length = 0U;
94+ if (!cursor.Read(length)) {
95+ return Fail(errorDetail, "truncated string-list element length");
96+ }
97+ Cursor value(nullptr, 0U);
98+ if (!cursor.Take(length, value)) {
99+ return Fail(errorDetail, "string-list element exceeds TLV value");
100+ }
101+ std::string item;
102+ value.ReadString(item);
103+ values.emplace_back(std::move(item));
104+ }
105+ return true;
106+}
107+ 
108+bool ParseShape(Cursor& cursor, std::vector<int64_t>& shape, std::string& errorDetail)
109+{
110+ if ((cursor.Remaining() % sizeof(int64_t)) != 0U) {
111+ return Fail(errorDetail, "shape TLV length is not a multiple of int64_t");
112+ }
113+ const size_t count = cursor.Remaining() / sizeof(int64_t);
114+ shape.reserve(count);
115+ for (size_t index = 0U; index < count; ++index) {
116+ int64_t dimension = 0;
117+ if (!cursor.Read(dimension)) {
118+ return Fail(errorDetail, "truncated shape dimension");
119+ }
120+ shape.emplace_back(dimension);
121+ }
122+ return true;
123+}
124+ 
125+bool ParseTensorNested(
126+ Cursor& cursor, TensorDumpInfo& tensor, std::string* const originalName, std::string& errorDetail)
127+{
128+ constexpr size_t tensorLevel3TypeCount = static_cast<size_t>(tlv::TensorLevel3Type::ORIGINAL_NAME) + 1U;
129+ std::array<bool, tensorLevel3TypeCount> seen = {};
130+ while (!cursor.Empty()) {
131+ tlv::TlvHeader header = {};
132+ Cursor value(nullptr, 0U);
133+ if (!ReadTlv(cursor, header, value, errorDetail)) {
134+ return false;
135+ }
136+ if (header.type > static_cast<uint32_t>(tlv::TensorLevel3Type::ORIGINAL_NAME)) {
137+ continue;
138+ }
139+ if (seen[header.type]) {
140+ return Fail(errorDetail, "duplicate tensor level-3 TLV");
141+ }
142+ seen[header.type] = true;
143+ switch (static_cast<tlv::TensorLevel3Type>(header.type)) {
144+ case tlv::TensorLevel3Type::SHAPE:
145+ if (!ParseShape(value, tensor.shape, errorDetail)) {
146+ return false;
147+ }
148+ break;
149+ case tlv::TensorLevel3Type::ORIGINAL_SHAPE:
150+ if (!ParseShape(value, tensor.originalShape, errorDetail)) {
151+ return false;
152+ }
153+ break;
154+ case tlv::TensorLevel3Type::ORIGINAL_NAME:
155+ if (originalName == nullptr) {
156+ return Fail(errorDetail, "input descriptor contains an output-only original-name TLV");
157+ }
158+ value.ReadString(*originalName);
159+ break;
160+ default:
161+ break;
162+ }
163+ }
164+ return true;
165+}
166+ 
167+bool IsKnownAddressType(const int32_t value)
168+{
169+ return (value >= static_cast<int32_t>(AddressType::TRADITIONAL_ADDR)) &&
170+ (value <= static_cast<int32_t>(AddressType::NANO_WORK_ADDR));
171+}
172+ 
173+bool SetMemoryRegion(
174+ const int32_t addressType, const uint64_t address, const uint64_t offset, const uint64_t size, MemoryRegion& memory,
175+ std::string& errorDetail)
176+{
177+ if (!IsKnownAddressType(addressType)) {
178+ return Fail(errorDetail, "invalid tensor address type");
179+ }
180+ if (offset > (std::numeric_limits<uint64_t>::max() - address)) {
181+ return Fail(errorDetail, "tensor address and offset overflow uint64_t");
182+ }
183+ memory.addressType = static_cast<AddressType>(addressType);
184+ memory.address = address;
185+ memory.offset = offset;
186+ memory.size = size;
187+ return true;
188+}
189+ 
190+bool ParseInputList(Cursor& cursor, std::vector<InputDumpInfo>& inputs, std::string& errorDetail)
191+{
192+ tlv::ListPrefix list = {};
193+ if (!cursor.Read(list)) {
194+ return Fail(errorDetail, "truncated input list prefix");
195+ }
196+ if (list.count > (cursor.Remaining() / sizeof(tlv::InputDescPrefix))) {
197+ return Fail(errorDetail, "input count exceeds TLV value");
198+ }
199+ inputs.reserve(list.count);
200+ for (uint32_t index = 0U; index < list.count; ++index) {
201+ tlv::InputDescPrefix prefix = {};
202+ if (!cursor.Read(prefix)) {
203+ return Fail(errorDetail, "truncated input descriptor");
204+ }
205+ Cursor nested(nullptr, 0U);
206+ if (!cursor.Take(prefix.nestedLength, nested)) {
207+ return Fail(errorDetail, "input level-3 TLVs exceed input list");
208+ }
209+ InputDumpInfo input;
210+ input.dataType = prefix.dataType;
211+ input.format = prefix.format;
212+ if (!SetMemoryRegion(
213+ prefix.addressType, prefix.address, prefix.offset, prefix.size, input.memory, errorDetail) ||
214+ !ParseTensorNested(nested, input, nullptr, errorDetail)) {
215+ return false;
216+ }
217+ inputs.emplace_back(std::move(input));
218+ }
219+ return cursor.Empty() || Fail(errorDetail, "input list has trailing bytes");
220+}
221+ 
222+bool ParseOutputList(Cursor& cursor, std::vector<OutputDumpInfo>& outputs, std::string& errorDetail)
223+{
224+ tlv::ListPrefix list = {};
225+ if (!cursor.Read(list)) {
226+ return Fail(errorDetail, "truncated output list prefix");
227+ }
228+ if (list.count > (cursor.Remaining() / sizeof(tlv::OutputDescPrefix))) {
229+ return Fail(errorDetail, "output count exceeds TLV value");
230+ }
231+ outputs.reserve(list.count);
232+ for (uint32_t index = 0U; index < list.count; ++index) {
233+ tlv::OutputDescPrefix prefix = {};
234+ if (!cursor.Read(prefix)) {
235+ return Fail(errorDetail, "truncated output descriptor");
236+ }
237+ Cursor nested(nullptr, 0U);
238+ if (!cursor.Take(prefix.nestedLength, nested)) {
239+ return Fail(errorDetail, "output level-3 TLVs exceed output list");
240+ }
241+ OutputDumpInfo output;
242+ output.dataType = prefix.dataType;
243+ output.format = prefix.format;
244+ output.originalIndex = prefix.originalIndex;
245+ output.originalDataType = prefix.originalDataType;
246+ output.originalFormat = prefix.originalFormat;
247+ if (!SetMemoryRegion(
248+ prefix.addressType, prefix.address, prefix.offset, prefix.size, output.memory, errorDetail) ||
249+ !ParseTensorNested(nested, output, &output.originalName, errorDetail)) {
250+ return false;
251+ }
252+ outputs.emplace_back(std::move(output));
253+ }
254+ return cursor.Empty() || Fail(errorDetail, "output list has trailing bytes");
255+}
256+ 
257+bool ParseWorkspaceList(Cursor& cursor, std::vector<WorkspaceDumpInfo>& workspaces, std::string& errorDetail)
258+{
259+ tlv::ListPrefix list = {};
260+ if (!cursor.Read(list)) {
261+ return Fail(errorDetail, "truncated workspace list prefix");
262+ }
263+ if (list.count > (cursor.Remaining() / sizeof(tlv::WorkspaceDescPrefix))) {
264+ return Fail(errorDetail, "workspace count exceeds TLV value");
265+ }
266+ workspaces.reserve(list.count);
267+ for (uint32_t index = 0U; index < list.count; ++index) {
268+ tlv::WorkspaceDescPrefix prefix = {};
269+ if (!cursor.Read(prefix)) {
270+ return Fail(errorDetail, "truncated workspace descriptor");
271+ }
272+ Cursor nested(nullptr, 0U);
273+ if (!cursor.Take(prefix.nestedLength, nested)) {
274+ return Fail(errorDetail, "workspace level-3 TLVs exceed workspace list");
275+ }
276+ if (prefix.type != static_cast<int32_t>(WorkspaceType::LOG)) {
277+ return Fail(errorDetail, "invalid workspace type");
278+ }
279+ WorkspaceDumpInfo workspace;
280+ workspace.type = static_cast<WorkspaceType>(prefix.type);
281+ workspace.dataAddress = prefix.dataAddress;
282+ workspace.size = prefix.size;
283+ workspaces.emplace_back(workspace);
284+ }
285+ return cursor.Empty() || Fail(errorDetail, "workspace list has trailing bytes");
286+}
287+ 
288+bool ParseBufferList(Cursor& cursor, std::vector<OpBufferInfo>& buffers, std::string& errorDetail)
289+{
290+ tlv::ListPrefix list = {};
291+ if (!cursor.Read(list)) {
292+ return Fail(errorDetail, "truncated op-buffer list prefix");
293+ }
294+ if (list.count > (cursor.Remaining() / sizeof(tlv::OpBufferPrefix))) {
295+ return Fail(errorDetail, "op-buffer count exceeds TLV value");
296+ }
297+ buffers.reserve(list.count);
298+ for (uint32_t index = 0U; index < list.count; ++index) {
299+ tlv::OpBufferPrefix prefix = {};
300+ if (!cursor.Read(prefix)) {
301+ return Fail(errorDetail, "truncated op-buffer descriptor");
302+ }
303+ Cursor nested(nullptr, 0U);
304+ if (!cursor.Take(prefix.nestedLength, nested)) {
305+ return Fail(errorDetail, "op-buffer level-3 TLVs exceed op-buffer list");
306+ }
307+ if (prefix.type != static_cast<uint8_t>(BufferType::L1)) {
308+ return Fail(errorDetail, "invalid op-buffer type");
309+ }
310+ OpBufferInfo buffer;
311+ buffer.type = static_cast<BufferType>(prefix.type);
312+ buffer.address = prefix.address;
313+ buffer.size = prefix.size;
314+ buffers.emplace_back(buffer);
315+ }
316+ return cursor.Empty() || Fail(errorDetail, "op-buffer list has trailing bytes");
317+}
318+ 
319+bool ParseMemoryInfoList(Cursor& cursor, std::vector<MemoryUsageInfo>& memoryUsage, std::string& errorDetail)
320+{
321+ tlv::ListPrefix list = {};
322+ if (!cursor.Read(list)) {
323+ return Fail(errorDetail, "truncated memory-info list prefix");
324+ }
325+ if (list.count > (cursor.Remaining() / sizeof(tlv::MemoryInfoPrefix))) {
326+ return Fail(errorDetail, "memory-info count exceeds TLV value");
327+ }
328+ memoryUsage.reserve(list.count);
329+ for (uint32_t index = 0U; index < list.count; ++index) {
330+ tlv::MemoryInfoPrefix prefix = {};
331+ if (!cursor.Read(prefix)) {
332+ return Fail(errorDetail, "truncated memory-info descriptor");
333+ }
334+ Cursor nested(nullptr, 0U);
335+ if (!cursor.Take(prefix.nestedLength, nested)) {
336+ return Fail(errorDetail, "memory-info level-3 TLVs exceed memory-info list");
337+ }
338+ MemoryUsageInfo info;
339+ info.inputSize = prefix.inputSize;
340+ info.outputSize = prefix.outputSize;
341+ info.weightSize = prefix.weightSize;
342+ info.workspaceSize = prefix.workspaceSize;
343+ info.totalSize = prefix.totalSize;
344+ memoryUsage.emplace_back(info);
345+ }
346+ return cursor.Empty() || Fail(errorDetail, "memory-info list has trailing bytes");
347+}
348+ 
349+bool ParseOpNested(Cursor& cursor, OpDumpInfo& op, std::string& errorDetail)
350+{
351+ constexpr size_t level2TypeCount = static_cast<size_t>(tlv::Level2Type::MEMORY_INFO) + 1U;
352+ std::array<bool, level2TypeCount> seen = {};
353+ while (!cursor.Empty()) {
354+ const uint8_t* const tlvBegin = cursor.Current();
355+ const size_t remainingBeforeRead = cursor.Remaining();
356+ tlv::TlvHeader header = {};
357+ Cursor value(nullptr, 0U);
358+ if (!ReadTlv(cursor, header, value, errorDetail)) {
359+ return false;
360+ }
361+ const size_t tlvSize = remainingBeforeRead - cursor.Remaining();
362+ if (header.type > static_cast<uint32_t>(tlv::Level2Type::MEMORY_INFO)) {
363+ continue;
364+ }
365+ if (seen[header.type]) {
366+ return Fail(errorDetail, "duplicate op level-2 TLV");
367+ }
368+ seen[header.type] = true;
369+ switch (static_cast<tlv::Level2Type>(header.type)) {
370+ case tlv::Level2Type::OP_NAME:
371+ value.ReadString(op.opName);
372+ break;
373+ case tlv::Level2Type::OP_TYPE:
374+ value.ReadString(op.opType);
375+ break;
376+ case tlv::Level2Type::ORIGINAL_OP_NAME:
377+ if (!ParseStringList(value, op.originalOpNames, errorDetail)) {
378+ return false;
379+ }
380+ break;
381+ case tlv::Level2Type::L1_SUB_GRAPH_NO:
382+ value.ReadString(op.l1SubGraphNo);
383+ break;
384+ case tlv::Level2Type::INPUT_DESC:
385+ op.inputDescTlv.assign(tlvBegin, tlvBegin + tlvSize);
386+ if (!ParseInputList(value, op.inputList, errorDetail)) {
387+ return false;
388+ }
389+ break;
390+ case tlv::Level2Type::OUTPUT_DESC:
391+ op.outputDescTlv.assign(tlvBegin, tlvBegin + tlvSize);
392+ if (!ParseOutputList(value, op.outputList, errorDetail)) {
393+ return false;
394+ }
395+ break;
396+ case tlv::Level2Type::WORKSPACE_DESC:
397+ if (!ParseWorkspaceList(value, op.workspaces, errorDetail)) {
398+ return false;
399+ }
400+ break;
401+ case tlv::Level2Type::OP_BUFFER:
402+ if (!ParseBufferList(value, op.buffers, errorDetail)) {
403+ return false;
404+ }
405+ break;
406+ case tlv::Level2Type::MEMORY_INFO:
407+ if (!ParseMemoryInfoList(value, op.memoryUsage, errorDetail)) {
408+ return false;
409+ }
410+ break;
411+ default:
412+ break;
413+ }
414+ }
415+ if (op.opName.empty() || op.opType.empty()) {
416+ return Fail(errorDetail, "op descriptor is missing its name or type");
417+ }
418+ return true;
419+}
420+ 
421+bool IsKnownTaskType(const int32_t value)
422+{
423+ return (value >= static_cast<int32_t>(DataDumpTaskType::AICORE)) &&
424+ (value <= static_cast<int32_t>(DataDumpTaskType::DSA));
425+}
426+ 
427+bool ParseOpList(Cursor& cursor, std::vector<OpDumpInfoPtr>& ops, std::string& errorDetail)
428+{
429+ tlv::ListPrefix list = {};
430+ if (!cursor.Read(list)) {
431+ return Fail(errorDetail, "truncated op list prefix");
432+ }
433+ if (list.count > (cursor.Remaining() / sizeof(tlv::OpDescPrefix))) {
434+ return Fail(errorDetail, "op count exceeds TLV value");
435+ }
436+ ops.reserve(list.count);
437+ for (uint32_t index = 0U; index < list.count; ++index) {
438+ tlv::OpDescPrefix prefix = {};
439+ if (!cursor.Read(prefix)) {
440+ return Fail(errorDetail, "truncated op descriptor");
441+ }
442+ if ((prefix.streamId > std::numeric_limits<uint16_t>::max()) ||
443+ (prefix.taskId > std::numeric_limits<uint16_t>::max())) {
444+ return Fail(errorDetail, "op stream ID or task ID exceeds callback-report width");
445+ }
446+ if (!IsKnownTaskType(prefix.taskType)) {
447+ return Fail(errorDetail, "invalid DataDump task type");
448+ }
449+ if (prefix.isMultiOp > 1U) {
450+ return Fail(errorDetail, "invalid is-multi-op value");
451+ }
452+ Cursor nested(nullptr, 0U);
453+ if (!cursor.Take(prefix.nestedLength, nested)) {
454+ return Fail(errorDetail, "op level-2 TLVs exceed op list");
455+ }
456+ OpDumpInfoPtr op = std::make_shared<OpDumpInfo>();
457+ op->taskKey.streamId = static_cast<uint16_t>(prefix.streamId);
458+ op->taskKey.taskId = static_cast<uint16_t>(prefix.taskId);
459+ op->logicStreamId = prefix.logicStreamId;
460+ op->taskType = static_cast<DataDumpTaskType>(prefix.taskType);
461+ op->blockDim = prefix.blockDim;
462+ op->isMultiOp = prefix.isMultiOp != 0U;
463+ if (!ParseOpNested(nested, *op, errorDetail)) {
464+ return false;
465+ }
466+ ops.emplace_back(std::move(op));
467+ }
468+ return cursor.Empty() || Fail(errorDetail, "op list has trailing bytes");
469+}
470+ 
471+bool ParseModelDesc(Cursor& cursor, tlv::ModelDescPrefix& model, std::string& errorDetail)
472+{
473+ if (!cursor.Read(model)) {
474+ return Fail(errorDetail, "truncated model descriptor");
475+ }
476+ Cursor nested(nullptr, 0U);
477+ if (!cursor.Take(model.nestedLength, nested)) {
478+ return Fail(errorDetail, "model level-2 TLVs exceed model descriptor");
479+ }
480+ if (!cursor.Empty()) {
481+ return Fail(errorDetail, "model descriptor has trailing bytes");
482+ }
483+ if ((model.action != static_cast<uint32_t>(DumpInfoAction::UNLOAD)) &&
484+ (model.action != static_cast<uint32_t>(DumpInfoAction::LOAD))) {
485+ return Fail(errorDetail, "invalid DataDump action");
486+ }
487+ if (model.dumpMode > static_cast<uint32_t>(DumpMode::ALL)) {
488+ return Fail(errorDetail, "invalid DataDump mode");
489+ }
490+ if (model.dumpData > static_cast<uint64_t>(DumpOutputType::TENSOR)) {
491+ return Fail(errorDetail, "invalid DataDump data type");
492+ }
493+ return true;
494+}
495+ 
496+RuntimeThreadAicpuStatus ValidateSupportedScope(const ModelDumpInfo& model, std::string& errorDetail)
497+{
498+ for (const auto& item : model.ops) {
499+ const OpDumpInfo& op = *item.second;
500+ if ((op.taskType != DataDumpTaskType::AICORE) || op.isMultiOp) {
501+ errorDetail = "only ordinary AI Core operators are supported in this phase";
502+ return RuntimeThreadAicpuStatus::NOT_SUPPORTED;
503+ }
504+ for (const InputDumpInfo& input : op.inputList) {
505+ if (input.memory.addressType != AddressType::RAW_ADDR) {
506+ errorDetail = "only raw host addresses are supported for DataDump inputs in this phase";
507+ return RuntimeThreadAicpuStatus::NOT_SUPPORTED;
508+ }
509+ }
510+ for (const OutputDumpInfo& output : op.outputList) {
511+ if (output.memory.addressType != AddressType::RAW_ADDR) {
512+ errorDetail = "only raw host addresses are supported for DataDump outputs in this phase";
513+ return RuntimeThreadAicpuStatus::NOT_SUPPORTED;
514+ }
515+ }
516+ }
517+ return RuntimeThreadAicpuStatus::OK;
518+}
519+ 
520+RuntimeThreadAicpuStatus ParseDumpInfo(
521+ const void* const dumpInfo, const uint32_t length, ParsedDumpCommand& command, std::string& errorDetail)
522+{
523+ if ((dumpInfo == nullptr) || (length < sizeof(tlv::DataHeader))) {
524+ errorDetail = "DataDump TLV buffer is null or shorter than its header";
525+ return RuntimeThreadAicpuStatus::INVALID_PARAM;
526+ }
527+ Cursor cursor(static_cast<const uint8_t*>(dumpInfo), length);
528+ tlv::DataHeader dataHeader = {};
529+ if (!cursor.Read(dataHeader) || (dataHeader.version != tlv::DATA_VERSION) ||
530+ (dataHeader.magic != tlv::DATA_MAGIC)) {
531+ errorDetail = "invalid DataDump TLV version or magic";
532+ return RuntimeThreadAicpuStatus::DATADUMP_PARSE_FAILED;
533+ }
534+ 
535+ constexpr size_t level1TypeCount = static_cast<size_t>(tlv::Level1Type::DUMP_PATH) + 1U;
536+ std::array<bool, level1TypeCount> seen = {};
537+ std::string modelName;
538+ std::string dumpPath;
539+ std::vector<OpDumpInfoPtr> ops;
540+ tlv::ModelDescPrefix modelDesc = {};
541+ while (!cursor.Empty()) {
542+ tlv::TlvHeader header = {};
543+ Cursor value(nullptr, 0U);
544+ if (!ReadTlv(cursor, header, value, errorDetail)) {
545+ return RuntimeThreadAicpuStatus::DATADUMP_PARSE_FAILED;
546+ }
547+ if (header.type > static_cast<uint32_t>(tlv::Level1Type::DUMP_PATH)) {
548+ continue;
549+ }
550+ if (seen[header.type]) {
551+ errorDetail = "duplicate DataDump level-1 TLV";
552+ return RuntimeThreadAicpuStatus::DATADUMP_PARSE_FAILED;
553+ }
554+ seen[header.type] = true;
555+ bool success = true;
556+ switch (static_cast<tlv::Level1Type>(header.type)) {
557+ case tlv::Level1Type::MODEL_NAME:
558+ value.ReadString(modelName);
559+ break;
560+ case tlv::Level1Type::OP_DESC:
561+ success = ParseOpList(value, ops, errorDetail);
562+ break;
563+ case tlv::Level1Type::MODEL_DESC:
564+ success = ParseModelDesc(value, modelDesc, errorDetail);
565+ break;
566+ case tlv::Level1Type::DUMP_PATH:
567+ value.ReadString(dumpPath);
568+ break;
569+ default:
570+ break;
571+ }
572+ if (!success) {
573+ return RuntimeThreadAicpuStatus::DATADUMP_PARSE_FAILED;
574+ }
575+ }
576+ 
577+ if (!seen[static_cast<uint32_t>(tlv::Level1Type::MODEL_DESC)]) {
578+ errorDetail = "DataDump TLV is missing the model descriptor";
579+ return RuntimeThreadAicpuStatus::DATADUMP_PARSE_FAILED;
580+ }
581+ command.action = static_cast<DumpInfoAction>(modelDesc.action);
582+ command.modelId = modelDesc.modelId;
583+ if (command.action == DumpInfoAction::UNLOAD) {
584+ command.model.reset();
585+ return RuntimeThreadAicpuStatus::OK;
586+ }
587+ if (!seen[static_cast<uint32_t>(tlv::Level1Type::MODEL_NAME)] ||
588+ !seen[static_cast<uint32_t>(tlv::Level1Type::OP_DESC)] ||
589+ !seen[static_cast<uint32_t>(tlv::Level1Type::DUMP_PATH)] || modelName.empty() || dumpPath.empty()) {
590+ errorDetail = "DataDump load TLV is missing its model name, op list, or dump path";
591+ return RuntimeThreadAicpuStatus::DATADUMP_PARSE_FAILED;
592+ }
593+ 
594+ std::shared_ptr<ModelDumpConfig> config = std::make_shared<ModelDumpConfig>();
595+ config->modelId = modelDesc.modelId;
596+ config->modelName = std::move(modelName);
597+ config->dumpPath = std::move(dumpPath);
598+ config->stepIdAddress = modelDesc.stepIdAddress;
599+ config->iterationsPerLoopAddress = modelDesc.iterationsPerLoopAddress;
600+ config->loopCondAddress = modelDesc.loopCondAddress;
601+ config->dumpMode = static_cast<DumpMode>(modelDesc.dumpMode);
602+ config->dumpOutputType = static_cast<DumpOutputType>(modelDesc.dumpData);
603+ 
604+ ModelDumpInfoPtr model = std::make_shared<ModelDumpInfo>();
605+ model->config = config;
606+ for (const OpDumpInfoPtr& op : ops) {
607+ op->config = config;
608+ const auto previous = model->ops.find(op->taskKey);
609+ if (previous != model->ops.end()) {
610+ aicpusd_warn(
611+ "Duplicate DataDump task key in one model; the later op wins, model_id=%u, stream_id=%u, task_id=%u.",
612+ config->modelId, static_cast<uint32_t>(op->taskKey.streamId),
613+ static_cast<uint32_t>(op->taskKey.taskId));
614+ }
615+ model->ops[op->taskKey] = op;
616+ }
617+ const RuntimeThreadAicpuStatus scopeStatus = ValidateSupportedScope(*model, errorDetail);
618+ if (scopeStatus != RuntimeThreadAicpuStatus::OK) {
619+ return scopeStatus;
620+ }
621+ command.model = std::move(model);
622+ return RuntimeThreadAicpuStatus::OK;
623+}
624+ 
625+} // namespace
626+ 
627+RuntimeThreadAicpuStatus DataDumpParser::Parse(
628+ const void* const dumpInfo, const uint32_t length, ParsedDumpCommand& command, std::string& errorDetail) const
629+{
630+ command = ParsedDumpCommand();
631+ errorDetail.clear();
632+ try {
633+ return ParseDumpInfo(dumpInfo, length, command, errorDetail);
634+ } catch (const std::bad_alloc&) {
635+ command = ParsedDumpCommand();
636+ errorDetail = "memory allocation failed while parsing DataDump TLV";
637+ return RuntimeThreadAicpuStatus::NO_MEMORY;
638+ } catch (...) {
639+ command = ParsedDumpCommand();
640+ errorDetail = "unexpected exception while parsing DataDump TLV";
641+ return RuntimeThreadAicpuStatus::INTERNAL_ERROR;
642+ }
643+}
644+ 
645+} // namespace datadump
646+} // namespace runtime_thread_aicpu
647+} // namespace cce
@@ -0,0 +1,34 @@
1+/**
2+ * Copyright (c) 2026 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+#ifndef RUNTIME_THREAD_AICPU_DATA_DUMP_PARSER_HPP
12+#define RUNTIME_THREAD_AICPU_DATA_DUMP_PARSER_HPP
13+ 
14+#include <cstdint>
15+#include <string>
16+ 
17+#include "aicpu_sched/runtime_thread_aicpu_plugin.h"
18+#include "data_dump_types.hpp"
19+ 
20+namespace cce {
21+namespace runtime_thread_aicpu {
22+namespace datadump {
23+ 
24+class DataDumpParser final {
25+public:
26+ RuntimeThreadAicpuStatus Parse(
27+ const void* const dumpInfo, const uint32_t length, ParsedDumpCommand& command, std::string& errorDetail) const;
28+};
29+ 
30+} // namespace datadump
31+} // namespace runtime_thread_aicpu
32+} // namespace cce
33+ 
34+#endif
@@ -0,0 +1,150 @@
1+/**
2+ * Copyright (c) 2026 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+#ifndef RUNTIME_THREAD_AICPU_DATA_DUMP_TLV_HPP
12+#define RUNTIME_THREAD_AICPU_DATA_DUMP_TLV_HPP
13+ 
14+#include <cstdint>
15+ 
16+namespace cce {
17+namespace runtime_thread_aicpu {
18+namespace datadump {
19+namespace tlv {
20+ 
21+constexpr uint32_t DATA_VERSION = 0U;
22+constexpr uint32_t DATA_MAGIC = 0x5A5A5A5AU;
23+ 
24+enum class Level1Type : uint32_t {
25+ MODEL_NAME = 0U,
26+ OP_DESC = 1U,
27+ MODEL_DESC = 2U,
28+ DUMP_PATH = 3U,
29+};
30+ 
31+enum class Level2Type : uint32_t {
32+ OP_NAME = 0U,
33+ OP_TYPE = 1U,
34+ ORIGINAL_OP_NAME = 2U,
35+ L1_SUB_GRAPH_NO = 3U,
36+ INPUT_DESC = 4U,
37+ OUTPUT_DESC = 5U,
38+ WORKSPACE_DESC = 6U,
39+ OP_BUFFER = 7U,
40+ MEMORY_INFO = 8U,
41+};
42+ 
43+enum class TensorLevel3Type : uint32_t {
44+ SHAPE = 0U,
45+ ORIGINAL_SHAPE = 1U,
46+ ORIGINAL_NAME = 2U,
47+};
48+ 
49+#pragma pack(push, 1)
50+ 
51+struct DataHeader {
52+ uint32_t version;
53+ uint32_t magic;
54+};
55+ 
56+struct TlvHeader {
57+ uint32_t type;
58+ uint32_t length;
59+};
60+ 
61+struct ListPrefix {
62+ uint32_t count;
63+};
64+ 
65+struct OpDescPrefix {
66+ uint32_t taskId;
67+ uint32_t streamId;
68+ uint32_t logicStreamId;
69+ int32_t taskType;
70+ uint32_t blockDim;
71+ uint8_t isMultiOp;
72+ uint32_t nestedLength;
73+};
74+ 
75+struct ModelDescPrefix {
76+ uint32_t action;
77+ uint32_t modelId;
78+ uint64_t stepIdAddress;
79+ uint64_t iterationsPerLoopAddress;
80+ uint64_t loopCondAddress;
81+ uint32_t dumpMode;
82+ uint64_t dumpData;
83+ uint32_t nestedLength;
84+};
85+ 
86+struct InputDescPrefix {
87+ int32_t dataType;
88+ int32_t format;
89+ int32_t addressType;
90+ uint64_t address;
91+ uint64_t offset;
92+ uint64_t size;
93+ uint32_t nestedLength;
94+};
95+ 
96+struct OutputDescPrefix {
97+ int32_t dataType;
98+ int32_t format;
99+ int32_t addressType;
100+ int32_t originalIndex;
101+ int32_t originalDataType;
102+ int32_t originalFormat;
103+ uint64_t address;
104+ uint64_t offset;
105+ uint64_t size;
106+ uint32_t nestedLength;
107+};
108+ 
109+struct WorkspaceDescPrefix {
110+ int32_t type;
111+ uint64_t dataAddress;
112+ uint64_t size;
113+ uint32_t nestedLength;
114+};
115+ 
116+struct OpBufferPrefix {
117+ uint8_t type;
118+ uint64_t address;
119+ uint64_t size;
120+ uint32_t nestedLength;
121+};
122+ 
123+struct MemoryInfoPrefix {
124+ uint64_t inputSize;
125+ uint64_t outputSize;
126+ uint64_t weightSize;
127+ uint64_t workspaceSize;
128+ uint64_t totalSize;
129+ uint32_t nestedLength;
130+};
131+ 
132+#pragma pack(pop)
133+ 
134+static_assert(sizeof(DataHeader) == 8U, "DataDump data header layout changed");
135+static_assert(sizeof(TlvHeader) == 8U, "DataDump TLV header layout changed");
136+static_assert(sizeof(ListPrefix) == 4U, "DataDump list prefix layout changed");
137+static_assert(sizeof(OpDescPrefix) == 25U, "DataDump op prefix layout changed");
138+static_assert(sizeof(ModelDescPrefix) == 48U, "DataDump model prefix layout changed");
139+static_assert(sizeof(InputDescPrefix) == 40U, "DataDump input prefix layout changed");
140+static_assert(sizeof(OutputDescPrefix) == 52U, "DataDump output prefix layout changed");
141+static_assert(sizeof(WorkspaceDescPrefix) == 24U, "DataDump workspace prefix layout changed");
142+static_assert(sizeof(OpBufferPrefix) == 21U, "DataDump op buffer prefix layout changed");
143+static_assert(sizeof(MemoryInfoPrefix) == 44U, "DataDump memory info prefix layout changed");
144+ 
145+} // namespace tlv
146+} // namespace datadump
147+} // namespace runtime_thread_aicpu
148+} // namespace cce
149+ 
150+#endif
@@ -0,0 +1,183 @@
1+/**
2+ * Copyright (c) 2026 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+#ifndef RUNTIME_THREAD_AICPU_DATA_DUMP_TYPES_HPP
12+#define RUNTIME_THREAD_AICPU_DATA_DUMP_TYPES_HPP
13+ 
14+#include <cstddef>
15+#include <cstdint>
16+#include <limits>
17+#include <memory>
18+#include <string>
19+#include <unordered_map>
20+#include <vector>
21+ 
22+namespace cce {
23+namespace runtime_thread_aicpu {
24+namespace datadump {
25+ 
26+enum class DumpInfoAction : uint32_t {
27+ UNLOAD = 0U,
28+ LOAD = 1U,
29+};
30+ 
31+enum class DumpMode : uint32_t {
32+ INPUT = 0U,
33+ OUTPUT = 1U,
34+ ALL = 2U,
35+};
36+ 
37+enum class DumpOutputType : uint64_t {
38+ STATS = 0U,
39+ TENSOR = 1U,
40+};
41+ 
42+enum class AddressType : int32_t {
43+ TRADITIONAL_ADDR = 0,
44+ NOTILING_ADDR = 1,
45+ RAW_ADDR = 2,
46+ NANO_IO_ADDR = 3,
47+ NANO_WEIGHT_ADDR = 4,
48+ NANO_WORK_ADDR = 5,
49+};
50+ 
51+enum class DataDumpTaskType : int32_t {
52+ AICORE = 0,
53+ AICPU = 1,
54+ DEBUG = 2,
55+ SDMA = 3,
56+ FFTSPLUS = 4,
57+ DSA = 5,
58+};
59+ 
60+enum class WorkspaceType : int32_t {
61+ LOG = 0,
62+};
63+ 
64+enum class BufferType : uint8_t {
65+ L1 = 0U,
66+};
67+ 
68+struct TaskKey {
69+ TaskKey() = default;
70+ TaskKey(const uint16_t stream, const uint16_t task) : streamId(stream), taskId(task) {}
71+ 
72+ uint16_t streamId = 0U;
73+ uint16_t taskId = 0U;
74+ 
75+ bool operator==(const TaskKey& other) const { return (streamId == other.streamId) && (taskId == other.taskId); }
76+};
77+ 
78+struct TaskKeyHash {
79+ size_t operator()(const TaskKey& key) const
80+ {
81+ return static_cast<size_t>(
82+ (static_cast<uint32_t>(key.streamId) << std::numeric_limits<uint16_t>::digits) | key.taskId);
83+ }
84+};
85+ 
86+struct MemoryRegion {
87+ AddressType addressType = AddressType::RAW_ADDR;
88+ uint64_t address = 0U;
89+ uint64_t offset = 0U;
90+ uint64_t size = 0U;
91+};
92+ 
93+struct TensorDumpInfo {
94+ int32_t dataType = 0;
95+ int32_t format = 0;
96+ MemoryRegion memory;
97+ std::vector<int64_t> shape;
98+ std::vector<int64_t> originalShape;
99+};
100+ 
101+struct InputDumpInfo : public TensorDumpInfo {};
102+ 
103+struct OutputDumpInfo : public TensorDumpInfo {
104+ int32_t originalIndex = 0;
105+ int32_t originalDataType = 0;
106+ int32_t originalFormat = 0;
107+ std::string originalName;
108+};
109+ 
110+struct WorkspaceDumpInfo {
111+ WorkspaceType type = WorkspaceType::LOG;
112+ uint64_t dataAddress = 0U;
113+ uint64_t size = 0U;
114+};
115+ 
116+struct OpBufferInfo {
117+ BufferType type = BufferType::L1;
118+ uint64_t address = 0U;
119+ uint64_t size = 0U;
120+};
121+ 
122+struct MemoryUsageInfo {
123+ uint64_t inputSize = 0U;
124+ uint64_t outputSize = 0U;
125+ uint64_t weightSize = 0U;
126+ uint64_t workspaceSize = 0U;
127+ uint64_t totalSize = 0U;
128+};
129+ 
130+struct ModelDumpConfig {
131+ uint32_t modelId = 0U;
132+ std::string modelName;
133+ std::string dumpPath;
134+ uint64_t stepIdAddress = 0U;
135+ uint64_t iterationsPerLoopAddress = 0U;
136+ uint64_t loopCondAddress = 0U;
137+ DumpMode dumpMode = DumpMode::ALL;
138+ DumpOutputType dumpOutputType = DumpOutputType::STATS;
139+};
140+ 
141+using ModelDumpConfigPtr = std::shared_ptr<const ModelDumpConfig>;
142+ 
143+struct OpDumpInfo {
144+ TaskKey taskKey;
145+ ModelDumpConfigPtr config;
146+ uint32_t logicStreamId = 0U;
147+ DataDumpTaskType taskType = DataDumpTaskType::AICORE;
148+ uint32_t blockDim = 0U;
149+ bool isMultiOp = false;
150+ std::string opName;
151+ std::string opType;
152+ std::vector<std::string> originalOpNames;
153+ std::string l1SubGraphNo;
154+ std::vector<InputDumpInfo> inputList;
155+ std::vector<OutputDumpInfo> outputList;
156+ std::vector<uint8_t> inputDescTlv;
157+ std::vector<uint8_t> outputDescTlv;
158+ std::vector<WorkspaceDumpInfo> workspaces;
159+ std::vector<OpBufferInfo> buffers;
160+ std::vector<MemoryUsageInfo> memoryUsage;
161+};
162+ 
163+using OpDumpInfoPtr = std::shared_ptr<OpDumpInfo>;
164+using ConstOpDumpInfoPtr = std::shared_ptr<const OpDumpInfo>;
165+ 
166+struct ModelDumpInfo {
167+ ModelDumpConfigPtr config;
168+ std::unordered_map<TaskKey, OpDumpInfoPtr, TaskKeyHash> ops;
169+};
170+ 
171+using ModelDumpInfoPtr = std::shared_ptr<ModelDumpInfo>;
172+ 
173+struct ParsedDumpCommand {
174+ DumpInfoAction action = DumpInfoAction::LOAD;
175+ uint32_t modelId = 0U;
176+ ModelDumpInfoPtr model;
177+};
178+ 
179+} // namespace datadump
180+} // namespace runtime_thread_aicpu
181+} // namespace cce
182+ 
183+#endif
@@ -0,0 +1,30 @@
1+/**
2+ * Copyright (c) 2026 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+#ifndef RUNTIME_THREAD_AICPU_DATA_DUMP_WRITER_HPP
12+#define RUNTIME_THREAD_AICPU_DATA_DUMP_WRITER_HPP
13+ 
14+#include "aicpu_sched/runtime_thread_aicpu_plugin.h"
15+#include "data_dump_types.hpp"
16+ 
17+namespace cce {
18+namespace runtime_thread_aicpu {
19+namespace datadump {
20+ 
21+class DataDumpWriter final {
22+public:
23+ RuntimeThreadAicpuStatus DumpOp(const OpDumpInfo& op) const;
24+};
25+ 
26+} // namespace datadump
27+} // namespace runtime_thread_aicpu
28+} // namespace cce
29+ 
30+#endif
@@ -50,11 +50,36 @@ void StreamDestroyed(void* const streamHandle)
50 }50 }
51}51}
52 52 
53+RuntimeThreadAicpuStatus StartWorker(const RuntimeThreadAicpuStartRequest* const request)
54+{
55+ if ((g_pluginService == nullptr) || (request == nullptr)) {
56+ aicpusd_err(
57+ "Start RuntimeThreadAicpu worker failed because plugin input is invalid, service_valid=%u, "
58+ "request_valid=%u.",
59+ static_cast<uint32_t>(g_pluginService != nullptr), static_cast<uint32_t>(request != nullptr));
60+ return RuntimeThreadAicpuStatus::INVALID_PARAM;
61+ }
62+ return g_pluginService->StartWorker(*request);
63+}
64+ 
65+RuntimeThreadAicpuStatus LoadDumpInfo(const RuntimeThreadAicpuDumpInfoRequest* const request)
66+{
67+ if ((g_pluginService == nullptr) || (request == nullptr)) {
68+ aicpusd_err(
69+ "Load DataDump info failed because plugin input is invalid, service_valid=%u, request_valid=%u.",
70+ static_cast<uint32_t>(g_pluginService != nullptr), static_cast<uint32_t>(request != nullptr));
71+ return RuntimeThreadAicpuStatus::INVALID_PARAM;
72+ }
73+ return g_pluginService->LoadDumpInfo(*request);
74+}
75+ 
53const RuntimeThreadAicpuPluginApi PLUGIN_API = {76const RuntimeThreadAicpuPluginApi PLUGIN_API = {
54 .structSize = sizeof(RuntimeThreadAicpuPluginApi),77 .structSize = sizeof(RuntimeThreadAicpuPluginApi),
55 .prepareKernel = &PrepareKernel,78 .prepareKernel = &PrepareKernel,
56 .releasePreparedKernel = &ReleasePreparedKernel,79 .releasePreparedKernel = &ReleasePreparedKernel,
57 .streamDestroyed = &StreamDestroyed,80 .streamDestroyed = &StreamDestroyed,
81+ .startWorker = &StartWorker,
82+ .loadDumpInfo = &LoadDumpInfo,
58};83};
59 84 
60} // namespace85} // namespace
@@ -35,6 +35,11 @@ constexpr int32_t REPORT_WAIT_TIMEOUT_MS = 1000;
35constexpr uint8_t CALLBACK_EVENT_RECORD_COMMAND = 15U;35constexpr uint8_t CALLBACK_EVENT_RECORD_COMMAND = 15U;
36constexpr char RUN_KERNEL_WITH_BLOCK[] = "RunCpuKernelWithBlock";36constexpr char RUN_KERNEL_WITH_BLOCK[] = "RunCpuKernelWithBlock";
37 37 
38+enum class CallbackReportType : uint8_t {
39+ AICPU = 0U,
40+ DATADUMP = 1U,
41+};
42+ 
38struct CallbackReport {43struct CallbackReport {
39 volatile uint16_t phase : 1;44 volatile uint16_t phase : 1;
40 volatile uint16_t sop : 1;45 volatile uint16_t sop : 1;
@@ -151,7 +156,7 @@ void RuntimeThreadAicpuService::ReleaseCallbackChannel()
151 callbackCqId_ = 0U;156 callbackCqId_ = 0U;
152}157}
153 158 
154-RuntimeThreadAicpuStatus RuntimeThreadAicpuService::EnsureStarted(const RuntimeThreadAicpuKernelRequest& request)159+RuntimeThreadAicpuStatus RuntimeThreadAicpuService::EnsureStarted(const uint32_t deviceId, const uint32_t tsId)
155{160{
156 if (failed_.load(std::memory_order_acquire)) {161 if (failed_.load(std::memory_order_acquire)) {
157 aicpusd_err("RuntimeThreadAicpu worker is already in failed state.");162 aicpusd_err("RuntimeThreadAicpu worker is already in failed state.");
@@ -160,11 +165,11 @@ RuntimeThreadAicpuStatus RuntimeThreadAicpuService::EnsureStarted(const RuntimeT
160 165 
161 std::lock_guard<std::mutex> lock(startMutex_);166 std::lock_guard<std::mutex> lock(startMutex_);
162 if (started_) {167 if (started_) {
163- if ((request.deviceId != deviceId_) || (request.tsId != tsId_)) {168+ if ((deviceId != deviceId_) || (tsId != tsId_)) {
164 aicpusd_err(169 aicpusd_err(
165 "RuntimeThreadAicpu worker cannot switch device, request_device_id=%u, request_ts_id=%u, "170 "RuntimeThreadAicpu worker cannot switch device, request_device_id=%u, request_ts_id=%u, "
166 "worker_device_id=%u, worker_ts_id=%u.",171 "worker_device_id=%u, worker_ts_id=%u.",
167- request.deviceId, request.tsId, deviceId_, tsId_);172+ deviceId, tsId, deviceId_, tsId_);
168 return RuntimeThreadAicpuStatus::RUNTIME_ERROR;173 return RuntimeThreadAicpuStatus::RUNTIME_ERROR;
169 }174 }
170 return RuntimeThreadAicpuStatus::OK;175 return RuntimeThreadAicpuStatus::OK;
@@ -186,8 +191,8 @@ RuntimeThreadAicpuStatus RuntimeThreadAicpuService::EnsureStarted(const RuntimeT
186 return RuntimeThreadAicpuStatus::INVALID_PARAM;191 return RuntimeThreadAicpuStatus::INVALID_PARAM;
187 }192 }
188 193 
189- deviceId_ = request.deviceId;194+ deviceId_ = deviceId;
190- tsId_ = request.tsId;195+ tsId_ = tsId;
191 RuntimeThreadAicpuStatus status = hooks_.reserveGroupId(hooks_.runtimeData, &groupId_);196 RuntimeThreadAicpuStatus status = hooks_.reserveGroupId(hooks_.runtimeData, &groupId_);
192 if (status != RuntimeThreadAicpuStatus::OK) {197 if (status != RuntimeThreadAicpuStatus::OK) {
193 aicpusd_err("Reserve callback group ID failed, status=%u.", static_cast<uint32_t>(status));198 aicpusd_err("Reserve callback group ID failed, status=%u.", static_cast<uint32_t>(status));
@@ -396,7 +401,7 @@ RuntimeThreadAicpuStatus RuntimeThreadAicpuService::PrepareKernel(
396 return RuntimeThreadAicpuStatus::INVALID_PARAM;401 return RuntimeThreadAicpuStatus::INVALID_PARAM;
397 }402 }
398 403 
399- RuntimeThreadAicpuStatus status = EnsureStarted(request);404+ RuntimeThreadAicpuStatus status = EnsureStarted(request.deviceId, request.tsId);
400 if (status != RuntimeThreadAicpuStatus::OK) {405 if (status != RuntimeThreadAicpuStatus::OK) {
401 return status;406 return status;
402 }407 }
@@ -433,6 +438,46 @@ RuntimeThreadAicpuStatus RuntimeThreadAicpuService::PrepareKernel(
433 return RuntimeThreadAicpuStatus::OK;438 return RuntimeThreadAicpuStatus::OK;
434}439}
435 440 
441+RuntimeThreadAicpuStatus RuntimeThreadAicpuService::StartWorker(const RuntimeThreadAicpuStartRequest& request)
442+{
443+ if (request.structSize < sizeof(RuntimeThreadAicpuStartRequest)) {
444+ aicpusd_err(
445+ "Start RuntimeThreadAicpu worker failed because request is invalid, request_size=%u, expected_size=%zu.",
446+ request.structSize, sizeof(RuntimeThreadAicpuStartRequest));
447+ return RuntimeThreadAicpuStatus::INVALID_PARAM;
448+ }
449+ return EnsureStarted(request.deviceId, request.tsId);
450+}
451+ 
452+RuntimeThreadAicpuStatus RuntimeThreadAicpuService::LoadDumpInfo(const RuntimeThreadAicpuDumpInfoRequest& request)
453+{
454+ if ((request.structSize < sizeof(RuntimeThreadAicpuDumpInfoRequest)) || (request.dumpInfo == nullptr) ||
455+ (request.length == 0U)) {
456+ aicpusd_err(
457+ "Load DataDump info failed because request is invalid, request_size=%u, expected_size=%zu, "
458+ "dump_info_valid=%u, length=%u.",
459+ request.structSize, sizeof(RuntimeThreadAicpuDumpInfoRequest),
460+ static_cast<uint32_t>(request.dumpInfo != nullptr), request.length);
461+ return RuntimeThreadAicpuStatus::INVALID_PARAM;
462+ }
463+ RuntimeThreadAicpuStatus status = EnsureStarted(request.deviceId, request.tsId);
464+ if (status != RuntimeThreadAicpuStatus::OK) {
465+ return status;
466+ }
467+ 
468+ datadump::ParsedDumpCommand command;
469+ std::string errorDetail;
470+ status = dataDumpParser_.Parse(request.dumpInfo, request.length, command, errorDetail);
471+ if (status != RuntimeThreadAicpuStatus::OK) {
472+ aicpusd_err(
473+ "Parse DataDump info failed, status=%u, length=%u, reason=%s.", static_cast<uint32_t>(status),
474+ request.length, errorDetail.c_str());
475+ return status;
476+ }
477+ return (command.action == datadump::DumpInfoAction::LOAD) ? dataDumpManager_.Load(command.model) :
478+ dataDumpManager_.Unload(command.modelId);
479+}
480+ 
436void RuntimeThreadAicpuService::ReleasePreparedKernel(const uint64_t taskCookie)481void RuntimeThreadAicpuService::ReleasePreparedKernel(const uint64_t taskCookie)
437{482{
438 std::lock_guard<std::mutex> lock(taskMutex_);483 std::lock_guard<std::mutex> lock(taskMutex_);
@@ -548,7 +593,7 @@ uint32_t RuntimeThreadAicpuService::ExecuteKernel(KernelContext& context)
548 return 0U;593 return 0U;
549}594}
550 595 
551-uint32_t RuntimeThreadAicpuService::ProcessOneReport(const void* const reportAddress)596+uint32_t RuntimeThreadAicpuService::ProcessAicpuReport(const void* const reportAddress)
552{597{
553 const auto* const report = static_cast<const CallbackReport*>(reportAddress);598 const auto* const report = static_cast<const CallbackReport*>(reportAddress);
554 const uint64_t expectedFunction = PtrToValue(599 const uint64_t expectedFunction = PtrToValue(
@@ -571,14 +616,29 @@ uint32_t RuntimeThreadAicpuService::ProcessOneReport(const void* const reportAdd
571 return execute(ValueToPtr(report->fnData));616 return execute(ValueToPtr(report->fnData));
572}617}
573 618 
619+uint32_t RuntimeThreadAicpuService::ProcessDumpReport(const void* const reportAddress)
620+{
621+ const auto* const report = static_cast<const CallbackReport*>(reportAddress);
622+ const datadump::TaskKey key = {report->streamId, report->taskId};
623+ const datadump::ConstOpDumpInfoPtr op = dataDumpManager_.SearchOp(key);
624+ if (op == nullptr) {
625+ aicpusd_err(
626+ "Cannot find DataDump op for report, stream_id=%u, task_id=%u.", static_cast<uint32_t>(report->streamId),
627+ static_cast<uint32_t>(report->taskId));
628+ return static_cast<uint32_t>(RuntimeThreadAicpuStatus::DATADUMP_OP_NOT_FOUND);
629+ }
630+ return static_cast<uint32_t>(dataDumpWriter_.DumpOp(*op));
631+}
632+ 
574RuntimeThreadAicpuStatus RuntimeThreadAicpuService::FinishReport(633RuntimeThreadAicpuStatus RuntimeThreadAicpuService::FinishReport(
575- const void* const reportAddress, const uint32_t executeResult)634+ const void* const reportAddress, const uint32_t executeResult, const RuntimeThreadAicpuSqeSubtype subtype)
576{635{
577 const auto* const report = static_cast<const CallbackReport*>(reportAddress);636 const auto* const report = static_cast<const CallbackReport*>(reportAddress);
578 if (executeResult != 0U) {637 if (executeResult != 0U) {
579 aicpusd_err(638 aicpusd_err(
580- "AICPU operator report execution failed, stream_id=%u, task_id=%u, execute_result=%#x.",639+ "Callback report processing failed, stream_id=%u, task_id=%u, sqe_subtype=%u, execute_result=%#x.",
581- static_cast<uint32_t>(report->streamId), static_cast<uint32_t>(report->taskId), executeResult);640+ static_cast<uint32_t>(report->streamId), static_cast<uint32_t>(report->taskId),
641+ static_cast<uint32_t>(subtype), executeResult);
582 hooks_.setStreamError(642 hooks_.setStreamError(
583 hooks_.runtimeData, deviceId_, tsId_, static_cast<uint32_t>(report->streamId), executeResult);643 hooks_.runtimeData, deviceId_, tsId_, static_cast<uint32_t>(report->streamId), executeResult);
584 }644 }
@@ -609,11 +669,11 @@ RuntimeThreadAicpuStatus RuntimeThreadAicpuService::FinishReport(
609 command->recordId = report->eventId;669 command->recordId = report->eventId;
610 command->taskId = report->taskId;670 command->taskId = report->taskId;
611 command->reserved = static_cast<uint16_t>(groupId_);671 command->reserved = static_cast<uint16_t>(groupId_);
612- const uint32_t sqeSubtype = static_cast<uint32_t>(RuntimeThreadAicpuSqeSubtype::AICPU);672+ const uint32_t sqeSubtype = static_cast<uint32_t>(subtype);
613 command->reserved1[0] = sqeSubtype;673 command->reserved1[0] = sqeSubtype;
614 command->reserved1[1] = executeResult;674 command->reserved1[1] = executeResult;
615 aicpusd_debug(675 aicpusd_debug(
616- "Construct AICPU finish command, stream_id=%u, task_id=%u, event_id=%u, group_id=%u, sqe_subtype=%u, "676+ "Construct callback finish command, stream_id=%u, task_id=%u, event_id=%u, group_id=%u, sqe_subtype=%u, "
617 "execute_result=%#x.",677 "execute_result=%#x.",
618 static_cast<uint32_t>(report->streamId), static_cast<uint32_t>(report->taskId),678 static_cast<uint32_t>(report->streamId), static_cast<uint32_t>(report->taskId),
619 static_cast<uint32_t>(report->eventId), groupId_, sqeSubtype, executeResult);679 static_cast<uint32_t>(report->eventId), groupId_, sqeSubtype, executeResult);
@@ -709,13 +769,28 @@ bool RuntimeThreadAicpuService::ProcessReports()
709 bool success = true;769 bool success = true;
710 for (uint32_t index = 0U; index < getOutput.count; ++index) {770 for (uint32_t index = 0U; index < getOutput.count; ++index) {
711 aicpusd_info(771 aicpusd_info(
712- "AICPU report[%u], sq_id=%u, stream_id=%u, task_id=%u, event_id=%u, is_block=%u.", index,772+ "Callback report[%u], sq_id=%u, stream_id=%u, task_id=%u, event_id=%u, is_block=%u, report_type=%u.", index,
713 static_cast<uint32_t>(reports[index].sqId), static_cast<uint32_t>(reports[index].streamId),773 static_cast<uint32_t>(reports[index].sqId), static_cast<uint32_t>(reports[index].streamId),
714 static_cast<uint32_t>(reports[index].taskId), static_cast<uint32_t>(reports[index].eventId),774 static_cast<uint32_t>(reports[index].taskId), static_cast<uint32_t>(reports[index].eventId),
715- static_cast<uint32_t>(reports[index].isBlock));775+ static_cast<uint32_t>(reports[index].isBlock), static_cast<uint32_t>(reports[index].reserved));
716- const uint32_t executeResult = ProcessOneReport(&reports[index]);776+ const CallbackReportType reportType = static_cast<CallbackReportType>(reports[index].reserved);
717- if (FinishReport(&reports[index], executeResult) != RuntimeThreadAicpuStatus::OK) {777+ if (reportType == CallbackReportType::AICPU) {
718- success = false;778+ const uint32_t executeResult = ProcessAicpuReport(&reports[index]);
779+ if (FinishReport(&reports[index], executeResult, RuntimeThreadAicpuSqeSubtype::AICPU) !=
780+ RuntimeThreadAicpuStatus::OK) {
781+ success = false;
782+ }
783+ } else if (reportType == CallbackReportType::DATADUMP) {
784+ const uint32_t executeResult = ProcessDumpReport(&reports[index]);
785+ if (FinishReport(&reports[index], executeResult, RuntimeThreadAicpuSqeSubtype::DATADUMP) !=
786+ RuntimeThreadAicpuStatus::OK) {
787+ success = false;
788+ }
789+ } else {
790+ aicpusd_warn(
791+ "Unknown callback report type, stream_id=%u, task_id=%u, report_type=%u.",
792+ static_cast<uint32_t>(reports[index].streamId), static_cast<uint32_t>(reports[index].taskId),
793+ static_cast<uint32_t>(reports[index].reserved));
719 }794 }
720 795 
721 halReportReleaseInfo releaseInfo = {};796 halReportReleaseInfo releaseInfo = {};
@@ -20,6 +20,9 @@
20#include <vector>20#include <vector>
21 21 
22#include "aicpu_sched/runtime_thread_aicpu_plugin.h"22#include "aicpu_sched/runtime_thread_aicpu_plugin.h"
23+#include "datadump/data_dump_manager.hpp"
24+#include "datadump/data_dump_parser.hpp"
25+#include "datadump/data_dump_writer.hpp"
23#include "runtime_thread_aicpu_so_manager.hpp"26#include "runtime_thread_aicpu_so_manager.hpp"
24 27 
25namespace cce {28namespace cce {
@@ -31,6 +34,8 @@ public:
31 34 
32 RuntimeThreadAicpuStatus PrepareKernel(35 RuntimeThreadAicpuStatus PrepareKernel(
33 const RuntimeThreadAicpuKernelRequest& request, RuntimeThreadAicpuPreparedKernel& preparedKernel);36 const RuntimeThreadAicpuKernelRequest& request, RuntimeThreadAicpuPreparedKernel& preparedKernel);
37+ RuntimeThreadAicpuStatus StartWorker(const RuntimeThreadAicpuStartRequest& request);
38+ RuntimeThreadAicpuStatus LoadDumpInfo(const RuntimeThreadAicpuDumpInfoRequest& request);
34 void ReleasePreparedKernel(const uint64_t taskCookie);39 void ReleasePreparedKernel(const uint64_t taskCookie);
35 void StreamDestroyed(void* const streamHandle);40 void StreamDestroyed(void* const streamHandle);
36 static uint32_t ExecutePreparedKernelEntry(void* const cookieData);41 static uint32_t ExecutePreparedKernelEntry(void* const cookieData);
@@ -54,7 +59,7 @@ private:
54 uint32_t streamId = 0U;59 uint32_t streamId = 0U;
55 };60 };
56 61 
57- RuntimeThreadAicpuStatus EnsureStarted(const RuntimeThreadAicpuKernelRequest& request);62+ RuntimeThreadAicpuStatus EnsureStarted(const uint32_t deviceId, const uint32_t tsId);
58 RuntimeThreadAicpuStatus AllocateCallbackChannel();63 RuntimeThreadAicpuStatus AllocateCallbackChannel();
59 void ReleaseCallbackChannel();64 void ReleaseCallbackChannel();
60 RuntimeThreadAicpuStatus GetOrCreateEvent(void* const streamHandle, const uint32_t streamId, EventEntry& event);65 RuntimeThreadAicpuStatus GetOrCreateEvent(void* const streamHandle, const uint32_t streamId, EventEntry& event);
@@ -66,8 +71,10 @@ private:
66 uint32_t ExecuteKernel(KernelContext& context);71 uint32_t ExecuteKernel(KernelContext& context);
67 void WorkerLoop();72 void WorkerLoop();
68 bool ProcessReports();73 bool ProcessReports();
69- uint32_t ProcessOneReport(const void* const reportAddress);74+ uint32_t ProcessAicpuReport(const void* const reportAddress);
70- RuntimeThreadAicpuStatus FinishReport(const void* const reportAddress, const uint32_t executeResult);75+ uint32_t ProcessDumpReport(const void* const reportAddress);
76+ RuntimeThreadAicpuStatus FinishReport(
77+ const void* const reportAddress, const uint32_t executeResult, const RuntimeThreadAicpuSqeSubtype subtype);
71 78 
72 RuntimeThreadAicpuRuntimeHooks hooks_;79 RuntimeThreadAicpuRuntimeHooks hooks_;
73 std::mutex startMutex_;80 std::mutex startMutex_;
@@ -85,6 +92,9 @@ private:
85 std::unordered_map<void*, EventEntry> events_;92 std::unordered_map<void*, EventEntry> events_;
86 std::unordered_map<uint64_t, std::unique_ptr<KernelContext>> kernelContexts_;93 std::unordered_map<uint64_t, std::unique_ptr<KernelContext>> kernelContexts_;
87 SoManager soManager_;94 SoManager soManager_;
95+ datadump::DataDumpParser dataDumpParser_;
96+ datadump::DataDumpManager dataDumpManager_;
97+ datadump::DataDumpWriter dataDumpWriter_;
88};98};
89 99 
90void SetRuntimeThreadAicpuService(RuntimeThreadAicpuService* const service);100void SetRuntimeThreadAicpuService(RuntimeThreadAicpuService* const service);
@@ -1310,21 +1310,6 @@ rtError_t ApiImpl::LaunchKernel(
1310 return error;1310 return error;
1311}1311}
1312 1312 
1313-rtError_t ApiImpl::DatadumpInfoLoad(const void* const dumpInfo, const uint32_t length, const uint32_t flag)
1314-{
1315- RT_LOG(RT_LOG_DEBUG, "length=%u, flag=%u.", length, flag);
1316- Context* const curCtx = CurrentContext();
1317- CHECK_CONTEXT_VALID_WITH_RETURN(curCtx, RT_ERROR_CONTEXT_NULL);
1318- 
1319- Runtime* const rtInstance = Runtime::Instance();
1320- COND_RETURN_ERROR(rtInstance == nullptr, RT_ERROR_INSTANCE_NULL, "Runtime instance is null.");
1321- ERROR_RETURN_MSG_INNER(
1322- rtInstance->StartAicpuSd(curCtx->Device_()),
1323- "Data dump info load failed, check and start tsd open aicpu sd error.");
1324- 
1325- return StreamDatadumpInfoLoad(dumpInfo, length, flag, curCtx->DefaultStream_());
1326-}
1327- 
1328rtError_t ApiImpl::AicpuInfoLoad(const void* const aicpuInfo, const uint32_t length)1313rtError_t ApiImpl::AicpuInfoLoad(const void* const aicpuInfo, const uint32_t length)
1329{1314{
1330 RT_LOG(RT_LOG_DEBUG, "length=%u.", length);1315 RT_LOG(RT_LOG_DEBUG, "length=%u.", length);
@@ -52,6 +52,19 @@ rtError_t ApiImpl::CpuKernelLaunchEx(
52 return LaunchRuntimeThreadAicpuKernel(this, kernel, coreDim, argsInfo, stream);52 return LaunchRuntimeThreadAicpuKernel(this, kernel, coreDim, argsInfo, stream);
53}53}
54 54 
55+rtError_t ApiImpl::DatadumpInfoLoad(const void* const dumpInfo, const uint32_t length, const uint32_t flag)
56+{
57+ RT_LOG(RT_LOG_DEBUG, "length=%u, flag=%u.", length, flag);
58+ if (flag != RT_KERNEL_DEFAULT) {
Y
Yyanhaiyan11 天前

和其他芯片相比,丢失日志RT_LOG(RT_LOG_DEBUG, "length=%u, flag=%u."),导致flag != RT_KERNEL_DEFAULT 拒绝路径无日志,用户无从得知不支持原因。建议补充。

likedislike
FengHaozhan
FengHaozhan
11 天前 评论:
59+ return RT_ERROR_FEATURE_NOT_SUPPORT;
60+ }
61+ Context* const context = CurrentContext();
62+ CHECK_CONTEXT_VALID_WITH_RETURN(context, RT_ERROR_CONTEXT_NULL);
63+ Device* const device = context->Device_();
64+ COND_RETURN_ERROR(device == nullptr, RT_ERROR_DEVICE_NULL, "Device is null.");
65+ return LoadRuntimeThreadAicpuDumpInfo(this, device->Id_(), device->DevGetTsId(), dumpInfo, length);
FengHaozhan
FengHaozhanFengHaozhan11 天前

🔴 Critical:这里把现有 rtDatadumpInfoLoad 载荷直接转给 Host 侧 TLV 解析,破坏了当前跨仓接口契约。

当前 GE V1/OM2 在调用该接口前都会先把 OpMappingInfo protobuf H2D 拷到 Device,再传入 Device 地址(runtime/v1/common/dump/data_dumper.cc:1016-1023、runtime/om2/dump/data_dump_impl.cc:128-140);而新路径最终在 DataDumpParser::Parse 中直接对 dumpInfo 做 Host memcpy,并要求内容是 0x5A5A5A5A TLV。这样现有 arch5162 调用会把 Device 地址当 Host 指针解引用,可能直接异常,即使地址可访问也必然因 protobuf/TLV 格式不符而加载失败。

建议先同步生产端与接口契约:要么由 GE 通过明确的 Host-TLV 接口传入完整 TLV,要么保留现有 Device-protobuf 通路;同时补一条从真实 GE 调用形态进入该实现的集成用例。

likedislike
FengHaozhan
FengHaozhan
11 天前 评论:
66+}
67+ 
55rtError_t ApiImpl::FlushCache(const uint64_t base, const size_t len)68rtError_t ApiImpl::FlushCache(const uint64_t base, const size_t len)
56{69{
57 RT_LOG(RT_LOG_INFO, "flush cache base=%" PRIu64 ", len=%zu.", base, len);70 RT_LOG(RT_LOG_INFO, "flush cache base=%" PRIu64 ", len=%zu.", base, len);
@@ -16,6 +16,7 @@
16#include "kernel.hpp"16#include "kernel.hpp"
17#include "runtime.hpp"17#include "runtime.hpp"
18#include "stream.hpp"18#include "stream.hpp"
19+#include "stream_task_c.hpp"
19 20 
20namespace cce {21namespace cce {
21namespace runtime {22namespace runtime {
@@ -53,5 +54,20 @@ rtError_t ApiImpl::CpuKernelLaunchEx(
53 argsInfo->cpuParamHeadOffset);54 argsInfo->cpuParamHeadOffset);
54}55}
55 56 
57+rtError_t ApiImpl::DatadumpInfoLoad(const void* const dumpInfo, const uint32_t length, const uint32_t flag)
58+{
59+ RT_LOG(RT_LOG_DEBUG, "length=%u, flag=%u.", length, flag);
60+ Context* const curCtx = CurrentContext();
61+ CHECK_CONTEXT_VALID_WITH_RETURN(curCtx, RT_ERROR_CONTEXT_NULL);
62+ 
63+ Runtime* const rtInstance = Runtime::Instance();
64+ COND_RETURN_ERROR(rtInstance == nullptr, RT_ERROR_INSTANCE_NULL, "Runtime instance is null.");
65+ ERROR_RETURN_MSG_INNER(
66+ rtInstance->StartAicpuSd(curCtx->Device_()),
67+ "Data dump info load failed, check and start tsd open aicpu sd error.");
68+ 
69+ return StreamDatadumpInfoLoad(dumpInfo, length, flag, curCtx->DefaultStream_());
70+}
71+ 
56} // namespace runtime72} // namespace runtime
57} // namespace cce73} // namespace cce
@@ -8,6 +8,8 @@
8 * See LICENSE in the root of the software repository for the full text of the License.8 * See LICENSE in the root of the software repository for the full text of the License.
9 */9 */
10 10 
11+#include <cstddef>
12+ 
11#include "davinci_kernel_task.h"13#include "davinci_kernel_task.h"
12#include "stars.hpp"14#include "stars.hpp"
13#include "stream.hpp"15#include "stream.hpp"
@@ -26,7 +28,8 @@ namespace cce {
26namespace runtime {28namespace runtime {
27namespace {29namespace {
28constexpr uint32_t DRV_CALLBACK_GROUPID = 11U; // Driver-defined callback group ID.30constexpr uint32_t DRV_CALLBACK_GROUPID = 11U; // Driver-defined callback group ID.
29-}31+constexpr size_t DATADUMP_FLAG_RES7_INDEX = 1U;
32+} // namespace
30 33 
31#if F_DESC("DavinciKernelTask")34#if F_DESC("DavinciKernelTask")
32void ConstructAICoreSqeForDavinciTask(TaskInfo* const taskInfo, void* const sqeBuffer, const TaskSqeInfo& sqeInfo)35void ConstructAICoreSqeForDavinciTask(TaskInfo* const taskInfo, void* const sqeBuffer, const TaskSqeInfo& sqeInfo)
@@ -108,6 +111,11 @@ void ConstructAICoreSqeForDavinciTask(TaskInfo* const taskInfo, void* const sqeB
108 const uint32_t stackLevel = static_cast<uint32_t>(stackSize / KERNEL_STACK_SIZE_16K - 2U);111 const uint32_t stackLevel = static_cast<uint32_t>(stackSize / KERNEL_STACK_SIZE_16K - 2U);
109 sqe->TaskParamPtrHigh |= stackLevel << 20U;112 sqe->TaskParamPtrHigh |= stackLevel << 20U;
110 }113 }
114+ if ((aicTaskInfo->comm.kernelFlag & RT_KERNEL_DUMPFLAG) != 0U) {
115+ sqe->header.postP = RT_STARS_SQE_INT_DIR_TO_TSCPU;
116+ // res7[1] starts at byte 52 of the SQE; bit 0 is the DataDump marker reported to TSCPU.
117+ sqe->res7[DATADUMP_FLAG_RES7_INDEX] |= SQE_BIZ_FLAG_DATADUMP;
118+ }
111 PrintSqe(command, "AIC or AIV Task");119 PrintSqe(command, "AIC or AIV Task");
112}120}
113 121 
@@ -92,6 +92,9 @@ constexpr char STREAM_OBSERVER_NAME[] = "Inner#RuntimeThreadAicpu";
92static_assert(92static_assert(
93 static_cast<uint32_t>(RuntimeThreadAicpuSqeSubtype::AICPU) == static_cast<uint32_t>(RT_SQE_SUBTYPE_AICPU),93 static_cast<uint32_t>(RuntimeThreadAicpuSqeSubtype::AICPU) == static_cast<uint32_t>(RT_SQE_SUBTYPE_AICPU),
94 "RuntimeThreadAicpu SQE subtype does not match the runtime protocol");94 "RuntimeThreadAicpu SQE subtype does not match the runtime protocol");
95+static_assert(
96+ static_cast<uint32_t>(RuntimeThreadAicpuSqeSubtype::DATADUMP) == static_cast<uint32_t>(RT_SQE_SUBTYPE_DATADUMP),
97+ "RuntimeThreadAicpu DataDump SQE subtype does not match the runtime protocol");
95 98 
96RuntimeThreadAicpuStatus ToPluginStatus(const rtError_t error)99RuntimeThreadAicpuStatus ToPluginStatus(const rtError_t error)
97{100{
@@ -116,6 +119,7 @@ rtError_t ToRuntimeStatus(const RuntimeThreadAicpuStatus status)
116 case RuntimeThreadAicpuStatus::OK:119 case RuntimeThreadAicpuStatus::OK:
117 return RT_ERROR_NONE;120 return RT_ERROR_NONE;
118 case RuntimeThreadAicpuStatus::INVALID_PARAM:121 case RuntimeThreadAicpuStatus::INVALID_PARAM:
122+ case RuntimeThreadAicpuStatus::DATADUMP_PARSE_FAILED:
Y
Yyanhaiyan11 天前

ToRuntimeStatus 仅映射 DATADUMP_PARSE_FAILED,其余 6 个新 DATADUMP_* 落 default→RT_ERROR_AICPU_INTERNAL_ERROR;DumpOp 失败时这些枚举值经 FinishReport→setStreamError 直接写入 Stream errCode(用 8-13,非 rtError_t 语义);RUNTIME_ERROR(设备不匹配)同样落 default 语义失配(arch5162 UT 已将该失配固化为断言)。 建议补全映射或定义 executeResult 转换值。

likedislike
FengHaozhan
FengHaozhan
11 天前 评论:
119 return RT_ERROR_INVALID_VALUE;123 return RT_ERROR_INVALID_VALUE;
120 case RuntimeThreadAicpuStatus::NO_MEMORY:124 case RuntimeThreadAicpuStatus::NO_MEMORY:
121 return RT_ERROR_MEMORY_ALLOCATION;125 return RT_ERROR_MEMORY_ALLOCATION;
@@ -294,6 +298,30 @@ public:
294 return ToRuntimeStatus(pluginApi_->prepareKernel(&request, &preparedKernel));298 return ToRuntimeStatus(pluginApi_->prepareKernel(&request, &preparedKernel));
295 }299 }
296 300 
301+ rtError_t LoadDumpInfo(
302+ const uint32_t deviceId, const uint32_t tsId, const void* const dumpInfo, const uint32_t length)
303+ {
304+ std::lock_guard<std::mutex> lock(mutex_);
305+ rtError_t error = EnsurePlugin();
306+ if (error != RT_ERROR_NONE) {
307+ return error;
308+ }
309+ const RuntimeThreadAicpuStartRequest startRequest = {
310+ .structSize = sizeof(RuntimeThreadAicpuStartRequest), .deviceId = deviceId, .tsId = tsId};
311+ error = ToRuntimeStatus(pluginApi_->startWorker(&startRequest));
312+ if (error != RT_ERROR_NONE) {
313+ return error;
314+ }
315+ const RuntimeThreadAicpuDumpInfoRequest loadRequest = {
316+ .structSize = sizeof(RuntimeThreadAicpuDumpInfoRequest),
317+ .deviceId = deviceId,
318+ .tsId = tsId,
319+ .dumpInfo = dumpInfo,
320+ .length = length,
321+ };
322+ return ToRuntimeStatus(pluginApi_->loadDumpInfo(&loadRequest));
323+ }
324+ 
297 void ReleasePreparedKernel(const uint64_t taskCookie)325 void ReleasePreparedKernel(const uint64_t taskCookie)
298 {326 {
299 std::lock_guard<std::mutex> lock(mutex_);327 std::lock_guard<std::mutex> lock(mutex_);
@@ -351,19 +379,23 @@ private:
351 const RuntimeThreadAicpuRuntimeHooks hooks = BuildRuntimeHooks(api_);379 const RuntimeThreadAicpuRuntimeHooks hooks = BuildRuntimeHooks(api_);
352 const RuntimeThreadAicpuStatus status = queryPlugin(&hooks, &pluginApi_);380 const RuntimeThreadAicpuStatus status = queryPlugin(&hooks, &pluginApi_);
353 const uint32_t apiSize = (pluginApi_ == nullptr) ? 0U : pluginApi_->structSize;381 const uint32_t apiSize = (pluginApi_ == nullptr) ? 0U : pluginApi_->structSize;
354- const bool prepareValid = (pluginApi_ != nullptr) && (pluginApi_->prepareKernel != nullptr);382+ const bool apiTableValid = (pluginApi_ != nullptr) && (apiSize >= sizeof(RuntimeThreadAicpuPluginApi));
355- const bool releaseValid = (pluginApi_ != nullptr) && (pluginApi_->releasePreparedKernel != nullptr);383+ const bool prepareValid = apiTableValid && (pluginApi_->prepareKernel != nullptr);
356- const bool streamDestroyedValid = (pluginApi_ != nullptr) && (pluginApi_->streamDestroyed != nullptr);384+ const bool releaseValid = apiTableValid && (pluginApi_->releasePreparedKernel != nullptr);
357- if ((status != RuntimeThreadAicpuStatus::OK) || (pluginApi_ == nullptr) ||385+ const bool streamDestroyedValid = apiTableValid && (pluginApi_->streamDestroyed != nullptr);
358- (apiSize < sizeof(RuntimeThreadAicpuPluginApi)) || (!prepareValid) || (!releaseValid) ||386+ const bool startWorkerValid = apiTableValid && (pluginApi_->startWorker != nullptr);
359- (!streamDestroyedValid)) {387+ const bool loadDumpInfoValid = apiTableValid && (pluginApi_->loadDumpInfo != nullptr);
388+ if ((status != RuntimeThreadAicpuStatus::OK) || (!apiTableValid) || (!prepareValid) || (!releaseValid) ||
389+ (!streamDestroyedValid) || (!startWorkerValid) || (!loadDumpInfoValid)) {
360 RT_LOG(390 RT_LOG(
361 RT_LOG_ERROR,391 RT_LOG_ERROR,
362 "Initialize RuntimeThreadAicpu plugin interface failed, plugin_status=%u, api_valid=%u, "392 "Initialize RuntimeThreadAicpu plugin interface failed, plugin_status=%u, api_valid=%u, "
363- "api_size=%u, expected_size=%zu, prepare_valid=%u, release_valid=%u, stream_destroy_valid=%u.",393+ "api_size=%u, expected_size=%zu, prepare_valid=%u, release_valid=%u, stream_destroy_valid=%u, "
394+ "start_worker_valid=%u, load_dump_info_valid=%u.",
364 static_cast<uint32_t>(status), static_cast<uint32_t>(pluginApi_ != nullptr), apiSize,395 static_cast<uint32_t>(status), static_cast<uint32_t>(pluginApi_ != nullptr), apiSize,
365 sizeof(RuntimeThreadAicpuPluginApi), static_cast<uint32_t>(prepareValid),396 sizeof(RuntimeThreadAicpuPluginApi), static_cast<uint32_t>(prepareValid),
366- static_cast<uint32_t>(releaseValid), static_cast<uint32_t>(streamDestroyedValid));397+ static_cast<uint32_t>(releaseValid), static_cast<uint32_t>(streamDestroyedValid),
398+ static_cast<uint32_t>(startWorkerValid), static_cast<uint32_t>(loadDumpInfoValid));
367 unsupported_ = true;399 unsupported_ = true;
368 pluginApi_ = nullptr;400 pluginApi_ = nullptr;
369 return RT_ERROR_FEATURE_NOT_SUPPORT;401 return RT_ERROR_FEATURE_NOT_SUPPORT;
@@ -503,5 +535,15 @@ rtError_t LaunchRuntimeThreadAicpuKernel(
503 return RT_ERROR_NONE;535 return RT_ERROR_NONE;
504}536}
505 537 
538+rtError_t LoadRuntimeThreadAicpuDumpInfo(
539+ Api* const api, const uint32_t deviceId, const uint32_t tsId, const void* const dumpInfo, const uint32_t length)
540+{
541+ if ((api == nullptr) || (dumpInfo == nullptr) || (length == 0U)) {
542+ return RT_ERROR_INVALID_VALUE;
543+ }
544+ RuntimeThreadAicpuAdapter* const adapter = GetAdapter(api);
545+ return (adapter == nullptr) ? RT_ERROR_MEMORY_ALLOCATION : adapter->LoadDumpInfo(deviceId, tsId, dumpInfo, length);
546+}
547+ 
506} // namespace runtime548} // namespace runtime
507} // namespace cce549} // namespace cce
@@ -24,6 +24,9 @@ rtError_t LaunchRuntimeThreadAicpuKernel(
24 Api* const api, const Kernel* const kernel, const uint32_t blockDim, const rtCpuKernelArgs_t* const argsInfo,24 Api* const api, const Kernel* const kernel, const uint32_t blockDim, const rtCpuKernelArgs_t* const argsInfo,
25 Stream* const stream);25 Stream* const stream);
26 26 
27+rtError_t LoadRuntimeThreadAicpuDumpInfo(
28+ Api* const api, const uint32_t deviceId, const uint32_t tsId, const void* const dumpInfo, const uint32_t length);
29+ 
27} // namespace runtime30} // namespace runtime
28} // namespace cce31} // namespace cce
29 32 
@@ -12,7 +12,11 @@ set(RUNTIME_THREAD_AICPU_SRC_PATH ${AICPU_SCHED_PATH}/runtime_thread_aicpu)
12 12 
13add_executable(runtime_thread_aicpu_utest13add_executable(runtime_thread_aicpu_utest
14 main_ut.cc14 main_ut.cc
15+ data_dump_ut.cc
15 runtime_thread_aicpu_ut.cc16 runtime_thread_aicpu_ut.cc
17+ ${RUNTIME_THREAD_AICPU_SRC_PATH}/datadump/data_dump_manager.cc
18+ ${RUNTIME_THREAD_AICPU_SRC_PATH}/datadump/data_dump_parser.cc
19+ ${RUNTIME_THREAD_AICPU_SRC_PATH}/datadump/data_dump_writer.cc
16 ${RUNTIME_THREAD_AICPU_SRC_PATH}/runtime_thread_aicpu_plugin.cc20 ${RUNTIME_THREAD_AICPU_SRC_PATH}/runtime_thread_aicpu_plugin.cc
17 ${RUNTIME_THREAD_AICPU_SRC_PATH}/runtime_thread_aicpu_service.cc21 ${RUNTIME_THREAD_AICPU_SRC_PATH}/runtime_thread_aicpu_service.cc
18 ${RUNTIME_THREAD_AICPU_SRC_PATH}/runtime_thread_aicpu_so_manager.cc22 ${RUNTIME_THREAD_AICPU_SRC_PATH}/runtime_thread_aicpu_so_manager.cc
@@ -399,17 +399,17 @@ TEST_F(RuntimeThreadAicpuTest, EnsureStartedValidatesHooksAndRollsBackFailures)
399 RuntimeThreadAicpuRuntimeHooks invalidHooks = MakeHooks(state);399 RuntimeThreadAicpuRuntimeHooks invalidHooks = MakeHooks(state);
400 invalidHooks.reserveGroupId = nullptr;400 invalidHooks.reserveGroupId = nullptr;
401 RuntimeThreadAicpuService invalidService(invalidHooks);401 RuntimeThreadAicpuService invalidService(invalidHooks);
402- EXPECT_EQ(invalidService.EnsureStarted(MakeRequest()), RuntimeThreadAicpuStatus::INVALID_PARAM);402+ EXPECT_EQ(invalidService.EnsureStarted(DEVICE_ID, TS_ID), RuntimeThreadAicpuStatus::INVALID_PARAM);
403 403 
404 state.reserveResult = RuntimeThreadAicpuStatus::NO_MEMORY;404 state.reserveResult = RuntimeThreadAicpuStatus::NO_MEMORY;
405 RuntimeThreadAicpuService reserveFailure(MakeHooks(state));405 RuntimeThreadAicpuService reserveFailure(MakeHooks(state));
406- EXPECT_EQ(reserveFailure.EnsureStarted(MakeRequest()), RuntimeThreadAicpuStatus::NO_MEMORY);406+ EXPECT_EQ(reserveFailure.EnsureStarted(DEVICE_ID, TS_ID), RuntimeThreadAicpuStatus::NO_MEMORY);
407 EXPECT_EQ(reserveFailure.deviceId_, 0U);407 EXPECT_EQ(reserveFailure.deviceId_, 0U);
408 408 
409 HookState allocateState;409 HookState allocateState;
410 g_driver.allocateResult = static_cast<drvError_t>(1);410 g_driver.allocateResult = static_cast<drvError_t>(1);
411 RuntimeThreadAicpuService allocateFailure(MakeHooks(allocateState));411 RuntimeThreadAicpuService allocateFailure(MakeHooks(allocateState));
412- EXPECT_EQ(allocateFailure.EnsureStarted(MakeRequest()), RuntimeThreadAicpuStatus::RUNTIME_ERROR);412+ EXPECT_EQ(allocateFailure.EnsureStarted(DEVICE_ID, TS_ID), RuntimeThreadAicpuStatus::RUNTIME_ERROR);
413 EXPECT_EQ(allocateState.releaseCalls, 1U);413 EXPECT_EQ(allocateState.releaseCalls, 1U);
414 EXPECT_EQ(allocateFailure.groupId_, 0U);414 EXPECT_EQ(allocateFailure.groupId_, 0U);
415}415}
@@ -420,19 +420,19 @@ TEST_F(RuntimeThreadAicpuTest, EnsureStartedCreatesOneReusableWorker)
420 state.processExiting.store(true);420 state.processExiting.store(true);
421 RuntimeThreadAicpuService service(MakeHooks(state));421 RuntimeThreadAicpuService service(MakeHooks(state));
422 const RuntimeThreadAicpuKernelRequest request = MakeRequest();422 const RuntimeThreadAicpuKernelRequest request = MakeRequest();
423- ASSERT_EQ(service.EnsureStarted(request), RuntimeThreadAicpuStatus::OK);423+ ASSERT_EQ(service.EnsureStarted(request.deviceId, request.tsId), RuntimeThreadAicpuStatus::OK);
424 ASSERT_TRUE(service.worker_.joinable());424 ASSERT_TRUE(service.worker_.joinable());
425 service.worker_.join();425 service.worker_.join();
426 EXPECT_TRUE(service.started_);426 EXPECT_TRUE(service.started_);
427 EXPECT_EQ(state.reserveCalls, 1U);427 EXPECT_EQ(state.reserveCalls, 1U);
428 EXPECT_EQ(state.monitorEnterCalls, 1U);428 EXPECT_EQ(state.monitorEnterCalls, 1U);
429 EXPECT_EQ(state.monitorExitCalls, 1U);429 EXPECT_EQ(state.monitorExitCalls, 1U);
430- EXPECT_EQ(service.EnsureStarted(request), RuntimeThreadAicpuStatus::OK);430+ EXPECT_EQ(service.EnsureStarted(request.deviceId, request.tsId), RuntimeThreadAicpuStatus::OK);
431 EXPECT_EQ(state.reserveCalls, 1U);431 EXPECT_EQ(state.reserveCalls, 1U);
432 432 
433 RuntimeThreadAicpuKernelRequest otherDevice = request;433 RuntimeThreadAicpuKernelRequest otherDevice = request;
434 otherDevice.deviceId = DEVICE_ID + 1U;434 otherDevice.deviceId = DEVICE_ID + 1U;
435- EXPECT_EQ(service.EnsureStarted(otherDevice), RuntimeThreadAicpuStatus::RUNTIME_ERROR);435+ EXPECT_EQ(service.EnsureStarted(otherDevice.deviceId, otherDevice.tsId), RuntimeThreadAicpuStatus::RUNTIME_ERROR);
436 service.ReleaseCallbackChannel();436 service.ReleaseCallbackChannel();
437 ReleaseGroupId(&state, GROUP_ID);437 ReleaseGroupId(&state, GROUP_ID);
438}438}
@@ -442,7 +442,28 @@ TEST_F(RuntimeThreadAicpuTest, EnsureStartedRejectsFailedWorker)
442 HookState state;442 HookState state;
443 RuntimeThreadAicpuService service(MakeHooks(state));443 RuntimeThreadAicpuService service(MakeHooks(state));
444 service.failed_.store(true);444 service.failed_.store(true);
445- EXPECT_EQ(service.EnsureStarted(MakeRequest()), RuntimeThreadAicpuStatus::RUNTIME_ERROR);445+ EXPECT_EQ(service.EnsureStarted(DEVICE_ID, TS_ID), RuntimeThreadAicpuStatus::RUNTIME_ERROR);
446+}
447+ 
448+TEST_F(RuntimeThreadAicpuTest, DataDumpWorkerAndLoadRequestsAreValidated)
449+{
450+ HookState state;
451+ RuntimeThreadAicpuService service(MakeHooks(state));
452+ RuntimeThreadAicpuStartRequest start = {};
453+ EXPECT_EQ(service.StartWorker(start), RuntimeThreadAicpuStatus::INVALID_PARAM);
454+ start.structSize = sizeof(start);
455+ start.deviceId = DEVICE_ID;
456+ start.tsId = TS_ID;
457+ service.started_ = true;
458+ service.deviceId_ = DEVICE_ID;
459+ service.tsId_ = TS_ID;
460+ EXPECT_EQ(service.StartWorker(start), RuntimeThreadAicpuStatus::OK);
461+ 
462+ RuntimeThreadAicpuDumpInfoRequest load = {};
463+ load.structSize = sizeof(load);
464+ load.deviceId = DEVICE_ID;
465+ load.tsId = TS_ID;
466+ EXPECT_EQ(service.LoadDumpInfo(load), RuntimeThreadAicpuStatus::INVALID_PARAM);
446}467}
447 468 
448TEST_F(RuntimeThreadAicpuTest, CompletionEventIsCachedAndDestroyedWithStream)469TEST_F(RuntimeThreadAicpuTest, CompletionEventIsCachedAndDestroyedWithStream)
@@ -664,16 +685,43 @@ TEST_F(RuntimeThreadAicpuTest, ExecutePreparedKernelConsumesContextOnce)
664 static_cast<uint32_t>(RuntimeThreadAicpuStatus::INTERNAL_ERROR));685 static_cast<uint32_t>(RuntimeThreadAicpuStatus::INTERNAL_ERROR));
665}686}
666 687 
667-TEST_F(RuntimeThreadAicpuTest, ProcessOneReportValidatesFunctionAndCookie)688+TEST_F(RuntimeThreadAicpuTest, ProcessAicpuReportValidatesFunctionAndCookie)
668{689{
669 HookState state;690 HookState state;
670 RuntimeThreadAicpuService service(MakeHooks(state));691 RuntimeThreadAicpuService service(MakeHooks(state));
671 TestCallbackReport report = {};692 TestCallbackReport report = {};
672 report.funcPtr = 1U;693 report.funcPtr = 1U;
673- EXPECT_EQ(service.ProcessOneReport(&report), static_cast<uint32_t>(RuntimeThreadAicpuStatus::INTERNAL_ERROR));694+ EXPECT_EQ(service.ProcessAicpuReport(&report), static_cast<uint32_t>(RuntimeThreadAicpuStatus::INTERNAL_ERROR));
674 report.funcPtr = reinterpret_cast<uint64_t>(&RuntimeThreadAicpuService::ExecutePreparedKernelEntry);695 report.funcPtr = reinterpret_cast<uint64_t>(&RuntimeThreadAicpuService::ExecutePreparedKernelEntry);
675 report.fnData = 100U;696 report.fnData = 100U;
676- EXPECT_EQ(service.ProcessOneReport(&report), static_cast<uint32_t>(RuntimeThreadAicpuStatus::INTERNAL_ERROR));697+ EXPECT_EQ(service.ProcessAicpuReport(&report), static_cast<uint32_t>(RuntimeThreadAicpuStatus::INTERNAL_ERROR));
698+}
699+ 
700+TEST_F(RuntimeThreadAicpuTest, ProcessDumpReportFindsOpAndReturnsWriterStatus)
701+{
702+ HookState state;
703+ RuntimeThreadAicpuService service(MakeHooks(state));
704+ std::shared_ptr<cce::runtime_thread_aicpu::datadump::ModelDumpConfig> config =
705+ std::make_shared<cce::runtime_thread_aicpu::datadump::ModelDumpConfig>();
706+ config->modelId = 5U;
707+ cce::runtime_thread_aicpu::datadump::ModelDumpInfoPtr model =
708+ std::make_shared<cce::runtime_thread_aicpu::datadump::ModelDumpInfo>();
709+ model->config = config;
710+ cce::runtime_thread_aicpu::datadump::OpDumpInfoPtr op =
711+ std::make_shared<cce::runtime_thread_aicpu::datadump::OpDumpInfo>();
712+ op->taskKey = {STREAM_ID, 31U};
713+ op->opName = "MatMul";
714+ op->config = config;
715+ model->ops[op->taskKey] = op;
716+ ASSERT_EQ(service.dataDumpManager_.Load(model), RuntimeThreadAicpuStatus::OK);
717+ 
718+ TestCallbackReport report = {};
719+ report.streamId = STREAM_ID;
720+ report.taskId = 31U;
721+ EXPECT_EQ(service.ProcessDumpReport(&report), static_cast<uint32_t>(RuntimeThreadAicpuStatus::INVALID_PARAM));
722+ report.taskId = 32U;
723+ EXPECT_EQ(
724+ service.ProcessDumpReport(&report), static_cast<uint32_t>(RuntimeThreadAicpuStatus::DATADUMP_OP_NOT_FOUND));
677}725}
678 726 
679TEST_F(RuntimeThreadAicpuTest, FinishReportWritesCompletionCommandAndStreamError)727TEST_F(RuntimeThreadAicpuTest, FinishReportWritesCompletionCommandAndStreamError)
@@ -697,7 +745,9 @@ TEST_F(RuntimeThreadAicpuTest, FinishReportWritesCompletionCommandAndStreamError
697 value = 1U;745 value = 1U;
698 }746 }
699 constexpr uint32_t executeResult = 0x5678U;747 constexpr uint32_t executeResult = 0x5678U;
700- ASSERT_EQ(service.FinishReport(&report, executeResult), RuntimeThreadAicpuStatus::OK);748+ ASSERT_EQ(
749+ service.FinishReport(&report, executeResult, RuntimeThreadAicpuSqeSubtype::AICPU),
750+ RuntimeThreadAicpuStatus::OK);
701 EXPECT_EQ(state.streamErrorCalls, 1U);751 EXPECT_EQ(state.streamErrorCalls, 1U);
702 EXPECT_EQ(state.streamErrorDeviceId, DEVICE_ID);752 EXPECT_EQ(state.streamErrorDeviceId, DEVICE_ID);
703 EXPECT_EQ(state.streamErrorTsId, TS_ID);753 EXPECT_EQ(state.streamErrorTsId, TS_ID);
@@ -727,16 +777,39 @@ TEST_F(RuntimeThreadAicpuTest, FinishReportHandlesDriverFailures)
727 RuntimeThreadAicpuService service(MakeHooks(state));777 RuntimeThreadAicpuService service(MakeHooks(state));
728 TestCallbackReport report = {};778 TestCallbackReport report = {};
729 g_driver.memoryGetResult = static_cast<drvError_t>(1);779 g_driver.memoryGetResult = static_cast<drvError_t>(1);
730- EXPECT_EQ(service.FinishReport(&report, 0U), RuntimeThreadAicpuStatus::RUNTIME_ERROR);780+ EXPECT_EQ(
781+ service.FinishReport(&report, 0U, RuntimeThreadAicpuSqeSubtype::AICPU),
782+ RuntimeThreadAicpuStatus::RUNTIME_ERROR);
731 g_driver.memoryGetResult = DRV_ERROR_NONE;783 g_driver.memoryGetResult = DRV_ERROR_NONE;
732 g_driver.provideCommand = false;784 g_driver.provideCommand = false;
733- EXPECT_EQ(service.FinishReport(&report, 0U), RuntimeThreadAicpuStatus::RUNTIME_ERROR);785+ EXPECT_EQ(
786+ service.FinishReport(&report, 0U, RuntimeThreadAicpuSqeSubtype::AICPU),
787+ RuntimeThreadAicpuStatus::RUNTIME_ERROR);
734 g_driver.provideCommand = true;788 g_driver.provideCommand = true;
735 g_driver.memoryCommandCount = 0U;789 g_driver.memoryCommandCount = 0U;
736- EXPECT_EQ(service.FinishReport(&report, 0U), RuntimeThreadAicpuStatus::RUNTIME_ERROR);790+ EXPECT_EQ(
791+ service.FinishReport(&report, 0U, RuntimeThreadAicpuSqeSubtype::AICPU),
792+ RuntimeThreadAicpuStatus::RUNTIME_ERROR);
737 g_driver.memoryCommandCount = 1U;793 g_driver.memoryCommandCount = 1U;
738 g_driver.messageSendResult = static_cast<drvError_t>(1);794 g_driver.messageSendResult = static_cast<drvError_t>(1);
739- EXPECT_EQ(service.FinishReport(&report, 0U), RuntimeThreadAicpuStatus::RUNTIME_ERROR);795+ EXPECT_EQ(
796+ service.FinishReport(&report, 0U, RuntimeThreadAicpuSqeSubtype::AICPU),
797+ RuntimeThreadAicpuStatus::RUNTIME_ERROR);
798+}
799+ 
800+TEST_F(RuntimeThreadAicpuTest, FinishReportWritesDataDumpSubtype)
801+{
802+ HookState state;
803+ RuntimeThreadAicpuService service(MakeHooks(state));
804+ service.groupId_ = GROUP_ID;
805+ service.callbackSqId_ = SQ_ID;
806+ TestCallbackReport report = {};
807+ report.streamId = STREAM_ID;
808+ report.taskId = 31U;
809+ report.eventId = EVENT_ID;
810+ ASSERT_EQ(service.FinishReport(&report, 0U, RuntimeThreadAicpuSqeSubtype::DATADUMP), RuntimeThreadAicpuStatus::OK);
811+ EXPECT_EQ(g_driver.command.reserved1[0], static_cast<uint32_t>(RuntimeThreadAicpuSqeSubtype::DATADUMP));
812+ EXPECT_EQ(g_driver.command.reserved1[1], 0U);
740}813}
741 814 
742TEST_F(RuntimeThreadAicpuTest, ProcessReportsHandlesWaitAndCqSelection)815TEST_F(RuntimeThreadAicpuTest, ProcessReportsHandlesWaitAndCqSelection)
@@ -809,6 +882,43 @@ TEST_F(RuntimeThreadAicpuTest, ProcessReportsSurfacesFinishAndReleaseFailures)
809 EXPECT_FALSE(service.ProcessReports());882 EXPECT_FALSE(service.ProcessReports());
810}883}
811 884 
885+TEST_F(RuntimeThreadAicpuTest, ProcessReportsRoutesDataDumpByReservedField)
886+{
887+ HookState state;
888+ RuntimeThreadAicpuService service(MakeHooks(state));
889+ service.deviceId_ = DEVICE_ID;
890+ service.tsId_ = TS_ID;
891+ service.groupId_ = GROUP_ID;
892+ service.callbackSqId_ = SQ_ID;
893+ service.callbackCqId_ = CQ_ID;
894+ std::shared_ptr<cce::runtime_thread_aicpu::datadump::ModelDumpConfig> config =
895+ std::make_shared<cce::runtime_thread_aicpu::datadump::ModelDumpConfig>();
896+ config->modelId = 5U;
897+ cce::runtime_thread_aicpu::datadump::ModelDumpInfoPtr model =
898+ std::make_shared<cce::runtime_thread_aicpu::datadump::ModelDumpInfo>();
899+ model->config = config;
900+ cce::runtime_thread_aicpu::datadump::OpDumpInfoPtr op =
901+ std::make_shared<cce::runtime_thread_aicpu::datadump::OpDumpInfo>();
902+ op->taskKey = {STREAM_ID, 31U};
903+ op->opName = "MatMul";
904+ op->config = config;
905+ model->ops[op->taskKey] = op;
906+ ASSERT_EQ(service.dataDumpManager_.Load(model), RuntimeThreadAicpuStatus::OK);
907+ 
908+ g_driver.waitResult = DRV_ERROR_NONE;
909+ g_driver.setExpectedCqBit = true;
910+ g_driver.reportCount = 1U;
911+ g_driver.reports[0].streamId = STREAM_ID;
912+ g_driver.reports[0].taskId = 31U;
913+ g_driver.reports[0].eventId = EVENT_ID;
914+ g_driver.reports[0].reserved = 1U;
915+ ASSERT_TRUE(service.ProcessReports());
916+ EXPECT_EQ(g_driver.command.reserved1[0], static_cast<uint32_t>(RuntimeThreadAicpuSqeSubtype::DATADUMP));
917+ EXPECT_EQ(g_driver.command.reserved1[1], static_cast<uint32_t>(RuntimeThreadAicpuStatus::INVALID_PARAM));
918+ EXPECT_EQ(state.streamErrorCalls, 1U);
919+ EXPECT_EQ(g_driver.reportReleaseCalls, 1U);
920+}
921+ 
812TEST_F(RuntimeThreadAicpuTest, WorkerLoopMarksUnexpectedDriverFailure)922TEST_F(RuntimeThreadAicpuTest, WorkerLoopMarksUnexpectedDriverFailure)
813{923{
814 HookState state;924 HookState state;
@@ -841,9 +951,13 @@ TEST_F(RuntimeThreadAicpuTest, PluginApiValidatesInputsAndReturnsCompleteTable)
841 EXPECT_NE(api->prepareKernel, nullptr);951 EXPECT_NE(api->prepareKernel, nullptr);
842 EXPECT_NE(api->releasePreparedKernel, nullptr);952 EXPECT_NE(api->releasePreparedKernel, nullptr);
843 EXPECT_NE(api->streamDestroyed, nullptr);953 EXPECT_NE(api->streamDestroyed, nullptr);
954+ EXPECT_NE(api->startWorker, nullptr);
955+ EXPECT_NE(api->loadDumpInfo, nullptr);
844 EXPECT_EQ(api->prepareKernel(nullptr, nullptr), RuntimeThreadAicpuStatus::INVALID_PARAM);956 EXPECT_EQ(api->prepareKernel(nullptr, nullptr), RuntimeThreadAicpuStatus::INVALID_PARAM);
845 api->releasePreparedKernel(0U);957 api->releasePreparedKernel(0U);
846 api->streamDestroyed(nullptr);958 api->streamDestroyed(nullptr);
959+ EXPECT_EQ(api->startWorker(nullptr), RuntimeThreadAicpuStatus::INVALID_PARAM);
960+ EXPECT_EQ(api->loadDumpInfo(nullptr), RuntimeThreadAicpuStatus::INVALID_PARAM);
847}961}
848 962 
849} // namespace963} // namespace
@@ -38,15 +38,21 @@ namespace {
38struct PluginState {38struct PluginState {
39 RuntimeThreadAicpuStatus queryStatus = RuntimeThreadAicpuStatus::OK;39 RuntimeThreadAicpuStatus queryStatus = RuntimeThreadAicpuStatus::OK;
40 RuntimeThreadAicpuStatus prepareStatus = RuntimeThreadAicpuStatus::OK;40 RuntimeThreadAicpuStatus prepareStatus = RuntimeThreadAicpuStatus::OK;
41+ RuntimeThreadAicpuStatus startStatus = RuntimeThreadAicpuStatus::OK;
42+ RuntimeThreadAicpuStatus loadStatus = RuntimeThreadAicpuStatus::OK;
41 bool returnNullApi = false;43 bool returnNullApi = false;
42 uint32_t prepareCalls = 0U;44 uint32_t prepareCalls = 0U;
43 uint32_t releaseCalls = 0U;45 uint32_t releaseCalls = 0U;
44 uint32_t streamDestroyedCalls = 0U;46 uint32_t streamDestroyedCalls = 0U;
47+ uint32_t startCalls = 0U;
48+ uint32_t loadCalls = 0U;
45 uint64_t releasedCookie = 0U;49 uint64_t releasedCookie = 0U;
46 void* destroyedStream = nullptr;50 void* destroyedStream = nullptr;
47 RuntimeThreadAicpuKernelRequest request = {};51 RuntimeThreadAicpuKernelRequest request = {};
48 RuntimeThreadAicpuRuntimeHooks hooks = {};52 RuntimeThreadAicpuRuntimeHooks hooks = {};
49 RuntimeThreadAicpuPreparedKernel prepared = {};53 RuntimeThreadAicpuPreparedKernel prepared = {};
54+ RuntimeThreadAicpuStartRequest startRequest = {};
55+ RuntimeThreadAicpuDumpInfoRequest loadRequest = {};
50};56};
51 57 
52PluginState g_plugin;58PluginState g_plugin;
@@ -80,6 +86,24 @@ void FakeStreamDestroyed(void* const streamHandle)
80 g_plugin.destroyedStream = streamHandle;86 g_plugin.destroyedStream = streamHandle;
81}87}
82 88 
89+RuntimeThreadAicpuStatus FakeStartWorker(const RuntimeThreadAicpuStartRequest* const request)
90+{
91+ ++g_plugin.startCalls;
92+ if (request != nullptr) {
93+ g_plugin.startRequest = *request;
94+ }
95+ return g_plugin.startStatus;
96+}
97+ 
98+RuntimeThreadAicpuStatus FakeLoadDumpInfo(const RuntimeThreadAicpuDumpInfoRequest* const request)
99+{
100+ ++g_plugin.loadCalls;
101+ if (request != nullptr) {
102+ g_plugin.loadRequest = *request;
103+ }
104+ return g_plugin.loadStatus;
105+}
106+ 
83RuntimeThreadAicpuStatus FakeQueryPlugin(107RuntimeThreadAicpuStatus FakeQueryPlugin(
84 const RuntimeThreadAicpuRuntimeHooks* const hooks, const RuntimeThreadAicpuPluginApi** const pluginApi)108 const RuntimeThreadAicpuRuntimeHooks* const hooks, const RuntimeThreadAicpuPluginApi** const pluginApi)
85{109{
@@ -165,6 +189,8 @@ protected:
165 .prepareKernel = &FakePrepareKernel,189 .prepareKernel = &FakePrepareKernel,
166 .releasePreparedKernel = &FakeReleasePreparedKernel,190 .releasePreparedKernel = &FakeReleasePreparedKernel,
167 .streamDestroyed = &FakeStreamDestroyed,191 .streamDestroyed = &FakeStreamDestroyed,
192+ .startWorker = &FakeStartWorker,
193+ .loadDumpInfo = &FakeLoadDumpInfo,
168 };194 };
169 g_plugin.prepared.structSize = sizeof(RuntimeThreadAicpuPreparedKernel);195 g_plugin.prepared.structSize = sizeof(RuntimeThreadAicpuPreparedKernel);
170 g_plugin.prepared.callbackCqId = 23U;196 g_plugin.prepared.callbackCqId = 23U;
@@ -368,7 +394,7 @@ TEST_F(RuntimeThreadAicpuRuntimeTest, AdapterValidatesPluginApiTable)
368 394 
369 MockSuccessfulDynamicLoad();395 MockSuccessfulDynamicLoad();
370 g_plugin.returnNullApi = false;396 g_plugin.returnNullApi = false;
371- g_pluginApi.structSize = sizeof(g_pluginApi) - 1U;397+ g_pluginApi.structSize = sizeof(RuntimeThreadAicpuPluginApi) - 1U;
372 RuntimeThreadAicpuAdapter shortApiAdapter(nullptr);398 RuntimeThreadAicpuAdapter shortApiAdapter(nullptr);
373 EXPECT_EQ(shortApiAdapter.PrepareKernel(request, prepared), RT_ERROR_FEATURE_NOT_SUPPORT);399 EXPECT_EQ(shortApiAdapter.PrepareKernel(request, prepared), RT_ERROR_FEATURE_NOT_SUPPORT);
374 GlobalMockObject::verify();400 GlobalMockObject::verify();
@@ -380,6 +406,40 @@ TEST_F(RuntimeThreadAicpuRuntimeTest, AdapterValidatesPluginApiTable)
380 EXPECT_EQ(missingFunctionAdapter.PrepareKernel(request, prepared), RT_ERROR_FEATURE_NOT_SUPPORT);406 EXPECT_EQ(missingFunctionAdapter.PrepareKernel(request, prepared), RT_ERROR_FEATURE_NOT_SUPPORT);
381}407}
382 408 
409+TEST_F(RuntimeThreadAicpuRuntimeTest, AdapterRejectsMissingDataDumpFunctions)
410+{
411+ MockSuccessfulDynamicLoad();
412+ g_pluginApi.startWorker = nullptr;
413+ RuntimeThreadAicpuAdapter missingStartWorkerAdapter(nullptr);
414+ RuntimeThreadAicpuKernelRequest request = {};
415+ EXPECT_EQ(missingStartWorkerAdapter.LoadDumpInfo(0U, 0U, &request, sizeof(request)), RT_ERROR_FEATURE_NOT_SUPPORT);
416+ GlobalMockObject::verify();
417+ 
418+ MockSuccessfulDynamicLoad();
419+ g_pluginApi.startWorker = &FakeStartWorker;
420+ g_pluginApi.loadDumpInfo = nullptr;
421+ RuntimeThreadAicpuAdapter missingLoadDumpInfoAdapter(nullptr);
422+ EXPECT_EQ(missingLoadDumpInfoAdapter.LoadDumpInfo(0U, 0U, &request, sizeof(request)), RT_ERROR_FEATURE_NOT_SUPPORT);
423+}
424+ 
425+TEST_F(RuntimeThreadAicpuRuntimeTest, AdapterStartsWorkerBeforeLoadingDataDumpInfo)
426+{
427+ MockSuccessfulDynamicLoad();
428+ RuntimeThreadAicpuAdapter adapter(nullptr);
429+ const uint32_t dumpInfo = 0x12345678U;
430+ ASSERT_EQ(adapter.LoadDumpInfo(3U, 2U, &dumpInfo, sizeof(dumpInfo)), RT_ERROR_NONE);
431+ EXPECT_EQ(g_plugin.startCalls, 1U);
432+ EXPECT_EQ(g_plugin.loadCalls, 1U);
433+ EXPECT_EQ(g_plugin.startRequest.deviceId, 3U);
434+ EXPECT_EQ(g_plugin.startRequest.tsId, 2U);
435+ EXPECT_EQ(g_plugin.loadRequest.dumpInfo, &dumpInfo);
436+ EXPECT_EQ(g_plugin.loadRequest.length, sizeof(dumpInfo));
437+ 
438+ g_plugin.startStatus = RuntimeThreadAicpuStatus::RUNTIME_ERROR;
439+ EXPECT_EQ(adapter.LoadDumpInfo(3U, 2U, &dumpInfo, sizeof(dumpInfo)), RT_ERROR_AICPU_INTERNAL_ERROR);
440+ EXPECT_EQ(g_plugin.loadCalls, 1U);
441+}
442+ 
383TEST_F(RuntimeThreadAicpuRuntimeTest, AdapterPropagatesPrepareAndForwardsLifecycleCalls)443TEST_F(RuntimeThreadAicpuRuntimeTest, AdapterPropagatesPrepareAndForwardsLifecycleCalls)
384{444{
385 MockSuccessfulDynamicLoad();445 MockSuccessfulDynamicLoad();
@@ -593,6 +653,29 @@ TEST_F(RuntimeThreadAicpuRuntimeTest, PublicLaunchPropagatesWaitAndResetFailures
593 EXPECT_EQ(g_plugin.prepareCalls, 2U);653 EXPECT_EQ(g_plugin.prepareCalls, 2U);
594}654}
595 655 
656+TEST_F(RuntimeThreadAicpuRuntimeTest, DataDumpInfoLoadValidatesFlagAndContext)
657+{
658+ ApiImpl api;
659+ const uint32_t dumpInfo = 0x12345678U;
660+ EXPECT_EQ(api.DatadumpInfoLoad(&dumpInfo, sizeof(dumpInfo), RT_KERNEL_CUSTOM_AICPU), RT_ERROR_FEATURE_NOT_SUPPORT);
661+ 
662+ MOCKER_CPP(&ApiImpl::CurrentContext).stubs().will(returnValue(static_cast<Context*>(nullptr)));
663+ EXPECT_EQ(api.DatadumpInfoLoad(&dumpInfo, sizeof(dumpInfo), RT_KERNEL_DEFAULT), RT_ERROR_CONTEXT_NULL);
664+}
665+ 
666+TEST_F(RuntimeThreadAicpuRuntimeTest, DataDumpInfoLoadRoutesToRuntimeThreadFeature)
667+{
668+ ApiImpl api;
669+ RuntimeThreadAicpuTestDevice device(3U);
670+ Context context(&device, false);
671+ const uint32_t dumpInfo = 0x12345678U;
672+ MOCKER_CPP(&ApiImpl::CurrentContext).stubs().will(returnValue(&context));
673+ MOCKER(ContextManage::CheckContextIsValid).stubs().will(returnValue(true));
674+ MOCKER(LoadRuntimeThreadAicpuDumpInfo).stubs().will(returnValue(RT_ERROR_DRV_ERR));
675+ 
676+ EXPECT_EQ(api.DatadumpInfoLoad(&dumpInfo, sizeof(dumpInfo), RT_KERNEL_DEFAULT), RT_ERROR_DRV_ERR);
677+}
678+ 
596TEST_F(RuntimeThreadAicpuRuntimeTest, CpuKernelLaunchExValidatesKernelContract)679TEST_F(RuntimeThreadAicpuRuntimeTest, CpuKernelLaunchExValidatesKernelContract)
597{680{
598 ApiImpl api;681 ApiImpl api;
@@ -320,11 +320,38 @@ TEST_F(Arch5162TaskTest, ConstructAICoreSqeForDavinciTask)
320 TaskInfo taskInfo = {};320 TaskInfo taskInfo = {};
321 taskInfo.stream = stream;321 taskInfo.stream = stream;
322 taskInfo.u.aicTaskInfo.kernel = nullptr;322 taskInfo.u.aicTaskInfo.kernel = nullptr;
323+ taskInfo.u.aicTaskInfo.comm.dim = 13U;
323 taskInfo.type = TS_TASK_TYPE_KERNEL_AICORE;324 taskInfo.type = TS_TASK_TYPE_KERNEL_AICORE;
324 rtStarsSqe_t sqe = {};325 rtStarsSqe_t sqe = {};
325 memset_s(&sqe, sizeof(sqe), 0, sizeof(sqe));326 memset_s(&sqe, sizeof(sqe), 0, sizeof(sqe));
326 ConstructAICoreSqeForDavinciTask(&taskInfo, &sqe, TaskSqeInfo{0ULL, 0ULL});327 ConstructAICoreSqeForDavinciTask(&taskInfo, &sqe, TaskSqeInfo{0ULL, 0ULL});
327 EXPECT_EQ(sqe.aicAivKernelSqe.header.type, TS_TASK_TYPE_KERNEL_AICORE);328 EXPECT_EQ(sqe.aicAivKernelSqe.header.type, TS_TASK_TYPE_KERNEL_AICORE);
329+ EXPECT_EQ(sqe.aicAivKernelSqe.header.u.blockDim, 13U);
330+ EXPECT_EQ(sqe.aicAivKernelSqe.header.postP, RT_STARS_SQE_INT_DIR_NO);
331+ EXPECT_EQ(sqe.aicAivKernelSqe.res7[1U], 0U);
332+ delete stream;
333+ delete device;
334+}
335+ 
336+TEST_F(Arch5162TaskTest, ConstructAICoreSqeEnablesDataDumpWithoutChangingBlockDim)
337+{
338+ MOCKER(GetAicoreKernelCredit).stubs().will(returnValue((uint16_t)0));
339+ RawDevice* device = new RawDevice(0);
340+ Stream* stream = new Stream(device, 0);
341+ ASSERT_NE(stream, nullptr);
342+ TaskInfo taskInfo = {};
343+ taskInfo.stream = stream;
344+ taskInfo.u.aicTaskInfo.kernel = nullptr;
345+ taskInfo.u.aicTaskInfo.comm.dim = 17U;
346+ taskInfo.u.aicTaskInfo.comm.kernelFlag = RT_KERNEL_DUMPFLAG;
347+ taskInfo.type = TS_TASK_TYPE_KERNEL_AICORE;
348+ rtStarsSqe_t sqe = {};
349+ 
350+ ConstructAICoreSqeForDavinciTask(&taskInfo, &sqe, TaskSqeInfo{0ULL, 0ULL});
351+ 
352+ EXPECT_EQ(sqe.aicAivKernelSqe.header.u.blockDim, 17U);
353+ EXPECT_EQ(sqe.aicAivKernelSqe.header.postP, RT_STARS_SQE_INT_DIR_TO_TSCPU);
354+ EXPECT_EQ(sqe.aicAivKernelSqe.res7[1U] & SQE_BIZ_FLAG_DATADUMP, SQE_BIZ_FLAG_DATADUMP);
328 delete stream;355 delete stream;
329 delete device;356 delete device;
330}357}