• 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_BBOX_ENABLE
16 
17 #include "bbox.h"
18 #include <sys/syscall.h>
19 #include <unistd.h>
20 #include <csignal>
21 #include <cstdlib>
22 #include <string>
23 #include <sstream>
24 #include <vector>
25 #include "dfx/log/ffrt_log_api.h"
26 #include "dfx/trace_record/ffrt_trace_record.h"
27 #include "sched/scheduler.h"
28 #include "tm/queue_task.h"
29 #include "queue/queue_monitor.h"
30 #include "tm/task_factory.h"
31 #include "eu/cpuworker_manager.h"
32 #include "util/time_format.h"
33 #ifdef OHOS_STANDARD_SYSTEM
34 #include "dfx/bbox/fault_logger_fd_manager.h"
35 #endif
36 #include "dfx/dump/dump.h"
37 #include "util/ffrt_facade.h"
38 #include "util/slab.h"
39 
40 using namespace ffrt;
41 
42 constexpr static size_t EACH_QUEUE_TASK_DUMP_SIZE = 64;
43 static std::atomic<unsigned int> g_taskPendingCounter(0);
44 static std::atomic<unsigned int> g_taskWakeCounter(0);
45 static CPUEUTask* g_cur_task;
46 static unsigned int g_cur_tid;
47 static const char* g_cur_signame;
48 std::mutex bbox_handle_lock;
49 std::condition_variable bbox_handle_end;
50 
51 static struct sigaction s_oldSa[SIGSYS + 1]; // SIGSYS = 31
52 
53 static FuncSaveKeyStatusInfo saveKeyStatusInfo = nullptr;
54 static FuncSaveKeyStatus saveKeyStatus = nullptr;
SetFuncSaveKeyStatus(FuncSaveKeyStatus func,FuncSaveKeyStatusInfo infoFunc)55 void SetFuncSaveKeyStatus(FuncSaveKeyStatus func, FuncSaveKeyStatusInfo infoFunc)
56 {
57     saveKeyStatus = func;
58     saveKeyStatusInfo = infoFunc;
59 }
60 
TaskWakeCounterInc(void)61 void TaskWakeCounterInc(void)
62 {
63     ++g_taskWakeCounter;
64 }
65 
TaskPendingCounterInc(void)66 void TaskPendingCounterInc(void)
67 {
68     ++g_taskPendingCounter;
69 }
70 
SaveCurrent()71 static inline void SaveCurrent()
72 {
73     FFRT_BBOX_LOG("<<<=== current status ===>>>");
74     auto t = g_cur_task;
75     if (t) {
76         if (t->type == ffrt_normal_task || t->type == ffrt_queue_task) {
77             FFRT_BBOX_LOG("signal %s triggered: source tid %d, task id %lu, qos %d, name %s",
78                 g_cur_signame, g_cur_tid, t->gid, t->qos_(), t->label.c_str());
79         }
80     }
81 }
82 
83 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2)
SaveTaskCounter()84 static inline void SaveTaskCounter()
85 {
86     FFRT_BBOX_LOG("<<<=== task counter ===>>>");
87     FFRT_BBOX_LOG("FFRT BBOX TaskSubmitCounter:%u TaskEnQueueCounter:%u TaskDoneCounter:%u",
88         FFRTTraceRecord::GetSubmitCount(), FFRTTraceRecord::GetEnqueueCount(), FFRTTraceRecord::GetDoneCount());
89     FFRT_BBOX_LOG("FFRT BBOX TaskRunCounter:%u TaskSwitchCounter:%u TaskFinishCounter:%u",
90         FFRTTraceRecord::GetRunCount(), FFRTTraceRecord::GetCoSwitchCount(), FFRTTraceRecord::GetFinishCount());
91     FFRT_BBOX_LOG("FFRT BBOX TaskWakeCounterInc:%u, TaskPendingCounter:%u",
92         g_taskWakeCounter.load(), g_taskPendingCounter.load());
93     if (FFRTTraceRecord::GetCoSwitchCount() + FFRTTraceRecord::GetFinishCount() == FFRTTraceRecord::GetRunCount()) {
94         FFRT_BBOX_LOG("TaskRunCounter equals TaskSwitchCounter + TaskFinishCounter");
95     } else {
96         FFRT_BBOX_LOG("TaskRunCounter is not equal to TaskSwitchCounter + TaskFinishCounter");
97     }
98 }
99 #endif
100 
SaveLocalFifoStatus(int qos,WorkerThread * thread)101 static inline void SaveLocalFifoStatus(int qos, WorkerThread* thread)
102 {
103     CPUWorker* worker = reinterpret_cast<CPUWorker*>(thread);
104     CPUEUTask* t = reinterpret_cast<CPUEUTask*>(worker->localFifo.PopHead());
105     while (t != nullptr) {
106         if (t->type == ffrt_normal_task || t->type == ffrt_queue_task) {
107             FFRT_BBOX_LOG("qos %d: worker tid %d is localFifo task id %lu name %s",
108                 qos, worker->Id(), t->gid, t->label.c_str());
109         }
110         t = reinterpret_cast<CPUEUTask*>(worker->localFifo.PopHead());
111     }
112 }
113 
SaveWorkerStatus()114 static inline void SaveWorkerStatus()
115 {
116     WorkerGroupCtl* workerGroup = FFRTFacade::GetEUInstance().GetGroupCtl();
117     FFRT_BBOX_LOG("<<<=== worker status ===>>>");
118     for (int i = 0; i < QoS::MaxNum(); i++) {
119         std::shared_lock<std::shared_mutex> lck(workerGroup[i].tgMutex);
120         for (auto& thread : workerGroup[i].threads) {
121             SaveLocalFifoStatus(i, thread.first);
122             TaskBase* t = thread.first->curTask;
123             if (t == nullptr) {
124                 FFRT_BBOX_LOG("qos %d: worker tid %d is running nothing", i, thread.first->Id());
125                 continue;
126             }
127             FFRT_BBOX_LOG("qos %d: worker tid %d is running task", i, thread.first->Id());
128         }
129     }
130 }
131 
SaveReadyQueueStatus()132 static inline void SaveReadyQueueStatus()
133 {
134     FFRT_BBOX_LOG("<<<=== ready queue status ===>>>");
135     for (int i = 0; i < QoS::MaxNum(); i++) {
136         int nt = FFRTFacade::GetSchedInstance()->GetScheduler(i).RQSize();
137         if (!nt) {
138             continue;
139         }
140 
141         for (int j = 0; j < nt; j++) {
142             CPUEUTask* t = FFRTFacade::GetSchedInstance()->GetScheduler(i).PickNextTask();
143             if (t == nullptr) {
144                 FFRT_BBOX_LOG("qos %d: ready queue task <%d/%d> null", i, j, nt);
145                 continue;
146             }
147             if (t->type == ffrt_normal_task || t->type == ffrt_queue_task) {
148                 FFRT_BBOX_LOG("qos %d: ready queue task <%d/%d> id %lu name %s",
149                     i, j, nt, t->gid, t->label.c_str());
150             }
151         }
152     }
153 }
154 
SaveKeyStatus()155 static inline void SaveKeyStatus()
156 {
157     FFRT_BBOX_LOG("<<<=== key status ===>>>");
158     if (saveKeyStatus == nullptr) {
159         FFRT_BBOX_LOG("no key status");
160         return;
161     }
162     saveKeyStatus();
163 }
164 
SaveNormalTaskStatus()165 static inline void SaveNormalTaskStatus()
166 {
167     TaskFactory<CPUEUTask>::LockMem();
168     auto unfree = TaskFactory<CPUEUTask>::GetUnfreedMem();
169     auto apply = [&](const char* tag, const std::function<bool(CPUEUTask*)>& filter) {
170         std::vector<CPUEUTask*> tmp;
171         for (auto task : unfree) {
172             auto t = reinterpret_cast<CPUEUTask*>(task);
173             if (filter(t)) {
174                 tmp.emplace_back(t);
175             }
176         }
177 
178         if (tmp.size() > 0) {
179             FFRT_BBOX_LOG("<<<=== %s ===>>>", tag);
180         }
181         size_t idx = 1;
182         for (auto t : tmp) {
183             if (t->type == ffrt_normal_task) {
184                 FFRT_BBOX_LOG("<%zu/%lu> id %lu qos %d name %s", idx,
185                     tmp.size(), t->gid, t->qos_(), t->label.c_str());
186                 idx++;
187             }
188             if (t->coRoutine && (t->coRoutine->status.load() == static_cast<int>(CoStatus::CO_NOT_FINISH))
189                 && t != g_cur_task) {
190 #ifdef FFRT_CO_BACKTRACE_OH_ENABLE
191                     std::string dumpInfo;
192                     DumpTask(t, dumpInfo, 1);
193                     if (!dumpInfo.empty()) {
194                         FFRT_BBOX_LOG("%s", dumpInfo.c_str());
195                     }
196 #else
197                     CoStart(t, GetCoEnv());
198 #endif // FFRT_CO_BACKTRACE_OH_ENABLE
199             }
200         }
201     };
202 
203     apply("blocked by synchronization primitive(mutex etc)", [](CPUEUTask* t) {
204         return (t->state == TaskState::RUNNING) && t->coRoutine &&
205             t->coRoutine->status.load() == static_cast<int>(CoStatus::CO_NOT_FINISH) && t != g_cur_task;
206     });
207     apply("blocked by task dependence", [](CPUEUTask* t) {
208         return t->state == TaskState::BLOCKED;
209     });
210     apply("pending task", [](CPUEUTask* t) {
211         return t->state == TaskState::PENDING;
212     });
213     TaskFactory<CPUEUTask>::UnlockMem();
214 }
215 
SaveQueueTaskStatus()216 static inline void SaveQueueTaskStatus()
217 {
218     TaskFactory<QueueTask>::LockMem();
219     auto unfreeQueueTask = TaskFactory<QueueTask>::GetUnfreedMem();
220     auto applyqueue = [&](const char* tag, const std::function<bool(QueueTask*)>& filter) {
221         std::vector<QueueTask*> tmp;
222         for (auto task : unfreeQueueTask) {
223             auto t = reinterpret_cast<QueueTask*>(task);
224             if (filter(t)) {
225                 tmp.emplace_back(t);
226             }
227         }
228 
229         if (tmp.size() > 0) {
230             FFRT_BBOX_LOG("<<<=== %s ===>>>", tag);
231         }
232         size_t idx = 1;
233         for (auto t : tmp) {
234             if (t->type == ffrt_queue_task) {
235                 FFRT_BBOX_LOG("<%zu/%lu> id %lu qos %d name %s", idx,
236                     tmp.size(), t->gid, t->GetQos(), t->label.c_str());
237                 idx++;
238             }
239 
240             if (t->coRoutine && (t->coRoutine->status.load() == static_cast<int>(CoStatus::CO_NOT_FINISH))) {
241                 CoStart(reinterpret_cast<CPUEUTask*>(t), GetCoEnv());
242             }
243         }
244     };
245 
246     applyqueue("queue task blocked by synchronization primitive(mutex etc)", [](QueueTask* t) {
247         return (t->GetFinishStatus() == false) && t->coRoutine &&
248             t->coRoutine->status.load() == static_cast<int>(CoStatus::CO_NOT_FINISH);
249     });
250     TaskFactory<QueueTask>::UnlockMem();
251 }
252 
253 static std::atomic_uint g_bbox_tid_is_dealing {0};
254 static std::atomic_uint g_bbox_called_times {0};
255 static std::condition_variable g_bbox_cv;
256 static std::mutex g_bbox_mtx;
257 
BboxFreeze()258 void BboxFreeze()
259 {
260     std::unique_lock<std::mutex> lk(g_bbox_mtx);
261     g_bbox_cv.wait(lk, [] { return g_bbox_tid_is_dealing.load() == 0; });
262 }
263 
backtrace(int ignoreDepth)264 void backtrace(int ignoreDepth)
265 {
266 #ifdef FFRT_CO_BACKTRACE_OH_ENABLE
267     std::string dumpInfo;
268     DumpTask(nullptr, dumpInfo, 1);
269     if (!dumpInfo.empty()) {
270         FFRT_BBOX_LOG("%s", dumpInfo.c_str());
271     }
272 #endif // FFRT_CO_BACKTRACE_OH_ENABLE
273 }
274 
GetBboxEnableState(void)275 unsigned int GetBboxEnableState(void)
276 {
277     return g_bbox_tid_is_dealing.load();
278 }
279 
GetBboxCalledTimes(void)280 unsigned int GetBboxCalledTimes(void)
281 {
282     return g_bbox_called_times.load();
283 }
284 
FFRTIsWork()285 bool FFRTIsWork()
286 {
287     return FFRTTraceRecord::FfrtBeUsed();
288 }
289 
RecordDebugInfo(void)290 void RecordDebugInfo(void)
291 {
292     auto t = ExecuteCtx::Cur()->task;
293     FFRT_BBOX_LOG("<<<=== ffrt debug log start ===>>>");
294 
295     if ((t != nullptr) && (t->type == ffrt_normal_task || t->type == ffrt_queue_task)) {
296         FFRT_BBOX_LOG("debug log: tid %d, task id %lu, qos %d, name %s", gettid(), t->gid, t->qos_(), t->label.c_str());
297     }
298     SaveKeyStatus();
299     FFRT_BBOX_LOG("<<<=== ffrt debug log finish ===>>>");
300 }
301 
302 /**
303  * @brief BBOX信息记录,包括task、queue、worker相关信息
304  *
305  * @param void
306  * @return void
307  * @约束:
308  *  1、FFRT模块收到信号,记录BBOX信息,支持信号如下:
309  *     SIGABRT、SIGBUS、SIGFPE、SIGILL、SIGSTKFLT、SIGSTOP、SIGSYS、SIGTRAP
310  * @规格:
311  *  1.调用时机:FFRT模块收到信号时
312  *  2.影响:1)FFRT功能不可用,FFRT任务不再执行
313  *          2)影响范围仅影响FFRT任务运行,不能造成处理过程中的空指针等异常,如ffrt处理过程造成进行Crash
314  */
SaveTheBbox()315 void SaveTheBbox()
316 {
317     if (g_bbox_called_times.fetch_add(1) == 0) { // only save once
318         std::thread([&]() {
319             unsigned int expect = 0;
320             unsigned int tid = static_cast<unsigned int>(gettid());
321             ffrt::CPUMonitor *monitor = ffrt::FFRTFacade::GetEUInstance().GetCPUMonitor();
322             (void)g_bbox_tid_is_dealing.compare_exchange_strong(expect, tid);
323             monitor->WorkerInit();
324 
325 #ifdef OHOS_STANDARD_SYSTEM
326             FaultLoggerFdManager::Instance().InitFaultLoggerFd();
327 #endif
328             FFRT_BBOX_LOG("<<<=== ffrt black box(BBOX) start ===>>>");
329             SaveCurrent();
330 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2)
331             SaveTaskCounter();
332 #endif
333             SaveWorkerStatus();
334             SaveKeyStatus();
335             SaveReadyQueueStatus();
336             SaveNormalTaskStatus();
337             SaveQueueTaskStatus();
338             FFRT_BBOX_LOG("<<<=== ffrt black box(BBOX) finish ===>>>");
339 #ifdef OHOS_STANDARD_SYSTEM
340             FaultLoggerFdManager::Instance().CloseFd();
341 #endif
342 
343             std::unique_lock handle_end_lk(bbox_handle_lock);
344             bbox_handle_end.notify_one();
345 
346             std::lock_guard lk(g_bbox_mtx);
347             g_bbox_tid_is_dealing.store(0);
348             g_bbox_cv.notify_all();
349         }).detach();
350 
351         {
352             std::unique_lock lk(bbox_handle_lock);
353             (void)bbox_handle_end.wait_for(lk, std::chrono::seconds(5));
354         }
355     } else {
356         unsigned int tid = static_cast<unsigned int>(gettid());
357         if (tid == g_bbox_tid_is_dealing.load()) {
358             FFRT_LOGE("thread %u black box save failed", tid);
359             g_bbox_tid_is_dealing.store(0);
360             g_bbox_cv.notify_all();
361         } else {
362             FFRT_LOGE("thread %u trigger signal again, when thread %u is saving black box",
363                 tid, g_bbox_tid_is_dealing.load());
364             BboxFreeze(); // hold other thread's signal resend
365         }
366     }
367 }
368 
ResendSignal(siginfo_t * info)369 static void ResendSignal(siginfo_t* info)
370 {
371     int rc = syscall(SYS_rt_tgsigqueueinfo, getpid(), syscall(SYS_gettid), info->si_signo, info);
372     if (rc != 0) {
373         FFRT_LOGE("ffrt failed to resend signal during crash");
374     }
375 }
376 
GetSigName(const siginfo_t * info)377 static const char* GetSigName(const siginfo_t* info)
378 {
379     switch (info->si_signo) {
380         case SIGABRT: return "SIGABRT";
381         case SIGBUS: return "SIGBUS";
382         case SIGFPE: return "SIGFPE";
383         case SIGILL: return "SIGILL";
384         case SIGSTKFLT: return "SIGSTKFLT";
385         case SIGSTOP: return "SIGSTOP";
386         case SIGSYS: return "SIGSYS";
387         case SIGTRAP: return "SIGTRAP";
388         default: return "?";
389     }
390 }
391 
SignalHandler(int signo,siginfo_t * info,void * context)392 static void SignalHandler(int signo, siginfo_t* info, void* context __attribute__((unused)))
393 {
394     if (FFRTIsWork()) {
395         // init is false to avoid deadlock occurs in the signal handling function due to memory allocation calls.
396         auto ctx = ExecuteCtx::Cur(false);
397         g_cur_task = ctx != nullptr ? ctx->task : nullptr;
398         g_cur_tid = gettid();
399         g_cur_signame = GetSigName(info);
400         SaveTheBbox();
401     }
402     // we need to deregister our signal handler for that signal before continuing.
403     sigaction(signo, &s_oldSa[signo], nullptr);
404     ResendSignal(info);
405 }
406 
SignalReg(int signo)407 static void SignalReg(int signo)
408 {
409     sigaction(signo, nullptr, &s_oldSa[signo]);
410     struct sigaction newAction;
411     newAction.sa_flags = SA_RESTART | SA_SIGINFO;
412     newAction.sa_sigaction = SignalHandler;
413     sigaction(signo, &newAction, nullptr);
414 }
415 
SignalUnReg(int signo)416 static void SignalUnReg(int signo)
417 {
418     sigaction(signo, &s_oldSa[signo], nullptr);
419 }
420 
BBoxInit()421 __attribute__((constructor)) static void BBoxInit()
422 {
423     SignalReg(SIGABRT);
424     SignalReg(SIGBUS);
425     SignalReg(SIGFPE);
426     SignalReg(SIGSTKFLT);
427     SignalReg(SIGSYS);
428     SignalReg(SIGTRAP);
429     SignalReg(SIGINT);
430     SignalReg(SIGKILL);
431 }
432 
BBoxDeInit()433 __attribute__((destructor)) static void BBoxDeInit()
434 {
435     SignalUnReg(SIGABRT);
436     SignalUnReg(SIGBUS);
437     SignalUnReg(SIGFPE);
438     SignalUnReg(SIGSTKFLT);
439     SignalUnReg(SIGSYS);
440     SignalUnReg(SIGTRAP);
441     SignalUnReg(SIGINT);
442     SignalUnReg(SIGKILL);
443 }
444 
FormatDateString(uint64_t timeStamp)445 static inline std::string FormatDateString(uint64_t timeStamp)
446 {
447 #if defined(__aarch64__)
448     return FormatDateString4CntCt(timeStamp, microsecond);
449 #else
450     return FormatDateString4SteadyClock(timeStamp, microsecond);
451 #endif
452 }
453 
GetDumpPreface(void)454 std::string GetDumpPreface(void)
455 {
456     std::ostringstream ss;
457     ss << "|-> Launcher proc ffrt, now:" << FormatDateString(FFRTTraceRecord::TimeStamp()) << " pid:" << GetPid()
458         << std::endl;
459     return ss.str();
460 }
461 
462 #ifdef FFRT_CO_BACKTRACE_OH_ENABLE
463 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2)
SaveTaskCounterInfo(void)464 std::string SaveTaskCounterInfo(void)
465 {
466     std::ostringstream ss;
467     ss << "    |-> task counter" << std::endl;
468     ss << "        TaskSubmitCounter:" << FFRTTraceRecord::GetSubmitCount() << " TaskEnQueueCounter:"
469        << FFRTTraceRecord::GetEnqueueCount() << " TaskDoneCounter:" << FFRTTraceRecord::GetDoneCount() << std::endl;
470 
471     ss << "        TaskRunCounter:" << FFRTTraceRecord::GetRunCount() << " TaskSwitchCounter:"
472        << FFRTTraceRecord::GetCoSwitchCount() << " TaskFinishCounter:" << FFRTTraceRecord::GetFinishCount()
473        << std::endl;
474 
475     if (FFRTTraceRecord::GetCoSwitchCount() + FFRTTraceRecord::GetFinishCount() == FFRTTraceRecord::GetRunCount()) {
476         ss << "        TaskRunCounter equals TaskSwitchCounter + TaskFinishCounter" << std::endl;
477     } else {
478         ss << "        TaskRunCounter is not equal to TaskSwitchCounter + TaskFinishCounter" << std::endl;
479     }
480     return ss.str();
481 }
482 #endif // FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2
483 
AppendTaskInfo(std::ostringstream & oss,TaskBase * task)484 void AppendTaskInfo(std::ostringstream& oss, TaskBase* task)
485 {
486     if (task->fromTid) {
487         oss << " fromTid " << task->fromTid;
488     }
489     if (task->createTime) {
490         oss << " createTime " << FormatDateString(task->createTime);
491     }
492     if (task->executeTime) {
493         oss << " executeTime " << FormatDateString(task->executeTime);
494     }
495 }
496 
SaveKeyInfo(void)497 std::string SaveKeyInfo(void)
498 {
499     ffrt::CPUMonitor *monitor = ffrt::FFRTFacade::GetEUInstance().GetCPUMonitor();
500     std::ostringstream oss;
501 
502     monitor->WorkerInit();
503     oss << "    |-> key status" << std::endl;
504     if (saveKeyStatusInfo == nullptr) {
505         oss << "no key status info" << std::endl;
506         return oss.str();
507     }
508     oss << saveKeyStatusInfo();
509     return oss.str();
510 }
511 
DumpThreadTaskInfo(WorkerThread * thread,int qos,std::ostringstream & ss)512 void DumpThreadTaskInfo(WorkerThread* thread, int qos, std::ostringstream& ss)
513 {
514     TaskBase* t = thread->curTask;
515     pid_t tid = thread->Id();
516     if (t == nullptr) {
517         ss << "        qos " << qos << ": worker tid " << tid << " is running nothing" << std::endl;
518         return;
519     }
520 
521     switch (thread->curTaskType_) {
522         case ffrt_normal_task: {
523             TaskFactory<CPUEUTask>::LockMem();
524             auto cpuTask = reinterpret_cast<CPUEUTask*>(t);
525             if ((!TaskFactory<CPUEUTask>::HasBeenFreed(cpuTask)) && (cpuTask->state != TaskState::EXITED)) {
526                 ss << "        qos " << qos << ": worker tid " << tid << " normal task is running, task id "
527                    << t->gid << " name " << t->GetLabel().c_str();
528                 AppendTaskInfo(ss, t);
529             }
530             TaskFactory<CPUEUTask>::UnlockMem();
531             ss << std::endl;
532             return;
533         }
534         case ffrt_queue_task: {
535             {
536                 TaskFactory<QueueTask>::LockMem();
537                 auto queueTask = reinterpret_cast<QueueTask*>(t);
538                 if ((!SimpleAllocator<QueueTask>::HasBeenFreed(queueTask)) && (!queueTask->GetFinishStatus())) {
539                     ss << "        qos " << qos << ": worker tid " << tid << " queue task is running, task id "
540                        << t->gid << " name " << t->GetLabel().c_str();
541                     AppendTaskInfo(ss, t);
542                 }
543                 TaskFactory<QueueTask>::UnlockMem();
544             }
545             ss << std::endl;
546             return;
547         }
548         case ffrt_io_task: {
549             ss << "        qos " << qos << ": worker tid " << tid << " io task is running" << std::endl;
550             return;
551         }
552         case ffrt_invalid_task: {
553             return;
554         }
555         default: {
556             ss << "        qos " << qos << ": worker tid " << tid << " uv task is running" << std::endl;
557             return;
558         }
559     }
560 }
561 
SaveWorkerStatusInfo(void)562 std::string SaveWorkerStatusInfo(void)
563 {
564     std::ostringstream ss;
565     std::ostringstream oss;
566     WorkerGroupCtl* workerGroup = FFRTFacade::GetEUInstance().GetGroupCtl();
567     oss << "    |-> worker count" << std::endl;
568     ss << "    |-> worker status" << std::endl;
569     for (int i = 0; i < QoS::MaxNum(); i++) {
570         std::vector<int> tidArr;
571         std::shared_lock<std::shared_mutex> lck(workerGroup[i].tgMutex);
572         for (auto& thread : workerGroup[i].threads) {
573             tidArr.push_back(thread.first->Id());
574             DumpThreadTaskInfo(thread.first, i, ss);
575         }
576         if (tidArr.size() == 0) {
577             continue;
578         }
579         oss << "        qos " << i << ": worker num:" << tidArr.size() << " tid:";
580         std::for_each(tidArr.begin(), tidArr.end(), [&](const int &t) {
581             if (&t == &tidArr.back()) {
582                 oss << t;
583             } else {
584                 oss << t << ", ";
585             }
586         });
587         oss << std::endl;
588     }
589     oss << ss.str();
590     return oss.str();
591 }
592 
SaveNormalTaskStatusInfo(void)593 std::string SaveNormalTaskStatusInfo(void)
594 {
595     std::string ffrtStackInfo;
596     std::ostringstream ss;
597     TaskFactory<CPUEUTask>::LockMem();
598     auto unfree = TaskFactory<CPUEUTask>::GetUnfreedMem();
599     auto apply = [&](const char* tag, const std::function<bool(CPUEUTask*)>& filter) {
600         std::vector<CPUEUTask*> tmp;
601         for (auto task : unfree) {
602             auto t = reinterpret_cast<CPUEUTask*>(task);
603             if (filter(t)) {
604                 tmp.emplace_back(reinterpret_cast<CPUEUTask*>(t));
605             }
606         }
607 
608         if (tmp.size() > 0) {
609             ss << "    |-> " << tag << std::endl;
610             ffrtStackInfo += ss.str();
611         }
612         size_t idx = 1;
613         for (auto t : tmp) {
614             ss.str("");
615             if (t->type == ffrt_normal_task) {
616                 ss << "        <" << idx++ << "/" << tmp.size() << ">" << "stack: task id " << t->gid << ",qos "
617                     << t->qos_() << ",name " << t->label.c_str();
618                 AppendTaskInfo(ss, t);
619                 ss << std::endl;
620             }
621             ffrtStackInfo += ss.str();
622             if (t->coRoutine && (t->coRoutine->status.load() == static_cast<int>(CoStatus::CO_NOT_FINISH))) {
623                 std::string dumpInfo;
624                 DumpTask(t, dumpInfo, 1);
625                 ffrtStackInfo += dumpInfo;
626             }
627         }
628     };
629 
630     apply("blocked by synchronization primitive(mutex etc)", [](CPUEUTask* t) {
631         return (t->state == TaskState::RUNNING) && t->coRoutine &&
632             t->coRoutine->status.load() == static_cast<int>(CoStatus::CO_NOT_FINISH);
633     });
634     apply("blocked by task dependence", [](CPUEUTask* t) {
635         return t->state == TaskState::BLOCKED;
636     });
637     apply("pending task", [](CPUEUTask* t) {
638         return t->state == TaskState::PENDING;
639     });
640     apply("ready task", [](CPUEUTask* t) {
641         return t->state == TaskState::READY;
642     });
643     TaskFactory<CPUEUTask>::UnlockMem();
644 
645     return ffrtStackInfo;
646 }
647 
DumpQueueTaskInfo(std::string & ffrtStackInfo,const char * tag,const std::vector<QueueTask * > & tasks,const std::function<bool (QueueTask *)> & filter,size_t limit=EACH_QUEUE_TASK_DUMP_SIZE)648 void DumpQueueTaskInfo(std::string& ffrtStackInfo, const char* tag, const std::vector<QueueTask*>& tasks,
649     const std::function<bool(QueueTask*)>& filter, size_t limit = EACH_QUEUE_TASK_DUMP_SIZE)
650 {
651     std::vector<QueueTask*> tmp;
652     for (auto t : tasks) {
653         if (tmp.size() < limit && filter(t)) {
654             tmp.emplace_back(t);
655         }
656     }
657     if (tmp.size() == 0) {
658         return;
659     }
660     std::ostringstream ss;
661     ss << "<<<=== " << tag << "===>>>" << std::endl;
662     ffrtStackInfo += ss.str();
663 
664     size_t idx = 1;
665     for (auto t : tmp) {
666         ss.str("");
667         if (t->type == ffrt_queue_task) {
668             ss << "<" << idx++ << "/" << tmp.size() << ">" << "id " << t->gid << " qos "
669                 << t->GetQos() << " name " << t->label.c_str();
670             AppendTaskInfo(ss, t);
671             ss << std::endl;
672         }
673         ffrtStackInfo += ss.str();
674         if (t->coRoutine && (t->coRoutine->status.load() == static_cast<int>(CoStatus::CO_NOT_FINISH))) {
675             std::string dumpInfo;
676             DumpTask(reinterpret_cast<CPUEUTask*>(t), dumpInfo, 1);
677             ffrtStackInfo += dumpInfo;
678         }
679     }
680 }
681 
SaveQueueTaskStatusInfo()682 std::string SaveQueueTaskStatusInfo()
683 {
684     std::string ffrtStackInfo;
685     std::lock_guard lk(SimpleAllocator<QueueTask>::Instance()->lock);
686     auto unfreeQueueTask = SimpleAllocator<QueueTask>::getUnfreedMem();
687     if (unfreeQueueTask.size() == 0) {
688         return ffrtStackInfo;
689     }
690 
691     std::map<QueueHandler*, std::vector<QueueTask*>> taskMap;
692     for (auto t : unfreeQueueTask) {
693         auto task = reinterpret_cast<QueueTask*>(t);
694         if (task->type == ffrt_queue_task && task->GetFinishStatus() == false && task->GetHandler() != nullptr) {
695             taskMap[task->GetHandler()].push_back(task);
696         }
697     }
698     if (taskMap.empty()) {
699         return ffrtStackInfo;
700     }
701 
702     for (auto entry : taskMap) {
703         std::sort(entry.second.begin(), entry.second.end(), [](QueueTask* first, QueueTask* second) {
704             return first->GetUptime() < second->GetUptime();
705         });
706     }
707 
708     for (auto entry : taskMap) {
709         ffrtStackInfo += "\n";
710         DumpQueueTaskInfo(ffrtStackInfo, "queue task blocked by synchronization primitive(mutex etc)", entry.second,
711             [](QueueTask* t) {
712                 return (t->GetFinishStatus() == false) && t->coRoutine &&
713                     t->coRoutine->status.load() == static_cast<int>(CoStatus::CO_NOT_FINISH);
714             });
715         DumpQueueTaskInfo(ffrtStackInfo, "queue task unFinished", entry.second, [](QueueTask* t) {
716             return (t->GetFinishStatus() == false && !(t->coRoutine &&
717                 t->coRoutine->status.load() == static_cast<int>(CoStatus::CO_NOT_FINISH)));
718         });
719     }
720 
721     return ffrtStackInfo;
722 }
723 #endif
724 #endif /* FFRT_BBOX_ENABLE */
725