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 40 : STATIC void AtraceClientWriteEventLog(char *data, uint32_t len)
27 : {
28 40 : TraceMsgInfo info = { 0 };
29 40 : (void)AtraceClientParseEventMsg(data, len, &info);
30 : // write to file
31 40 : TraceDirInfo dirInfo = { TRACER_SCHEDULE_NAME, TraceGetPid(), info.eventTime, true };
32 40 : TraceFileInfo fileInfo = { 0 };
33 40 : fileInfo.tracerName = TRACER_SCHEDULE_NAME;
34 40 : fileInfo.objName = info.eventName;
35 40 : if (info.saveType == FILE_SAVE_MODE_BIN) {
36 0 : fileInfo.suffix = TRACE_FILE_BIN_SUFFIX;
37 : } else {
38 40 : fileInfo.suffix = TRACE_FILE_TXT_SUFFIX;
39 : }
40 40 : int32_t fd = -1;
41 40 : 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 40 : TraStatus ret = TraceRecorderWrite(fd, info.buf, info.bufLen);
46 40 : if (ret != TRACE_SUCCESS) {
47 0 : ADIAG_ERR("write to file failed, ret = %d, strerr = %s.", ret, strerror(AdiagGetErrorCode()));
48 : }
49 40 : TraceClose(&fd);
50 : }
51 :
52 180 : STATIC void AtraceClientRecvAndWrite(int32_t devId, int32_t timeout, void **handle)
53 : {
54 180 : char *data = (char *)AdiagMalloc(RECV_BUFF_SIZE);
55 180 : if (data == NULL) {
56 0 : ADIAG_ERR("malloc buffer failed, devId=%d.", devId);
57 0 : return;
58 : }
59 180 : uint32_t bufLen = 0;
60 180 : int32_t retryTime = 0;
61 180 : TraStatus ret = TRACE_FAILURE;
62 180 : int32_t recvTimeout = timeout / MAX_RETRY_TIME;
63 16700 : while (retryTime < MAX_RETRY_TIME) {
64 16540 : 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 16540 : bufLen = RECV_BUFF_SIZE;
77 16540 : ret = AtraceClientRecv(*handle, (char **)&data, &bufLen, recvTimeout);
78 16540 : if (AtraceThreadGetStatus(devId) == THREAD_STATUS_WAIT_EXIT) {
79 480 : retryTime++;
80 : }
81 16540 : if ((ret != TRACE_SUCCESS) || (bufLen == 0U)) {
82 16460 : (void)usleep(TEN_MILLISECOND); // sleep 10ms
83 16460 : continue;
84 : }
85 :
86 80 : if (AtraceClientIsEventMsg(data, bufLen)) {
87 40 : ADIAG_DBG("atrace client receive event msg, buffer len = %u bytes.", bufLen);
88 40 : retryTime = 0;
89 : // write to file
90 40 : AtraceClientWriteEventLog(data, bufLen);
91 40 : } else if (AtraceClientIsEndMsg(data, bufLen)) {
92 20 : ADIAG_RUN_INF("receive end msg, devId=%d.", devId);
93 20 : break;
94 : } else {
95 20 : ADIAG_ERR("message is invalid, devId=%d.", devId);
96 : }
97 : }
98 180 : 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 200 : STATIC void* AtraceClientRecvThread(void *pArgs)
107 : {
108 200 : if (pArgs == NULL) {
109 0 : ADIAG_ERR("args is null.");
110 0 : return NULL;
111 : }
112 200 : if (TraceSetThreadName("TraceClientRecv") != TRACE_SUCCESS) {
113 20 : ADIAG_WAR("can not set thread name(TraceClientRecv) but continue.");
114 : }
115 200 : const int32_t devId = ((TraceThreadArgs *)pArgs)->devId;
116 :
117 200 : int32_t timeout = TraceGetTimeout();
118 200 : void *handle = NULL;
119 200 : TraStatus ret = AtraceClientCreateLongLink(devId, timeout, &handle);
120 200 : if (ret != TRACE_SUCCESS) {
121 20 : ADIAG_ERR("create long link failed, devId=%d.", devId);
122 20 : return NULL;
123 : }
124 180 : const int32_t timeReserve = 1000; // 1s for receive thread waiting device timeout exit
125 180 : AtraceClientRecvAndWrite(devId, timeout + timeReserve, &handle);
126 180 : AtraceClientReleaseHandle(&handle);
127 180 : ADIAG_RUN_INF("atrace receive thread exited, devId=%d.", devId);
128 180 : return NULL;
129 : }
130 :
131 240 : TraStatus AtraceClientStart(int32_t devId)
132 : {
133 240 : if ((devId >= HOST_MAX_DEV_NUM) || (devId < 0)) {
134 20 : ADIAG_ERR("atrace client start failed, device id [%d] is invalid.", devId);
135 20 : return TRACE_INVALID_PARAM;
136 : }
137 220 : 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 220 : if (AtraceThreadSingleTask(devId)) {
143 0 : ADIAG_RUN_INF("thread has been started, devId=%d.", devId);
144 0 : return TRACE_SUCCESS;
145 : }
146 :
147 220 : TraStatus ret = AtraceClientSendHello(devId);
148 220 : if (ret != TRACE_SUCCESS) {
149 20 : ADIAG_WAR("can not send hello, devId=%d.", devId);
150 20 : return TRACE_UNSUPPORTED;
151 : }
152 : // create thread to receive device trace log
153 200 : TraceThreadArgs args = { devId };
154 200 : ret = AtraceThreadCreate(devId, &args, AtraceClientRecvThread);
155 200 : 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 200 : ADIAG_RUN_INF("start to receive device[%d] trace log.", devId);
161 200 : return TRACE_SUCCESS;
162 : }
163 :
164 200 : void AtraceClientStop(int32_t devId)
165 : {
166 200 : if ((devId >= HOST_MAX_DEV_NUM) || (devId < 0)) {
167 20 : ADIAG_ERR("stop report failed, device id is invalid, devId=%d.", devId);
168 20 : return;
169 : }
170 180 : if (devId == HOST_AI_DEVID) {
171 0 : ADIAG_INF("devId[%d] no need to stop a thread.", devId);
172 0 : return;
173 : }
174 :
175 180 : AtraceThreadRelease(devId, AtraceClientSendEnd, true);
176 180 : ADIAG_RUN_INF("stop to receive device[%d] trace log.", devId);
177 : }
178 :
179 901 : TraStatus AtraceClientInit(void)
180 : {
181 : // init thread pool
182 901 : TraStatus ret = AtraceThreadPoolInit();
183 901 : ADIAG_CHK_EXPR_ACTION(ret != TRACE_SUCCESS, return ret, "init thread pool failed.");
184 :
185 901 : ADIAG_INF("init atrace client successfully.");
186 901 : 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 80 : STATIC int32_t AtraceClientExitNoSend(int32_t devId)
199 : {
200 : (void)devId;
201 80 : return TRACE_SUCCESS;
202 : }
203 :
204 951 : void AtraceClientExit(void)
205 : {
206 : // release all receive thread; do not send [end] in destructor path
207 951 : AtraceThreadPoolExit(AtraceClientExitNoSend);
208 951 : }
|