• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #ifdef FFRT_CO_BACKTRACE_OH_ENABLE
16 #include <dlfcn.h>
17 #include <sstream>
18 #include "unwinder.h"
19 #include "backtrace_local.h"
20 #endif
21 #include <securec.h>
22 #include "dfx/bbox/bbox.h"
23 #include "internal_inc/osal.h"
24 #include "dfx/log/ffrt_log_api.h"
25 #include "dfx/trace_record/ffrt_trace_record.h"
26 #include "util/common_const.h"
27 #include "dump.h"
28 
29 #ifdef FFRT_CO_BACKTRACE_OH_ENABLE
30 using namespace OHOS::HiviewDFX;
31 #endif
32 namespace {
33 ffrt::HiTraceIdStruct traceid;
34 ffrt_task_timeout_cb timeoutCb = nullptr;
35 
HitraceChainCbWrap(uint64_t gid,const char * msg,uint32_t size)36 void HitraceChainCbWrap(uint64_t gid, const char *msg, uint32_t size)
37 {
38 #ifdef FFRT_ENABLE_HITRACE_CHAIN
39     if (traceid.valid == ffrt::HITRACE_ID_VALID) {
40         ffrt::TraceChainAdapter::Instance().HiTraceChainRestoreId(&traceid);
41     }
42     timeoutCb(gid, msg, size);
43     ffrt::TraceChainAdapter::Instance().HiTraceChainClearId();
44 #endif
45 }
46 }
47 namespace ffrt {
48 constexpr uint32_t DEFAULT_TIMEOUT_MS = 30000;
49 struct TimeoutCfg {
Instanceffrt::TimeoutCfg50     static inline TimeoutCfg* Instance()
51     {
52         static TimeoutCfg inst;
53         return &inst;
54     }
55 
56     uint32_t timeout = DEFAULT_TIMEOUT_MS;
57     ffrt_task_timeout_cb callback = nullptr;
58 };
59 
60 #ifdef FFRT_CO_BACKTRACE_OH_ENABLE
DumpTask(CoTask * task,std::string & stackInfo,uint8_t flag)61 void DumpTask(CoTask* task, std::string& stackInfo, uint8_t flag)
62 {
63     ucontext_t ctx;
64 
65     if (ExecuteCtx::Cur()->task == task || task == nullptr) {
66         if (flag == 0) {
67             OHOS::HiviewDFX::PrintTrace(-1);
68         } else {
69             OHOS::HiviewDFX::GetBacktrace(stackInfo, false);
70         }
71         return;
72     } else {
73         memset_s(&ctx, sizeof(ctx), 0, sizeof(ctx));
74 #if defined(__aarch64__)
75         ctx.uc_mcontext.regs[REG_AARCH64_X29] = task->coRoutine->ctx.storage[10];
76         ctx.uc_mcontext.sp = task->coRoutine->ctx.storage[13];
77         ctx.uc_mcontext.pc = task->coRoutine->ctx.storage[11];
78 #elif defined(__x86_64__)
79         ctx.uc_mcontext.gregs[REG_RBX] = task->coRoutine->ctx.storage[0];
80         ctx.uc_mcontext.gregs[REG_RBP] = task->coRoutine->ctx.storage[1];
81         ctx.uc_mcontext.gregs[REG_RSP] = task->coRoutine->ctx.storage[6];
82         ctx.uc_mcontext.gregs[REG_RIP] = *(reinterpret_cast<greg_t *>(ctx.uc_mcontext.gregs[REG_RSP] - 8));
83 #elif defined(__arm__)
84         ctx.uc_mcontext.arm_sp = task->coRoutine->ctx.storage[0]; /* sp */
85         ctx.uc_mcontext.arm_pc = task->coRoutine->ctx.storage[1]; /* pc */
86         ctx.uc_mcontext.arm_lr = task->coRoutine->ctx.storage[1]; /* lr */
87         ctx.uc_mcontext.arm_fp = task->coRoutine->ctx.storage[10]; /* fp */
88 #endif
89     }
90 
91     auto co = task->coRoutine;
92     uintptr_t stackBottom = reinterpret_cast<uintptr_t>(reinterpret_cast<char*>(co) + sizeof(CoRoutine) - 8);
93     uintptr_t stackTop = static_cast<uintptr_t>(stackBottom + co->stkMem.size);
94     auto unwinder = std::make_shared<Unwinder>();
95     auto regs = DfxRegs::CreateFromUcontext(ctx);
96     unwinder->SetRegs(regs);
97     UnwindContext context;
98     context.pid = UNWIND_TYPE_LOCAL;
99     context.regs = regs;
100     context.maps = unwinder->GetMaps();
101     context.stackCheck = false;
102     context.stackBottom = stackBottom;
103     context.stackTop = stackTop;
104     bool resFlag = unwinder->Unwind(&context);
105     if (!resFlag) {
106         FFRT_LOGE("Call Unwind failed");
107         return;
108     }
109     std::ostringstream ss;
110     auto frames = unwinder->GetFrames();
111     if (flag != 0) {
112         ss << Unwinder::GetFramesStr(frames);
113         ss << std::endl;
114         stackInfo = ss.str();
115         return;
116     }
117     FFRT_LOGE("%s", Unwinder::GetFramesStr(frames).c_str());
118 }
119 #endif
120 }
121 
122 #ifdef __cplusplus
123 extern "C" {
124 #endif //__cplusplus
125 
126 API_ATTRIBUTE((visibility("default")))
dump_info_all(char * buf,uint32_t len)127 int dump_info_all(char *buf, uint32_t len)
128 {
129 #ifdef FFRT_CO_BACKTRACE_OH_ENABLE
130     if (FFRTIsWork()) {
131         std::string dumpInfo;
132         dumpInfo += GetDumpPreface();
133 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2)
134         dumpInfo += SaveTaskCounterInfo();
135 #endif
136         dumpInfo += SaveKeyInfo();
137         dumpInfo += SaveWorkerStatusInfo();
138         dumpInfo += SaveNormalTaskStatusInfo();
139         dumpInfo += SaveQueueTaskStatusInfo();
140         dumpInfo += SaveTimeoutTaskInfo();
141         dumpInfo += SaveQueueTrafficRecordInfo();
142         if (dumpInfo.length() > (len - 1)) {
143             FFRT_LOGW("dumpInfo exceeds the buffer length, info length:%d, input len:%u", dumpInfo.length(), len);
144         }
145         return snprintf_s(buf, len, len - 1, "%s", dumpInfo.c_str());
146     } else {
147         return snprintf_s(buf, len, len - 1, "|-> FFRT has done all tasks, pid: %u \n", GetPid());
148     }
149 #else
150     return -1;
151 #endif
152 }
153 
154 API_ATTRIBUTE((visibility("default")))
ffrt_dump(ffrt_dump_cmd_t cmd,char * buf,uint32_t len)155 int ffrt_dump(ffrt_dump_cmd_t cmd, char *buf, uint32_t len)
156 {
157     FFRT_COND_RETURN_ERROR(buf == nullptr || len < 1, -1, "buf is nullptr or len is less than 1, len %u", len);
158     switch (cmd) {
159         case DUMP_INFO_ALL: {
160             return dump_info_all(buf, len);
161         }
162         case DUMP_TASK_STATISTIC_INFO: {
163 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2)
164             return ffrt::FFRTTraceRecord::StatisticInfoDump(buf, len);
165 #else
166             return -1;
167 #endif
168         }
169         case DUMP_START_STAT: {
170             return ffrt::FFRTTraceRecord::StatEnable(buf, len);
171         }
172         case DUMP_STOP_STAT: {
173             return ffrt::FFRTTraceRecord::StatsDisable(buf);
174         }
175         default: {
176             FFRT_LOGE("ffrt_dump unsupport cmd[%d]", cmd);
177         }
178     }
179     return -1;
180 }
181 
182 API_ATTRIBUTE((visibility("default")))
ffrt_task_timeout_get_cb(void)183 ffrt_task_timeout_cb ffrt_task_timeout_get_cb(void)
184 {
185     return ffrt::TimeoutCfg::Instance()->callback;
186 }
187 
188 API_ATTRIBUTE((visibility("default")))
ffrt_task_timeout_set_cb(ffrt_task_timeout_cb cb)189 void ffrt_task_timeout_set_cb(ffrt_task_timeout_cb cb)
190 {
191     FFRT_COND_DO_ERR((cb == nullptr), return, "input invalid, cb is nullptr");
192 #ifdef FFRT_ENABLE_HITRACE_CHAIN
193     if (ffrt::TraceChainAdapter::Instance().HiTraceChainGetId().valid == ffrt::HITRACE_ID_VALID) {
194         traceid = ffrt::TraceChainAdapter::Instance().HiTraceChainCreateSpan();
195         timeoutCb = cb;
196         ffrt::TimeoutCfg::Instance()->callback = HitraceChainCbWrap;
197     } else {
198         ffrt::TimeoutCfg::Instance()->callback = cb;
199     }
200 #else
201     ffrt::TimeoutCfg::Instance()->callback = cb;
202 #endif
203 }
204 
205 API_ATTRIBUTE((visibility("default")))
ffrt_task_timeout_get_threshold(void)206 uint32_t ffrt_task_timeout_get_threshold(void)
207 {
208     return ffrt::TimeoutCfg::Instance()->timeout;
209 }
210 
211 API_ATTRIBUTE((visibility("default")))
ffrt_task_timeout_set_threshold(uint32_t threshold_ms)212 void ffrt_task_timeout_set_threshold(uint32_t threshold_ms)
213 {
214     if (threshold_ms < ONE_THOUSAND) {
215         ffrt::TimeoutCfg::Instance()->timeout = ONE_THOUSAND;
216         return;
217     }
218     ffrt::TimeoutCfg::Instance()->timeout = threshold_ms;
219 }
220 #ifdef __cplusplus
221 }
222 #endif
223