Line data Source code
1 : /**
2 : * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3 : * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4 : * CANN Open Software License Agreement Version 2.0 (the "License").
5 : * Please refer to the License for details. You may not use this file except in compliance with the License.
6 : * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7 : * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8 : * See LICENSE in the root of the software repository for the full text of the License.
9 : */
10 : #include "ascend_hal.h"
11 : #include "protocol/adx_msg_proto.h"
12 : #include "adx_datadump_callback.h"
13 : #include "log/adx_log.h"
14 : #include "memory_utils.h"
15 : #include "hdc_api.h"
16 : #include "adcore_api.h"
17 : #include "string_utils.h"
18 : #include "create_func.h"
19 : #include "sys_utils.h"
20 : #include "config.h"
21 : #include "adx_dump_hdc_helper.h"
22 :
23 : namespace Adx {
24 1 : AdxDumpHdcHelper::AdxDumpHdcHelper() : init_(false)
25 : {
26 1 : client_.type = NR_COMM;
27 1 : client_.session = 0U;
28 1 : client_.comp = NR_COMPONENTS;
29 1 : client_.timeout = 0;
30 1 : client_.client = nullptr;
31 1 : }
32 :
33 1 : AdxDumpHdcHelper::~AdxDumpHdcHelper() { UnInit(); }
34 :
35 2 : bool AdxDumpHdcHelper::Init()
36 : {
37 2 : if (!init_) {
38 1 : std::unique_ptr<AdxCommOpt> opt(CreateAdxCommOpt(OptType::COMM_HDC));
39 1 : IDE_CTRL_VALUE_FAILED(opt != nullptr, return false, "create hdc commopt exception");
40 1 : bool ret = AdxCommOptManager::Instance().CommOptsRegister(opt);
41 1 : IDE_CTRL_VALUE_FAILED(ret, return false, "register hdc failed");
42 1 : std::map<std::string, std::string> info;
43 1 : info[OPT_SERVICE_KEY] = std::to_string(HDC_SERVICE_TYPE_DUMP);
44 1 : client_ = AdxCommOptManager::Instance().OpenClient(OptType::COMM_HDC, info);
45 1 : IDE_CTRL_VALUE_FAILED(client_.session != ADX_OPT_INVALID_HANDLE, return false, "open client failed");
46 1 : IDE_LOGI("dump data client init end<%lu, %d>", client_.session, static_cast<int32_t>(client_.type));
47 1 : init_ = true;
48 1 : }
49 2 : return true;
50 : }
51 :
52 1 : void AdxDumpHdcHelper::UnInit()
53 : {
54 1 : if (init_) {
55 1 : IDE_LOGI("dump data client close <%lu, %d>", client_.session, static_cast<int32_t>(client_.type));
56 1 : HdcClientDestroy(reinterpret_cast<HDC_CLIENT>(client_.session));
57 1 : init_ = false;
58 : }
59 1 : }
60 :
61 : /**
62 : * @brief parse connect info
63 : * @param [in] connectInfo: string of connect info
64 : * @param [in] proto: struct of conect info
65 : *
66 : * @return
67 : * IDE_DAEMON_NONE_ERROR: parse connect info success
68 : * IDE_DAEMON_INVALID_PARAM_ERROR: parse connect info failed
69 : */
70 8 : IdeErrorT AdxDumpHdcHelper::ParseConnectInfo(
71 : const std::string& connectInfo, std::map<std::string, std::string>& proto) const
72 : {
73 8 : std::string hostId;
74 8 : std::string hostPid;
75 8 : bool ret = StringUtils::ParseConnectInfo(connectInfo, hostId, hostPid);
76 8 : IDE_CTRL_VALUE_FAILED(ret == true, return IDE_DAEMON_INVALID_PARAM_ERROR, "ParseConnectInfo failed");
77 5 : std::string helperHostPid;
78 5 : ADX_GET_ENV(MM_ENV_ASCEND_HOSTPID, helperHostPid);
79 5 : if (!helperHostPid.empty() && StringUtils::IsIntDigital(helperHostPid)) {
80 1 : hostPid = helperHostPid;
81 : }
82 5 : proto[OPT_DEVICE_KEY] = hostId;
83 5 : proto[OPT_PID_KEY] = hostPid;
84 5 : return IDE_DAEMON_NONE_ERROR;
85 8 : }
86 :
87 2 : IdeErrorT AdxDumpHdcHelper::HandShake(const std::string& info, IDE_SESSION& session) const
88 : {
89 2 : uint16_t devId = 0;
90 2 : std::map<std::string, std::string> proto;
91 2 : IdeErrorT err = ParseConnectInfo(info, proto);
92 2 : IDE_CTRL_VALUE_FAILED(err == IDE_DAEMON_NONE_ERROR, return err, "parse connect info failed");
93 2 : IDE_LOGI("proto: hostId: %s, hostPid: %s", proto[OPT_DEVICE_KEY].c_str(), proto[OPT_PID_KEY].c_str());
94 2 : CommHandle handle = AdxCommOptManager::Instance().Connect(client_, proto);
95 2 : IDE_CTRL_VALUE_FAILED(
96 : handle.session != ADX_OPT_INVALID_HANDLE, return IDE_DAEMON_INVALID_PARAM_ERROR, "dump data connect failed");
97 2 : err = AdxMsgProto::SendResponse(handle, IDE_DUMP_REQ, devId, MsgStatus::MSG_STATUS_HAND_SHAKE);
98 2 : IDE_CTRL_VALUE_FAILED(err == IDE_DAEMON_NONE_ERROR, return err, "dump data handshake failed");
99 :
100 1 : err = AdxMsgProto::RecvResponse(handle);
101 1 : IDE_CTRL_VALUE_FAILED(err == IDE_DAEMON_NONE_ERROR, return err, "dump data handshake response failed");
102 :
103 1 : session = reinterpret_cast<HDC_SESSION>(handle.session);
104 1 : IDE_LOGD("handshake success");
105 1 : return IDE_DAEMON_NONE_ERROR;
106 2 : }
107 :
108 3 : IdeErrorT AdxDumpHdcHelper::DataProcess(const IDE_SESSION& session, const IdeDumpChunk& dumpChunk)
109 : {
110 3 : uint32_t dataLen = 0;
111 : // malloc memory for save user data
112 3 : IDE_RETURN_IF_CHECK_ASSIGN_32U_ADD(
113 : sizeof(DumpChunk), dumpChunk.bufLen, dataLen, return IDE_DAEMON_INTERGER_REVERSED_ERROR);
114 3 : MsgProto* msg = AdxMsgProto::CreateMsgPacket(IDE_DUMP_REQ, 0, nullptr, dataLen);
115 3 : IDE_CTRL_VALUE_FAILED(msg != nullptr, return IDE_DAEMON_MALLOC_ERROR, "create message failed");
116 3 : std::unique_ptr<MsgProto, decltype(&IdeXfree)> sendDataMsgPtr(msg, IdeXfree);
117 3 : msg = nullptr;
118 3 : DumpChunk* data = reinterpret_cast<DumpChunk*>(sendDataMsgPtr->data);
119 : // check file name length, not longer than IDE_MAX_FILE_PATH
120 3 : IDE_CTRL_VALUE_FAILED(
121 : strlen(dumpChunk.fileName) < IDE_MAX_FILE_PATH, return IDE_DAEMON_INVALID_PATH_ERROR,
122 : "fileName is too long, not longer than %d length", IDE_MAX_FILE_PATH);
123 3 : int32_t err = strcpy_s(data->fileName, MAX_FILE_PATH_LENGTH, dumpChunk.fileName);
124 3 : IDE_CTRL_VALUE_FAILED(
125 : err == EOK, return IDE_DAEMON_INVALID_PATH_ERROR, "copy file name failed, err=%d, strerror=%s", err,
126 : strerror(errno));
127 3 : data->bufLen = dumpChunk.bufLen;
128 3 : data->flag = dumpChunk.flag;
129 3 : data->isLastChunk = dumpChunk.isLastChunk;
130 3 : data->offset = dumpChunk.offset;
131 3 : IDE_LOGI(
132 : "dataLen: %u, bufLen: %u, flag: %d, isLastChunk: %u, offset: %ld, fileName: %s", dataLen, data->bufLen,
133 : data->flag, data->isLastChunk, data->offset, data->fileName);
134 3 : err = memcpy_s(data->dataBuf, data->bufLen, dumpChunk.dataBuf, dumpChunk.bufLen);
135 3 : IDE_CTRL_VALUE_FAILED(err == EOK, return IDE_DAEMON_MEMCPY_ERROR, "memcpy_s data buffer failed, err=%d", err);
136 3 : IDE_LOGI("the data to be sent has been assembled");
137 : CommHandle handle;
138 3 : handle.type = client_.type;
139 3 : handle.session = reinterpret_cast<OptHandle>(session);
140 3 : IdeErrorT code = SessionIsConnected(handle);
141 3 : IDE_CTRL_VALUE_WARN(
142 : code == IDE_DAEMON_NONE_ERROR, return code, "check session status failed, err=%d", static_cast<int32_t>(code));
143 4 : uint32_t ret = AdxCommOptManager::Instance().Write(
144 2 : handle, sendDataMsgPtr.get(), sendDataMsgPtr->sliceLen + sizeof(MsgProto), COMM_OPT_BLOCK);
145 2 : IDE_CTRL_VALUE_WARN(
146 : ret != IDE_DAEMON_SOCK_CLOSE, return IDE_DAEMON_CHANNEL_ERROR,
147 : "write dump data error, session[%zu] has been closed, ret: %d", handle.session, ret);
148 2 : IDE_CTRL_VALUE_FAILED(
149 : ret == IDE_DAEMON_OK, return IDE_DAEMON_WRITE_ERROR, "write dump data error, session: %zu, ret: %d",
150 : handle.session, ret);
151 1 : code = AdxMsgProto::RecvResponse(handle);
152 1 : IDE_CTRL_VALUE_FAILED(
153 : (code == IDE_DAEMON_NONE_ERROR) || (code == IDE_DAEMON_DUMP_QUEUE_FULL), return code,
154 : "send file shake response failed, ret=%d", static_cast<int32_t>(code));
155 1 : IDE_LOGD("dump data process normal");
156 1 : return code;
157 3 : }
158 :
159 3 : IdeErrorT AdxDumpHdcHelper::SessionIsConnected(const CommHandle handle) const
160 : {
161 3 : int32_t status = 0;
162 3 : int32_t ret = AdxGetAttrByCommHandle(&handle, HDC_SESSION_ATTR_STATUS, &status);
163 3 : if (ret != IDE_DAEMON_OK || status != HDC_SESSION_STATUS_CONNECT) {
164 1 : IDE_LOGW("session[%zu] is not connected, ret: %d, status: %d", handle.session, ret, status);
165 1 : return IDE_DAEMON_CHANNEL_ERROR;
166 : }
167 2 : return IDE_DAEMON_NONE_ERROR;
168 : }
169 :
170 1 : IdeErrorT AdxDumpHdcHelper::Finish(IDE_SESSION& session)
171 : {
172 : CommHandle handle;
173 1 : handle.type = client_.type;
174 1 : handle.session = reinterpret_cast<OptHandle>(session);
175 : // 直接关闭会话,不再发送MSG_STATUS_DATA_END消息
176 1 : AdxCommOptManager::Instance().Close(handle);
177 1 : session = nullptr;
178 1 : return IDE_DAEMON_NONE_ERROR;
179 : }
180 :
181 : /**
182 : * @brief dump start api,create a HDC session for dump
183 : * @param [in] connectInfo: remote connect info
184 : *
185 : * @return
186 : * not NULL: Handle used by hdc
187 : * NULL: dump start failed
188 : */
189 2 : IDE_SESSION HdcDumpStart(const char* connectInfo)
190 : {
191 2 : IDE_CTRL_VALUE_FAILED(
192 : connectInfo != nullptr && strlen(connectInfo) != 0, return nullptr, "dump start msg is empty");
193 2 : if (!Adx::AdxDumpHdcHelper::Instance().Init()) {
194 0 : return nullptr;
195 : }
196 2 : IDE_SESSION session = nullptr;
197 2 : std::string connectInfoStr = std::string(connectInfo);
198 2 : Adx::AdxDumpHdcHelper::Instance().HandShake(connectInfoStr, session);
199 2 : return session;
200 2 : }
201 :
202 : /**
203 : * @brief dump data to remote server
204 : * @param [in] session: HDC session to dump data
205 : * @param [in] dumpChunk: Dump information
206 : * @return
207 : * IDE_DAEMON_INVALID_PARAM_ERROR: invalid parameter
208 : * IDE_DAEMON_UNKNOW_ERROR: write data failed
209 : * IDE_DAEMON_NONE_ERROR: write data succ
210 : */
211 8 : IdeErrorT HdcDumpData(const IDE_SESSION session, const IdeDumpChunk* dumpChunk)
212 : {
213 : IdeErrorT ret;
214 8 : IDE_CTRL_VALUE_FAILED(session != nullptr, return IDE_DAEMON_INVALID_PARAM_ERROR, "session is nullptr");
215 5 : IDE_CTRL_VALUE_FAILED(dumpChunk != nullptr, return IDE_DAEMON_INVALID_PARAM_ERROR, "IdeDumpChunk is nullptr");
216 3 : const uint32_t waitInsertDumpQueueTime = 100;
217 3 : int32_t retryInsertDumpQueueTimes = 3000; // 5min(3000 * 100ms)
218 3 : IDE_LOGD("dump data process entry");
219 : do {
220 3 : ret = Adx::AdxDumpHdcHelper::Instance().DataProcess(session, *dumpChunk);
221 3 : if (ret == IDE_DAEMON_DUMP_QUEUE_FULL) {
222 0 : (void)mmSleep(waitInsertDumpQueueTime);
223 0 : retryInsertDumpQueueTimes--;
224 : }
225 3 : } while (ret == IDE_DAEMON_DUMP_QUEUE_FULL && retryInsertDumpQueueTimes > 0);
226 3 : IDE_LOGD("dump data process exit");
227 3 : return ret;
228 : }
229 :
230 : /**
231 : * @brief send dump end msg
232 : * @param [in] session: HDC session to dump data
233 : * @return
234 : * IDE_DAEMON_UNKNOW_ERROR: send dump end msg failed
235 : * IDE_DAEMON_NONE_ERROR: send dump end msg success
236 : */
237 1 : IdeErrorT HdcDumpEnd(IDE_SESSION session)
238 : {
239 1 : IDE_CTRL_VALUE_FAILED(session != nullptr, return IDE_DAEMON_INVALID_PARAM_ERROR, "session is nullptr");
240 1 : IDE_LOGI("dump data finish");
241 1 : return Adx::AdxDumpHdcHelper::Instance().Finish(session);
242 : }
243 : } // namespace Adx
|