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