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