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 :
11 : #include "atrace_client_core.h"
12 : #include "atrace_client_communication.h"
13 : #include "atrace_client_thread.h"
14 : #include "adiag_print.h"
15 : #include "trace_attr.h"
16 : #include "trace_msg.h"
17 : #include "trace_recorder.h"
18 : #include "trace_types.h"
19 : #include "trace_system_api.h"
20 :
21 : #define HOST_AI_DEVID 64
22 : #define MAX_RETRY_TIME 3
23 : #define TEN_MILLISECOND (10 * 1000) // 10 milliseconds
24 : #define RECV_BUFF_SIZE (512U * 1024U + (uint32_t)sizeof(TraceEventMsg)) // 512K + head
25 :
26 44 : STATIC void AtraceClientWriteEventLog(char* data, uint32_t len)
27 : {
28 44 : TraceMsgInfo info = {0};
29 44 : (void)AtraceClientParseEventMsg(data, len, &info);
30 : // write to file
31 44 : TraceDirInfo dirInfo = {TRACER_SCHEDULE_NAME, TraceGetPid(), info.eventTime, true};
32 44 : TraceFileInfo fileInfo = {0};
33 44 : fileInfo.tracerName = TRACER_SCHEDULE_NAME;
34 44 : fileInfo.objName = info.eventName;
35 44 : if (info.saveType == FILE_SAVE_MODE_BIN) {
36 0 : fileInfo.suffix = TRACE_FILE_BIN_SUFFIX;
37 : } else {
38 44 : fileInfo.suffix = TRACE_FILE_TXT_SUFFIX;
39 : }
40 44 : int32_t fd = -1;
41 44 : if (TraceRecorderGetFd(&dirInfo, &fileInfo, &fd) != TRACE_SUCCESS) {
42 0 : ADIAG_ERR("get event fd failed, event name=%s.", info.eventName);
43 0 : return;
44 : }
45 44 : TraStatus ret = TraceRecorderWrite(fd, info.buf, info.bufLen);
46 44 : if (ret != TRACE_SUCCESS) {
47 0 : ADIAG_ERR("write to file failed, ret = %d, strerr = %s.", ret, strerror(AdiagGetErrorCode()));
48 : }
49 44 : TraceClose(&fd);
50 : }
51 :
52 198 : STATIC void AtraceClientRecvAndWrite(int32_t devId, int32_t timeout, void** handle)
53 : {
54 198 : char* data = (char*)AdiagMalloc(RECV_BUFF_SIZE);
55 198 : if (data == NULL) {
56 0 : ADIAG_ERR("malloc buffer failed, devId=%d.", devId);
57 0 : return;
58 : }
59 198 : uint32_t bufLen = 0;
60 198 : int32_t retryTime = 0;
61 198 : TraStatus ret = TRACE_FAILURE;
62 198 : int32_t recvTimeout = timeout / MAX_RETRY_TIME;
63 18414 : while (retryTime < MAX_RETRY_TIME) {
64 18238 : if (!AtraceClientIsHandleValid(*handle)) { // handle is invalid
65 0 : AtraceClientReleaseHandle(handle);
66 0 : if (AtraceThreadGetStatus(devId) == THREAD_STATUS_WAIT_EXIT) {
67 0 : break;
68 : }
69 0 : ret = AtraceClientCreateLongLink(devId, timeout, handle);
70 0 : if (ret == TRACE_SUCCESS) {
71 0 : continue;
72 : }
73 0 : (void)usleep(TEN_MILLISECOND); // sleep 10ms
74 0 : continue;
75 : }
76 18238 : bufLen = RECV_BUFF_SIZE;
77 18238 : ret = AtraceClientRecv(*handle, (char**)&data, &bufLen, recvTimeout);
78 18238 : if (AtraceThreadGetStatus(devId) == THREAD_STATUS_WAIT_EXIT) {
79 528 : retryTime++;
80 : }
81 18238 : if ((ret != TRACE_SUCCESS) || (bufLen == 0U)) {
82 18150 : (void)usleep(TEN_MILLISECOND); // sleep 10ms
83 18150 : continue;
84 : }
85 :
86 88 : if (AtraceClientIsEventMsg(data, bufLen)) {
87 44 : ADIAG_DBG("atrace client receive event msg, buffer len = %u bytes.", bufLen);
88 44 : retryTime = 0;
89 : // write to file
90 44 : AtraceClientWriteEventLog(data, bufLen);
91 44 : } else if (AtraceClientIsEndMsg(data, bufLen)) {
92 22 : ADIAG_RUN_INF("receive end msg, devId=%d.", devId);
93 22 : break;
94 : } else {
95 22 : ADIAG_ERR("message is invalid, devId=%d.", devId);
96 : }
97 : }
98 198 : ADIAG_SAFE_FREE(data);
99 : }
100 :
101 : /**
102 : * @brief : atrace client thread run function
103 : * @param [in] : pArgs pointer of thread args
104 : * @return : NA
105 : */
106 220 : STATIC void* AtraceClientRecvThread(void* pArgs)
107 : {
108 220 : if (pArgs == NULL) {
109 0 : ADIAG_ERR("args is null.");
110 0 : return NULL;
111 : }
112 220 : if (TraceSetThreadName("TraceClientRecv") != TRACE_SUCCESS) {
113 22 : ADIAG_WAR("can not set thread name(TraceClientRecv) but continue.");
114 : }
115 220 : const int32_t devId = ((TraceThreadArgs*)pArgs)->devId;
116 :
117 220 : int32_t timeout = TraceGetTimeout();
118 220 : void* handle = NULL;
119 220 : TraStatus ret = AtraceClientCreateLongLink(devId, timeout, &handle);
120 220 : if (ret != TRACE_SUCCESS) {
121 22 : ADIAG_WAR("create long link failed, devId=%d.", devId);
122 22 : return NULL;
123 : }
124 198 : const int32_t timeReserve = 2000; // 2s for receive thread waiting device timeout exit
125 198 : AtraceClientRecvAndWrite(devId, timeout + timeReserve, &handle);
126 198 : AtraceClientReleaseHandle(&handle);
127 198 : ADIAG_RUN_INF("atrace receive thread exited, devId=%d.", devId);
128 198 : return NULL;
129 : }
130 :
131 264 : TraStatus AtraceClientStart(int32_t devId)
132 : {
133 264 : if ((devId >= HOST_MAX_DEV_NUM) || (devId < 0)) {
134 22 : ADIAG_ERR("atrace client start failed, device id [%d] is invalid.", devId);
135 22 : return TRACE_INVALID_PARAM;
136 : }
137 242 : if (devId == HOST_AI_DEVID) {
138 0 : ADIAG_INF("devId[%d] no need to create a thread.", devId);
139 0 : return TRACE_SUCCESS;
140 : }
141 :
142 242 : if (AtraceThreadSingleTask(devId)) {
143 0 : ADIAG_RUN_INF("thread has been started, devId=%d.", devId);
144 0 : return TRACE_SUCCESS;
145 : }
146 :
147 242 : TraStatus ret = AtraceClientSendHello(devId);
148 242 : if (ret != TRACE_SUCCESS) {
149 22 : ADIAG_WAR("can not send hello, devId=%d.", devId);
150 22 : return TRACE_UNSUPPORTED;
151 : }
152 : // create thread to receive device trace log
153 220 : TraceThreadArgs args = {devId};
154 220 : ret = AtraceThreadCreate(devId, &args, AtraceClientRecvThread);
155 220 : if (ret != TRACE_SUCCESS) {
156 0 : ADIAG_ERR("create thread failed, devId=%d, ret=%d.", devId, ret);
157 0 : return TRACE_FAILURE;
158 : }
159 :
160 220 : ADIAG_RUN_INF("start to receive device[%d] trace log.", devId);
161 220 : return TRACE_SUCCESS;
162 : }
163 :
164 220 : void AtraceClientStop(int32_t devId)
165 : {
166 220 : if ((devId >= HOST_MAX_DEV_NUM) || (devId < 0)) {
167 22 : ADIAG_ERR("stop report failed, device id is invalid, devId=%d.", devId);
168 22 : return;
169 : }
170 198 : if (devId == HOST_AI_DEVID) {
171 0 : ADIAG_INF("devId[%d] no need to stop a thread.", devId);
172 0 : return;
173 : }
174 :
175 198 : AtraceThreadRelease(devId, AtraceClientSendEnd, true);
176 198 : ADIAG_RUN_INF("stop to receive device[%d] trace log.", devId);
177 : }
178 :
179 1017 : TraStatus AtraceClientInit(void)
180 : {
181 : // init thread pool
182 1017 : TraStatus ret = AtraceThreadPoolInit();
183 1017 : ADIAG_CHK_EXPR_ACTION(ret != TRACE_SUCCESS, return ret, "init thread pool failed.");
184 :
185 1017 : ADIAG_INF("init atrace client successfully.");
186 1017 : return TRACE_SUCCESS;
187 : }
188 :
189 : /**
190 : * @brief : stub stop function used in process-exit destructor.
191 : * Skips sending [end] over HDC because runtime/HDC resources may
192 : * already be torn down (e.g. when Runtime::DeviceRelease is bypassed
193 : * in isExiting_ path). Sending [end] there would re-create an HDC
194 : * session and trigger hdc_ub_connect/register_urma_seg failures.
195 : * Recv threads still exit safely via THREAD_STATUS_WAIT_EXIT set by
196 : * AtraceThreadRelease.
197 : */
198 88 : STATIC int32_t AtraceClientExitNoSend(int32_t devId)
199 : {
200 : (void)devId;
201 88 : return TRACE_SUCCESS;
202 : }
203 :
204 1073 : void AtraceClientExit(void)
205 : {
206 : // release all receive thread; do not send [end] in destructor path
207 1073 : AtraceThreadPoolExit(AtraceClientExitNoSend);
208 1073 : }
|