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()
34 : {
35 1 : UnInit();
36 1 : }
37 :
38 2 : bool AdxDumpHdcHelper::Init()
39 : {
40 2 : if (!init_) {
41 1 : std::unique_ptr<AdxCommOpt> opt (CreateAdxCommOpt(OptType::COMM_HDC));
42 1 : IDE_CTRL_VALUE_FAILED(opt != nullptr, return false, "create hdc commopt exception");
43 1 : bool ret = AdxCommOptManager::Instance().CommOptsRegister(opt);
44 1 : IDE_CTRL_VALUE_FAILED(ret, return false, "register hdc failed");
45 1 : std::map<std::string, std::string> info;
46 1 : info[OPT_SERVICE_KEY] = std::to_string(HDC_SERVICE_TYPE_DUMP);
47 1 : client_ = AdxCommOptManager::Instance().OpenClient(OptType::COMM_HDC, info);
48 1 : IDE_CTRL_VALUE_FAILED(client_.session != ADX_OPT_INVALID_HANDLE, return false,
49 : "open client failed");
50 1 : IDE_LOGI("dump data client init end<%lu, %d>", client_.session, static_cast<int32_t>(client_.type));
51 1 : init_ = true;
52 1 : }
53 2 : return true;
54 : }
55 :
56 1 : void AdxDumpHdcHelper::UnInit()
57 : {
58 1 : if (init_) {
59 1 : IDE_LOGI("dump data client close <%lu, %d>", client_.session, static_cast<int32_t>(client_.type));
60 1 : HdcClientDestroy(reinterpret_cast<HDC_CLIENT>(client_.session));
61 1 : init_ = false;
62 : }
63 1 : }
64 :
65 : /**
66 : * @brief parse connect info
67 : * @param [in] connectInfo: string of connect info
68 : * @param [in] proto: struct of conect info
69 : *
70 : * @return
71 : * IDE_DAEMON_NONE_ERROR: parse connect info success
72 : * IDE_DAEMON_INVALID_PARAM_ERROR: parse connect info failed
73 : */
74 8 : IdeErrorT AdxDumpHdcHelper::ParseConnectInfo(const std::string &connectInfo,
75 : std::map<std::string, std::string> &proto) const
76 : {
77 8 : std::string hostId;
78 8 : std::string hostPid;
79 8 : bool ret = StringUtils::ParseConnectInfo(connectInfo, hostId, hostPid);
80 8 : IDE_CTRL_VALUE_FAILED(ret == true, return IDE_DAEMON_INVALID_PARAM_ERROR, "ParseConnectInfo failed");
81 5 : std::string helperHostPid;
82 5 : ADX_GET_ENV(MM_ENV_ASCEND_HOSTPID, helperHostPid);
83 5 : if (!helperHostPid.empty() && StringUtils::IsIntDigital(helperHostPid)) {
84 1 : hostPid = helperHostPid;
85 : }
86 5 : proto[OPT_DEVICE_KEY] = hostId;
87 5 : proto[OPT_PID_KEY] = hostPid;
88 5 : return IDE_DAEMON_NONE_ERROR;
89 8 : }
90 :
91 2 : IdeErrorT AdxDumpHdcHelper::HandShake(const std::string &info, IDE_SESSION &session) const
92 : {
93 2 : uint16_t devId = 0;
94 2 : std::map<std::string, std::string> proto;
95 2 : IdeErrorT err = ParseConnectInfo(info, proto);
96 2 : IDE_CTRL_VALUE_FAILED(err == IDE_DAEMON_NONE_ERROR, return err, "parse connect info failed");
97 2 : IDE_LOGI("proto: hostId: %s, hostPid: %s", proto[OPT_DEVICE_KEY].c_str(), proto[OPT_PID_KEY].c_str());
98 2 : CommHandle handle = AdxCommOptManager::Instance().Connect(client_, proto);
99 2 : IDE_CTRL_VALUE_FAILED(handle.session != ADX_OPT_INVALID_HANDLE,
100 : return IDE_DAEMON_INVALID_PARAM_ERROR, "dump data connect failed");
101 2 : err = AdxMsgProto::SendResponse(handle, IDE_DUMP_REQ, devId, MsgStatus::MSG_STATUS_HAND_SHAKE);
102 2 : IDE_CTRL_VALUE_FAILED(err == IDE_DAEMON_NONE_ERROR, return err, "dump data hand shake failed");
103 :
104 1 : err = AdxMsgProto::RecvResponse(handle);
105 1 : IDE_CTRL_VALUE_FAILED(err == IDE_DAEMON_NONE_ERROR, return err, "dump date shake response failed");
106 :
107 1 : session = reinterpret_cast<HDC_SESSION>(handle.session);
108 1 : IDE_LOGD("handshake success");
109 1 : return IDE_DAEMON_NONE_ERROR;
110 2 : }
111 :
112 3 : IdeErrorT AdxDumpHdcHelper::DataProcess(const IDE_SESSION &session, const IdeDumpChunk &dumpChunk)
113 : {
114 3 : uint32_t dataLen = 0;
115 : // malloc memory for save user data
116 3 : IDE_RETURN_IF_CHECK_ASSIGN_32U_ADD(sizeof(DumpChunk),
117 : dumpChunk.bufLen, dataLen, return IDE_DAEMON_INTERGER_REVERSED_ERROR);
118 3 : MsgProto *msg = AdxMsgProto::CreateMsgPacket(IDE_DUMP_REQ, 0, nullptr, dataLen);
119 3 : IDE_CTRL_VALUE_FAILED(msg != nullptr, return IDE_DAEMON_MALLOC_ERROR, "create message failed");
120 3 : std::unique_ptr<MsgProto, decltype(&IdeXfree)> sendDataMsgPtr(msg, IdeXfree);
121 3 : msg = nullptr;
122 3 : DumpChunk* data = reinterpret_cast<DumpChunk*>(sendDataMsgPtr->data);
123 : // check file name length, not longer than IDE_MAX_FILE_PATH
124 3 : IDE_CTRL_VALUE_FAILED(strlen(dumpChunk.fileName) < IDE_MAX_FILE_PATH, return IDE_DAEMON_INVALID_PATH_ERROR,
125 : "fileName is too long, not longer than %d length", IDE_MAX_FILE_PATH);
126 3 : int32_t err = strcpy_s(data->fileName, MAX_FILE_PATH_LENGTH, dumpChunk.fileName);
127 3 : IDE_CTRL_VALUE_FAILED(err == EOK, return IDE_DAEMON_INVALID_PATH_ERROR,
128 : "copy file name failed, err=%d, strerr=%s", err, strerror(errno));
129 3 : data->bufLen = dumpChunk.bufLen;
130 3 : data->flag = dumpChunk.flag;
131 3 : data->isLastChunk = dumpChunk.isLastChunk;
132 3 : data->offset = dumpChunk.offset;
133 3 : IDE_LOGI("dataLen: %u, bufLen: %u, flag: %d, isLastChunk: %u, offset: %ld, fileName: %s",
134 : dataLen, data->bufLen, data->flag, data->isLastChunk, data->offset, data->fileName);
135 3 : err = memcpy_s(data->dataBuf, data->bufLen, dumpChunk.dataBuf, dumpChunk.bufLen);
136 3 : IDE_CTRL_VALUE_FAILED(err == EOK, return IDE_DAEMON_MEMCPY_ERROR, "memcpy_s data buffer failed, err=%d", err);
137 3 : IDE_LOGI("the data to be sent has been assembled");
138 : CommHandle handle;
139 3 : handle.type = client_.type;
140 3 : handle.session = reinterpret_cast<OptHandle>(session);
141 3 : IdeErrorT code = SessionIsConnected(handle);
142 3 : IDE_CTRL_VALUE_WARN(code == IDE_DAEMON_NONE_ERROR,
143 : return code, "check session status failed, err=%d", static_cast<int32_t>(code));
144 4 : uint32_t ret = AdxCommOptManager::Instance().Write(handle, sendDataMsgPtr.get(),
145 2 : sendDataMsgPtr->sliceLen + sizeof(MsgProto), COMM_OPT_BLOCK);
146 2 : IDE_CTRL_VALUE_WARN(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(ret == IDE_DAEMON_OK, return IDE_DAEMON_WRITE_ERROR,
149 : "write dump data error, session: %zu, ret: %d", handle.session, ret);
150 1 : code = AdxMsgProto::RecvResponse(handle);
151 1 : IDE_CTRL_VALUE_FAILED((code == IDE_DAEMON_NONE_ERROR) || (code == IDE_DAEMON_DUMP_QUEUE_FULL),
152 : return code, "send file shake response failed, ret=%d", static_cast<int32_t>(code));
153 1 : IDE_LOGD("dump data process normal");
154 1 : return code;
155 3 : }
156 :
157 3 : IdeErrorT AdxDumpHdcHelper::SessionIsConnected(const CommHandle handle) const
158 : {
159 3 : int32_t status = 0;
160 3 : int32_t ret = AdxGetAttrByCommHandle(&handle, HDC_SESSION_ATTR_STATUS, &status);
161 3 : if (ret != IDE_DAEMON_OK || status != HDC_SESSION_STATUS_CONNECT) {
162 1 : IDE_LOGW("session[%zu] is not connected, ret: %d, status: %d", handle.session, ret, status);
163 1 : return IDE_DAEMON_CHANNEL_ERROR;
164 : }
165 2 : return IDE_DAEMON_NONE_ERROR;
166 : }
167 :
168 1 : IdeErrorT AdxDumpHdcHelper::Finish(IDE_SESSION &session)
169 : {
170 : CommHandle handle;
171 1 : handle.type = client_.type;
172 1 : handle.session = reinterpret_cast<OptHandle>(session);
173 : // 直接关闭会话,不再发送MSG_STATUS_DATA_END消息
174 1 : AdxCommOptManager::Instance().Close(handle);
175 1 : session = nullptr;
176 1 : return IDE_DAEMON_NONE_ERROR;
177 : }
178 :
179 : /**
180 : * @brief dump start api,create a HDC session for dump
181 : * @param [in] connectInfo: remote connect info
182 : *
183 : * @return
184 : * not NULL: Handle used by hdc
185 : * NULL: dump start failed
186 : */
187 2 : IDE_SESSION HdcDumpStart(const char *connectInfo)
188 : {
189 2 : IDE_CTRL_VALUE_FAILED(connectInfo != nullptr && strlen(connectInfo) != 0,
190 : return nullptr, "dump start msg is empty");
191 2 : if (!Adx::AdxDumpHdcHelper::Instance().Init()) {
192 0 : return nullptr;
193 : }
194 2 : IDE_SESSION session = nullptr;
195 2 : std::string connectInfoStr = std::string(connectInfo);
196 2 : Adx::AdxDumpHdcHelper::Instance().HandShake(connectInfoStr, session);
197 2 : return session;
198 2 : }
199 :
200 : /**
201 : * @brief dump data to remote server
202 : * @param [in] session: HDC session to dump data
203 : * @param [in] dumpChunk: Dump information
204 : * @return
205 : * IDE_DAEMON_INVALID_PARAM_ERROR: invalid parameter
206 : * IDE_DAEMON_UNKNOW_ERROR: write data failed
207 : * IDE_DAEMON_NONE_ERROR: write data succ
208 : */
209 8 : IdeErrorT HdcDumpData(const IDE_SESSION session, const IdeDumpChunk *dumpChunk)
210 : {
211 : IdeErrorT ret;
212 8 : IDE_CTRL_VALUE_FAILED(session != nullptr, return IDE_DAEMON_INVALID_PARAM_ERROR, "session is nullptr");
213 5 : IDE_CTRL_VALUE_FAILED(dumpChunk != nullptr, return IDE_DAEMON_INVALID_PARAM_ERROR, "IdeDumpChunk is nullptr");
214 3 : const uint32_t waitInsertDumpQueueTime = 100;
215 3 : int32_t retryInsertDumpQueueTimes = 3000; // 5min(3000 * 100ms)
216 3 : IDE_LOGD("dump data process entry");
217 : do {
218 3 : ret = Adx::AdxDumpHdcHelper::Instance().DataProcess(session, *dumpChunk);
219 3 : if (ret == IDE_DAEMON_DUMP_QUEUE_FULL) {
220 0 : (void)mmSleep(waitInsertDumpQueueTime);
221 0 : retryInsertDumpQueueTimes--;
222 : }
223 3 : } while (ret == IDE_DAEMON_DUMP_QUEUE_FULL && retryInsertDumpQueueTimes > 0);
224 3 : IDE_LOGD("dump data process exit");
225 3 : return ret;
226 : }
227 :
228 : /**
229 : * @brief send dump end msg
230 : * @param [in] session: HDC session to dump data
231 : * @return
232 : * IDE_DAEMON_UNKNOW_ERROR: send dump end msg failed
233 : * IDE_DAEMON_NONE_ERROR: send dump end msg success
234 : */
235 1 : IdeErrorT HdcDumpEnd(IDE_SESSION session)
236 : {
237 1 : IDE_CTRL_VALUE_FAILED(session != nullptr, return IDE_DAEMON_INVALID_PARAM_ERROR, "session is nullptr");
238 1 : IDE_LOGI("dump data finish");
239 1 : return Adx::AdxDumpHdcHelper::Instance().Finish(session);
240 : }
241 : }
|