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