• 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             CPUEUTask* 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             if (t->type == ffrt_normal_task || t->type == ffrt_queue_task) {
128                 FFRT_BBOX_LOG("qos %d: worker tid %d is running task id %lu name %s", i, thread.first->Id(),
129                     t->gid, t->label.c_str());
130             }
131         }
132     }
133 }
134 
SaveReadyQueueStatus()135 static inline void SaveReadyQueueStatus()
136 {
137     FFRT_BBOX_LOG("<<<=== ready queue status ===>>>");
138     for (int i = 0; i < QoS::MaxNum(); i++) {
139         int nt = FFRTFacade::GetSchedInstance()->GetScheduler(i).RQSize();
140         if (!nt) {
141             continue;
142         }
143 
144         for (int j = 0; j < nt; j++) {
145             CPUEUTask* t = FFRTFacade::GetSchedInstance()->GetScheduler(i).PickNextTask();
146             if (t == nullptr) {
147                 FFRT_BBOX_LOG("qos %d: ready queue task <%d/%d> null", i, j, nt);
148                 continue;
149             }
150             if (t->type == ffrt_normal_task || t->type == ffrt_queue_task) {
151                 FFRT_BBOX_LOG("qos %d: ready queue task <%d/%d> id %lu name %s",
152                     i, j, nt, t->gid, t->label.c_str());
153             }
154         }
155     }
156 }
157 
SaveKeyStatus()158 static inline void SaveKeyStatus()
159 {
160     FFRT_BBOX_LOG("<<<=== key status ===>>>");
161     if (saveKeyStatus == nullptr) {
162         FFRT_BBOX_LOG("no key status");
163         return;
164     }
165     saveKeyStatus();
166 }
167 
SaveNormalTaskStatus()168 static inline void SaveNormalTaskStatus()
169 {
170     TaskFactory::LockMem();
171     auto unfree = TaskFactory::GetUnfreedMem();
172     auto apply = [&](const char* tag, const std::function<bool(CPUEUTask*)>& filter) {
173         std::vector<CPUEUTask*> tmp;
174         for (auto task : unfree) {
175             auto t = reinterpret_cast<CPUEUTask*>(task);
176             if (filter(t)) {
177                 tmp.emplace_back(t);
178             }
179         }
180 
181         if (tmp.size() > 0) {
182             FFRT_BBOX_LOG("<<<=== %s ===>>>", tag);
183         }
184         size_t idx = 1;
185         for (auto t : tmp) {
186             if (t->type == ffrt_normal_task) {
187                 FFRT_BBOX_LOG("<%zu/%lu> id %lu qos %d name %s", idx,
188                     tmp.size(), t->gid, t->qos(), t->label.c_str());
189                 idx++;
190             }
191             if (t->coRoutine && (t->coRoutine->status.load() == static_cast<int>(CoStatus::CO_NOT_FINISH))
192                 && t != g_cur_task) {
193 #ifdef FFRT_CO_BACKTRACE_OH_ENABLE
194                     std::string dumpInfo;
195                     DumpTask(t, dumpInfo, 1);
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::UnlockMem();
214 }
215 
SaveQueueTaskStatus()216 static inline void SaveQueueTaskStatus()
217 {
218     std::lock_guard lk(SimpleAllocator<QueueTask>::Instance()->lock);
219     auto unfreeQueueTask = SimpleAllocator<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 }
251 
252 static std::atomic_uint g_bbox_tid_is_dealing {0};
253 static std::atomic_uint g_bbox_called_times {0};
254 static std::condition_variable g_bbox_cv;
255 static std::mutex g_bbox_mtx;
256 
BboxFreeze()257 void BboxFreeze()
258 {
259     std::unique_lock<std::mutex> lk(g_bbox_mtx);
260     g_bbox_cv.wait(lk, [] { return g_bbox_tid_is_dealing.load() == 0; });
261 }
262 
backtrace(int ignoreDepth)263 void backtrace(int ignoreDepth)
264 {
265 #ifdef FFRT_CO_BACKTRACE_OH_ENABLE
266     std::string dumpInfo;
267     DumpTask(nullptr, dumpInfo, 1);
268     if (!dumpInfo.empty()) {
269         FFRT_BBOX_LOG("%s", dumpInfo.c_str());
270     }
271 #endif // FFRT_CO_BACKTRACE_OH_ENABLE
272 }
273 
GetBboxEnableState(void)274 unsigned int GetBboxEnableState(void)
275 {
276     return g_bbox_tid_is_dealing.load();
277 }
278 
GetBboxCalledTimes(void)279 unsigned int GetBboxCalledTimes(void)
280 {
281     return g_bbox_called_times.load();
282 }
283 
FFRTIsWork()284 bool FFRTIsWork()
285 {
286     return FFRTTraceRecord::FfrtBeUsed();
287 }
288 
RecordDebugInfo(void)289 void RecordDebugInfo(void)
290 {
291     auto t = ExecuteCtx::Cur()->task;
292     FFRT_BBOX_LOG("<<<=== ffrt debug log start ===>>>");
293 
294     if ((t != nullptr) && (t->type == ffrt_normal_task || t->type == ffrt_queue_task)) {
295         FFRT_BBOX_LOG("debug log: tid %d, task id %lu, qos %d, name %s", gettid(), t->gid, t->qos(), t->label.c_str());
296     }
297     SaveKeyStatus();
298     FFRT_BBOX_LOG("<<<=== ffrt debug log finish ===>>>");
299 }
300 
SaveTheBbox()301 void SaveTheBbox()
302 {
303     if (g_bbox_called_times.fetch_add(1) == 0) { // only save once
304         std::thread([&]() {
305             unsigned int expect = 0;
306             unsigned int tid = static_cast<unsigned int>(gettid());
307             ffrt::CPUMonitor *monitor = ffrt::FFRTFacade::GetEUInstance().GetCPUMonitor();
308             (void)g_bbox_tid_is_dealing.compare_exchange_strong(expect, tid);
309             monitor->WorkerInit();
310 
311 #ifdef OHOS_STANDARD_SYSTEM
312             FaultLoggerFdManager::Instance().InitFaultLoggerFd();
313 #endif
314             FFRT_BBOX_LOG("<<<=== ffrt black box(BBOX) start ===>>>");
315             SaveCurrent();
316 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2)
317             SaveTaskCounter();
318 #endif
319             SaveWorkerStatus();
320             SaveKeyStatus();
321             SaveReadyQueueStatus();
322             SaveNormalTaskStatus();
323             SaveQueueTaskStatus();
324             FFRT_BBOX_LOG("<<<=== ffrt black box(BBOX) finish ===>>>");
325 #ifdef OHOS_STANDARD_SYSTEM
326             FaultLoggerFdManager::Instance().CloseFd();
327 #endif
328 
329             std::unique_lock handle_end_lk(bbox_handle_lock);
330             bbox_handle_end.notify_one();
331 
332             std::lock_guard lk(g_bbox_mtx);
333             g_bbox_tid_is_dealing.store(0);
334             g_bbox_cv.notify_all();
335         }).detach();
336 
337         {
338             std::unique_lock lk(bbox_handle_lock);
339             (void)bbox_handle_end.wait_for(lk, std::chrono::seconds(5));
340         }
341     } else {
342         unsigned int tid = static_cast<unsigned int>(gettid());
343         if (tid == g_bbox_tid_is_dealing.load()) {
344             FFRT_LOGE("thread %u black box save failed", tid);
345             g_bbox_tid_is_dealing.store(0);
346             g_bbox_cv.notify_all();
347         } else {
348             FFRT_LOGE("thread %u trigger signal again, when thread %u is saving black box",
349                 tid, g_bbox_tid_is_dealing.load());
350             BboxFreeze(); // hold other thread's signal resend
351         }
352     }
353 }
354 
ResendSignal(siginfo_t * info)355 static void ResendSignal(siginfo_t* info)
356 {
357     int rc = syscall(SYS_rt_tgsigqueueinfo, getpid(), syscall(SYS_gettid), info->si_signo, info);
358     if (rc != 0) {
359         FFRT_LOGE("ffrt failed to resend signal during crash");
360     }
361 }
362 
GetSigName(const siginfo_t * info)363 static const char* GetSigName(const siginfo_t* info)
364 {
365     switch (info->si_signo) {
366         case SIGABRT: return "SIGABRT";
367         case SIGBUS: return "SIGBUS";
368         case SIGFPE: return "SIGFPE";
369         case SIGILL: return "SIGILL";
370         case SIGSTKFLT: return "SIGSTKFLT";
371         case SIGSTOP: return "SIGSTOP";
372         case SIGSYS: return "SIGSYS";
373         case SIGTRAP: return "SIGTRAP";
374         default: return "?";
375     }
376 }
377 
SignalHandler(int signo,siginfo_t * info,void * context)378 static void SignalHandler(int signo, siginfo_t* info, void* context __attribute__((unused)))
379 {
380     if (FFRTIsWork()) {
381         g_cur_task = ExecuteCtx::Cur()->task;
382         g_cur_tid = gettid();
383         g_cur_signame = GetSigName(info);
384         SaveTheBbox();
385     }
386     // we need to deregister our signal handler for that signal before continuing.
387     sigaction(signo, &s_oldSa[signo], nullptr);
388     ResendSignal(info);
389 }
390 
SignalReg(int signo)391 static void SignalReg(int signo)
392 {
393     sigaction(signo, nullptr, &s_oldSa[signo]);
394     struct sigaction newAction;
395     newAction.sa_flags = SA_RESTART | SA_SIGINFO;
396     newAction.sa_sigaction = SignalHandler;
397     sigaction(signo, &newAction, nullptr);
398 }
399 
SignalUnReg(int signo)400 static void SignalUnReg(int signo)
401 {
402     sigaction(signo, &s_oldSa[signo], nullptr);
403 }
404 
BBoxInit()405 __attribute__((constructor)) static void BBoxInit()
406 {
407     SignalReg(SIGABRT);
408     SignalReg(SIGBUS);
409     SignalReg(SIGFPE);
410     SignalReg(SIGILL);
411     SignalReg(SIGSTKFLT);
412     SignalReg(SIGSYS);
413     SignalReg(SIGTRAP);
414     SignalReg(SIGINT);
415     SignalReg(SIGKILL);
416 }
417 
BBoxDeInit()418 __attribute__((destructor)) static void BBoxDeInit()
419 {
420     SignalUnReg(SIGABRT);
421     SignalUnReg(SIGBUS);
422     SignalUnReg(SIGFPE);
423     SignalUnReg(SIGILL);
424     SignalUnReg(SIGSTKFLT);
425     SignalUnReg(SIGSYS);
426     SignalUnReg(SIGTRAP);
427     SignalUnReg(SIGINT);
428     SignalUnReg(SIGKILL);
429 }
430 
FormatDateString(uint64_t timeStamp)431 static inline std::string FormatDateString(uint64_t timeStamp)
432 {
433 #if defined(__aarch64__)
434     return FormatDateString4CntCt(timeStamp, microsecond);
435 #else
436     return FormatDateString4SteadyClock(timeStamp, microsecond);
437 #endif
438 }
439 
GetDumpPreface(void)440 std::string GetDumpPreface(void)
441 {
442     std::ostringstream ss;
443     ss << "|-> Launcher proc ffrt, now:" << FormatDateString(FFRTTraceRecord::TimeStamp()) << " pid:" << GetPid()
444         << std::endl;
445     return ss.str();
446 }
447 
448 #ifdef FFRT_CO_BACKTRACE_OH_ENABLE
449 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2)
SaveTaskCounterInfo(void)450 std::string SaveTaskCounterInfo(void)
451 {
452     std::ostringstream ss;
453     ss << "    |-> task counter" << std::endl;
454     ss << "        TaskSubmitCounter:" << FFRTTraceRecord::GetSubmitCount() << " TaskEnQueueCounter:"
455        << FFRTTraceRecord::GetEnqueueCount() << " TaskDoneCounter:" << FFRTTraceRecord::GetDoneCount() << std::endl;
456 
457     ss << "        TaskRunCounter:" << FFRTTraceRecord::GetRunCount() << " TaskSwitchCounter:"
458        << FFRTTraceRecord::GetCoSwitchCount() << " TaskFinishCounter:" << FFRTTraceRecord::GetFinishCount()
459        << std::endl;
460 
461     if (FFRTTraceRecord::GetCoSwitchCount() + FFRTTraceRecord::GetFinishCount() == FFRTTraceRecord::GetRunCount()) {
462         ss << "        TaskRunCounter equals TaskSwitchCounter + TaskFinishCounter" << std::endl;
463     } else {
464         ss << "        TaskRunCounter is not equal to TaskSwitchCounter + TaskFinishCounter" << std::endl;
465     }
466     return ss.str();
467 }
468 #endif // FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2
469 
AppendTaskInfo(std::ostringstream & oss,TaskBase * task)470 void AppendTaskInfo(std::ostringstream& oss, TaskBase* task)
471 {
472 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_1)
473     if (task->fromTid) {
474         oss << " fromTid " << task->fromTid;
475     }
476     if (task->createTime) {
477         oss << " createTime " << FormatDateString(task->createTime);
478     }
479     if (task->executeTime) {
480         oss << " executeTime " << FormatDateString(task->executeTime);
481     }
482 #endif
483 }
484 
SaveKeyInfo(void)485 std::string SaveKeyInfo(void)
486 {
487     ffrt::CPUMonitor *monitor = ffrt::FFRTFacade::GetEUInstance().GetCPUMonitor();
488     std::ostringstream oss;
489 
490     monitor->WorkerInit();
491     oss << "    |-> key status" << std::endl;
492     if (saveKeyStatusInfo == nullptr) {
493         oss << "no key status info" << std::endl;
494         return oss.str();
495     }
496     oss << saveKeyStatusInfo();
497     return oss.str();
498 }
499 
DumpThreadTaskInfo(WorkerThread * thread,int qos,std::ostringstream & ss)500 void DumpThreadTaskInfo(WorkerThread* thread, int qos, std::ostringstream& ss)
501 {
502     CPUEUTask* t = thread->curTask;
503     pid_t tid = thread->Id();
504     if (t == nullptr) {
505         ss << "        qos " << qos << ": worker tid " << tid << " is running nothing" << std::endl;
506         return;
507     }
508 
509     switch (thread->curTaskType_) {
510         case ffrt_normal_task: {
511             TaskFactory::LockMem();
512             if ((!TaskFactory::HasBeenFreed(t)) && (t->state != TaskState::EXITED)) {
513                 ss << "        qos " << qos << ": worker tid " << tid << " normal task is running, task id "
514                     << t->gid << " name " << t->label.c_str();
515                 AppendTaskInfo(ss, t);
516             }
517             TaskFactory::UnlockMem();
518             ss << std::endl;
519             return;
520         }
521         case ffrt_queue_task: {
522             {
523                 std::lock_guard lk(SimpleAllocator<QueueTask>::Instance()->lock);
524                 auto queueTask = reinterpret_cast<QueueTask*>(t);
525                 if ((!SimpleAllocator<QueueTask>::HasBeenFreed(queueTask)) && (!queueTask->GetFinishStatus())) {
526                     ss << "        qos " << qos << ": worker tid " << tid << " queue task is running, task id"
527                         << t->gid << " name " << t->label.c_str();
528                     AppendTaskInfo(ss, t);
529                 }
530             }
531             ss << std::endl;
532             return;
533         }
534         case ffrt_io_task: {
535             ss << "        qos " << qos << ": worker tid " << tid << " io task is running" << std::endl;
536             return;
537         }
538         case ffrt_invalid_task: {
539             return;
540         }
541         default: {
542             ss << "       qos " << qos << ": worker tid " << tid << " uv task is running" << std::endl;
543             return;
544         }
545     }
546 }
547 
SaveWorkerStatusInfo(void)548 std::string SaveWorkerStatusInfo(void)
549 {
550     std::ostringstream ss;
551     std::ostringstream oss;
552     WorkerGroupCtl* workerGroup = FFRTFacade::GetEUInstance().GetGroupCtl();
553     oss << "    |-> worker count" << std::endl;
554     ss << "    |-> worker status" << std::endl;
555     for (int i = 0; i < QoS::MaxNum(); i++) {
556         std::vector<int> tidArr;
557         std::shared_lock<std::shared_mutex> lck(workerGroup[i].tgMutex);
558         for (auto& thread : workerGroup[i].threads) {
559             tidArr.push_back(thread.first->Id());
560             DumpThreadTaskInfo(thread.first, i, ss);
561         }
562         if (tidArr.size() == 0) {
563             continue;
564         }
565         oss << "        qos " << i << ": worker num:" << tidArr.size() << " tid:";
566         std::for_each(tidArr.begin(), tidArr.end(), [&](const int &t) {
567             if (&t == &tidArr.back()) {
568                 oss << t;
569             } else {
570                 oss << t << ", ";
571             }
572         });
573         oss << std::endl;
574     }
575     oss << ss.str();
576     return oss.str();
577 }
578 
SaveNormalTaskStatusInfo(void)579 std::string SaveNormalTaskStatusInfo(void)
580 {
581     std::string ffrtStackInfo;
582     std::ostringstream ss;
583     TaskFactory::LockMem();
584     auto unfree = TaskFactory::GetUnfreedMem();
585     auto apply = [&](const char* tag, const std::function<bool(CPUEUTask*)>& filter) {
586         std::vector<CPUEUTask*> tmp;
587         for (auto task : unfree) {
588             auto t = reinterpret_cast<CPUEUTask*>(task);
589             if (filter(t)) {
590                 tmp.emplace_back(reinterpret_cast<CPUEUTask*>(t));
591             }
592         }
593 
594         if (tmp.size() > 0) {
595             ss << "    |-> " << tag << std::endl;
596             ffrtStackInfo += ss.str();
597         }
598         size_t idx = 1;
599         for (auto t : tmp) {
600             ss.str("");
601             if (t->type == ffrt_normal_task) {
602                 ss << "        <" << idx++ << "/" << tmp.size() << ">" << "stack: task id " << t->gid << ",qos "
603                     << t->qos() << ",name " << t->label.c_str();
604                 AppendTaskInfo(ss, t);
605                 ss << std::endl;
606             }
607             ffrtStackInfo += ss.str();
608             if (t->coRoutine && (t->coRoutine->status.load() == static_cast<int>(CoStatus::CO_NOT_FINISH))) {
609                 std::string dumpInfo;
610                 DumpTask(t, dumpInfo, 1);
611                 ffrtStackInfo += dumpInfo;
612             }
613         }
614     };
615 
616     apply("blocked by synchronization primitive(mutex etc)", [](CPUEUTask* t) {
617         return (t->state == TaskState::RUNNING) && t->coRoutine &&
618             t->coRoutine->status.load() == static_cast<int>(CoStatus::CO_NOT_FINISH);
619     });
620     apply("blocked by task dependence", [](CPUEUTask* t) {
621         return t->state == TaskState::BLOCKED;
622     });
623     apply("pending task", [](CPUEUTask* t) {
624         return t->state == TaskState::PENDING;
625     });
626     apply("ready task", [](CPUEUTask* t) {
627         return t->state == TaskState::READY;
628     });
629     TaskFactory::UnlockMem();
630 
631     return ffrtStackInfo;
632 }
633 
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)634 void DumpQueueTaskInfo(std::string& ffrtStackInfo, const char* tag, const std::vector<QueueTask*>& tasks,
635     const std::function<bool(QueueTask*)>& filter, size_t limit = EACH_QUEUE_TASK_DUMP_SIZE)
636 {
637     std::vector<QueueTask*> tmp;
638     for (auto t : tasks) {
639         if (tmp.size() < limit && filter(t)) {
640             tmp.emplace_back(t);
641         }
642     }
643     if (tmp.size() == 0) {
644         return;
645     }
646     std::ostringstream ss;
647     ss << "<<<=== " << tag << "===>>>" << std::endl;
648     ffrtStackInfo += ss.str();
649 
650     size_t idx = 1;
651     for (auto t : tmp) {
652         ss.str("");
653         if (t->type == ffrt_queue_task) {
654             ss << "<" << idx++ << "/" << tmp.size() << ">" << "id " << t->gid << " qos "
655                 << t->GetQos() << " name " << t->label.c_str();
656             AppendTaskInfo(ss, t);
657             ss << std::endl;
658         }
659         ffrtStackInfo += ss.str();
660         if (t->coRoutine && (t->coRoutine->status.load() == static_cast<int>(CoStatus::CO_NOT_FINISH))) {
661             std::string dumpInfo;
662             DumpTask(reinterpret_cast<CPUEUTask*>(t), dumpInfo, 1);
663             ffrtStackInfo += dumpInfo;
664         }
665     }
666 }
667 
SaveQueueTaskStatusInfo()668 std::string SaveQueueTaskStatusInfo()
669 {
670     std::string ffrtStackInfo;
671     std::lock_guard lk(SimpleAllocator<QueueTask>::Instance()->lock);
672     auto unfreeQueueTask = SimpleAllocator<QueueTask>::getUnfreedMem();
673     if (unfreeQueueTask.size() == 0) {
674         return ffrtStackInfo;
675     }
676 
677     std::map<QueueHandler*, std::vector<QueueTask*>> taskMap;
678     for (auto t : unfreeQueueTask) {
679         auto task = reinterpret_cast<QueueTask*>(t);
680         if (task->type == ffrt_queue_task && task->GetFinishStatus() == false && task->GetHandler() != nullptr) {
681             taskMap[task->GetHandler()].push_back(task);
682         }
683     }
684     if (taskMap.empty()) {
685         return ffrtStackInfo;
686     }
687 
688     for (auto entry : taskMap) {
689         std::sort(entry.second.begin(), entry.second.end(), [](QueueTask* first, QueueTask* second) {
690             return first->GetUptime() < second->GetUptime();
691         });
692     }
693 
694     for (auto entry : taskMap) {
695         ffrtStackInfo += "\n";
696         DumpQueueTaskInfo(ffrtStackInfo, "queue task blocked by synchronization primitive(mutex etc)", entry.second,
697             [](QueueTask* t) {
698                 return (t->GetFinishStatus() == false) && t->coRoutine &&
699                     t->coRoutine->status.load() == static_cast<int>(CoStatus::CO_NOT_FINISH);
700             });
701         DumpQueueTaskInfo(ffrtStackInfo, "queue task unFinished", entry.second, [](QueueTask* t) {
702             return (t->GetFinishStatus() == false && !(t->coRoutine &&
703                 t->coRoutine->status.load() == static_cast<int>(CoStatus::CO_NOT_FINISH)));
704         });
705     }
706 
707     return ffrtStackInfo;
708 }
709 #endif
710 #endif /* FFRT_BBOX_ENABLE */
711