• 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 #include "dfx/watchdog/watchdog_util.h"
16 #include <sstream>
17 #include <algorithm>
18 #include <map>
19 #include "sync/sync.h"
20 #ifdef FFRT_OH_WATCHDOG_ENABLE
21 #include "c/ffrt_dump.h"
22 #endif
23 #include "dfx/log/ffrt_log_api.h"
24 #include "util/ffrt_facade.h"
25 #include "util/slab.h"
26 namespace {
27 constexpr uint64_t VALID_TIMEOUT_MIN = 10000;
28 constexpr uint64_t VALID_TIMEOUT_MAX = 30000;
29 constexpr uint32_t CONVERT_TIME_UNIT = 1000;
30 constexpr int SEND_COUNT_MIN = 1;
31 constexpr int SEND_COUNT_MAX = 3;
32 }
33 
34 namespace ffrt {
35     static std::map<uint64_t, int> taskStatusMap;
36     static std::mutex lock;
37 
38 
IsValidTimeout(uint64_t gid,uint64_t timeout_us)39     bool IsValidTimeout(uint64_t gid, uint64_t timeout_us)
40     {
41         // us convert to ms
42         uint64_t timeout_ms = timeout_us / CONVERT_TIME_UNIT;
43         // 当前有效的并行任务timeout时间范围是10-30s
44         if (timeout_ms >= VALID_TIMEOUT_MIN && timeout_ms <= VALID_TIMEOUT_MAX) {
45             FFRT_LOGI("task gid=%llu with timeout [%llu ms] is valid", gid, timeout_ms);
46             return true;
47         } else if (timeout_ms > 0) {
48             FFRT_LOGE("task gid=%llu with timeout [%llu ms] is invalid", gid, timeout_ms);
49         }
50         return false;
51     }
52 
AddTaskToWatchdog(uint64_t gid)53     void AddTaskToWatchdog(uint64_t gid)
54     {
55         std::lock_guard<decltype(lock)> l(lock);
56         taskStatusMap.insert(std::make_pair(gid, SEND_COUNT_MIN));
57     }
58 
RemoveTaskFromWatchdog(uint64_t gid)59     void RemoveTaskFromWatchdog(uint64_t gid)
60     {
61         std::lock_guard<decltype(lock)> l(lock);
62         taskStatusMap.erase(gid);
63     }
64 
SendTimeoutWatchdog(uint64_t gid,uint64_t timeout,uint64_t delay)65     bool SendTimeoutWatchdog(uint64_t gid, uint64_t timeout, uint64_t delay)
66     {
67 #ifdef FFRT_OH_WATCHDOG_ENABLE
68         // us convert to ms
69         uint64_t timeout_ms = timeout / CONVERT_TIME_UNIT;
70         FFRT_LOGI("start to set watchdog for task gid=%llu with timeout [%llu ms] ", gid, timeout_ms);
71         auto now = std::chrono::steady_clock::now();
72         WaitUntilEntry* we = new (SimpleAllocator<WaitUntilEntry>::AllocMem()) WaitUntilEntry();
73         // set dealyedworker callback
74         we->cb = ([gid, timeout_ms](WaitEntry* we) {
75             bool taskFinished = true;
76             {
77                 std::lock_guard<decltype(lock)> l(lock);
78                 if (taskStatusMap.count(gid) > 0) {
79                     int sendCount = taskStatusMap[gid];
80                     if (sendCount > SEND_COUNT_MAX) {
81                         FFRT_LOGE("parallel task gid=%llu send watchdog delaywork failed, the count more than %d times",
82                             gid, SEND_COUNT_MAX);
83                         SimpleAllocator<WaitUntilEntry>::FreeMem(static_cast<WaitUntilEntry*>(we));
84                         return;
85                     }
86                     taskStatusMap[gid] = (++sendCount);
87                     taskFinished = false;
88                 }
89             }
90 
91             if (!taskFinished) {
92                 RunTimeOutCallback(gid, timeout_ms);
93                 if (!SendTimeoutWatchdog(gid, timeout_ms * CONVERT_TIME_UNIT, 0)) {
94                     FFRT_LOGE("parallel task gid=%llu send next watchdog delaywork failed", gid);
95                     SimpleAllocator<WaitUntilEntry>::FreeMem(static_cast<WaitUntilEntry*>(we));
96                     return;
97                 };
98             } else {
99                 FFRT_LOGI("task gid=%llu has finished", gid);
100             }
101             SimpleAllocator<WaitUntilEntry>::FreeMem(static_cast<WaitUntilEntry*>(we));
102         });
103         // set dealyedworker wakeup time
104         std::chrono::microseconds timeoutTime(timeout);
105         std::chrono::microseconds delayTime(delay);
106         we->tp = (now + timeoutTime + delayTime);
107         if (!DelayedWakeup(we->tp, we, we->cb, true)) {
108             SimpleAllocator<WaitUntilEntry>::FreeMem(we);
109             FFRT_LOGE("failed to set watchdog for task gid=%llu with timeout [%llu ms] ", gid, timeout_ms);
110             return false;
111         }
112 #endif
113         return true;
114     }
115 
RunTimeOutCallback(uint64_t gid,uint64_t timeout)116     void RunTimeOutCallback(uint64_t gid, uint64_t timeout)
117     {
118 #ifdef FFRT_OH_WATCHDOG_ENABLE
119         std::stringstream ss;
120         ss << "parallel task gid=" << gid << " execution time exceeds " << timeout << " ms";
121         std::string msg = ss.str();
122         FFRT_LOGE("%s", msg.c_str());
123 
124         if (ffrt_task_timeout_get_cb()) {
125             FFRTFacade::GetDWInstance().SubmitAsyncTask([gid, msg] {
126                 ffrt_task_timeout_cb func = ffrt_task_timeout_get_cb();
127                 if (func) {
128                     func(gid, msg.c_str(), msg.size());
129                 }
130             });
131         }
132 #endif
133     }
134 }