已关闭
[feat] arch5162 support datadump #5290
FengHaozhan创建于 12 天前关闭于 10 天前
[feat] arch5162 support datadump #5290
已关闭
共 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 | ||
| 28 | enum class RuntimeThreadAicpuSqeSubtype : uint32_t { | 35 | enum class RuntimeThreadAicpuSqeSubtype : uint32_t { |
| 29 | AICPU = 22U, | 36 | AICPU = 22U, |
| 37 | + DATADUMP = 23U, | ||
| 30 | }; | 38 | }; |
| 31 | 39 | ||
| 32 | struct RuntimeThreadAicpuRuntimeHooks { | 40 | struct 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 | + | ||
| 76 | struct RuntimeThreadAicpuPluginApi { | 98 | struct 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 | ||
| 84 | using RuntimeThreadAicpuGetPluginApiFunc = RuntimeThreadAicpuStatus (*)( | 108 | using RuntimeThreadAicpuGetPluginApiFunc = RuntimeThreadAicpuStatus (*)( |
| @@ -12,6 +12,9 @@ set(RUNTIME_THREAD_AICPU_RUNTIME_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) | |||
| 12 | set(RUNTIME_THREAD_AICPU_CONTEXT_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/../aicpu_sharder/aicpu_context.cc) | 12 | set(RUNTIME_THREAD_AICPU_CONTEXT_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/../aicpu_sharder/aicpu_context.cc) |
| 13 | 13 | ||
| 14 | add_library(runtime_thread_aicpu SHARED | 14 | add_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.cc | 18 | runtime_thread_aicpu_plugin.cc |
| 16 | runtime_thread_aicpu_service.cc | 19 | runtime_thread_aicpu_service.cc |
| 17 | runtime_thread_aicpu_so_manager.cc | 20 | 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 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 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 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 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 | + | ||
| @@ -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 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 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 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 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 | + | ||
| @@ -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 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 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 | + | ||
| 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 | + | ||
| 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 | + | ||
| @@ -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 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 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 | + | ||
| @@ -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 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 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 | + | ||
| @@ -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 | + | ||
| 53 | const RuntimeThreadAicpuPluginApi PLUGIN_API = { | 76 | const 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 | } // namespace | 85 | } // namespace |
| @@ -35,6 +35,11 @@ constexpr int32_t REPORT_WAIT_TIMEOUT_MS = 1000; | |||
| 35 | constexpr uint8_t CALLBACK_EVENT_RECORD_COMMAND = 15U; | 35 | constexpr uint8_t CALLBACK_EVENT_RECORD_COMMAND = 15U; |
| 36 | constexpr char RUN_KERNEL_WITH_BLOCK[] = "RunCpuKernelWithBlock"; | 36 | constexpr char RUN_KERNEL_WITH_BLOCK[] = "RunCpuKernelWithBlock"; |
| 37 | 37 | ||
| 38 | +enum class CallbackReportType : uint8_t { | ||
| 39 | + AICPU = 0U, | ||
| 40 | + DATADUMP = 1U, | ||
| 41 | +}; | ||
| 42 | + | ||
| 38 | struct CallbackReport { | 43 | struct 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 | + | ||
| 436 | void RuntimeThreadAicpuService::ReleasePreparedKernel(const uint64_t taskCookie) | 481 | void 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 | + | ||
| 574 | RuntimeThreadAicpuStatus RuntimeThreadAicpuService::FinishReport( | 633 | RuntimeThreadAicpuStatus 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 | 20 | ||
| 21 | 21 | ||
| 22 | 22 | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 23 | 26 | ||
| 24 | 27 | ||
| 25 | namespace cce { | 28 | namespace 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 | ||
| 90 | void SetRuntimeThreadAicpuService(RuntimeThreadAicpuService* const service); | 100 | void 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 | - | ||
| 1328 | rtError_t ApiImpl::AicpuInfoLoad(const void* const aicpuInfo, const uint32_t length) | 1313 | rtError_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 | |||
| 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); | ||
🔴 Critical:这里把现有 当前 GE V1/OM2 在调用该接口前都会先把 建议先同步生产端与接口契约:要么由 GE 通过明确的 Host-TLV 接口传入完整 TLV,要么保留现有 Device-protobuf 通路;同时补一条从真实 GE 调用形态进入该实现的集成用例。 ![]() ![]() | |||
| 66 | +} | ||
| 67 | + | ||
| 55 | rtError_t ApiImpl::FlushCache(const uint64_t base, const size_t len) | 68 | rtError_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 | 16 | ||
| 17 | 17 | ||
| 18 | 18 | ||
| 19 | + | ||
| 19 | 20 | ||
| 20 | namespace cce { | 21 | namespace cce { |
| 21 | namespace runtime { | 22 | namespace 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 runtime | 72 | } // namespace runtime |
| 57 | } // namespace cce | 73 | } // 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 | + | ||
| 12 | + | ||
| 11 | 13 | ||
| 12 | 14 | ||
| 13 | 15 | ||
| @@ -26,7 +28,8 @@ namespace cce { | |||
| 26 | namespace runtime { | 28 | namespace runtime { |
| 27 | namespace { | 29 | namespace { |
| 28 | constexpr uint32_t DRV_CALLBACK_GROUPID = 11U; // Driver-defined callback group ID. | 30 | constexpr 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 | 34 | ||
| 32 | void ConstructAICoreSqeForDavinciTask(TaskInfo* const taskInfo, void* const sqeBuffer, const TaskSqeInfo& sqeInfo) | 35 | void 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"; | |||
| 92 | static_assert( | 92 | static_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 | ||
| 96 | RuntimeThreadAicpuStatus ToPluginStatus(const rtError_t error) | 99 | RuntimeThreadAicpuStatus 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: | ||
| 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 runtime | 548 | } // namespace runtime |
| 507 | } // namespace cce | 549 | } // 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 runtime | 30 | } // namespace runtime |
| 28 | } // namespace cce | 31 | } // namespace cce |
| 29 | 32 | ||
| @@ -12,7 +12,11 @@ set(RUNTIME_THREAD_AICPU_SRC_PATH ${AICPU_SCHED_PATH}/runtime_thread_aicpu) | |||
| 12 | 12 | ||
| 13 | add_executable(runtime_thread_aicpu_utest | 13 | add_executable(runtime_thread_aicpu_utest |
| 14 | main_ut.cc | 14 | main_ut.cc |
| 15 | + data_dump_ut.cc | ||
| 15 | runtime_thread_aicpu_ut.cc | 16 | 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.cc | 20 | ${RUNTIME_THREAD_AICPU_SRC_PATH}/runtime_thread_aicpu_plugin.cc |
| 17 | ${RUNTIME_THREAD_AICPU_SRC_PATH}/runtime_thread_aicpu_service.cc | 21 | ${RUNTIME_THREAD_AICPU_SRC_PATH}/runtime_thread_aicpu_service.cc |
| 18 | ${RUNTIME_THREAD_AICPU_SRC_PATH}/runtime_thread_aicpu_so_manager.cc | 22 | ${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 | ||
| 448 | TEST_F(RuntimeThreadAicpuTest, CompletionEventIsCachedAndDestroyedWithStream) | 469 | TEST_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 | ||
| 679 | TEST_F(RuntimeThreadAicpuTest, FinishReportWritesCompletionCommandAndStreamError) | 727 | TEST_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 | ||
| 742 | TEST_F(RuntimeThreadAicpuTest, ProcessReportsHandlesWaitAndCqSelection) | 815 | TEST_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 | + | ||
| 812 | TEST_F(RuntimeThreadAicpuTest, WorkerLoopMarksUnexpectedDriverFailure) | 922 | TEST_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 | } // namespace | 963 | } // namespace |
| @@ -38,15 +38,21 @@ namespace { | |||
| 38 | struct PluginState { | 38 | struct 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 | ||
| 52 | PluginState g_plugin; | 58 | PluginState 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 | + | ||
| 83 | RuntimeThreadAicpuStatus FakeQueryPlugin( | 107 | RuntimeThreadAicpuStatus 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 | + | ||
| 383 | TEST_F(RuntimeThreadAicpuRuntimeTest, AdapterPropagatesPrepareAndForwardsLifecycleCalls) | 443 | TEST_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 | + | ||
| 596 | TEST_F(RuntimeThreadAicpuRuntimeTest, CpuKernelLaunchExValidatesKernelContract) | 679 | TEST_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 | } |


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