diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..bcf187b --- /dev/null +++ b/.clang-format @@ -0,0 +1,202 @@ +# document ref: http://clang.llvm.org/docs/ClangFormatStyleOptions.html + +#禁用当前format文件 +DisableFormat: false +# BasedOnStyle: LLVM +# 访问说明符(public、 private等)的偏移 +AccessModifierOffset: -4 +# 开括号(开圆括号、 开尖括号、 开方括号)后的对齐: Align, DontAlign, AlwaysBreak(总是在开括号后换行) +AlignAfterOpenBracket: DontAlign +# 连续赋值时, 对齐所有等号 +AlignConsecutiveAssignments: false +# 连续声明时, 对齐所有声明的变量名 +AlignConsecutiveDeclarations: false +# 使用反斜杠换行不做对齐 +AlignEscapedNewlines: DontAlign +# 左对齐逃脱换行(使用反斜杠换行)的反斜杠 +AlignEscapedNewlinesLeft: false +# 水平对齐二元和三元表达式的操作数 +AlignOperands: false +# 对齐连续的尾随的注释 +AlignTrailingComments: false +# 允许函数声明的所有参数在放在下一行 +AllowAllParametersOfDeclarationOnNextLine: false +# 允许短的块放在同一行 +AllowShortBlocksOnASingleLine: false +# 允许短的case标签放在同一行 +AllowShortCaseLabelsOnASingleLine: false +# 允许短的函数放在同一行: None, InlineOnly(定义在类中), Empty(空函数), Inline(定义在类中,空函数), All +AllowShortFunctionsOnASingleLine: None +# 允许短的if语句保持在同一行 +AllowShortIfStatementsOnASingleLine: false +# 允许短的循环保持在同一行 +AllowShortLoopsOnASingleLine: false +# 总是在定义返回类型后换行(deprecated) +AlwaysBreakAfterDefinitionReturnType: None +# 总是在返回类型后换行: None, All, TopLevel(顶级函数,不包括在类中的函数), +# AllDefinitions(所有的定义,不包括声明), TopLevelDefinitions(所有的顶级函数的定义) +AlwaysBreakAfterReturnType: None +# 总是在多行string字面量前换行 +AlwaysBreakBeforeMultilineStrings: false +# 总是在template声明后换行 +AlwaysBreakTemplateDeclarations: true +# false表示函数实参要么都在同一行,要么都各自一行 +BinPackArguments: true +# false表示所有形参要么都在同一行,要么都各自一行 +BinPackParameters: true +# 大括号换行,只有当BreakBeforeBraces设置为Custom时才有效 +BraceWrapping: + # class定义后面 + AfterClass: false + # 控制语句后面 + AfterControlStatement: false + # enum定义后面 + AfterEnum: false + # 函数定义后面 + AfterFunction: true + # 命名空间定义后面 + AfterNamespace: false + # ObjC定义后面 + AfterObjCDeclaration: false + # struct定义后面 + AfterStruct: false + # union定义后面 + AfterUnion: false + # extern "C"后面 + AfterExternBlock: false + # catch之前 + BeforeCatch: false + # else之前 + BeforeElse: false + # 缩进大括号 + IndentBraces: false + # 空函数 + SplitEmptyFunction: true + # 空的类、结构、枚举 + SplitEmptyRecord: true + # 空的namespace + SplitEmptyNamespace: true +# 在二元运算符前换行: None(在操作符后换行), NonAssignment(在非赋值的操作符前换行), All(在操作符前换行) +BreakBeforeBinaryOperators: None +# 在大括号前换行: Attach(始终将大括号附加到周围的上下文), Linux(除函数、命名空间和类定义,与Attach类似), +# Mozilla(除枚举、函数、记录定义,与Attach类似),Stroustrup(除函数定义、catch、else,与Attach类似), +# Allman(总是在大括号前换行), GNU(总是在大括号前换行,并对于控制语句的大括号增加额外的缩进), WebKit(在函数前换行), Custom +# 注:这里认为语句块也属于函数 +BreakBeforeBraces: Custom +BreakBeforeInheritanceComma: false +BreakInheritanceList: AfterColon +# 在三元运算符前换行 +BreakBeforeTernaryOperators: false +# 在构造函数的初始化列表的逗号前换行 +BreakConstructorInitializersBeforeComma: false +# 每行字符的限制,0表示没有限制 +ColumnLimit: 120 +# 描述具有特殊意义的注释的正则表达式,它不应该被分割为多行或以其它方式改变 +CommentPragmas: '^ IWYU pragma:' +# 构造函数的初始化列表要么都在同一行,要么都各自一行 +ConstructorInitializerAllOnOneLineOrOnePerLine: true +# 构造函数的初始化列表的缩进宽度 +ConstructorInitializerIndentWidth: 4 +# 延续的行的缩进宽度 +ContinuationIndentWidth: 4 +# 去除C++11的列表初始化的大括号{后和}前的空格 +Cpp11BracedListStyle: true +# 继承最常用的指针和引用的对齐方式 +DerivePointerAlignment: false +# 关闭格式化 +DisableFormat: false +# 自动检测函数的调用和定义是否被格式为每行一个参数(Experimental) +ExperimentalAutoDetectBinPacking: false +#增加namespace注释 +FixNamespaceComments: true +# 需要被解读为foreach循环而不是函数调用的宏 +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +# 对#include进行排序,匹配了某正则表达式的#include拥有对应的优先级, 匹配不到的则默认优先级为INT_MAX(优先级越小排序越靠前), +# 可以定义负数优先级从而保证某些#include永远在最前面 +IncludeCategories: + -Regex: '^' + Priority: 3 + -Regex: '^<.*\.h>' + Priority: 2 + -Regex: '^<.*' + Priority: 1 + -Regex: '.*' + Priority: 4 +# 缩进case标签 +IndentCaseLabels: true +# 预处理宏不缩进 +IndentPPDirectives: none +# 缩进宽度 +IndentWidth: 4 +# 函数返回类型换行时,缩进函数声明或函数定义的函数名 +IndentWrappedFunctionNames: false +# 保留在块开始处的空行 +KeepEmptyLinesAtTheStartOfBlocks: true +# 开始一个块的宏的正则表达式 +MacroBlockBegin: '' +# 结束一个块的宏的正则表达式 +MacroBlockEnd: '' +# 连续空行的最大数量 +MaxEmptyLinesToKeep: 1 +# 命名空间的缩进: None, Inner(缩进嵌套的命名空间中的内容), All +NamespaceIndentation: None +# 在call(后对函数调用换行的penalty +PenaltyBreakBeforeFirstCallParameter: 19 +# 在一个注释中引入换行的penalty +PenaltyBreakComment: 300 +# 第一次在<<前换行的penalty +PenaltyBreakFirstLessLess: 120 +# 在一个字符串字面量中引入换行的penalty +PenaltyBreakString: 1000 +# 对于每个在行字符数限制之外的字符的penalty +PenaltyExcessCharacter: 1000000 +# 将函数的返回类型放到它自己的行的penalty +PenaltyReturnTypeOnItsOwnLine: 60 +# 指针和引用的对齐: Left, Right, Middle +PointerAlignment: Left +# 允许重新排版注释 +ReflowComments: true +# 允许排序#include +SortIncludes: false +# 允许排序using +SortUsingDeclarations: true +# template后添加空格 +SpaceAfterTemplateKeyword: true +# 在C风格类型转换后添加空格 +SpaceAfterCStyleCast: false +# 在赋值运算符之前添加空格 +SpaceBeforeAssignmentOperators: true +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +# 开圆括号之前添加一个空格: Never, ControlStatements, Always +SpaceBeforeParens: ControlStatements + +SpaceBeforeRangeBasedForLoopColon: true +# 在空的圆括号中添加空格 +SpaceInEmptyParentheses: false +# 在尾随的评论前添加的空格数(只适用于//) +SpacesBeforeTrailingComments: 1 +# 在尖括号的<后和>前添加空格 +SpacesInAngles: false +# 在容器(ObjC和JavaScript的数组和字典等)字面量中添加空格 +SpacesInContainerLiterals: false +# 在C风格类型转换的括号中添加空格 +SpacesInCStyleCastParentheses: false +# 在圆括号的(后和)前添加空格 +SpacesInParentheses: false +# 在方括号的[后和]前添加空格,lamda表达式和未指明大小的数组的声明不受影响 +SpacesInSquareBrackets: false +# SpaceBeforeCpp11BracedList, 在C++11中用于初始化变量的大括号前添加一个空格 +# true: false: +# Foo foo { bar }; vs. Foo foo{ bar }; +# Foo {}; Foo{}; +# vector { 1, 2, 3 }; vector{ 1, 2, 3 }; +# new int[3]{ 1, 2, 3 }; new int[3]{ 1, 2, 3 }; +SpaceBeforeCpp11BracedList: true +# 标准 : Cpp03, Cpp11, Auto +Standard: Cpp11 +# tab宽度 +TabWidth: 4 +# 使用tab字符: Never, ForIndentation, ForContinuationAndIndentation, Always +UseTab: Never + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..541f2e6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +#ignore files +.vscode +ffrt.cfg +build +test/build +benchmarks/output +output +trace.json \ No newline at end of file diff --git a/BUILD.gn b/BUILD.gn index e1a84f6..36a78d0 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -132,6 +132,7 @@ ohos_shared_library("libffrt") { "src/eu/co2_context.c", "src/eu/co_routine.cpp", "src/eu/co_routine_factory.cpp", + "src/eu/cpu_manager_strategy.cpp", "src/eu/cpu_monitor.cpp", "src/eu/cpu_worker.cpp", "src/eu/cpuworker_manager.cpp", @@ -208,7 +209,7 @@ ohos_shared_library("libffrt") { defines = [] if (ffrt_async_stack_enable) { - defines += [ "ASYNC_STACKTRACE" ] + defines += [ "FFRT_ASYNC_STACKTRACE" ] sources += [ "src/dfx/async_stack/ffrt_async_stack.cpp" ] } @@ -240,22 +241,9 @@ ohos_prebuilt_etc("blacklist_cfg") { ] } -ohos_prebuilt_etc("log_ctr_whitelist_cfg") { - relative_install_dir = "ffrt" - source = "log_ctr_whitelist.conf" - part_name = "ffrt" - subsystem_name = "resourceschedule" - install_enable = true - install_images = [ - "system", - "updater", - ] -} - group("ffrt_ndk") { deps = [ ":blacklist_cfg", ":libffrt", - ":log_ctr_whitelist_cfg", ] } diff --git a/hisysevent.yaml b/hisysevent.yaml index 0fb5ebd..07cf5e5 100644 --- a/hisysevent.yaml +++ b/hisysevent.yaml @@ -14,7 +14,7 @@ domain: FFRT AI_KERN_POWER_UP_ERR: - __BASE: {type: FAULT, level: MINOR, desc: AI KERNEL ipu fail or status invalid, preserve: true} + __BASE: {type: FAULT, level: MINOR, desc: AI KERNEL ipu powerup fail or status invalid, preserve: true} ERROR_LEVEL: {type: INT32, desc: error level} IC_NAME: {type: STRING, desc: IC name} MODULE_NAME: {type: STRING, desc: module name} @@ -24,7 +24,7 @@ AI_KERN_POWER_UP_ERR: DEVICE_NAME: {type: STRING, desc: device name} RUNNING_TEST_SWITCH: {type: BOOL, desc: running_test_switch} FAULT_PHENOMENON: {type: STRING, desc: fault_phenomenon} - NFF_THRESHOLD_MOUTH: {type: INT32, desc: nff_threshold_mouth} + NFF_THRESHOLD_MONTH: {type: INT32, desc: nff_threshold_month} NFF_THRESHOLD_DAY: {type: INT32, desc: nff_threshold_day} AI_KERN_WTD_TIMEOUT_ERR: @@ -38,7 +38,7 @@ AI_KERN_WTD_TIMEOUT_ERR: DEVICE_NAME: {type: STRING, desc: device name} RUNNING_TEST_SWITCH: {type: BOOL, desc: running_test_switch} FAULT_PHENOMENON: {type: STRING, desc: fault_phenomenon} - NFF_THRESHOLD_MOUTH: {type: INT32, desc: nff_threshold_mouth} + NFF_THRESHOLD_MONTH: {type: INT32, desc: nff_threshold_month} NFF_THRESHOLD_DAY: {type: INT32, desc: nff_threshold_day} TASK_TIMEOUT: diff --git a/interfaces/inner_api/c/queue_ext.h b/interfaces/inner_api/c/queue_ext.h index af66e56..285816a 100644 --- a/interfaces/inner_api/c/queue_ext.h +++ b/interfaces/inner_api/c/queue_ext.h @@ -57,7 +57,7 @@ FFRT_C_API bool ffrt_queue_has_task(ffrt_queue_t queue, const char* name); FFRT_C_API void ffrt_queue_cancel_all(ffrt_queue_t queue); /** - * @brief Cancels all unexecuted tasks and wait for running tasks in the queue. + * @brief Cancels all unexecuted tasks and wait for running tasks in the queue. No new tasks will be accepted. * * @param queue Indicates a queue handle. * @version 1.0 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2042e2d..589ebda 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,13 +1,14 @@ # ----------------------------------------------------------------------------- # ffrt code # ----------------------------------------------------------------------------- -set(FFRT_LOG_PLAT "linux") +set(FFRT_LOG_PLAT_PATH "${FFRT_CODE_PATH}/dfx/log/linux") file(GLOB_RECURSE FFRT_SRC_LIST "${FFRT_CODE_PATH}/core/*.cpp" "${FFRT_CODE_PATH}/eu/*.cpp" "${FFRT_CODE_PATH}/eu/*.c" "${FFRT_CODE_PATH}/internal_inc/*.cpp" + "${FFRT_CODE_PATH}/ipc/*.cpp" "${FFRT_CODE_PATH}/queue/*.cpp" "${FFRT_CODE_PATH}/sched/*.cpp" "${FFRT_CODE_PATH}/sync/*.cpp" diff --git a/src/core/task_io.h b/src/core/task_io.h index cdde635..6bc948d 100644 --- a/src/core/task_io.h +++ b/src/core/task_io.h @@ -17,7 +17,11 @@ #define FFRT_TASK_IO_H #include "internal_inc/types.h" -#include "sched/qos.h" +#ifdef USE_OHOS_QOS +#include "qos.h" +#else +#include "staging_qos/sched/qos.h" +#endif #include "c/executor_task.h" namespace ffrt { diff --git a/src/dfx/bbox/bbox.cpp b/src/dfx/bbox/bbox.cpp index 9d9e2f7..881329b 100644 --- a/src/dfx/bbox/bbox.cpp +++ b/src/dfx/bbox/bbox.cpp @@ -186,7 +186,7 @@ static inline void SaveNormalTaskStatus() } if (t->coRoutine && (t->coRoutine->status.load() == static_cast(CoStatus::CO_NOT_FINISH)) && t != g_cur_task) { - CoStart(t); + CoStart(t, GetCoEnv()); } } }; @@ -229,7 +229,7 @@ static inline void SaveQueueTaskStatus() } if (t->coRoutine && (t->coRoutine->status.load() == static_cast(CoStatus::CO_NOT_FINISH))) { - CoStart(reinterpret_cast(t)); + CoStart(reinterpret_cast(t), GetCoEnv()); } } }; diff --git a/src/dfx/dump/dump.cpp b/src/dfx/dump/dump.cpp index 4357900..3f85655 100644 --- a/src/dfx/dump/dump.cpp +++ b/src/dfx/dump/dump.cpp @@ -125,7 +125,7 @@ int dump_info_all(char *buf, uint32_t len) dumpInfo += SaveNormalTaskStatusInfo(); dumpInfo += SaveQueueTaskStatusInfo(); if (dumpInfo.length() > (len - 1)) { - FFRT_LOGW("dumpInfo exceeds the buffer length, length:%d", dumpInfo.length()); + FFRT_LOGW("dumpInfo exceeds the buffer length, info length:%d, input len:%u", dumpInfo.length(), len); } return snprintf_s(buf, len, len - 1, "%s", dumpInfo.c_str()); } else { diff --git a/src/dfx/sysevent/sysevent.cpp b/src/dfx/sysevent/sysevent.cpp index b262eed..f5c5fb9 100644 --- a/src/dfx/sysevent/sysevent.cpp +++ b/src/dfx/sysevent/sysevent.cpp @@ -17,7 +17,7 @@ #include "hisysevent.h" namespace ffrt { -void TaskTimeoutReport(std::stringstream& ss, std::string& processNameStr, std::string& senarioName) +void TaskTimeoutReport(std::stringstream& ss, const std::string& processNameStr, const std::string& senarioName) { std::string msg = ss.str(); std::string eventName = "TASK_TIMEOUT"; diff --git a/src/dfx/sysevent/sysevent.h b/src/dfx/sysevent/sysevent.h index 03ff5e0..540074f 100644 --- a/src/dfx/sysevent/sysevent.h +++ b/src/dfx/sysevent/sysevent.h @@ -19,7 +19,7 @@ #include namespace ffrt { #ifdef FFRT_SEND_EVENT -void TaskTimeoutReport(std::stringstream& ss, std::string& processNameStr, std::string& senarioName); +void TaskTimeoutReport(std::stringstream& ss, const std::string& processNameStr, const std::string& senarioName); #endif } #endif diff --git a/src/dfx/trace/ffrt_trace.h b/src/dfx/trace/ffrt_trace.h index b50a23b..3f8873b 100644 --- a/src/dfx/trace/ffrt_trace.h +++ b/src/dfx/trace/ffrt_trace.h @@ -112,7 +112,7 @@ private: return true; } - handle = dlopen(TRACE_LIB_PATH, RTLD_NOW | RTLD_LOCAL); + handle = dlopen(TRACE_LIB_PATH, RTLD_NOW | RTLD_LOCAL | RTLD_NODELETE); if (handle == nullptr) { FFRT_LOGE("load so[%s] fail", TRACE_LIB_PATH); return false; @@ -221,6 +221,36 @@ static bool _IsTagEnabled(uint64_t label) if (__builtin_expect(!!(_IsTagEnabled(HITRACE_TAG_FFRT)), 0)) \ _TraceCount(HITRACE_TAG_FFRT, tag, value); \ } while (false) +#define FFRT_TASK_BEGIN(tag, gid) \ + do { \ + if (__builtin_expect(!!(_IsTagEnabled(HITRACE_TAG_FFRT)), 0)) \ + _StartTrace(HITRACE_TAG_FFRT, ("FFRT" + (tag) + "|" + std::to_string(gid)).c_str(), -1); \ + } while (false) +#define FFRT_BLOCK_TRACER(gid, tag) \ + do { \ + if (__builtin_expect(!!(_IsTagEnabled(HITRACE_TAG_FFRT)), 0)) \ + _StartTrace(HITRACE_TAG_FFRT, ("FFBK" #tag "|" + std::to_string(gid)).c_str(), -1); \ + FFRT_TRACE_END(); \ + } while (false) +#define FFRT_WAKE_TRACER(gid) \ + do { \ + if (__builtin_expect(!!(_IsTagEnabled(HITRACE_TAG_FFRT)), 0)) \ + _StartTrace(HITRACE_TAG_FFRT, ("FFWK|" + std::to_string(gid)).c_str(), -1); \ + FFRT_TRACE_END(); \ + } while (false) +#define FFRT_EXECUTOR_TASK_BEGIN(ptr) \ + do { \ + if (__builtin_expect(!!(_IsTagEnabled(HITRACE_TAG_FFRT)), 0)) \ + _StartTrace(HITRACE_TAG_FFRT, ("FFRTex_task|" + \ + std::to_string(((reinterpret_cast(ptr)) & 0xffffffff))).c_str(), -1); \ + } while (false) +#define FFRT_SERIAL_QUEUE_TASK_SUBMIT_MARKER(qid, gid) \ + do { \ + if (__builtin_expect(!!(_IsTagEnabled(HITRACE_TAG_FFRT)), 0)) \ + _StartTrace(HITRACE_TAG_FFRT, ("P[sq_" + \ + std::to_string(qid) + "]|" + std::to_string(gid)).c_str(), -1); \ + FFRT_TRACE_END(); \ + } while (false) #define FFRT_TRACE_SCOPE(level, tag) ffrt::ScopedTrace ___tracer##tag(level, #tag) #else #define FFRT_TRACE_BEGIN(tag) @@ -229,6 +259,11 @@ static bool _IsTagEnabled(uint64_t label) #define FFRT_TRACE_ASYNC_END(tag, tid) #define FFRT_TRACE_COUNT(tag, value) #define FFRT_TRACE_SCOPE(level, tag) +#define FFRT_TASK_BEGIN(tag, gid) +#define FFRT_BLOCK_TRACER(gid, tag) +#define FFRT_WAKE_TRACER(gid) +#define FFRT_EXECUTOR_TASK_BEGIN(ptr) +#define FFRT_SERIAL_QUEUE_TASK_SUBMIT_MARKER(qid, gid) #endif // DFX Trace for FFRT Normal Task @@ -254,24 +289,10 @@ static bool _IsTagEnabled(uint64_t label) { \ FFRT_TRACE_ASYNC_END("Co", gid); \ } -#define FFRT_TASK_BEGIN(tag, gid) \ - { \ - FFRT_TRACE_BEGIN(("FFRT" + (tag) + "|" + std::to_string(gid)).c_str()); \ - } #define FFRT_TASK_END() \ { \ FFRT_TRACE_END(); \ } -#define FFRT_BLOCK_TRACER(gid, tag) \ - do { \ - FFRT_TRACE_BEGIN(("FFBK" #tag "|" + std::to_string(gid)).c_str()); \ - FFRT_TRACE_END(); \ - } while (false) -#define FFRT_WAKE_TRACER(gid) \ - do { \ - FFRT_TRACE_BEGIN(("FFWK|" + std::to_string(gid)).c_str()); \ - FFRT_TRACE_END(); \ - } while (false) // DFX Trace for FFRT Executor Task #define FFRT_EXECUTOR_TASK_SUBMIT_MARKER(ptr) \ @@ -290,22 +311,11 @@ static bool _IsTagEnabled(uint64_t label) { \ FFRT_TRACE_ASYNC_END("F", ((reinterpret_cast(ptr)) & 0x7fffffff)); \ } -#define FFRT_EXECUTOR_TASK_BEGIN(ptr) \ - { \ - FFRT_TRACE_BEGIN(("FFRTex_task|" + \ - std::to_string(((reinterpret_cast(ptr)) & 0xffffffff))).c_str()); \ - } #define FFRT_EXECUTOR_TASK_END() \ { \ FFRT_TRACE_END(); \ } - // DFX Trace for FFRT Serial Queue Task -#define FFRT_SERIAL_QUEUE_TASK_SUBMIT_MARKER(qid, gid) \ - do { \ - FFRT_TRACE_BEGIN(("P[sq_" + std::to_string(qid) + "]|" + std::to_string(gid)).c_str()); \ - FFRT_TRACE_END(); \ - } while (false) #define FFRT_SERIAL_QUEUE_TASK_EXECUTE_MARKER(gid) \ { \ FFRT_TRACE_ASYNC_END("E", gid); \ @@ -314,4 +324,4 @@ static bool _IsTagEnabled(uint64_t label) { \ FFRT_TRACE_ASYNC_END("D", gid); \ } -#endif \ No newline at end of file +#endif diff --git a/src/dfx/trace_record/ffrt_trace_record.h b/src/dfx/trace_record/ffrt_trace_record.h index 7db9814..c1ea380 100644 --- a/src/dfx/trace_record/ffrt_trace_record.h +++ b/src/dfx/trace_record/ffrt_trace_record.h @@ -24,12 +24,12 @@ namespace ffrt { typedef struct ffrt_record_task_counter { - std::atomic submitCounter{0}; - std::atomic enqueueCounter{0}; - std::atomic coSwitchCounter{0}; - std::atomic runCounter{0}; - std::atomic doneCounter{0}; - std::atomic cancelCounter{0}; + alignas(cacheline_size) std::atomic submitCounter{0}; + alignas(cacheline_size) std::atomic enqueueCounter{0}; + alignas(cacheline_size) std::atomic coSwitchCounter{0}; + alignas(cacheline_size) std::atomic runCounter{0}; + alignas(cacheline_size) std::atomic doneCounter{0}; + alignas(cacheline_size) std::atomic cancelCounter{0}; } ffrt_record_task_counter_t; typedef struct ffrt_record_task_time { @@ -68,15 +68,22 @@ public: return ffrt_be_used_; } + static inline void UseFfrt() + { + if (unlikely(!ffrt_be_used_)) { + ffrt_be_used_ = true; + } + } + template - static inline void AddSubmitCounter(int qos) + static inline void TaskSubmit(int qos) { #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) g_recordTaskCounter_[taskType][qos].submitCounter.fetch_add(1, std::memory_order_relaxed); #endif } - static inline void RecordCreateTimeAndTid(uint64_t* createTime, int32_t* fromTid) + static inline void TaskSubmit(uint64_t* createTime, int32_t* fromTid) { #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_1) *createTime = TimeStamp(); @@ -84,31 +91,16 @@ public: #endif } - template - static inline void TaskSubmit(int qos) - { - if (unlikely(!ffrt_be_used_)) { - ffrt_be_used_ = true; - } - AddSubmitCounter(qos); - } - - static inline void TaskSubmit(uint64_t* createTime, int32_t* fromTid) - { - if (unlikely(!ffrt_be_used_)) { - ffrt_be_used_ = true; - } - RecordCreateTimeAndTid(createTime, fromTid); - } - template static inline void TaskSubmit(int qos, uint64_t* createTime, int32_t* fromTid) { - if (unlikely(!ffrt_be_used_)) { - ffrt_be_used_ = true; - } - AddSubmitCounter(qos); - RecordCreateTimeAndTid(createTime, fromTid); +#if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) + g_recordTaskCounter_[taskType][qos].submitCounter.fetch_add(1, std::memory_order_relaxed); +#endif +#if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_1) + *createTime = TimeStamp(); + *fromTid = ExecuteCtx::Cur()->tid; +#endif } static inline void TaskExecute(uint64_t* executeTime) diff --git a/src/dm/sdependence_manager.cpp b/src/dm/sdependence_manager.cpp index 04cc3f9..484e5ba 100644 --- a/src/dm/sdependence_manager.cpp +++ b/src/dm/sdependence_manager.cpp @@ -97,13 +97,11 @@ void SDependenceManager::onSubmit(bool has_handle, ffrt_task_handle_t &handle, f new (task)SCPUEUTask(attr, parent, ++parent->childNum, QoS()); } FFRT_TRACE_BEGIN(("submit|" + std::to_string(task->gid)).c_str()); - FFRT_LOGD("submit task[%lu], name[%s]", task->gid, task->label.c_str()); #ifdef FFRT_ASYNC_STACKTRACE { task->stackId = FFRTCollectAsyncStack(); } #endif - QoS qos = (attr == nullptr ? QoS() : QoS(attr->qos_)); FFRTTraceRecord::TaskSubmit(qos, &(task->createTime), &(task->fromTid)); @@ -156,12 +154,11 @@ void SDependenceManager::onSubmit(bool has_handle, ffrt_task_handle_t &handle, f return; } } - + if (attr != nullptr) { task->notifyWorker_ = attr->notifyWorker_; } - FFRT_LOGD("Submit completed, enter ready queue, task[%lu], name[%s]", task->gid, task->label.c_str()); task->UpdateState(TaskState::READY); FFRTTraceRecord::TaskEnqueue(qos); FFRT_TRACE_END(); diff --git a/src/eu/co_routine.cpp b/src/eu/co_routine.cpp index 60cc035..6bb7108 100644 --- a/src/eu/co_routine.cpp +++ b/src/eu/co_routine.cpp @@ -61,10 +61,8 @@ static inline void CoStackCheck(CoRoutine* co) } extern pthread_key_t g_executeCtxTlsKey; -namespace { pthread_key_t g_coThreadTlsKey = 0; pthread_once_t g_coThreadTlsKeyOnce = PTHREAD_ONCE_INIT; - void CoEnvDestructor(void* args) { auto coEnv = static_cast(args); @@ -92,7 +90,6 @@ CoRoutineEnv* GetCoEnv() } return coEnv; } -} // namespace #ifdef FFRT_TASK_LOCAL_ENABLE namespace { @@ -166,9 +163,9 @@ void UpdateWorkerTsdValueToThread(void** taskTsd) threadTsd[key] = taskVal; } else { FFRT_UNLIKELY_COND_DO_ABORT((threadVal && taskVal && (threadVal != taskVal)), - "FFRT abort: mismatch key = [%u]", key); + "FFRT abort: mismatch key=[%u]", key); FFRT_UNLIKELY_COND_DO_ABORT((threadVal && !taskVal), - "FFRT abort: unexpected: thread exist but task not exist, key = [%u]", key); + "FFRT abort: unexpected: thread exists but task not exist, key=[%u]", key); } taskTsd[key] = nullptr; } @@ -268,8 +265,7 @@ static void CoSetStackProt(CoRoutine* co, int prot) uint64_t mp = reinterpret_cast(co->stkMem.stk); mp = (mp + p_size - 1) / p_size * p_size; int ret = mprotect(reinterpret_cast(static_cast(mp)), p_size, prot); - FFRT_UNLIKELY_COND_DO_ABORT(ret < 0, - "coroutine size:%lu, mp:0x%lx, page_size:%zu, result:%d, prot:%d, err:%d, %s", + FFRT_UNLIKELY_COND_DO_ABORT(ret < 0, "coroutine size:%lu, mp:0x%lx, page_size:%zu, result:%d, prot:%d, err:%d, %s", static_cast(sizeof(struct CoRoutine)), static_cast(mp), p_size, ret, prot, errno, strerror(errno)); } @@ -412,7 +408,7 @@ static inline void CoSwitchOutTransaction(ffrt::CPUEUTask* task) } // called by thread work -int CoStart(ffrt::CPUEUTask* task) +int CoStart(ffrt::CPUEUTask* task, CoRoutineEnv* coRoutineEnv) { if (task->coRoutine) { int ret = task->coRoutine->status.exchange(static_cast(CoStatus::CO_RUNNING)); @@ -455,11 +451,11 @@ int CoStart(ffrt::CPUEUTask* task) // 2. couroutine task block, switch to thread // need suspend the coroutine task or continue to execute the coroutine task. - auto pending = GetCoEnv()->pending; + auto pending = coRoutineEnv->pending; if (pending == nullptr) { return 0; } - GetCoEnv()->pending = nullptr; + coRoutineEnv->pending = nullptr; FFRTTraceRecord::TaskCoSwitchOut(task); // Fast path: skip state transition if ((*pending)(task)) { @@ -468,7 +464,7 @@ int CoStart(ffrt::CPUEUTask* task) return 0; } FFRT_WAKE_TRACER(task->gid); // fast path wk - GetCoEnv()->runningCo = co; + coRoutineEnv->runningCo = co; } return 0; } @@ -514,7 +510,6 @@ void CoWake(ffrt::CPUEUTask* task, bool timeOut) return; } // Fast path: state transition without lock - FFRT_LOGD("Cowake task[%lu], name[%s], timeOut[%d]", task->gid, task->label.c_str(), timeOut); task->wakeupTimeOut = timeOut; FFRT_WAKE_TRACER(task->gid); switch (task->type) { diff --git a/src/eu/co_routine.h b/src/eu/co_routine.h index bb92ba1..a7c1586 100644 --- a/src/eu/co_routine.h +++ b/src/eu/co_routine.h @@ -18,6 +18,7 @@ #include #include #include +#include #include "co2_context.h" #if defined(__aarch64__) @@ -26,8 +27,6 @@ constexpr size_t STACK_MAGIC = 0x7BCDABCDABCDABCD; constexpr size_t STACK_MAGIC = 0x7BCDABCD; #elif defined(__x86_64__) constexpr size_t STACK_MAGIC = 0x7BCDABCDABCDABCD; -#elif defined(__riscv) && __riscv_xlen == 64 -constexpr size_t STACK_MAGIC = 0x7BCDABCDABCDABCD; #endif #ifndef FFRT_STACK_SIZE @@ -62,6 +61,8 @@ constexpr uint64_t MIN_STACK_SIZE = 32 * 1024; using CoCtx = struct co2_context; struct CoRoutineEnv { + // when task is running, runningCo same with task->co + // if task switch out, set to null. if task complete, be used as co cache for next task. CoRoutine* runningCo = nullptr; CoCtx schCtx; const std::function* pending = nullptr; @@ -125,12 +126,14 @@ private: void CoStackFree(void); void CoWorkerExit(void); -int CoStart(ffrt::CPUEUTask* task); +int CoStart(ffrt::CPUEUTask* task, CoRoutineEnv* coRoutineEnv); void CoYield(void); void CoWait(const std::function& pred); void CoWake(ffrt::CPUEUTask* task, bool timeOut); +CoRoutineEnv* GetCoEnv(void); + #ifdef FFRT_TASK_LOCAL_ENABLE void TaskTsdDeconstruct(ffrt::CPUEUTask* task); #endif diff --git a/src/eu/cpu_manager_strategy.cpp b/src/eu/cpu_manager_strategy.cpp new file mode 100644 index 0000000..483ae9d --- /dev/null +++ b/src/eu/cpu_manager_strategy.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cpu_manager_strategy.h" +#include "internal_inc/osal.h" +#include "eu/cpuworker_manager.h" +#include "eu/scpuworker_manager.h" +#include "eu/scpu_monitor.h" + +#include + +namespace ffrt { +WorkerThread* CPUManagerStrategy::CreateCPUWorker(const QoS& qos, void* manager) +{ + constexpr int processNameLen = 32; + static std::once_flag flag; + static char processName[processNameLen]; + std::call_once(flag, []() { + GetProcessName(processName, processNameLen); + }); + CPUWorkerManager* pIns = reinterpret_cast(manager); + // default strategy of worker ops + CpuWorkerOps ops { + CPUWorker::WorkerLooperDefault, + [pIns] (WorkerThread* thread) { return pIns->PickUpTaskFromGlobalQueue(thread); }, + [pIns] (const WorkerThread* thread) { pIns->NotifyTaskPicked(thread); }, + [pIns] (const WorkerThread* thread) { return pIns->WorkerIdleAction(thread); }, + [pIns] (WorkerThread* thread) { pIns->WorkerRetired(thread); }, + [pIns] (WorkerThread* thread) { pIns->WorkerPrepare(thread); }, + [pIns] (const WorkerThread* thread, int timeout) { return pIns->TryPoll(thread, timeout); }, + [pIns] (WorkerThread* thread) { return pIns->StealTaskBatch(thread); }, + [pIns] (WorkerThread* thread) { return pIns->PickUpTaskBatch(thread); }, +#ifdef FFRT_WORKERS_DYNAMIC_SCALING + [pIns] (const WorkerThread* thread) { return pIns->IsExceedRuningThreshold(thread); }, + [pIns] () { return pIns->IsBlockAwareInit(); }, +#endif + }; + + return new (std::nothrow) CPUWorker(qos, std::move(ops), pIns); +} + +CPUMonitor* CPUManagerStrategy::CreateCPUMonitor(void* manager) +{ + constexpr int processNameLen = 32; + static std::once_flag flag; + static char processName[processNameLen]; + std::call_once(flag, []() { + GetProcessName(processName, processNameLen); + }); + SCPUWorkerManager* pIns = reinterpret_cast(manager); + // default strategy of monitor ops + CpuMonitorOps ops { + [pIns] (const QoS& qos) { return pIns->IncWorker(qos); }, + [pIns] (const QoS& qos) { pIns-> WakeupWorkers(qos); }, + [pIns] (const QoS& qos) { return pIns->GetTaskCount(qos); }, + [pIns] (const QoS& qos) { return pIns->GetWorkerCount(qos); }, + CPUMonitor::HandleTaskNotifyDefault, + }; + return new SCPUMonitor(std::move(ops)); +} +} \ No newline at end of file diff --git a/src/eu/cpu_manager_strategy.h b/src/eu/cpu_manager_strategy.h new file mode 100644 index 0000000..a47a25b --- /dev/null +++ b/src/eu/cpu_manager_strategy.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FFRT_CPU_MANAGER_INTERFACE_HPP +#define FFRT_CPU_MANAGER_INTERFACE_HPP +#ifndef FFRT_CPU_MANAGER_STRATEGY_HPP +#define FFRT_CPU_MANAGER_STRATEGY_HPP + +#include "eu/worker_thread.h" +#include "qos.h" +#include "sync/poller.h" +#include "tm/cpu_task.h" + +namespace ffrt { +enum class WorkerAction { + RETRY = 0, + RETIRE, + MAX, +}; + +enum class TaskNotifyType { + TASK_PICKED = 0, + TASK_ADDED, + TASK_LOCAL, +}; + +enum class SleepType { + SLEEP_UNTIL_WAKEUP = 0, + SLEEP_UNTIL_INTERRUPT, + SLEEP_BREAK, +}; + +struct CpuWorkerOps { + std::function WorkerLooper; + std::function PickUpTask; + std::function NotifyTaskPicked; + std::function WaitForNewAction; + std::function WorkerRetired; + std::function WorkerPrepare; + std::function TryPoll; + std::function StealTaskBatch; + std::function PickUpTaskBatch; +#ifdef FFRT_WORKERS_DYNAMIC_SCALING + std::function IsExceedRunningThreshold; + std::function IsBlockAwareInit; +#endif +}; + +struct CpuMonitorOps { + std::function IncWorker; + std::function WakeupWorkers; + std::function GetTaskCount; + std::function GetWorkerCount; + std::function HandleTaskNotity; + std::function HandleTaskNotify; +}; + +class CPUMonitor; +class CPUManagerStrategy { +public: + static WorkerThread* CreateCPUWorker(const QoS& qos, void* manager); + static CPUMonitor* CreateCPUMonitor(void* manager); +}; +} +#endif +#endif + diff --git a/src/eu/cpu_monitor.cpp b/src/eu/cpu_monitor.cpp index 662a9a5..1c8b0b2 100644 --- a/src/eu/cpu_monitor.cpp +++ b/src/eu/cpu_monitor.cpp @@ -27,6 +27,7 @@ #include "sync/poller.h" #include "util/ffrt_facade.h" #include "util/spmc_queue.h" + namespace { const size_t TIGGER_SUPPRESS_WORKER_COUNT = 4; const size_t TIGGER_SUPPRESS_EXECUTION_NUM = 2; @@ -39,7 +40,6 @@ namespace ffrt { CPUMonitor::CPUMonitor(CpuMonitorOps&& ops) : ops(ops) { SetupMonitor(); - StartMonitor(); } CPUMonitor::~CPUMonitor() @@ -142,6 +142,7 @@ void CPUMonitor::MonitorMain() exceedUpperWaterLine[i] = true; } } + stopMonitor = true; } bool CPUMonitor::IsExceedRunningThreshold(const QoS& qos) @@ -162,25 +163,46 @@ bool CPUMonitor::IsBlockAwareInit(void) void CPUMonitor::TimeoutCount(const QoS& qos) { WorkerCtrl& workerCtrl = ctrlQueue[static_cast(qos)]; - workerCtrl.lock.lock(); + std::lock_guard lk(workerCtrl.lock); workerCtrl.sleepingWorkerNum--; - workerCtrl.lock.unlock(); } -void CPUMonitor::WakeupCount(const QoS& qos, bool isDeepSleepWork) +void CPUMonitor::WakeupSleep(const QoS& qos, bool irqWake) { WorkerCtrl& workerCtrl = ctrlQueue[static_cast(qos)]; - workerCtrl.lock.lock(); + std::lock_guard lk(workerCtrl.lock); + if (irqWake) { + workerCtrl.irqEnable = false; + } workerCtrl.sleepingWorkerNum--; workerCtrl.executionNum++; - workerCtrl.lock.unlock(); } -int CPUMonitor::WakedWorkerNum(const QoS& qos) +int CPUMonitor::TotalCount(const QoS& qos) { WorkerCtrl& workerCtrl = ctrlQueue[static_cast(qos)]; - std::unique_lock lk(workerCtrl.lock); - return workerCtrl.executionNum; + workerCtrl.lock.lock(); + int total = workerCtrl.sleepingWorkerNum + workerCtrl.executionNum; + workerCtrl.lock.unlock(); + return total; +} + +void CPUMonitor::RollbackDestroy(const QoS& qos, bool irqWake) +{ + WorkerCtrl& workerCtrl = ctrlQueue[static_cast(qos)]; + std::lock_guard lk(workerCtrl.lock); + if (irqWake) { + workerCtrl.irqEnable = false; + } + workerCtrl.executionNum++; +} + +bool CPUMonitor::TryDestroy(const QoS& qos) +{ + WorkerCtrl& workerCtrl = ctrlQueue[static_cast(qos)]; + std::lock_guard lk(workerCtrl.lock); + workerCtrl.sleepingWorkerNum--; + return workerCtrl.sleepingWorkerNum > 0; } int CPUMonitor::SleepingWorkerNum(const QoS& qos) @@ -190,45 +212,44 @@ int CPUMonitor::SleepingWorkerNum(const QoS& qos) return workerCtrl.sleepingWorkerNum; } -bool CPUMonitor::HasDeepSleepWork(const QoS& qos) +int CPUMonitor::WakedWorkerNum(const QoS& qos) { WorkerCtrl& workerCtrl = ctrlQueue[static_cast(qos)]; - std::lock_guard lock(workerCtrl.lock); - return workerCtrl.hasWorkDeepSleep; + std::lock_guard lk(workerCtrl.lock); + return workerCtrl.executionNum; } void CPUMonitor::IntoDeepSleep(const QoS& qos) { WorkerCtrl& workerCtrl = ctrlQueue[static_cast(qos)]; - workerCtrl.lock.lock(); + std::lock_guard lk(workerCtrl.lock); workerCtrl.deepSleepingWorkerNum++; - workerCtrl.lock.unlock(); } -void CPUMonitor::OutOfDeepSleep(const QoS& qos) +void CPUMonitor::WakeupDeepSleep(const QoS& qos, bool irqWake) { WorkerCtrl& workerCtrl = ctrlQueue[static_cast(qos)]; - workerCtrl.lock.lock(); + std::lock_guard lk(workerCtrl.lock); + if (irqWake) { + workerCtrl.irqEnable = false; + } workerCtrl.sleepingWorkerNum--; - workerCtrl.executionNum++; workerCtrl.deepSleepingWorkerNum--; - workerCtrl.lock.unlock(); + workerCtrl.executionNum++; } void CPUMonitor::IntoPollWait(const QoS& qos) { WorkerCtrl& workerCtrl = ctrlQueue[static_cast(qos)]; - workerCtrl.lock.lock(); + std::lock_guard lk(workerCtrl.lock); workerCtrl.pollWaitFlag = true; - workerCtrl.lock.unlock(); } void CPUMonitor::OutOfPollWait(const QoS& qos) { WorkerCtrl& workerCtrl = ctrlQueue[static_cast(qos)]; - workerCtrl.lock.lock(); + std::lock_guard lk(workerCtrl.lock); workerCtrl.pollWaitFlag = false; - workerCtrl.lock.unlock(); } bool CPUMonitor::IsExceedDeepSleepThreshold() @@ -237,10 +258,9 @@ bool CPUMonitor::IsExceedDeepSleepThreshold() int deepSleepingWorkerNum = 0; for (unsigned int i = 0; i < static_cast(QoS::Max()); i++) { WorkerCtrl& workerCtrl = ctrlQueue[i]; - workerCtrl.lock.lock(); + std::lock_guard lk(workerCtrl.lock); deepSleepingWorkerNum += workerCtrl.deepSleepingWorkerNum; totalWorker += workerCtrl.executionNum + workerCtrl.sleepingWorkerNum; - workerCtrl.lock.unlock(); } return deepSleepingWorkerNum * 2 > totalWorker; } @@ -278,7 +298,7 @@ void CPUMonitor::Poke(const QoS& qos, uint32_t taskCount, TaskNotifyType notifyT ops.WakeupWorkers(qos); } else if ((runningNum < workerCtrl.maxConcurrency) && (totalNum < workerCtrl.hardLimit)) { workerCtrl.executionNum++; - FFRTTraceRecord::WorkRecord(static_cast(qos), workerCtrl.executionNum); + FFRTTraceRecord::WorkRecord((int)qos, workerCtrl.executionNum); workerCtrl.lock.unlock(); ops.IncWorker(qos); } else { @@ -331,70 +351,84 @@ void CPUMonitor::HandleTaskNotifyDefault(const QoS& qos, void* p, TaskNotifyType } } - -void CPUMonitor::PokeAdd(const QoS& qos) +// conservative strategy for poking workers +void CPUMonitor::HandleTaskNotifyConservative(const QoS& qos, void* p, TaskNotifyType notifyType) { - WorkerCtrl& workerCtrl = ctrlQueue[static_cast(qos)]; - workerCtrl.lock.lock(); - if (static_cast(workerCtrl.sleepingWorkerNum) > 0) { - workerCtrl.lock.unlock(); + CPUMonitor* monitor = reinterpret_cast(p); + int taskCount = monitor->ops.GetTaskCount(qos); + if (taskCount == 0) { + //no available task in global queue, skip return; - } else { - size_t runningNum = workerCtrl.executionNum; - size_t totalNum = static_cast(workerCtrl.sleepingWorkerNum + workerCtrl.executionNum); -#ifdef FFRT_WORKERS_DYNAMIC_SCALING - if (workerCtrl.executionNum >= workerCtrl.maxConcurrency) { - if (blockAwareInit && !BlockawareLoadSnapshot(keyPtr, &domainInfoNotify)) { - runningNum = workerCtrl.executionNum - domainInfoNotify.localinfo[qos()].nrBlocked; - } - } -#endif - if ((runningNum < workerCtrl.maxConcurrency) && (totalNum < workerCtrl.hardLimit)) { - workerCtrl.executionNum++; - workerCtrl.lock.unlock(); - ops.IncWorker(qos); - } else { - if (workerCtrl.pollWaitFlag) { - FFRTFacade::GetPPInstance().GetPoller(qos).WakeUp(); - } - workerCtrl.lock.unlock(); - } } -} - -void CPUMonitor::PokePick(const QoS& qos) -{ - WorkerCtrl& workerCtrl = ctrlQueue[static_cast(qos)]; + constexpr double thresholdTaskPick = 1.0; + WorkerCtrl& workerCtrl = monitor->ctrlQueue[static_cast(qos)]; workerCtrl.lock.lock(); - if (static_cast(workerCtrl.sleepingWorkerNum) > 0) { - if (workerCtrl.hasWorkDeepSleep &&GetOps().GetTaskCount(qos) == 0) { + + if (notifyType == TaskNotifyType::TASK_PICKED) { + int wakedWorkerCount = workerCtrl.executionNum; + double remainingLoadRatio = (wakedWorkerCount == 0) ? static_cast(workerCtrl.maxConcurrency) : + static_cast(taskCount) / static_cast(wakedWorkerCount); + if (remainingLoadRatio <= thresholdTaskPick) { + //for task pick, wake worker when load ratio > 1 workerCtrl.lock.unlock(); return; } - - workerCtrl.lock.unlock(); - - ops.WakeupWorkers(qos); - } else { - size_t runningNum = workerCtrl.executionNum; - size_t totalNum = static_cast(workerCtrl.sleepingWorkerNum + workerCtrl.executionNum); -#ifdef FFRT_WORKERS_DYNAMIC_SCALING - if (workerCtrl.executionNum >= workerCtrl.maxConcurrency) { - if (blockAwareInit && !BlockawareLoadSnapshot(keyPtr, &domainInfoNotify)) { - runningNum = workerCtrl.executionNum - domainInfoNotify.localinfo[qos()].nrBlocked; - } - } -#endif - if ((runningNum < workerCtrl.maxConcurrency) && (totalNum < workerCtrl.hardLimit)) { + } + + if (static_cast(workerCtrl.executionNum) < workerCtrl.maxConcurrency) { + if (workerCtrl.sleepingWorkerNum == 0) { + FFRT_LOGI("begin to create worker, notifyType[%d]" + "execnum[%d], maxconcur[%d], slpnum[%d], dslpnum[%d]", + notifyType, workerCtrl.executionNum, workerCtrl.maxConcurrency, + workerCtrl.sleepingWorkerNum, workerCtrl.deepSleepingWorkerNum); workerCtrl.executionNum++; workerCtrl.lock.unlock(); - ops.IncWorker(qos); + monitor->ops.IncWorker(qos); } else { - if (workerCtrl.pollWaitFlag) { - FFRTFacade::GetPPInstance().GetPoller(qos).WakeUp(); - } workerCtrl.lock.unlock(); + monitor->ops.WakeupWorkers(qos); + } + } else { + workerCtrl.lock.unlock(); + } +} + +void CPUMonitor::HandleTaskNotifyUltraConservative(const QoS& qos, void* p, TaskNotifyType notifyType) +{ + (void)notifyType; + CPUMonitor* monitor = reinterpret_cast(p); + int taskCount = monitor->ops.GetTaskCount(qos); + if (taskCount == 0) { + // no available task in global queue, skip + return; + } + + WorkerCtrl& workerCtrl = monitor->ctrlQueue[static_cast(qos)]; + std::lock_guard lock(workerCtrl.lock); + + int runningNum = workerCtrl.executionNum; +#ifdef FFRT_WORKERS_DYNAMIC_SCALING + if (monitor->blockAwareInit && !BlockawareLoadSnapshot(monitor->keyPtr, &monitor->domainInfoNotify)) { + /* nrRunning may not be updated in a timely manner */ + runningNum = workerCtrl.executionNum - monitor->domainInfoNotify.localinfo[qos()].nrBlocked; + if (!monitor->stopMonitor && taskCount == runningNum) { + BlockawareWake(); + return; + } + } +#endif + + if (taskCount < runningNum) { + return; + } + + if (runningNum < static_cast(workerCtrl.maxConcurrency)) { + if (workerCtrl.sleepingWorkerNum == 0) { + workerCtrl.executionNum++; + monitor->ops.IncWorker(qos); + } else { + monitor->ops.WakeupWorkers(qos); } } } -} \ No newline at end of file +} diff --git a/src/eu/cpu_monitor.h b/src/eu/cpu_monitor.h index c3e0cbc..7b3cf89 100644 --- a/src/eu/cpu_monitor.h +++ b/src/eu/cpu_monitor.h @@ -22,23 +22,23 @@ #include #include "qos.h" #include "cpp/mutex.h" -#include "eu/cpu_manager_interface.h" +#include "eu/cpu_manager_strategy.h" #ifdef FFRT_WORKERS_DYNAMIC_SCALING #include "eu/blockaware.h" #endif +#include "sync/sync.h" namespace ffrt { - struct WorkerCtrl { + alignas(cacheline_size) fast_mutex lock; + alignas(cacheline_size) int executionNum = 0; + alignas(cacheline_size) int sleepingWorkerNum = 0; + alignas(cacheline_size) bool irqEnable = false; size_t hardLimit = 0; size_t maxConcurrency = 0; - int executionNum = 0; - int sleepingWorkerNum = 0; bool pollWaitFlag = false; int deepSleepingWorkerNum = 0; - bool hasWorkDeepSleep = false; bool retryBeforeDeepSleep = true; - std::mutex lock; }; class CPUMonitor { @@ -48,14 +48,18 @@ public: CPUMonitor& operator=(const CPUMonitor&) = delete; virtual ~CPUMonitor(); uint32_t GetMonitorTid() const; - virtual SleepType IntoSleep(const QoS& qos) = 0; - virtual void WakeupCount(const QoS& qos, bool isDeepSleepWork = false); + int TotalCount(const QoS& qos); + virtual void IntoSleep(const QoS& qos) = 0; + + void WakeupSleep(const QoS& qos, bool irqWake = false); void IntoDeepSleep(const QoS& qos); - void OutOfDeepSleep(const QoS& qos); + void WakeupDeepSleep(const QoS& qos, bool irqWake = false); void TimeoutCount(const QoS& qos); bool IsExceedDeepSleepThreshold(); void IntoPollWait(const QoS& qos); void OutOfPollWait(const QoS& qos); + void RollbackDestroy(const QoS& qos, bool irqWake = false); + bool TryDestroy(const QoS& qos); #ifdef FFRT_WORKERS_DYNAMIC_SCALING bool IsExceedRunningThreshold(const QoS& qos); bool IsBlockAwareInit(void); @@ -67,27 +71,23 @@ public: int SetWorkerMaxNum(const QoS& qos, int num); /* strategy options for handling task notify events */ static void HandleTaskNotifyDefault(const QoS& qos, void* p, TaskNotifyType notifyType); + static void HandleTaskNotifyConservative(const QoS& qos, void* p, TaskNotifyType notifyType); + static void HandleTaskNotifyUltraConservative(const QoS& qos, void* p, TaskNotifyType notifyType); int WakedWorkerNum(const QoS& qos); int SleepingWorkerNum(const QoS& qos); void NotifyWorkers(const QoS& qos, int number); - bool HasDeepSleepWork(const QoS& qos); + void StartMonitor(); + + CpuMonitorOps ops; + std::thread* monitorThread = nullptr; uint32_t monitorTid = 0; protected: WorkerCtrl ctrlQueue[QoS::MaxNum()]; - void PokeAdd(const QoS& qos); - void PokePick(const QoS& qos); void Poke(const QoS& qos, uint32_t taskCount, TaskNotifyType notifyType); CpuMonitorOps& GetOps() { return ops; } -private: - void SetupMonitor(); - void StartMonitor(); - - std::thread* monitorThread; - CpuMonitorOps ops; - std::atomic setWorkerMaxNum[QoS::MaxNum()]; #ifdef FFRT_WORKERS_DYNAMIC_SCALING bool blockAwareInit = false; bool stopMonitor = false; @@ -98,6 +98,10 @@ private: BlockawareDomainInfoArea domainInfoNotify; std::atomic exceedUpperWaterLine[QoS::MaxNum()]; #endif +private: + void SetupMonitor(); + std::atomic setWorkerMaxNum[QoS::MaxNum()]; }; } #endif /* CPU_MONITOR_H */ + diff --git a/src/eu/cpu_worker.cpp b/src/eu/cpu_worker.cpp index 93c9e26..3054d89 100644 --- a/src/eu/cpu_worker.cpp +++ b/src/eu/cpu_worker.cpp @@ -17,27 +17,30 @@ #include "eu/worker_thread.h" #include "ffrt_trace.h" #include "sched/scheduler.h" -#include "eu/cpu_manager_interface.h" +#include "eu/cpu_manager_strategy.h" +#include "dfx/bbox/bbox.h" #include "eu/func_manager.h" #include "dm/dependence_manager.h" #include "dfx/perf/ffrt_perf.h" #include "sync/poller.h" #include "util/spmc_queue.h" +#include "util/ffrt_facade.h" #include "tm/cpu_task.h" #include "tm/queue_task.h" #ifdef FFRT_ASYNC_STACKTRACE #include "dfx/async_stack/ffrt_async_stack.h" #endif +#include "eu/cpuworker_manager.h" namespace { int PLACE_HOLDER = 0; const unsigned int TRY_POLL_FREQ = 51; } namespace ffrt { -void CPUWorker::Run(CPUEUTask* task, CPUWorker* worker) +void CPUWorker::Run(CPUEUTask* task, CoRoutineEnv* coRoutineEnv, CPUWorker* worker) { if constexpr(USE_COROUTINE) { - if (CoStart(task) != 0) { + if (CoStart(task, coRoutineEnv) != 0) { worker->localFifo.PushTail(task); } return; @@ -104,7 +107,13 @@ void* CPUWorker::WrapDispatch(void* worker) void CPUWorker::RunTask(ffrt_executor_task_t* curtask, CPUWorker* worker) { - auto ctx = ExecuteCtx::Cur(); + ExecuteCtx* ctx = ExecuteCtx::Cur(); + CoRoutineEnv* coRoutineEnv = GetCoEnv(); + RunTask(curtask, worker, ctx, coRoutineEnv); +} + +void CPUWorker::RunTask(ffrt_executor_task_t* curtask, CPUWorker* worker, ExecuteCtx* ctx, CoRoutineEnv* coRoutineEnv) +{ CPUEUTask* task = reinterpret_cast(curtask); worker->curTask = task; worker->curTaskType_ = task->type; @@ -117,7 +126,7 @@ void CPUWorker::RunTask(ffrt_executor_task_t* curtask, CPUWorker* worker) #endif ctx->task = task; ctx->lastGid_ = task->gid; - Run(task, worker); + Run(task, coRoutineEnv, worker); ctx->task = nullptr; break; } @@ -213,7 +222,6 @@ void CPUWorker::Dispatch(CPUWorker* worker) FFRT_PERF_WORKER_AWAKE(static_cast(worker->GetQos())); worker->ops.WorkerLooper(worker); CoWorkerExit(); - FFRT_LOGD("ExecutionThread exited"); worker->ops.WorkerRetired(worker); } @@ -289,4 +297,37 @@ void CPUWorker::WorkerLooperDefault(WorkerThread* p) } } } + +// work looper with standard procedure which could be strategical +void CPUWorker::WorkerLooperStandard(WorkerThread* p) +{ + CPUWorker* worker = reinterpret_cast(p); + auto mgr = reinterpret_cast(p->worker_mgr); + auto& sched = FFRTFacade::GetSchedInstance()->GetScheduler(p->GetQos()); + auto lock = mgr->GetSleepCtl(static_cast(p->GetQos())); + ExecuteCtx* ctx = ExecuteCtx::Cur(); + CoRoutineEnv* coRoutineEnv = GetCoEnv(); + for (;;) { + // try get task + CPUEUTask* task = nullptr; + if (!mgr->tearDown) { + std::lock_guard lg(*lock); + task = sched.PickNextTask(); + } + + // if succ, notify picked and run task + if (task != nullptr) { + mgr->NotifyTaskPicked(worker); + RunTask(reinterpret_cast(task), worker, ctx, coRoutineEnv); + continue; + } + // otherwise, worker wait action + auto action = worker->ops.WaitForNewAction(worker); + if (action == WorkerAction::RETRY) { + continue; + } else if (action == WorkerAction::RETIRE) { + break; + } + } +} } // namespace ffrt diff --git a/src/eu/cpu_worker.h b/src/eu/cpu_worker.h index 0b0c159..9238522 100644 --- a/src/eu/cpu_worker.h +++ b/src/eu/cpu_worker.h @@ -17,7 +17,7 @@ #define FFRT_CPU_WORKER_HPP #include "eu/worker_thread.h" -#include "eu/cpu_manager_interface.h" +#include "eu/cpu_manager_strategy.h" #include "c/executor_task.h" #include "sync/poller.h" #include "util/spmc_queue.h" @@ -26,10 +26,12 @@ namespace ffrt { const unsigned int LOCAL_QUEUE_SIZE = 128; const unsigned int STEAL_BUFFER_SIZE = LOCAL_QUEUE_SIZE / 2; + class CPUWorker : public WorkerThread { public: - CPUWorker(const QoS& qos, CpuWorkerOps&& ops) : WorkerThread(qos), ops(ops) + CPUWorker(const QoS& qos, CpuWorkerOps&& ops, void* worker_mgr) : WorkerThread(qos), ops(ops) { + this->worker_mgr = worker_mgr; localFifo.Init(LOCAL_QUEUE_SIZE); #ifdef FFRT_PTHREAD_ENABLE Start(CPUWorker::WrapDispatch, this); @@ -48,13 +50,15 @@ public: public: /* strategy options for worklooper function */ static void WorkerLooperDefault(WorkerThread* p); + static void WorkerLooperStandard(WorkerThread* p); + static void Run(CPUEUTask* task, CoRoutineEnv* coRoutineEnv, CPUWorker* worker); private: static void* WrapDispatch(void* worker); static void Dispatch(CPUWorker* worker); - static void Run(CPUEUTask* task, CPUWorker* worker); static void Run(ffrt_executor_task_t* task, ffrt_qos_t qos); static void RunTask(ffrt_executor_task_t* curtask, CPUWorker* worker); + static void RunTask(ffrt_executor_task_t* curtask, CPUWorker* worker, ExecuteCtx* ctx, CoRoutineEnv* coRoutineEnv); static void RunTaskLifo(ffrt_executor_task_t* task, CPUWorker* worker); static void* GetTask(CPUWorker* worker); static PollerRet TryPoll(CPUWorker* worker, int timeout); diff --git a/src/eu/cpuworker_manager.cpp b/src/eu/cpuworker_manager.cpp index 0b711df..1a1f8cd 100644 --- a/src/eu/cpuworker_manager.cpp +++ b/src/eu/cpuworker_manager.cpp @@ -17,8 +17,9 @@ #include #include "qos.h" #include "dfx/perf/ffrt_perf.h" +#include "dfx/trace_record/ffrt_trace_record.h" #include "eu/cpu_monitor.h" -#include "eu/cpu_manager_interface.h" +#include "eu/cpu_manager_strategy.h" #include "sched/scheduler.h" #include "sched/workgroup_internal.h" #include "eu/qos_interface.h" @@ -72,8 +73,9 @@ bool CPUWorkerManager::IncWorker(const QoS& qos) FFRT_PERF_WORKER_WAKE(workerQos); lock.unlock(); #ifdef FFRT_WORKER_MONITOR - FFRTFFacade::GetWMInstance().SubmitTask(); + FFRTFacade::GetWMInstance().SubmitTask(); #endif + FFRTTraceRecord::UseFfrt(); return true; } diff --git a/src/eu/cpuworker_manager.h b/src/eu/cpuworker_manager.h index 14aa5d4..3dbd473 100644 --- a/src/eu/cpuworker_manager.h +++ b/src/eu/cpuworker_manager.h @@ -19,7 +19,7 @@ #include "eu/worker_manager.h" #include "eu/cpu_worker.h" #include "eu/cpu_monitor.h" -#include "eu/cpu_manager_interface.h" +#include "eu/cpu_manager_strategy.h" #include "sync/poller.h" #include "util/spmc_queue.h" #include "tm/cpu_task.h" @@ -72,7 +72,6 @@ public: return monitor; } -protected: virtual void WorkerPrepare(WorkerThread* thread) = 0; virtual void WakeupWorkers(const QoS& qos) = 0; bool IncWorker(const QoS& qos) override; @@ -92,10 +91,10 @@ protected: bool IsBlockAwareInit(void); #endif -private: bool WorkerTearDown(); bool DecWorker() override {return false;} + virtual void WorkerRetiredSimplified(WorkerThread* thread) = 0; void NotifyTaskPicked(const WorkerThread* thread); /* strategy options for task pick up */ virtual CPUEUTask* PickUpTaskFromGlobalQueue(WorkerThread* thread) = 0; @@ -103,6 +102,7 @@ private: /* strategy options for worker wait action */ virtual WorkerAction WorkerIdleAction(const WorkerThread* thread) = 0; + virtual WorkerAction WorkerIdleActionSimplified(const WorkerThread* thread) = 0; void WorkerSetup(WorkerThread* thread); PollerRet TryPoll(const WorkerThread* thread, int timeout = -1); diff --git a/src/eu/scpu_monitor.cpp b/src/eu/scpu_monitor.cpp index 50bf06f..0547eee 100644 --- a/src/eu/scpu_monitor.cpp +++ b/src/eu/scpu_monitor.cpp @@ -12,19 +12,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "eu/cpu_manager_interface.h" +#include "eu/cpu_manager_strategy.h" #include "eu/scpu_monitor.h" namespace ffrt { -SleepType SCPUMonitor::IntoSleep(const QoS& qos) +void SCPUMonitor::IntoSleep(const QoS& qos) { - SleepType type = SleepType::SLEEP_UNTIL_WAKEUP; WorkerCtrl& workerCtrl = ctrlQueue[static_cast(qos)]; workerCtrl.lock.lock(); workerCtrl.sleepingWorkerNum++; workerCtrl.executionNum--; workerCtrl.lock.unlock(); - return type; } void SCPUMonitor::Notify(const QoS& qos, TaskNotifyType notifyType) diff --git a/src/eu/scpu_monitor.h b/src/eu/scpu_monitor.h index 4b37ac9..49b83be 100644 --- a/src/eu/scpu_monitor.h +++ b/src/eu/scpu_monitor.h @@ -16,7 +16,7 @@ #ifndef SCPU_MONITOR_H #define SCPU_MONITOR_H -#include "eu/cpu_manager_interface.h" +#include "eu/cpu_manager_strategy.h" #include "eu/cpu_monitor.h" namespace ffrt { @@ -24,8 +24,7 @@ namespace ffrt { class SCPUMonitor : public CPUMonitor { public: SCPUMonitor(CpuMonitorOps&& ops) : CPUMonitor(std::move(ops)) {}; - SleepType IntoSleep(const QoS& qos) override; - + void IntoSleep(const QoS& qos) override; void Notify(const QoS& qos, TaskNotifyType notifyType) override; void WorkerInit() override; }; diff --git a/src/eu/scpuworker_manager.cpp b/src/eu/scpuworker_manager.cpp index 7f71a13..0e5a7d7 100644 --- a/src/eu/scpuworker_manager.cpp +++ b/src/eu/scpuworker_manager.cpp @@ -18,24 +18,34 @@ #include #include "dfx/perf/ffrt_perf.h" #include "eu/co_routine_factory.h" -#include "eu/cpu_manager_interface.h" +#include "eu/cpu_manager_strategy.h" #include "eu/qos_interface.h" #include "eu/scpu_monitor.h" #include "sched/scheduler.h" #include "sched/workgroup_internal.h" #include "util/ffrt_facade.h" -#include "eu/scpuworker_manager.h" #include "util/slab.h" +#include "eu/scpuworker_manager.h" #ifdef FFRT_WORKERS_DYNAMIC_SCALING #include "eu/blockaware.h" #endif namespace { -#if !defined(OHOS_STANDARD_SYSTEM) +/* SUPPORT_WORKER_DESTRUCT indicates that the idle thread destruction function is supported. + * The stack canary is saved or destored during coroutine switch-out and switch-in, + * currently, only the stack canary used by the ohos compiler stack protection is global + * and is not affected by worker destruction. +*/ +#if !defined(SUPPORT_WORKER_DESTRUCT) constexpr int waiting_seconds = 10; #else constexpr int waiting_seconds = 5; #endif + +const std::map NOTIFY_FUNCTION_FACTORY = { + { "CameraDaemon", ffrt::CPUMonitor::HandleTaskNotifyConservative }, + { "bluetooth", ffrt::CPUMonitor::HandleTaskNotifyUltraConservative }, +}; } namespace ffrt { @@ -44,6 +54,7 @@ constexpr uint64_t DELAYED_WAKED_UP_TASK_TIME_INTERVAL = 5 * 1000 * 1000; SCPUWorkerManager::SCPUWorkerManager() { monitor = CPUManagerStrategy::CreateCPUMonitor(this); + (void)monitor->StartMonitor(); } SCPUWorkerManager::~SCPUWorkerManager() @@ -71,81 +82,38 @@ SCPUWorkerManager::~SCPUWorkerManager() delete monitor; } -void SCPUWorkerManager::AddDelayedTask(int qos) +void SCPUWorkerManager::WorkerRetiredSimplified(WorkerThread* thread) { - WaitUntilEntry* we = new (SimpleAllocator::AllocMem()) WaitUntilEntry(); - we->tp = std::chrono::steady_clock::now() + std::chrono::microseconds(DELAYED_WAKED_UP_TASK_TIME_INTERVAL); - we->cb = ([this, qos](WaitEntry* we) { - int taskCount = GetTaskCount(QoS(qos)); + pid_t pid = thread->Id(); + int qos = static_cast(thread->GetQos()); + + bool isEmptyQosThreads = false; + { std::unique_lock lck(groupCtl[qos].tgMutex); - bool isEmpty = groupCtl[qos].threads.empty(); - lck.unlock(); - - if (!isEmpty) { - SimpleAllocator::FreeMem(static_cast(we)); - FFRT_LOGW("qos[%d] has worker, no need add delayed task", qos); - return; + thread->SetExited(true); + thread->Detach(); + auto worker = std::move(groupCtl[qos].threads[thread]); + int ret = groupCtl[qos].threads.erase(thread); + if (ret != 1) { + FFRT_LOGE("erase qos[%d] thread failed, %d elements removed", qos, ret); } - if (taskCount != 0) { - FFRT_LOGI("notify task, qos %d", qos); - FFRTFacade::GetEUInstance().NotifyTaskAdded(QoS(qos)); - } else { - AddDelayedTask(qos); + isEmptyQosThreads = groupCtl[qos].threads.empty(); + WorkerLeaveTg(QoS(qos), pid); +#ifdef FFRT_WORKERS_DYNAMIC_SCALING + if (IsBlockAwareInit()) { + ret = BlockawareUnregister(); + if (ret != 0) { + FFRT_LOGE("blockaware unregister fail, ret[%d]", ret); + } } - SimpleAllocator::FreeMem(static_cast(we)); - }); - if (!DelayedWakeup(we->tp, we, we->cb)) { - SimpleAllocator::FreeMem(we); - FFRT_LOGW("add delyaed task failed, qos %d", qos); - } -} - -WorkerAction SCPUWorkerManager::WorkerIdleAction(const WorkerThread* thread) -{ - if (tearDown) { - return WorkerAction::RETIRE; +#endif + worker = nullptr; } - auto& ctl = sleepCtl[thread->GetQos()]; - std::unique_lock lk(ctl.mutex); - (void)monitor->IntoSleep(thread->GetQos()); - FFRT_PERF_WORKER_IDLE(static_cast(thread->GetQos())); -#ifdef FFRT_WORKERS_DYNAMIC_SCALING - BlockawareEnterSleeping(); -#endif - if (ctl.cv.wait_for(lk, std::chrono::seconds(waiting_seconds), [this, thread] { - bool taskExistence = GetTaskCount(thread->GetQos()) || - reinterpret_cast(thread)->priority_task || - reinterpret_cast(thread)->localFifo.GetLength(); - bool needPoll = !FFRTFacade::GetPPInstance().GetPoller(thread->GetQos()).DetermineEmptyMap() && - (polling_[thread->GetQos()] == 0); - return tearDown || taskExistence || needPoll; - })) { - monitor->WakeupCount(thread->GetQos()); - FFRT_PERF_WORKER_AWAKE(static_cast(thread->GetQos())); -#ifdef FFRT_WORKERS_DYNAMIC_SCALING - BlockawareLeaveSleeping(); -#endif - return WorkerAction::RETRY; - } else { -#if !defined(OHOS_STANDARD_SYSTEM) - monitor->IntoDeepSleep(thread->GetQos()); - CoStackFree(); - if (monitor->IsExceedDeepSleepThreshold()) { - ffrt::CoRoutineReleaseMem(); - } - ctl.cv.wait(lk, [this, thread] { - return tearDown || GetTaskCount(thread->GetQos()) || - reinterpret_cast(thread)->priority_task || - reinterpret_cast(thread)->localFifo.GetLength(); - }); - monitor->OutOfDeepSleep(thread->GetQos()); - return WorkerAction::RETRY; -#else - monitor->TimeoutCount(thread->GetQos()); - FFRT_LOGD("worker exit"); - return WorkerAction::RETIRE; -#endif + //qos has no worker, start delay worker to monitor task + if (isEmptyQosThreads) { + FFRT_LOGI("qos has no worker, start delay worker to monitor task, qos %d", qos); + AddDelayedTask(qos); } } @@ -156,7 +124,7 @@ CPUEUTask* SCPUWorkerManager::PickUpTaskFromGlobalQueue(WorkerThread* thread) return nullptr; } - auto& sched = FFRTScheduler::Instance()->GetScheduler(thread->GetQos()); + auto& sched = FFRTFacade::GetSchedInstance()->GetScheduler(thread->GetQos()); auto lock = GetSleepCtl(static_cast(thread->GetQos())); std::lock_guard lg(*lock); return sched.PickNextTask(); @@ -168,7 +136,7 @@ CPUEUTask* SCPUWorkerManager::PickUpTaskBatch(WorkerThread* thread) return nullptr; } - auto& sched = FFRTScheduler::Instance()->GetScheduler(thread->GetQos()); + auto& sched = FFRTFacade::GetSchedInstance()->GetScheduler(thread->GetQos()); auto lock = GetSleepCtl(static_cast(thread->GetQos())); std::lock_guard lg(*lock); CPUEUTask* task = sched.PickNextTask(); @@ -201,6 +169,119 @@ CPUEUTask* SCPUWorkerManager::PickUpTaskBatch(WorkerThread* thread) return task; } +void SCPUWorkerManager::AddDelayedTask(int qos) +{ + WaitUntilEntry* we = new (SimpleAllocator::AllocMem()) WaitUntilEntry(); + we->tp = std::chrono::steady_clock::now() + std::chrono::microseconds(DELAYED_WAKED_UP_TASK_TIME_INTERVAL); + we->cb = ([this, qos](WaitEntry* we) { + int taskCount = GetTaskCount(QoS(qos)); + std::unique_lock lck(groupCtl[qos].tgMutex); + bool isEmpty = groupCtl[qos].threads.empty(); + lck.unlock(); + + if (!isEmpty) { + SimpleAllocator::FreeMem(static_cast(we)); + FFRT_LOGW("qos[%d] has worker, no need add delayed task", qos); + return; + } + + if (taskCount != 0) { + FFRT_LOGI("notify task, qos %d", qos); + FFRTFacade::GetEUInstance().NotifyTaskAdded(QoS(qos)); + } else { + AddDelayedTask(qos); + } + SimpleAllocator::FreeMem(static_cast(we)); + }); + + if (!DelayedWakeup(we->tp, we, we->cb)) { + SimpleAllocator::FreeMem(we); + FFRT_LOGW("add delyaed task failed, qos %d", qos); + } +} + +WorkerAction SCPUWorkerManager::WorkerIdleAction(const WorkerThread* thread) +{ + if (tearDown) { + return WorkerAction::RETIRE; + } + + auto& ctl = sleepCtl[thread->GetQos()]; + std::unique_lock lk(ctl.mutex); + monitor->IntoSleep(thread->GetQos()); + FFRT_PERF_WORKER_IDLE(static_cast(thread->GetQos())); +#ifdef FFRT_WORKERS_DYNAMIC_SCALING + BlockawareEnterSleeping(); +#endif + if (ctl.cv.wait_for(lk, std::chrono::seconds(waiting_seconds), [this, thread] { + bool taskExistence = GetTaskCount(thread->GetQos()) || + reinterpret_cast(thread)->priority_task || + reinterpret_cast(thread)->localFifo.GetLength(); + bool needPoll = !FFRTFacade::GetPPInstance().GetPoller(thread->GetQos()).DetermineEmptyMap() && + (polling_[thread->GetQos()] == 0); + return tearDown || taskExistence || needPoll; + })) { + monitor->WakeupSleep(thread->GetQos()); + FFRT_PERF_WORKER_AWAKE(static_cast(thread->GetQos())); +#ifdef FFRT_WORKERS_DYNAMIC_SCALING + BlockawareLeaveSleeping(); +#endif + return WorkerAction::RETRY; + } else { +#if !defined(SUPPORT_WORKER_DESTRUCT) + monitor->IntoDeepSleep(thread->GetQos()); + CoStackFree(); + if (monitor->IsExceedDeepSleepThreshold()) { + ffrt::CoRoutineReleaseMem(); + } + ctl.cv.wait(lk, [this, thread] { + return tearDown || GetTaskCount(thread->GetQos()) || + reinterpret_cast(thread)->priority_task || + reinterpret_cast(thread)->localFifo.GetLength(); + }); + monitor->WakeupDeepSleep(thread->GetQos()); + return WorkerAction::RETRY; +#else + monitor->TimeoutCount(thread->GetQos()); + return WorkerAction::RETIRE; +#endif + } +} + +WorkerAction SCPUWorkerManager::WorkerIdleActionSimplified(const WorkerThread* thread) +{ + if (tearDown) { + return WorkerAction::RETIRE; + } + + auto& ctl = sleepCtl[thread->GetQos()]; + std::unique_lock lk(ctl.mutex); + monitor->IntoSleep(thread->GetQos()); + FFRT_PERF_WORKER_IDLE(static_cast(thread->GetQos())); + if (ctl.cv.wait_for(lk, std::chrono::seconds(waiting_seconds), [this, thread] { + bool taskExistence = GetTaskCount(thread->GetQos()); + return tearDown || taskExistence; + })) { + monitor->WakeupSleep(thread->GetQos()); + FFRT_PERF_WORKER_AWAKE(static_cast(thread->GetQos())); + return WorkerAction::RETRY; + } else { +#if !defined(SUPPORT_WORKER_DESTRUCT) + monitor->IntoDeepSleep(thread->GetQos()); + CoStackFree(); + if (monitor->IsExceedDeepSleepThreshold()) { + ffrt::CoRoutineReleaseMem(); + } + ctl.cv.wait(lk, [this, thread] {return tearDown || GetTaskCount(thread->GetQos());}); + monitor->WakeupDeepSleep(thread->GetQos()); + return WorkerAction::RETRY; +#else + monitor->TimeoutCount(thread->GetQos()); + return WorkerAction::RETIRE; +#endif + } +} + void SCPUWorkerManager::WorkerPrepare(WorkerThread* thread) { WorkerJoinTg(thread->GetQos(), thread->Id()); @@ -217,54 +298,5 @@ void SCPUWorkerManager::WakeupWorkers(const QoS& qos) ctl.cv.notify_one(); FFRT_PERF_WORKER_WAKE(static_cast(qos)); } - -WorkerThread* CPUManagerStrategy::CreateCPUWorker(const QoS& qos, void* manager) -{ - constexpr int processNameLen = 32; - static std::once_flag flag; - static char processName[processNameLen]; - std::call_once(flag, []() { - GetProcessName(processName, processNameLen); - }); - CPUWorkerManager* pIns = reinterpret_cast(manager); - // default strategy of worker ops - CpuWorkerOps ops { - CPUWorker::WorkerLooperDefault, - [pIns] (WorkerThread* thread) { return pIns->PickUpTaskFromGlobalQueue(thread); }, - [pIns] (const WorkerThread* thread) { pIns->NotifyTaskPicked(thread); }, - [pIns] (const WorkerThread* thread) { return pIns->WorkerIdleAction(thread); }, - [pIns] (WorkerThread* thread) { pIns->WorkerRetired(thread); }, - [pIns] (WorkerThread* thread) { pIns->WorkerPrepare(thread); }, - [pIns] (const WorkerThread* thread, int timeout) { return pIns->TryPoll(thread, timeout); }, - [pIns] (WorkerThread* thread) { return pIns->StealTaskBatch(thread); }, - [pIns] (WorkerThread* thread) { return pIns->PickUpTaskBatch(thread); }, -#ifdef FFRT_WORKERS_DYNAMIC_SCALING - [pIns] (const WorkerThread* thread) { return pIns->IsExceedRunningThreshold(thread); }, - [pIns] () { return pIns->IsBlockAwareInit(); }, -#endif - }; - - return new (std::nothrow) CPUWorker(qos, std::move(ops)); -} - -CPUMonitor* CPUManagerStrategy::CreateCPUMonitor(void* manager) -{ - constexpr int processNameLen = 32; - static std::once_flag flag; - static char processName[processNameLen]; - std::call_once(flag, []() { - GetProcessName(processName, processNameLen); - }); - SCPUWorkerManager* pIns = reinterpret_cast(manager); - // default strategy of monitor ops - CpuMonitorOps ops { - [pIns] (const QoS& qos) { return pIns->IncWorker(qos); }, - [pIns] (const QoS& qos) { pIns->WakeupWorkers(qos); }, - [pIns] (const QoS& qos) { return pIns->GetTaskCount(qos); }, - [pIns] (const QoS& qos) { return pIns->GetWorkerCount(qos); }, - CPUMonitor::HandleTaskNotifyDefault, - }; - - return new SCPUMonitor(std::move(ops)); -} } // namespace ffrt + diff --git a/src/eu/scpuworker_manager.h b/src/eu/scpuworker_manager.h index d3ed325..c7a60d0 100644 --- a/src/eu/scpuworker_manager.h +++ b/src/eu/scpuworker_manager.h @@ -23,11 +23,12 @@ public: SCPUWorkerManager(); ~SCPUWorkerManager() override; WorkerAction WorkerIdleAction(const WorkerThread* thread) override; - void WorkerPrepare(WorkerThread* thread) override; - void WakeupWorkers(const QoS& qos) override; + WorkerAction WorkerIdleActionSimplified(const WorkerThread* thread) override; CPUEUTask* PickUpTaskFromGlobalQueue(WorkerThread* thread) override; CPUEUTask* PickUpTaskBatch(WorkerThread* thread) override; - friend class CPUManagerStrategy; + void WorkerRetiredSimplified(WorkerThread* thread) override; + void WorkerPrepare(WorkerThread* thread) override; + void WakeupWorkers(const QoS& qos) override; private: void AddDelayedTask(int qos); }; diff --git a/src/eu/worker_thread.h b/src/eu/worker_thread.h index 72be909..1a72dc3 100644 --- a/src/eu/worker_thread.h +++ b/src/eu/worker_thread.h @@ -186,6 +186,7 @@ public: void WorkerSetup(WorkerThread* wthread); void NativeConfig(); + void* worker_mgr; private: std::atomic_bool exited; diff --git a/src/queue/base_queue.cpp b/src/queue/base_queue.cpp index 0926fb0..50a8909 100644 --- a/src/queue/base_queue.cpp +++ b/src/queue/base_queue.cpp @@ -13,13 +13,14 @@ * limitations under the License. */ -#include "base_queue.h" +#include #include "dfx/log/ffrt_log_api.h" #include "tm/queue_task.h" #include "serial_queue.h" #include "concurrent_queue.h" #include "eventhandler_adapter_queue.h" #include "eventhandler_interactive_queue.h" +#include "base_queue.h" namespace { using CreateFunc = std::unique_ptr(*)(const ffrt_queue_attr_t*); diff --git a/src/queue/queue_handler.cpp b/src/queue/queue_handler.cpp index c823290..2cf1817 100644 --- a/src/queue/queue_handler.cpp +++ b/src/queue/queue_handler.cpp @@ -13,6 +13,7 @@ * limitations under the License. */ #include "queue_handler.h" +#include #include #include "dfx/log/ffrt_log_api.h" #include "dfx/trace_record/ffrt_trace_record.h" @@ -63,7 +64,6 @@ QueueHandler::QueueHandler(const char* name, const ffrt_queue_attr_t* attr, cons QueueHandler::~QueueHandler() { - FFRT_COND_DO_ERR((queue_ == nullptr), return, "cannot destruct, [queueId=%u] constructed failed", GetQueueId()); FFRT_LOGI("destruct %s enter", name_.c_str()); // clear tasks in queue CancelAndWait(); @@ -173,8 +173,8 @@ void QueueHandler::CancelAndWait() { FFRT_COND_DO_ERR((queue_ == nullptr), return, "cannot cancelAndWait, [queueId=%u] constructed failed", GetQueueId()); - queue_->Remove(); - while (FFRTFacade::GetQMInstance().QueryQueueStatus(GetQueueId()) != 0 || queue_->GetActiveStatus()) { + queue_->Stop(); + while (FFRTFacade::GetQMInstance().QueryQueueStatus(GetQueueId()) || queue_->GetActiveStatus()) { std::this_thread::sleep_for(std::chrono::microseconds(TASK_DONE_WAIT_UNIT)); } } @@ -200,6 +200,7 @@ int QueueHandler::Cancel(QueueTask* task) if (task->GetSchedTimeout() > 0) { RemoveSchedDeadline(task); } + int ret = queue_->Remove(task); if (ret == SUCC) { FFRT_LOGD("cancel task[%llu] %s succ", task->gid, task->label.c_str()); @@ -245,7 +246,6 @@ void QueueHandler::Dispatch(QueueTask* inTask) f->destroy(f); task->Notify(); - RemoveTimeoutMonitor(task); // run task batch nextTask = task->GetNextTask(); @@ -299,25 +299,25 @@ void QueueHandler::SetTimeoutMonitor(QueueTask* task) } task->IncDeleteRef(); - timeoutWe_ = new (SimpleAllocator::AllocMem()) WaitUntilEntry(); + WaitUntilEntry* we = new (SimpleAllocator::AllocMem()) WaitUntilEntry(); // set delayed worker callback - timeoutWe_->cb = ([this, task](WaitEntry* timeoutWe_) { + we->cb = ([this, task](WaitEntry* we) { if (!task->GetFinishStatus()) { RunTimeOutCallback(task); } delayedCbCnt_.fetch_sub(1); task->DecDeleteRef(); - SimpleAllocator::FreeMem(static_cast(timeoutWe_)); + SimpleAllocator::FreeMem(static_cast(we)); }); // set delayed worker wakeup time std::chrono::microseconds timeout(timeout_); auto now = std::chrono::time_point_cast(std::chrono::steady_clock::now()); - timeoutWe_->tp = std::chrono::time_point_cast(now + timeout); + we->tp = std::chrono::time_point_cast(now + timeout); - if (!DelayedWakeup(timeoutWe_->tp, timeoutWe_, timeoutWe_->cb)) { + if (!DelayedWakeup(we->tp, we, we->cb)) { task->DecDeleteRef(); - SimpleAllocator::FreeMem(timeoutWe_); + SimpleAllocator::FreeMem(we); FFRT_LOGW("failed to set watchdog for task gid=%llu in %s with timeout [%llu us] ", task->gid, name_.c_str(), timeout_); return; @@ -327,20 +327,6 @@ void QueueHandler::SetTimeoutMonitor(QueueTask* task) FFRT_LOGD("set watchdog of task gid=%llu of %s succ", task->gid, name_.c_str()); } -void QueueHandler::RemoveTimeoutMonitor(QueueTask* task) -{ - if (timeout_ <= 0) { - return; - } - - WaitEntry* dwe = static_cast(timeoutWe_); - if (DelayedRemove(timeoutWe_->tp, dwe)) { - delayedCbCnt_.fetch_sub(1); - SimpleAllocator::FreeMem(static_cast(timeoutWe_)); - } - return; -} - void QueueHandler::RunTimeOutCallback(QueueTask* task) { std::stringstream ss; @@ -392,7 +378,7 @@ void QueueHandler::SetEventHandler(void* eventHandler) void* QueueHandler::GetEventHandler() { FFRT_COND_DO_ERR((queue_ == nullptr), return nullptr, "[queueId=%u] constructed failed", GetQueueId()); - + bool typeInvalid = (queue_->GetQueueType() != ffrt_queue_eventhandler_interactive) && (queue_->GetQueueType() != ffrt_queue_eventhandler_adapter); FFRT_COND_DO_ERR(typeInvalid, return nullptr, "[queueId=%u] type invalid", GetQueueId()); @@ -422,7 +408,7 @@ void QueueHandler::SendSchedTimer(TimePoint delay) we_->cb = ([this](WaitEntry* we_) { CheckSchedDeadline(); }); bool result = DelayedWakeup(we_->tp, we_, we_->cb); while (!result) { - FFRT_LOGW("failed to set delayedwoker, retry"); + FFRT_LOGW("failed to set delayedworker, retry"); we_->tp = std::chrono::steady_clock::now() + std::chrono::microseconds(SCHED_TIME_ACC_ERROR_US); result = DelayedWakeup(we_->tp, we_, we_->cb); } diff --git a/src/queue/queue_handler.h b/src/queue/queue_handler.h index 93e236c..7cff32d 100644 --- a/src/queue/queue_handler.h +++ b/src/queue/queue_handler.h @@ -14,7 +14,7 @@ */ #ifndef FFRT_QUEUE_HANDLER_H #define FFRT_QUEUE_HANDLER_H - + #include #include #include @@ -24,7 +24,6 @@ #include "cpp/task.h" #include "base_queue.h" #include "sched/execute_ctx.h" -#include "sched/execute_ctx.h" namespace ffrt { class QueueTask; @@ -48,21 +47,21 @@ public: bool SetLoop(Loop* loop); bool ClearLoop(); - + QueueTask* PickUpTask(); - - inline bool IsValidForLoop() + + inline bool IsValidForLoop() { return !isUsed_.load() && (queue_->GetQueueType() == ffrt_queue_concurrent - || queue_->GetQueueType() == ffrt_queue_eventhandler_interactive); + || queue_->GetQueueType() == ffrt_queue_eventhandler_interactive); } - - inline std::string GetName() + + inline std::string GetName() { return name_; } - - inline uint32_t GetQueueId() + + inline uint32_t GetQueueId() { FFRT_COND_DO_ERR((queue_ == nullptr), return 0, "queue construct failed"); return queue_->GetQueueId(); @@ -81,7 +80,7 @@ public: inline uint64_t GetTaskCnt() { - FFRT_COND_DO_ERR((queue_ == nullptr), return false, "[queueID=%u] constructed failed", GetQueueId()); + FFRT_COND_DO_ERR((queue_ == nullptr), return false, "[queueId=%u] constructed failed", GetQueueId()); return queue_->GetMapSize(); } @@ -101,7 +100,6 @@ private: void Deliver(); void TransferInitTask(); void SetTimeoutMonitor(QueueTask* task); - void RemoveTimeoutMonitor(QueueTask* task); void RunTimeOutCallback(QueueTask* task); void CheckSchedDeadline(); @@ -120,7 +118,6 @@ private: uint64_t timeout_ = 0; std::atomic_int delayedCbCnt_ = {0}; ffrt_function_header_t* timeoutCb_ = nullptr; - WaitUntilEntry* timeoutWe_ = nullptr; std::mutex mutex_; bool initSchedTimer_ = false; diff --git a/src/queue/queue_monitor.cpp b/src/queue/queue_monitor.cpp index 6306a77..833ae0a 100644 --- a/src/queue/queue_monitor.cpp +++ b/src/queue/queue_monitor.cpp @@ -55,7 +55,7 @@ QueueMonitor::QueueMonitor() QueueMonitor::~QueueMonitor() { - FFRT_LOGI("destruction of QueueMonitor enter"); + FFRT_LOGI("destruction of QueueMonitor"); SimpleAllocator::FreeMem(we_); } diff --git a/src/sched/execute_ctx.cpp b/src/sched/execute_ctx.cpp index 00dbc14..692036a 100644 --- a/src/sched/execute_ctx.cpp +++ b/src/sched/execute_ctx.cpp @@ -15,9 +15,10 @@ #include "execute_ctx.h" #include #include +#include + pthread_key_t g_executeCtxTlsKey = 0; pthread_once_t g_executeCtxKeyOnce = PTHREAD_ONCE_INIT; - namespace ffrt { namespace { void ExecuteCtxTlsDestructor(void* args) @@ -32,7 +33,7 @@ void MakeExecuteCtxTlsKey() { pthread_key_create(&g_executeCtxTlsKey, ExecuteCtxTlsDestructor); } -} // namespace +} ExecuteCtx::ExecuteCtx() { diff --git a/src/sched/multi_workgroup.cpp b/src/sched/multi_workgroup.cpp index 1942261..c2d1455 100644 --- a/src/sched/multi_workgroup.cpp +++ b/src/sched/multi_workgroup.cpp @@ -20,6 +20,7 @@ #include "dfx/log/ffrt_log_api.h" #include "task_client_adapter.h" + #if (defined(QOS_WORKER_FRAME_RTG) || defined(QOS_FRAME_RTG)) constexpr int HWC_UID = 3039; constexpr int ROOT_UID = 0; @@ -27,7 +28,7 @@ constexpr int RS_RTG_ID = 10; namespace ffrt { static int wgId = -1; -static WorkGroup *rsWorkGroup = nullptr; +static WorkGroup* rsWorkGroup = nullptr; static int wgCount = 0; static std::mutex wgLock; @@ -115,7 +116,7 @@ bool LeaveRSWorkGroup(int tid) if (existIndex != -1) { rsWorkGroup->tids[existIndex] = -1; } - FFRT_LOGI("[RSWorkGroup] LeaveRSWorkGroup ,tid:%{public}d,existIndex:%{public}d", tid, existIndex); + FFRT_LOGI("[RSWorkGroup] LeaveRSWorkGroup ,tid: %{public}d, existIndex: %{public}d", tid, existIndex); return true; } @@ -165,7 +166,6 @@ bool JoinWG(int tid) } return false; } - int uid = getuid(); if (uid == RS_UID) { return JoinRSWorkGroup(tid); @@ -203,7 +203,7 @@ struct WorkGroup* WorkgroupCreate(uint64_t interval) FFRT_LOGE("[WorkGroup] create rtg group %d failed", rtgId); return nullptr; } - FFRT_LOGI("[WorkGroup] create rtg group %{public}d success", rtgId); + FFRT_LOGI("[WorkGroup] create rtg group %d success", rtgId); WorkGroup* wg = nullptr; wg = new struct WorkGroup(); @@ -225,7 +225,6 @@ int WorkgroupClear(struct WorkGroup* wg) if (uid == RS_UID) { return DestoryRSWorkGroup(); } - if (wg == nullptr) { FFRT_LOGE("[WorkGroup] input workgroup is null"); return 0; @@ -306,6 +305,7 @@ void WorkgroupJoin(struct WorkGroup* wg, int tid) FFRT_LOGE("[WorkGroup] join fail with %{public}d threads for %{public}d", addRet, tid); } } + #endif /* QOS_FRAME_RTG */ } diff --git a/src/sched/qos.cpp b/src/sched/qos.cpp index e9a3bb9..2135171 100644 --- a/src/sched/qos.cpp +++ b/src/sched/qos.cpp @@ -27,15 +27,15 @@ int QoSMap(int qos) } } -static FuncQosMap g_funcQosMap = nullptr; +static FuncQosMap funcQosMap = nullptr; void SetFuncQosMap(FuncQosMap func) { - g_funcQosMap = func; + funcQosMap = func; } FuncQosMap GetFuncQosMap(void) { - return g_funcQosMap; + return funcQosMap; } int QoSMax(void) @@ -43,14 +43,14 @@ int QoSMax(void) return qos_max + 1; } -static FuncQosMax g_funcQosMax = nullptr; +static FuncQosMax funcQosMax = nullptr; void SetFuncQosMax(FuncQosMax func) { - g_funcQosMax = func; + funcQosMax = func; } FuncQosMax GetFuncQosMax(void) { - return g_funcQosMax; + return funcQosMax; +} } -} \ No newline at end of file diff --git a/src/sched/scheduler.cpp b/src/sched/scheduler.cpp index b6e3195..081ae69 100644 --- a/src/sched/scheduler.cpp +++ b/src/sched/scheduler.cpp @@ -106,7 +106,7 @@ bool FFRTScheduler::WakeupTask(CPUEUTask* task) lock->unlock(); // The ownership of the task belongs to ReadyTaskQueue, and the task cannot be accessed any more. - FFRT_LOGD("qos[%d] task[%lu] entered q", level, gid); + FFRT_LOGD("qos[%d] task[%lu], name[%s] entered q", level, gid, label.c_str()); if (taskCount >= TASK_OVERRUN_THRESHOLD && taskCount % TASK_OVERRUN_ALARM_FREQ == 0) { FFRT_LOGW("qos [%d], task [%s] entered q, task count [%d] exceeds threshold.", level, label.c_str(), taskCount); diff --git a/src/sched/task_scheduler.h b/src/sched/task_scheduler.h index fead430..7b1cc1a 100644 --- a/src/sched/task_scheduler.h +++ b/src/sched/task_scheduler.h @@ -65,12 +65,12 @@ public: bool RemoveNode(LinkedList* node) { + FFRT_PERF_TASK_NUM(qos, RQSize()); bool ret = false; { que->RmQueueNode(node); ret = true; } - FFRT_PERF_TASK_NUM(qos, RQSize()); return ret; } diff --git a/src/sched/task_state.cpp b/src/sched/task_state.cpp index f6c4448..7a83d06 100644 --- a/src/sched/task_state.cpp +++ b/src/sched/task_state.cpp @@ -28,7 +28,6 @@ int TaskState::OnTransition(State state, CPUEUTask* task, Op&& op) return -1; } if (task->IsRoot()) { - FFRT_LOGD("task root no state transition"); return 0; } diff --git a/src/sync/delayed_worker.cpp b/src/sync/delayed_worker.cpp index 04832b5..341aa9f 100644 --- a/src/sync/delayed_worker.cpp +++ b/src/sync/delayed_worker.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "eu/blockaware.h" #include "eu/execute_unit.h" #include "dfx/log/ffrt_log_api.h" @@ -27,12 +28,36 @@ #include "util/name_manager.h" #include "sched/scheduler.h" namespace { + const uintptr_t FFRT_DELAY_WORKER_MAGICNUM = 0x5aa5; const int FFRT_DELAY_WORKER_IDLE_TIMEOUT_SECONDS = 3 * 60; const int NS_PER_SEC = 1000 * 1000 * 1000; const int WAIT_EVENT_SIZE = 5; const int64_t EXECUTION_TIMEOUT_MILISECONDS = 500; } + namespace ffrt { +pthread_key_t g_ffrtDelayWorkerFlagKey; +pthread_once_t g_ffrtDelayWorkerThreadKeyOnce = PTHREAD_ONCE_INIT; +void FFRTDelayWorkeEnvKeyCreate() +{ + pthread_key_create(&g_ffrtDelayWorkerFlagKey, nullptr); +} + +void DelayedWorker::ThreadEnvCreate() +{ + pthread_once(&g_ffrtDelayWorkerThreadKeyOnce, FFRTDelayWorkeEnvKeyCreate); +} + +bool DelayedWorker::IsDelayerWorkerThread() +{ + bool isDelayerWorkerFlag = false; + void* flag = pthread_getspecific(g_ffrtDelayWorkerFlagKey); + if ((flag != nullptr) && (reinterpret_cast(flag) == FFRT_DELAY_WORKER_MAGICNUM)) { + isDelayerWorkerFlag = true; + } + return isDelayerWorkerFlag; +} + void DelayedWorker::ThreadInit() { if (delayWorker != nullptr && delayWorker->joinable()) { @@ -48,6 +73,7 @@ void DelayedWorker::ThreadInit() FFRT_LOGI("thread init"); } prctl(PR_SET_NAME, DELAYED_WORKER_NAME); + pthread_setspecific(g_ffrtDelayWorkerFlagKey, reinterpret_cast(FFRT_DELAY_WORKER_MAGICNUM)); std::array waitedEvents; for (;;) { std::unique_lock lk(lock); @@ -115,7 +141,7 @@ DelayedWorker::DelayedWorker(): epollfd_ { ::epoll_create1(EPOLL_CLOEXEC) }, monitorfd_ = BlockawareMonitorfd(-1, monitor->WakeupCond()); FFRT_ASSERT(monitorfd_ >= 0); FFRT_LOGI("timerfd:%d, monitorfd:%d", timerfd_, monitorfd_); - /* monitorfd does not support 'CLOEXEC', add current kernel does not inherit monitorfd after 'fork'. + /* monitorfd does not support 'CLOEXEC', and current kernel does not inherit monitorfd after 'fork'. * 1. if user calls 'exec' directly after 'fork' and does not use ffrt, it's ok. * 2. if user calls 'exec' directly, the original process cannot close monitorfd automatically, and * it will be fail when new program use ffrt to create monitorfd. @@ -156,7 +182,7 @@ void CheckTimeInterval(const TimePoint& startTp, const TimePoint& endTp) int64_t durationMs = duration.count(); if (durationMs > EXECUTION_TIMEOUT_MILISECONDS) { FFRT_LOGW("handle work more than [%lld]ms", durationMs); - } + } } int DelayedWorker::HandleWork() @@ -233,4 +259,4 @@ bool DelayedWorker::remove(const TimePoint& to, WaitEntry* we) return false; } -} // namespace ffrt \ No newline at end of file +} // namespace ffrt diff --git a/src/sync/delayed_worker.h b/src/sync/delayed_worker.h index 073f237..074b182 100644 --- a/src/sync/delayed_worker.h +++ b/src/sync/delayed_worker.h @@ -41,13 +41,15 @@ class DelayedWorker { int timerfd_{-1}; #ifdef FFRT_WORKERS_DYNAMIC_SCALING int monitorfd_{-1}; - CPUMonitor* monitor; + CPUMonitor* monitor = nullptr; #endif int HandleWork(void); void ThreadInit(); public: static DelayedWorker &GetInstance(); + static void ThreadEnvCreate(); + static bool IsDelayerWorkerThread(); DelayedWorker(DelayedWorker const&) = delete; void operator=(DelayedWorker const&) = delete; diff --git a/src/sync/mutex_private.h b/src/sync/mutex_private.h index 60c61fd..42b9dab 100644 --- a/src/sync/mutex_private.h +++ b/src/sync/mutex_private.h @@ -141,7 +141,7 @@ public: bool try_lock() override; RecursiveMutexPrivate() = default; - ~RecursiveMutexPrivate() override = default; + ~RecursiveMutexPrivate() = default; RecursiveMutexPrivate(RecursiveMutexPrivate const&) = delete; void operator = (RecursiveMutexPrivate const&) = delete; diff --git a/src/sync/poller.cpp b/src/sync/poller.cpp index e03bcd9..4bda618 100644 --- a/src/sync/poller.cpp +++ b/src/sync/poller.cpp @@ -60,12 +60,12 @@ int Poller::AddFdEvent(int op, uint32_t events, int fd, void* data, ffrt_poller_ wakeData->monitorEvents = events; epoll_event ev = { .events = events, .data = { .ptr = ptr } }; - std::unique_lock lock(m_mapMutex); if (epoll_ctl(m_epFd, op, fd, &ev) != 0) { FFRT_LOGE("epoll_ctl add fd error: efd=%d, fd=%d, errorno=%d", m_epFd, fd, errno); return -1; } + std::unique_lock lock(m_mapMutex); if (op == EPOLL_CTL_ADD) { m_wakeDataMap[fd].emplace_back(std::move(wakeData)); fdEmpty_.store(false); @@ -84,12 +84,12 @@ int Poller::AddFdEvent(int op, uint32_t events, int fd, void* data, ffrt_poller_ int Poller::DelFdEvent(int fd) noexcept { - std::unique_lock lock(m_mapMutex); if (epoll_ctl(m_epFd, EPOLL_CTL_DEL, fd, nullptr) != 0) { FFRT_LOGE("epoll_ctl del fd error: efd=%d, fd=%d, errorno=%d", m_epFd, fd, errno); return -1; } + std::unique_lock lock(m_mapMutex); m_delCntMap[fd]++; WakeUp(); return 0; @@ -301,14 +301,6 @@ void Poller::CacheEventsAndDoMask(CPUEUTask* task, EventVec& eventVec) noexcept { for (size_t i = 0; i < eventVec.size(); i++) { int currFd = eventVec[i].data.fd; - auto delIter = m_delCntMap.find(currFd); - if (delIter != m_delCntMap.end()) { - unsigned int delCnt = static_cast(delIter->second); - auto& WakeDataList = m_wakeDataMap[currFd]; - if (WakeDataList.size() == delCnt) { - continue; - } - } struct epoll_event maskEv; maskEv.events = 0; if (epoll_ctl(m_epFd, EPOLL_CTL_MOD, currFd, &maskEv) != 0 && errno != ENOENT) { @@ -473,14 +465,11 @@ void Poller::ExecuteTimerCb(TimePoint timer) noexcept timerMutex_.unlock(); if (data.cb != nullptr) { data.cb(data.data); + executedHandle_[data.handle] = TimerStatus::EXECUTED; } else if (data.task != nullptr) { ProcessTimerDataCb(data.task); } - if (data.cb != nullptr) { - executedHandle_[data.handle] = TimerStatus::EXECUTED; - } - timerMutex_.lock(); if (data.repeat && (executedHandle_.find(data.handle) != executedHandle_.end())) { diff --git a/src/sync/shared_mutex.cpp b/src/sync/shared_mutex.cpp index 95e05e1..9d2a293 100644 --- a/src/sync/shared_mutex.cpp +++ b/src/sync/shared_mutex.cpp @@ -14,6 +14,7 @@ */ #include "shared_mutex_private.h" +#include "dfx/log/ffrt_log_api.h" #include "ffrt_trace.h" #include "internal_inc/osal.h" diff --git a/src/sync/sync.cpp b/src/sync/sync.cpp index 79294a7..d85a26e 100644 --- a/src/sync/sync.cpp +++ b/src/sync/sync.cpp @@ -23,9 +23,9 @@ #include #include #include -#include "sync.h" #include "delayed_worker.h" #include "util/ffrt_facade.h" +#include "sync.h" #ifdef NS_PER_SEC #undef NS_PER_SEC @@ -60,9 +60,6 @@ static void spin() asm volatile("isb sy"); #elif defined(__arm__) asm volatile("yield"); -#elif defined(__riscv) - // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/riscv/include/asm/vdso/processor.h?h=v6.6#n25 - asm volatile(".4byte 0x100000F"); #endif } diff --git a/src/sync/wait_queue.h b/src/sync/wait_queue.h index bef3132..468df33 100644 --- a/src/sync/wait_queue.h +++ b/src/sync/wait_queue.h @@ -59,10 +59,6 @@ struct TaskWithNode : public TaskListNode { }; class WaitQueue { -private: - spin_mutex wqlock; - WaitUntilEntry* whead; - public: using TimePoint = std::chrono::steady_clock::time_point; void SuspendAndWait(mutexPrivate* lk); @@ -88,6 +84,10 @@ public: wqlock.unlock(); } +private: + spin_mutex wqlock; + WaitUntilEntry* whead; + private: bool WeNotifyProc(WaitUntilEntry* we); void ThreadWait(WaitUntilEntry* wn, mutexPrivate* lk, bool legacyMode, CPUEUTask* task); diff --git a/src/tm/cpu_task.cpp b/src/tm/cpu_task.cpp index 696d8da..6606e90 100644 --- a/src/tm/cpu_task.cpp +++ b/src/tm/cpu_task.cpp @@ -103,6 +103,5 @@ CPUEUTask::CPUEUTask(const task_attr_private *attr, CPUEUTask *parent, const uin if (attr) { stack_size = std::max(attr->stackSize_, MIN_STACK_SIZE); } - FFRT_LOGD("create task name:%s gid=%lu taskLocal:%d", label.c_str(), gid, taskLocal); } } /* namespace ffrt */ \ No newline at end of file diff --git a/src/tm/scpu_task.cpp b/src/tm/scpu_task.cpp index b1e630a..364079d 100644 --- a/src/tm/scpu_task.cpp +++ b/src/tm/scpu_task.cpp @@ -55,8 +55,6 @@ void SCPUEUTask::DecDepRef() void SCPUEUTask::DecChildRef() { SCPUEUTask* parent = reinterpret_cast(this->parent); - FFRT_LOGD("DecChildRef parent task:%s, childRefCnt=%u, task[%lu], name[%s]", - parent->label.c_str(), parent->childRefCnt.load(), gid, label.c_str()); FFRT_TRACE_SCOPE(2, taskDecChildRef); std::unique_lockmutex_)> lck(parent->mutex_); parent->childRefCnt--; diff --git a/src/tm/task_base.h b/src/tm/task_base.h index d0cbea3..51afa0d 100644 --- a/src/tm/task_base.h +++ b/src/tm/task_base.h @@ -24,6 +24,7 @@ namespace ffrt { static std::atomic_uint64_t s_gid(0); +static constexpr uint64_t cacheline_size = 64; class TaskBase { public: uintptr_t reserved = 0; diff --git a/src/util/slab.h b/src/util/slab.h index 8d9e3c3..474c7c9 100644 --- a/src/util/slab.h +++ b/src/util/slab.h @@ -23,9 +23,8 @@ #include #endif #include -#include "dfx/log/ffrt_log_api.h" -#include "spmc_queue.h" #include "sync/sync.h" +#include "dfx/log/ffrt_log_api.h" namespace ffrt { const std::size_t BatchAllocSize = 32 * 1024; @@ -83,7 +82,7 @@ public: return Instance()->SimpleAllocatorUnLock(); } private: - SpmcQueue primaryCache; + std::vector primaryCache; #ifdef FFRT_BBOX_ENABLE std::unordered_set secondaryCache; #endif @@ -99,7 +98,8 @@ private: char* p = reinterpret_cast(basePtr); for (std::size_t i = 0; i + TSize <= MmapSz; i += TSize) { if (basePtr != nullptr && - primaryCache.FindElement(reinterpret_cast(p + i)) == false) { + std::find(primaryCache.begin(), primaryCache.end(), + reinterpret_cast(p + i)) == primaryCache.end()) { ret.push_back(reinterpret_cast(p + i)); } } @@ -122,56 +122,53 @@ private: void init() { - lock.lock(); - if (basePtr) { - lock.unlock(); - return; - } - char* p = reinterpret_cast(operator new(MmapSz)); count = MmapSz / TSize; - primaryCache.Init(count); + primaryCache.reserve(count); for (std::size_t i = 0; i + TSize <= MmapSz; i += TSize) { - primaryCache.PushTail(p + i); + primaryCache.push_back(reinterpret_cast(p + i)); } basePtr = reinterpret_cast(p); - lock.unlock(); } T* Alloc() { - // 未初始化 - if (primaryCache.GetCapacity() == 0) { + lock.lock(); + T* t = nullptr; + if (count == 0) { + if (basePtr != nullptr) { + t = reinterpret_cast(::operator new(TSize)); +#ifdef FFRT_BBOX_ENABLE + secondaryCache.insert(t); +#endif + lock.unlock(); + return t; + } init(); } - // 一级cache已耗尽 - if (primaryCache.GetLength()) { - T* t = reinterpret_cast(::operator new(TSize)); -#ifdef FFRT_BBOX_ENABLE - lock.lock(); - secondaryCache.insert(t); - lock.unlock(); -#endif - return t; - } - return static_cast(primaryCache.PopHead()); + t = primaryCache.back(); + primaryCache.pop_back(); + count--; + lock.unlock(); + return t; } void free(T* t) { - if (basePtr && basePtr <= t && + lock.lock(); + if (basePtr != nullptr && + basePtr <= t && static_cast(reinterpret_cast(t)) < static_cast(reinterpret_cast(basePtr)) + MmapSz) { - primaryCache.PushTail(t); - return; - } - + primaryCache.push_back(t); + count++; + } else { #ifdef FFRT_BBOX_ENABLE - lock.lock(); secondaryCache.erase(t); - lock.unlock(); #endif ::operator delete(t); + } + lock.unlock(); } SimpleAllocator(std::size_t size = sizeof(T)) : TSize(size) @@ -187,7 +184,7 @@ private: uint32_t try_cnt = ALLOCATOR_DESTRUCT_TIMESOUT; std::size_t reserved = MmapSz / TSize; while (try_cnt > 0) { - if (primaryCache.GetLength() == reserved && secondaryCache.size() == 0) { + if (primaryCache.size() == reserved && secondaryCache.size() == 0) { break; } lck.unlock(); diff --git a/src/util/spmc_queue.cpp b/src/util/spmc_queue.cpp index f990846..5c78861 100644 --- a/src/util/spmc_queue.cpp +++ b/src/util/spmc_queue.cpp @@ -89,23 +89,6 @@ int SpmcQueue::PushTail(void* object) return -1; } -bool SpmcQueue::FindElement(void* target) -{ - if (buf_ == nullptr) { - return false; - } - unsigned int head = head_.load(); - unsigned int tail = tail_.load(); - while (head != tail) { - void* element = buf_[head % capacity_]; - if (target == element) { - return true; - } - head++; - } - return false; -} - unsigned int SpmcQueue::PopHeadToAnotherQueue(SpmcQueue& dstQueue, unsigned int elementNum, int qos, PushFunc func) { if (elementNum == 0) { diff --git a/src/util/spmc_queue.h b/src/util/spmc_queue.h index 2a2fe2e..f04d882 100644 --- a/src/util/spmc_queue.h +++ b/src/util/spmc_queue.h @@ -46,13 +46,6 @@ public: */ int PushTail(void* object); - /** - * @brief 查找特定元素。 - * @param target 目标元素。 - * @retval 成功返回true,失败返回false。 - */ - bool FindElement(void* target); - /** * @brief 从队列首部批量取出元素后将元素批量推入目标队列尾部。 * @param dstQueue 目标队列。 diff --git a/src/util/time_format.h b/src/util/time_format.h index 833951d..3653fd4 100644 --- a/src/util/time_format.h +++ b/src/util/time_format.h @@ -35,7 +35,7 @@ static std::string FormatDateString(const std::chrono::system_clock::time_point& constexpr int UsPerSecond = 1000 * 1000; std::string remainder; - if (timeUnit == microsecond) { + if (microsecond == timeUnit) { auto tp = std::chrono::time_point_cast(timePoint); auto us = tp.time_since_epoch().count() % UsPerSecond; remainder = std::to_string(us); diff --git a/src/util/worker_monitor.cpp b/src/util/worker_monitor.cpp index 6910d2e..4a43f91 100644 --- a/src/util/worker_monitor.cpp +++ b/src/util/worker_monitor.cpp @@ -49,20 +49,20 @@ namespace ffrt { WorkerMonitor::WorkerMonitor() { // 获取当前进程名称 - char processName[PROCESS_NAME_BUFFER_LENGTH] = {0}; + char processName[PROCESS_NAME_BUFFER_LENGTH] = ""; GetProcessName(processName, PROCESS_NAME_BUFFER_LENGTH); if (strlen(processName) == 0) { - FFRT_LOGW("Can't get process name, no permission for /proc folder or prctl exec, skip worker monitor"); + FFRT_LOGW("Get process name failed, skip worker monitor."); skipSampling_ = true; return; } - // 从配置文件中读取屏蔽进程 + // 从配置文件读取黑名单 std::string skipProcess; std::ifstream file(CONF_FILEPATH); if (file.is_open()) { while (std::getline(file, skipProcess)) { - if (std::string(processName).find(skipProcess) != std::string::npos) { + if (strstr(processName, skipProcess.c_str()) != nullptr) { skipSampling_ = true; return; } diff --git a/src/util/worker_monitor.h b/src/util/worker_monitor.h index 3edfb09..a33391c 100644 --- a/src/util/worker_monitor.h +++ b/src/util/worker_monitor.h @@ -87,6 +87,7 @@ private: CPUEUTask* workerTask, std::vector& timeoutFunctions); void RecordSymbolAndBacktrace(const TimeoutFunctionInfo& timeoutFunction); void RecordIpcInfo(const std::string& dumpInfo, int tid); + void RecordKeyInfo(const std::string& dumpInfo); private: std::mutex mutex_; diff --git a/test/ut/BUILD.gn b/test/ut/BUILD.gn index 07a5b85..ed8609b 100644 --- a/test/ut/BUILD.gn +++ b/test/ut/BUILD.gn @@ -76,7 +76,7 @@ config("ffrt_test_config") { defines += [ "TDD_MUSL" ] } if (ffrt_async_stack_enable) { - defines += [ "ASYNC_STACKTRACE" ] + defines += [ "FFRT_ASYNC_STACKTRACE" ] } if (target_cpu == "arm") { defines += [ "APP_USE_ARM" ] diff --git a/test/ut/cpu_monitor_test.cpp b/test/ut/cpu_monitor_test.cpp index e3fbdc6..cda0b5e 100644 --- a/test/ut/cpu_monitor_test.cpp +++ b/test/ut/cpu_monitor_test.cpp @@ -80,25 +80,6 @@ HWTEST_F(CpuMonitorTest, IntoSleep, TestSize.Level1) cpu.IntoSleep(QoS(5)); } -#ifdef FFRT_GITEE -/** - * @tc.name: WakeupCount - * @tc.desc: Test whether the WakeupCount interface are normal. - * @tc.type: FUNC - * - * - */ -HWTEST_F(CpuMonitorTest, WakeupCount, TestSize.Level1) -{ - CPUWorkerManager *it = new SCPUWorkerManager(); - SCPUMonitor cpu({ - std::bind(&CPUWorkerManager::IncWorker, it, std::placeholders::_1), - std::bind(&CPUWorkerManager::WakeupWorkers, it, std::placeholders::_1), - std::bind(&CPUWorkerManager::GetTaskCount, it, std::placeholders::_1)}); - - cpu.WakeupCount(QoS(5)); -} -#else /** * @tc.name: WakeupSleep * @tc.desc: Test whether the WakeupSleep interface are normal. @@ -109,6 +90,7 @@ HWTEST_F(CpuMonitorTest, WakeupCount, TestSize.Level1) HWTEST_F(CpuMonitorTest, WakeupSleep, TestSize.Level1) { CPUWorkerManager *it = new SCPUWorkerManager(); + EXPECT_NE(it, nullptr); SCPUMonitor cpu({ std::bind(&CPUWorkerManager::IncWorker, it, std::placeholders::_1), @@ -117,7 +99,7 @@ HWTEST_F(CpuMonitorTest, WakeupSleep, TestSize.Level1) cpu.WakeupSleep(QoS(5)); } -#endif + /** * @tc.name: TimeoutCount @@ -129,6 +111,7 @@ HWTEST_F(CpuMonitorTest, WakeupSleep, TestSize.Level1) HWTEST_F(CpuMonitorTest, TimeoutCount, TestSize.Level1) { CPUWorkerManager *it = new SCPUWorkerManager(); + EXPECT_NE(it, nullptr); SCPUMonitor cpu({ std::bind(&CPUWorkerManager::IncWorker, it, std::placeholders::_1), std::bind(&CPUWorkerManager::WakeupWorkers, it, std::placeholders::_1), @@ -147,6 +130,7 @@ HWTEST_F(CpuMonitorTest, TimeoutCount, TestSize.Level1) HWTEST_F(CpuMonitorTest, Notify, TestSize.Level1) { CPUWorkerManager *it = new SCPUWorkerManager(); + EXPECT_NE(it, nullptr); SCPUMonitor cpu({ std::bind(&CPUWorkerManager::IncWorker, it, std::placeholders::_1), std::bind(&CPUWorkerManager::WakeupWorkers, it, std::placeholders::_1), @@ -167,6 +151,7 @@ HWTEST_F(CpuMonitorTest, Notify, TestSize.Level1) HWTEST_F(CpuMonitorTest, IntoDeepSleep, TestSize.Level1) { CPUWorkerManager *it = new SCPUWorkerManager(); + EXPECT_NE(it, nullptr); SCPUMonitor cpu({ std::bind(&CPUWorkerManager::IncWorker, it, std::placeholders::_1), std::bind(&CPUWorkerManager::WakeupWorkers, it, std::placeholders::_1), @@ -175,28 +160,11 @@ HWTEST_F(CpuMonitorTest, IntoDeepSleep, TestSize.Level1) cpu.IntoDeepSleep(QoS(5)); } -#ifdef FFRT_GITEE -/** - * @tc.name: OutOfDeepSleep - * @tc.desc: Test whether the OutOfDeepSleep interface are normal. - * @tc.type: FUNC - * - * - */ -HWTEST_F(CpuMonitorTest, OutOfDeepSleep, TestSize.Level1) -{ - CPUWorkerManager *it = new SCPUWorkerManager(); - SCPUMonitor cpu({ - std::bind(&CPUWorkerManager::IncWorker, it, std::placeholders::_1), - std::bind(&CPUWorkerManager::WakeupWorkers, it, std::placeholders::_1), - std::bind(&CPUWorkerManager::GetTaskCount, it, std::placeholders::_1)}); - cpu.OutOfDeepSleep(QoS(5)); -} -#else HWTEST_F(CpuMonitorTest, WakeupDeepSleep, TestSize.Level1) { CPUWorkerManager *it = new SCPUWorkerManager(); + EXPECT_NE(it, nullptr); SCPUMonitor cpu({ std::bind(&CPUWorkerManager::IncWorker, it, std::placeholders::_1), std::bind(&CPUWorkerManager::WakeupWorkers, it, std::placeholders::_1), @@ -204,7 +172,6 @@ HWTEST_F(CpuMonitorTest, WakeupDeepSleep, TestSize.Level1) cpu.WakeupDeepSleep(QoS(5)); } -#endif /** * @tc.name: IsExceedDeepSleepThreshold @@ -216,6 +183,7 @@ HWTEST_F(CpuMonitorTest, WakeupDeepSleep, TestSize.Level1) HWTEST_F(CpuMonitorTest, IsExceedDeepSleepThreshold, TestSize.Level1) { CPUWorkerManager *it = new SCPUWorkerManager(); + EXPECT_NE(it, nullptr); SCPUMonitor cpu({ std::bind(&CPUWorkerManager::IncWorker, it, std::placeholders::_1), std::bind(&CPUWorkerManager::WakeupWorkers, it, std::placeholders::_1), diff --git a/test/ut/deadline_test.cpp b/test/ut/deadline_test.cpp index 1c992a8..c513429 100644 --- a/test/ut/deadline_test.cpp +++ b/test/ut/deadline_test.cpp @@ -59,11 +59,11 @@ HWTEST_F(DeadlineTest, qos_interval_create_test, TestSize.Level1) qos qos = qos_deadline_request; interval qi = qos_interval_create(deadline_us, qos); - EXPECT_NE(&qi, nullptr); + EXPECT_NE(qi, nullptr); qos = qos_max + 1; interval qi1 = qos_interval_create(deadline_us, qos); - EXPECT_NE(&qi1, nullptr); + EXPECT_EQ(qi1, nullptr); } /** @@ -74,12 +74,14 @@ HWTEST_F(DeadlineTest, qos_interval_create_test, TestSize.Level1) HWTEST_F(DeadlineTest, qos_interval_destroy_test, TestSize.Level1) { interval* qi = new interval(); + EXPECT_NE(qi, nullptr); qos_interval_destroy(*qi); uint64_t deadline_us = 50000; qos qos = qos_max + 1; interval qi1 = qos_interval_create(deadline_us, qos); + EXPECT_EQ(qi1, nullptr); qos_interval_destroy(qi1); } @@ -97,6 +99,7 @@ HWTEST_F(DeadlineTest, qos_interval_begin_test, TestSize.Level1) qos qos = qos_max + 1; interval qi1 = qos_interval_create(deadline_us, qos); + EXPECT_EQ(qi1, nullptr); qos_interval_begin(qi1); } @@ -114,6 +117,7 @@ HWTEST_F(DeadlineTest, qos_interval_update_test, TestSize.Level1) qos_interval_update(*qi, new_deadline_us); interval qi1 = qos_interval_create(deadline_us, qos); + EXPECT_EQ(qi1, nullptr); qos_interval_update(qi1, new_deadline_us); } @@ -130,6 +134,7 @@ HWTEST_F(DeadlineTest, qos_interval_end_test, TestSize.Level1) qos_interval_end(*qi); interval qi1 = qos_interval_create(deadline_us, qos); + EXPECT_EQ(qi1, nullptr); qos_interval_end(qi1); } @@ -143,10 +148,12 @@ HWTEST_F(DeadlineTest, qos_interval_join_test, TestSize.Level1) uint64_t deadline_us = 50000; qos qos = qos_deadline_request; interval ret = qos_interval_create(deadline_us, qos); + EXPECT_NE(ret, nullptr); qos_interval_join(ret); qos = qos_max + 1; interval ret1 = qos_interval_create(deadline_us, qos); + EXPECT_EQ(ret1, nullptr); qos_interval_join(ret1); } @@ -160,9 +167,11 @@ HWTEST_F(DeadlineTest, qos_interval_leave_test, TestSize.Level1) uint64_t deadline_us = 50000; qos qos = qos_deadline_request; interval ret = qos_interval_create(deadline_us, qos); + EXPECT_NE(ret, nullptr); qos_interval_leave(ret); qos = qos_max + 1; interval ret1 = qos_interval_create(deadline_us, qos); + EXPECT_EQ(ret1, nullptr); qos_interval_leave(ret1); } diff --git a/test/ut/execute_unit_test.cpp b/test/ut/execute_unit_test.cpp index 7a2598b..f37e047 100644 --- a/test/ut/execute_unit_test.cpp +++ b/test/ut/execute_unit_test.cpp @@ -69,6 +69,7 @@ HWTEST_F(ExecuteUnitTest, BindWG, TestSize.Level1) { QoS *qos1 = new QoS(); FFRTFacade::GetEUInstance().BindWG(DevType(0), *qos1); + EXPECT_EQ(*qos1, qos_default); } /** @@ -80,6 +81,7 @@ HWTEST_F(ExecuteUnitTest, UnbindTG, TestSize.Level1) { QoS *qos1 = new QoS(); FFRTFacade::GetEUInstance().UnbindTG(DevType(0), *qos1); + EXPECT_EQ(*qos1, qos_default); } /** @@ -91,6 +93,7 @@ HWTEST_F(ExecuteUnitTest, BindTG, TestSize.Level1) { QoS *qos1 = new QoS(); ThreadGroup* it = FFRTFacade::GetEUInstance().BindTG(DevType(0), *qos1); + EXPECT_EQ(*qos1, qos_default); } } diff --git a/test/ut/frame_interval_test.cpp b/test/ut/frame_interval_test.cpp index 18994c6..8953f51 100644 --- a/test/ut/frame_interval_test.cpp +++ b/test/ut/frame_interval_test.cpp @@ -70,6 +70,7 @@ HWTEST_F(FrameIntervalTest, OnQoSIntervalsTest, TestSize.Level1) FrameInterval* fi = new FrameInterval(100000, QoS(5)); fi->OnQoSIntervals(ffrt::IntervalState::DEADLINE_BEGIN); fi->OnQoSIntervals(ffrt::IntervalState::DEADLINE_END); + EXPECT_NE(fi, nullptr); } /** @@ -110,6 +111,7 @@ HWTEST_F(FrameIntervalTest, EndTest, TestSize.Level1) HWTEST_F(FrameIntervalTest, updateTest, TestSize.Level1) { FrameInterval* fi = new FrameInterval(100000, QoS(5)); + EXPECT_NE(fi, nullptr); uint64_t deadline = 900; fi->Update(deadline); deadline = 1500000; @@ -127,6 +129,7 @@ HWTEST_F(FrameIntervalTest, updateTest, TestSize.Level1) HWTEST_F(FrameIntervalTest, JoinTest, TestSize.Level1) { FrameInterval* fi = new FrameInterval(100000, QoS(5)); + EXPECT_NE(fi, nullptr); fi->Join(); fi->Leave(); } \ No newline at end of file diff --git a/test/ut/testcase/delay_work_deinit_test.cpp b/test/ut/testcase/delay_work_deinit_test.cpp index 6f93b3e..5d8b768 100644 --- a/test/ut/testcase/delay_work_deinit_test.cpp +++ b/test/ut/testcase/delay_work_deinit_test.cpp @@ -18,6 +18,7 @@ #include "c/ffrt_dump.h" #include "sync/delayed_worker.h" #include "../common.h" +#include "util/ffrt_facade.h" using namespace std; using namespace ffrt; @@ -59,7 +60,7 @@ void SendDelayedWorker(uint64_t timeoutUs) g_delayWorkerThreadTestWe.tp = delay; g_delayWorkerThreadTestWe.cb = ([](ffrt::WaitEntry* we) { CheckCallBackThreadName(); }); - DelayedWorker::GetInstance().dispatch(g_delayWorkerThreadTestWe.tp, + FFRTFacade::GetDWInstance().dispatch(g_delayWorkerThreadTestWe.tp, &g_delayWorkerThreadTestWe, g_delayWorkerThreadTestWe.cb); } diff --git a/test/ut/testcase/inherit_test.cpp b/test/ut/testcase/inherit_test.cpp index 4c28447..550a976 100644 --- a/test/ut/testcase/inherit_test.cpp +++ b/test/ut/testcase/inherit_test.cpp @@ -13,11 +13,11 @@ * limitations under the License. */ #include +#include #include "ffrt_inner.h" #include "c/executor_task.h" #include "tm/scpu_task.h" #include "dfx/log/ffrt_log_api.h" -#include #include "../common.h" using namespace std; diff --git a/test/ut/testcase/ut_cgroup_qos.cpp b/test/ut/testcase/ut_cgroup_qos.cpp index 86b89aa..7bfd673 100644 --- a/test/ut/testcase/ut_cgroup_qos.cpp +++ b/test/ut/testcase/ut_cgroup_qos.cpp @@ -73,32 +73,41 @@ HWTEST_F(CgroupQosTest, UpdateSchedAttr_test, TestSize.Level1) HWTEST_F(CgroupQosTest, SetTidToCGroup_test, TestSize.Level1) { - OSAttrManager::Instance()->SetTidToCGroup(100); + int32_t pid = 100; + OSAttrManager::Instance()->SetTidToCGroup(pid); OSAttrManager::Instance()->SetTidToCGroup(-1); + EXPECT_EQ(pid, 100); } HWTEST_F(CgroupQosTest, SetCGroupCtlPara_test, TestSize.Level1) { - OSAttrManager::Instance()->SetCGroupCtlPara("", 1); - OSAttrManager::Instance()->SetCGroupCtlPara("test", 1); + int32_t value = 1; + OSAttrManager::Instance()->SetCGroupCtlPara("", value); + OSAttrManager::Instance()->SetCGroupCtlPara("test", value); + EXPECT_EQ(value, 1); } HWTEST_F(CgroupQosTest, SetCGroupSetPara_test, TestSize.Level1) { - OSAttrManager::Instance()->SetCGroupSetPara("", "1"); - OSAttrManager::Instance()->SetCGroupSetPara("test", "1"); + std::string value = "1"; + OSAttrManager::Instance()->SetCGroupSetPara("", value); + OSAttrManager::Instance()->SetCGroupSetPara("test", value); + EXPECT_EQ(value, "1"); } HWTEST_F(CgroupQosTest, SetTidToCGroupPrivate_test, TestSize.Level1) { - OSAttrManager::Instance()->SetTidToCGroupPrivate("test", 100); + int32_t pid = 100; + OSAttrManager::Instance()->SetTidToCGroupPrivate("test", pid); OSAttrManager::Instance()->SetTidToCGroupPrivate("test", -1); + EXPECT_EQ(pid, 100); } HWTEST_F(CgroupQosTest, SetCGroupPara_test, TestSize.Level1) { int a = 100; OSAttrManager::Instance()->SetCGroupPara("/proc/cpuinfo", a); + EXPECT_EQ(a, 100); } HWTEST_F(CgroupQosTest, SetCGroupPara_err_test, TestSize.Level1) @@ -109,6 +118,7 @@ HWTEST_F(CgroupQosTest, SetCGroupPara_err_test, TestSize.Level1) #endif int a = 3; OSAttrManager::Instance()->SetCGroupPara("/proc/cpuinfo", a); + EXPECT_EQ(a, 3); #ifndef WITH_NO_MOCKER MOCKER(write).stubs().will(returnValue(-1)); MOCKER(read).stubs().will(returnValue(0)); @@ -143,7 +153,12 @@ protected: HWTEST_F(QosTest, QosConfig_test, TestSize.Level1) { #ifndef WITH_NO_MOCKER + int i = 0; + auto handle = ffrt::submit_h([]{ QosConfig::Instance().setPolicySystem(); + i++; + }); + EXPECT_EQ(i, 1); #endif } @@ -171,13 +186,15 @@ HWTEST_F(QosInterfaceTest, QosPolicyTest, TestSize.Level1) struct QosPolicyData qp = {0, 0, 0, 0, 0}; struct QosPolicyDatas policyDatas = {0, 0, {qp}}; - QosPolicy(&policyDatas); + int ret = QosPolicy(&policyDatas); + EXPECT_NE(ret, 0); } HWTEST_F(QosInterfaceTest, FFRTEnableRtgTest, TestSize.Level1) { bool flag = false; FFRTEnableRtg(flag); + EXPECT_EQ(flag, false); } HWTEST_F(QosInterfaceTest, FFRTAuthEnableTest, TestSize.Level1) @@ -186,6 +203,7 @@ HWTEST_F(QosInterfaceTest, FFRTAuthEnableTest, TestSize.Level1) unsigned int uaFlag = 0x1fff; unsigned int status = 3; FFRTAuthEnable(uid, uaFlag, status); + EXPECT_EQ(status, 3); } HWTEST_F(QosInterfaceTest, FFRTAuthSwitchTest, TestSize.Level1) @@ -195,12 +213,14 @@ HWTEST_F(QosInterfaceTest, FFRTAuthSwitchTest, TestSize.Level1) unsigned int qosFlag = 0x0003; unsigned int status = 3; FFRTAuthSwitch(uid, rtgFlag, qosFlag, status); + EXPECT_EQ(status, 3); } HWTEST_F(QosInterfaceTest, FFRTAuthDeleteTest, TestSize.Level1) { unsigned int uid = 3039; FFRTAuthDelete(uid); + EXPECT_EQ(uid, 3039); } HWTEST_F(QosInterfaceTest, FFRTAuthPauseTest, TestSize.Level1) @@ -210,6 +230,7 @@ HWTEST_F(QosInterfaceTest, FFRTAuthPauseTest, TestSize.Level1) unsigned int status = 3; FFRTAuthEnable(uid, uaFlag, status); FFRTAuthPause(uid); + EXPECT_EQ(uid, 3039); } HWTEST_F(QosInterfaceTest, FFRTAuthGetTest, TestSize.Level1) @@ -220,6 +241,7 @@ HWTEST_F(QosInterfaceTest, FFRTAuthGetTest, TestSize.Level1) FFRTAuthEnable(uid, uaFlag, status); FFRTAuthGet(uid, &uaFlag, &status); + EXPECT_EQ(status, 3); } HWTEST_F(QosInterfaceTest, FFRTQosApplyTest, TestSize.Level1) @@ -227,6 +249,7 @@ HWTEST_F(QosInterfaceTest, FFRTQosApplyTest, TestSize.Level1) unsigned int level = 1; FFRTQosApply(level); + EXPECT_EQ(level, 1); } HWTEST_F(QosInterfaceTest, FFRTQosApplyForOtherTest, TestSize.Level1) @@ -235,6 +258,7 @@ HWTEST_F(QosInterfaceTest, FFRTQosApplyForOtherTest, TestSize.Level1) int tid = 0; FFRTQosApplyForOther(level, tid); + EXPECT_EQ(level, 1); } HWTEST_F(QosInterfaceTest, FFRTQosLeaveTest, TestSize.Level1) @@ -249,6 +273,7 @@ HWTEST_F(QosInterfaceTest, FFRTQosLeaveForOtherTest, TestSize.Level1) FFRTQosApplyForOther(level, tid); FFRTQosLeaveForOther(tid); + EXPECT_EQ(level, 1); } HWTEST_F(QosInterfaceTest, FFRTQosConvertInt, TestSize.Level1) @@ -257,4 +282,5 @@ HWTEST_F(QosInterfaceTest, FFRTQosConvertInt, TestSize.Level1) QoS qos2 = 2; QoS qos3 = qos1 + qos2; printf("qos3=%d", qos3()); + EXPECT_EQ(qos3, 3); } \ No newline at end of file diff --git a/test/ut/testcase/ut_core.cpp b/test/ut/testcase/ut_core.cpp index 890cdf7..8a92d84 100644 --- a/test/ut/testcase/ut_core.cpp +++ b/test/ut/testcase/ut_core.cpp @@ -56,7 +56,9 @@ protected: HWTEST_F(CoreTest, core_test_success_01, TestSize.Level1) { - sync_io(0); + int fd = 0; + sync_io(fd); + EXPECT_EQ(fd, 0); } HWTEST_F(CoreTest, task_ctx_success_01, TestSize.Level1) @@ -202,8 +204,10 @@ HWTEST_F(CoreTest, task_attr_set_timeout_nullptr, TestSize.Level1) */ HWTEST_F(CoreTest, ffrt_task_handle_ref_nullptr, TestSize.Level1) { - ffrt_task_handle_inc_ref(nullptr); - ffrt_task_handle_dec_ref(nullptr); + ffrt_task_handle_t handle = nullptr; + ffrt_task_handle_inc_ref(handle); + ffrt_task_handle_dec_ref(handle); + EXPECT_EQ(handle, nullptr); } /** diff --git a/test/ut/testcase/ut_coroutine.cpp b/test/ut/testcase/ut_coroutine.cpp index c54bd6c..1e8df5d 100644 --- a/test/ut/testcase/ut_coroutine.cpp +++ b/test/ut/testcase/ut_coroutine.cpp @@ -24,8 +24,12 @@ #include "c/executor_task.h" #include "ffrt_inner.h" #include "eu/cpu_monitor.h" +#include "eu/cpu_worker.h" +#include "eu/co_routine.h" +#include "eu/scpuworker_manager.h" #include "sched/scheduler.h" #include "../common.h" +#include "tm/scpu_task.h" using namespace std; using namespace ffrt; @@ -154,3 +158,38 @@ HWTEST_F(CoroutineTest, ffrt_epoll_ctl_add_del, TestSize.Level1) ffrt_epoll_ctl(ffrt_qos_default, EPOLL_CTL_DEL, testFd, 0, nullptr, nullptr); close(testFd); } + +HWTEST_F(CoroutineTest, coroutine_alloc_fail, TestSize.Level1) +{ + ffrt::task_attr attr; + const uint64_t id = 0; + ffrt::SCPUEUTask task(reinterpret_cast(&attr), nullptr, id, ffrt::QoS(2)); + task.coRoutine = nullptr; + task.stack_size = 100 * (1ULL << 40); //100T + struct CoRoutineEnv env; + + CPUWorkerManager* manager = new SCPUWorkerManager(); + CpuWorkerOps ops { + CPUWorker::WorkerLooperStandard, + std::bind(&CPUWorkerManager::PickUpTaskFromGlobalQueue, manager, std::placeholders::_1), + std::bind(&CPUWorkerManager::NotifyTaskPicked, manager, std::placeholders::_1), + std::bind(&CPUWorkerManager::WorkerIdleActionSimplified, manager, std::placeholders::_1), + std::bind(&CPUWorkerManager::WorkerRetired, manager, std::placeholders::_1), + std::bind(&CPUWorkerManager::WorkerPrepare, manager, std::placeholders::_1), + std::bind(&CPUWorkerManager::TryPoll, manager, std::placeholders::_1, std::placeholders::_2), + std::bind(&CPUWorkerManager::StealTaskBatch, manager, std::placeholders::_1), + std::bind(&CPUWorkerManager::PickUpTaskBatch, manager, std::placeholders::_1), +#ifdef FFRT_WORKERS_DYNAMIC_SCALING + std::bind(&CPUWorkerManager::IsExceedRunningThreshold, manager, std::placeholders::_1), + std::bind(&CPUWorkerManager::IsBlockAwareInit, manager), +#endif + }; + CPUWorker* worker = new CPUWorker(QoS(2), std::move(ops), manager); + EXPECT_NE(worker, nullptr); + sleep(1); // wait worker into wait action + worker->Run(&task, &env, worker); + + delete manager; + worker->Join(); + delete worker; +} \ No newline at end of file diff --git a/test/ut/testcase/ut_dependency.cpp b/test/ut/testcase/ut_dependency.cpp index d75b2c8..288a0f7 100644 --- a/test/ut/testcase/ut_dependency.cpp +++ b/test/ut/testcase/ut_dependency.cpp @@ -21,6 +21,7 @@ #include "c/executor_task.h" #include "tm/scpu_task.h" #include "dfx/log/ffrt_log_api.h" +#include "dm/sdependence_manager.h" #ifndef WITH_NO_MOCKER extern "C" int ffrt_set_cgroup_attr(ffrt_qos_t qos, ffrt_os_sched_attr *attr); #endif @@ -100,8 +101,6 @@ HWTEST_F(DependencyTest, update_qos_success_04, TestSize.Level1) ffrt::submit([] { printf("return %d\n", ffrt::this_task::update_qos(static_cast(ffrt::qos_user_initiated))); }); - int ret2 = ffrt_set_cpu_worker_max_num(static_cast(ffrt::qos_user_initiated), 4); - EXPECT_EQ(ret2, 0); } HWTEST_F(DependencyTest, update_qos_success_05, TestSize.Level1) @@ -165,28 +164,21 @@ HWTEST_F(DependencyTest, update_qos_failed_02, TestSize.Level1) ffrt::submit([] { printf("return %d\n", ffrt::this_task::update_qos(static_cast(ffrt::qos_user_initiated))); }); - int ret1 = ffrt_set_cpu_worker_max_num(static_cast(ffrt::qos_inherit), 4); - EXPECT_EQ(ret1, -1); } -HWTEST_F(DependencyTest, executor_task_submit_success_01, TestSize.Level1) +HWTEST_F(DependencyTest, executor_task_submit_success_cancel_01, TestSize.Level1) { ffrt_task_attr_t attr; static ffrt_executor_task_t work; work.wq[0] = &work.wq; work.wq[1] = &work.wq; work.type = reinterpret_cast(&attr); + ffrt_executor_task_submit(nullptr, nullptr); ffrt_executor_task_submit(&work, &attr); -} -HWTEST_F(DependencyTest, executor_task_submit_nullptr_01, TestSize.Level1) -{ - ffrt_executor_task_submit(nullptr, nullptr); -} -HWTEST_F(DependencyTest, executor_task_submit_cancel_01, TestSize.Level1) -{ - ffrt_executor_task_cancel(nullptr, static_cast(ffrt::qos_user_initiated)); + int ret = ffrt_executor_task_cancel(nullptr, static_cast(ffrt::qos_user_initiated)); + EXPECT_EQ(ret, 0); } HWTEST_F(DependencyTest, executor_task_submit_cancel_02, TestSize.Level1) @@ -205,19 +197,16 @@ HWTEST_F(DependencyTest, executor_task_submit_cancel_02, TestSize.Level1) ffrt_task_attr_destroy(&attr); } -HWTEST_F(DependencyTest, update_trace_tag_success_02, TestSize.Level1) +HWTEST_F(DependencyTest, update_trace_tag_task_attr_success, TestSize.Level1) { ffrt::set_trace_tag("TASK A"); ffrt::clear_trace_tag(); -} -HWTEST_F(DependencyTest, task_attr_success_02, TestSize.Level1) -{ ffrt::task_attr tmpTask; tmpTask.name("Task A"); tmpTask.qos(static_cast(ffrt::qos_user_initiated)); - tmpTask.name(); - tmpTask.qos(); + + EXPECT_EQ(ffrt_task_attr_get_qos(&tmpTask), ffrt::qos_user_initiated); } HWTEST_F(DependencyTest, sample_pingpong_pipe_interval_checkpoint, TestSize.Level1) @@ -285,3 +274,15 @@ HWTEST_F(DependencyTest, sample_pingpong_pipe_interval_checkpoint, TestSize.Leve ffrt::qos_interval_destroy(it); } + +void AddOne(void* args) +{ + *(static_cast(args)) += 1; +} + +HWTEST_F(DependencyTest, dependency_onsubmit_dev, TestSize.Level1) +{ + int data = 0; + ffrt_task_handle_t handle = nullptr; + ffrt::SDependenceManager& dependenceManager = ffrt::SDependenceManager::Instance(); +} diff --git a/test/ut/testcase/ut_dump.cpp b/test/ut/testcase/ut_dump.cpp index d865e80..f0b0b33 100644 --- a/test/ut/testcase/ut_dump.cpp +++ b/test/ut/testcase/ut_dump.cpp @@ -15,9 +15,13 @@ #include #include "ffrt_inner.h" +#include "../common.h" using namespace std; using namespace testing; +#ifdef HWTEST_TESTING_EXT_ENABLE +using namespace testing::ext; +#endif class DumpTest : public testing::Test { protected: @@ -37,3 +41,15 @@ protected: { } }; + +/* + * 测试用例名称:dump_succ + * 测试用例描述:获取dump info失败 + * 操作步骤 :1、调用函数ffrt_dump获取dump info + * 预期结果 :获取失败 + */ +HWTEST_F(DumpTest, dump_succ, TestSize.Level1) +{ + char dumpinfo[1024 * 512] = {0}; + ffrt_dump(ffrt_dump_cmd_t::DUMP_INFO_ALL, dumpinfo, 1024 * 512); +} \ No newline at end of file diff --git a/test/ut/testcase/ut_execute_unit.cpp b/test/ut/testcase/ut_execute_unit.cpp index ef04c9b..f170365 100644 --- a/test/ut/testcase/ut_execute_unit.cpp +++ b/test/ut/testcase/ut_execute_unit.cpp @@ -72,7 +72,7 @@ HWTEST_F(ExecuteUnitTest, submit_cancel_failed, TestSize.Level1) auto h2 = ffrt::submit_h([&]() { x += 2; }, {&x}, {&x}, ffrt::task_attr().delay(1)); int cancel_ret = ffrt::skip(h2); EXPECT_EQ(cancel_ret, 0); - ffrt::wait(); + ffrt::wait({h1}); EXPECT_EQ(x, 1); cancel_ret = ffrt::skip(h1); diff --git a/test/ut/testcase/ut_ffrt_io.cpp b/test/ut/testcase/ut_ffrt_io.cpp index 9b1c835..eaa77de 100644 --- a/test/ut/testcase/ut_ffrt_io.cpp +++ b/test/ut/testcase/ut_ffrt_io.cpp @@ -582,6 +582,7 @@ HWTEST_F(ffrtIoTest, ffrt_task_attr_set_local_attr_invalid, TestSize.Level1) { bool isLocalSet = true; ffrt_task_attr_set_local(nullptr, isLocalSet); + EXPECT_EQ(isLocalSet, true); } struct WakeData { diff --git a/test/ut/testcase/ut_flo.cpp b/test/ut/testcase/ut_flo.cpp index 39bebf8..70da49e 100644 --- a/test/ut/testcase/ut_flo.cpp +++ b/test/ut/testcase/ut_flo.cpp @@ -106,9 +106,12 @@ protected: HWTEST_F(FloTest, FFRTFloApiSuccess, TestSize.Level1) { + int i = 0; InitCfg(1); ffrt_flo_start(1); + i++; ffrt_flo_end(1); + EXCEPT_EQ(i, 1); } HWTEST_F(FloTest, FFRTFloTaskWithoutYield, TestSize.Level1) diff --git a/test/ut/testcase/ut_init.cpp b/test/ut/testcase/ut_init.cpp index c633486..4deea3f 100644 --- a/test/ut/testcase/ut_init.cpp +++ b/test/ut/testcase/ut_init.cpp @@ -14,8 +14,8 @@ */ #include -#include "ffrt_inner.h" #include +#include "ffrt_inner.h" #include "../common.h" using namespace testing; diff --git a/test/ut/testcase/ut_loop.cpp b/test/ut/testcase/ut_loop.cpp index a30f57b..a2b95b4 100644 --- a/test/ut/testcase/ut_loop.cpp +++ b/test/ut/testcase/ut_loop.cpp @@ -45,6 +45,7 @@ protected: virtual void SetUp() { + ffrt_task_timeout_set_threshold(1); } virtual void TearDown() diff --git a/test/ut/testcase/ut_poller.cpp b/test/ut/testcase/ut_poller.cpp index e42257b..3368ea1 100644 --- a/test/ut/testcase/ut_poller.cpp +++ b/test/ut/testcase/ut_poller.cpp @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - + #include #include #include @@ -30,26 +30,26 @@ using namespace testing; #ifdef HWTEST_TESTING_EXT_ENABLE using namespace testing::ext; #endif - + class PollerTest : public testing::Test { protected: static void SetUpTestCase() { } - + static void TearDownTestCase() { } - + virtual void SetUp() { } - + virtual void TearDown() { } }; - + static void Testfun(void* data) { int* testData = static_cast(data); @@ -57,7 +57,7 @@ static void Testfun(void* data) printf("%d, timeout callback\n", *testData); } static void (*g_cb)(void*) = Testfun; - + /* * 测试用例名称:poll_once_batch_timeout * 测试用例描述:PollOnce批量超时测试 @@ -85,7 +85,7 @@ HWTEST_F(PollerTest, poll_once_batch_timeout, TestSize.Level1) usleep(sleepTime); poller.PollOnce(1); EXPECT_EQ(true, poller.DetermineEmptyMap()); - + uint64_t timeout3 = 10000; uint64_t timeout4 = 100; int loopNum = 2; @@ -99,7 +99,7 @@ HWTEST_F(PollerTest, poll_once_batch_timeout, TestSize.Level1) // 预计等待时间为100,可能有几毫秒的误差 EXPECT_EQ(true, m >= timeout4 && m < timeout3); } - + /* * 测试用例名称:cache_events_mask_test * 测试用例描述:本地events缓存 @@ -117,7 +117,7 @@ HWTEST_F(PollerTest, cache_events_mask_test, TestSize.Level1) poller.CacheEventsAndDoMask(currTask, eventVec); EXPECT_EQ(1, poller.m_cachedTaskEvents[currTask].size()); } - + /* * 测试用例名称:fetch_cached_event_unmask * 测试用例描述:遍历本地events缓存,并提出缓存event @@ -171,4 +171,97 @@ HWTEST_F(PollerTest, unregister_timer_001, TestSize.Level1) poller.timerMap_.clear(); poller.executedHandle_.clear(); } +} + +std::mutex g_mutexRegister; +std::condition_variable g_cvRegister; + +void WaitCallback(void* data) +{ + int* dependency = reinterpret_cast(data); + while (*dependency != 1) { + std::this_thread::yield(); + } +} + +void EmptyCallback(void* data) {} + +/* + * 测试用例名称: multi_timer_dependency + * 测试用例描述: poller批量超时回调依赖测试 + * 预置条件 : 构造三个超时时间相同的timer, 回调A依赖回调B执行完成,回调B依赖timer C取消成功,三者并发 + * 操作步骤 : 1、调用PollOnce接口 + * 预期结果 : 1、三个回调执行完成,没有卡死现象 + */ +HWTEST_F(PollerTest, multi_timer_dependency, TestSize.Level1) +{ + int dependency = 0; + ffrt::task_handle handle = ffrt::submit_h([&] { + std::unique_lock lk(g_mutexRegister); + g_cvRegister.wait(lk); + dependency = 1; + }); + + TimePoint timeout = std::chrono::steady_clock::now() + std::chrono::milliseconds(100); + TimerDataWithCb data(&dependency, WaitCallback, nullptr, false, 100); + data.handle = 0; + + Poller poller; + poller.timerMap_.emplace(timeout, data); + + data.handle++; + data.cb = EmptyCallback; + poller.timerMap_.emplace(timeout, data); + + std::thread th1([&] { poller.PollOnce(-1); }); + std::thread th2([&] { + usleep(100 * 1000); + poller.UnregisterTimer(1); + g_cvRegister.notify_all(); + }); + + th1.join(); + th2.join(); + ffrt::wait({handle}); +} + +/* + * 测试用例名称 : multi_timer_dependency_unregister_self + * 测试用例描述 : poller批量超时回调,解注册自身依赖测试 + * 预置条件 : 构造两个超时时间相同的timer, 回调A依赖回调B执行完成,回调B依赖另一个线程的timer A取消成功,三者并发 + * 操作步骤 : 1、调用PollOnce接口 + * 预期结果 : 1、三个回调执行完成,没有卡死现象 + */ +HWTEST_F(PollerTest, multi_timer_dependency_unregister_self, TestSize.Level1) +{ + int dependency = 0; + + TimePoint timeout = std::chrono::steady_clock::now() + std::chrono::milliseconds(100); + TimerDataWithCb data(&dependency, WaitCallback, nullptr, false, 100); + data.handle = 0; + + Poller poller; + poller.timerMap_.emplace(timeout, data); + + data.handle++; + data.cb = EmptyCallback; + poller.timerMap_.emplace(timeout, data); + + ffrt::task_handle handle = ffrt::submit_h([&] { + std::unique_lock lk(g_mutexRegister); + g_cvRegister.wait(lk); + poller.IsTimerReady(); + dependency = 1; + }); + + std::thread th1([&] { poller.PollOnce(-1); }); + std::thread th2([&] { + usleep(100 * 1000); + g_cvRegister.notify_all(); + poller.UnregisterTimer(0); + }); + + th1.join(); + th2.join(); + ffrt::wait({handle}); } \ No newline at end of file diff --git a/test/ut/testcase/ut_queue.cpp b/test/ut/testcase/ut_queue.cpp index 1ca313a..e8483af 100644 --- a/test/ut/testcase/ut_queue.cpp +++ b/test/ut/testcase/ut_queue.cpp @@ -19,6 +19,7 @@ #include "ffrt_inner.h" #include "c/queue_ext.h" #include "../common.h" +#include "queue/base_queue.h" using namespace std; using namespace ffrt; @@ -791,12 +792,12 @@ HWTEST_F(QueueTest, ffrt_get_current_queue, TestSize.Level1) /* * 测试用例名称 : ffrt_queue_set_eventhand * 测试用例描述:设置串行队列的eventhandler - * 操作步骤 :1、创建队列 - 2、调用ffrt_queue_set_eventhandler接口设置串行队列的eventhandler - 3、删除队列 - * 预期结果 :查询结果与预期相同 + * 操作步骤 : 1、创建队列 + 2、调用ffrt_queue_set_eventhandler接口设置串行队列的eventhandler + 3、删除队列 + * 预期结果 : 查询结果与预期相同 */ -TEST_F(QueueTest, ffrt_queue_set_eventhand) +HWTEST_F(QueueTest, ffrt_queue_set_eventhand, TestSize.Level1) { ffrt_queue_attr_t queue_attr; (void)ffrt_queue_attr_init(&queue_attr); @@ -807,4 +808,17 @@ TEST_F(QueueTest, ffrt_queue_set_eventhand) EXPECT_EQ(temphandler, nullptr); ffrt_queue_attr_destroy(&queue_attr); ffrt_queue_destroy(queue_handle); -} \ No newline at end of file +} + +TEST_F(QueueTest, ffrt_queue_print_mutex_owner_info) +{ + ffrt_queue_attr_t queue_attr; + (void)ffrt_queue_attr_init(&queue_attr); + + std::unique_ptr queue = CreateQueue(ffrt_queue_serial, &queue_attr); + queue->PrintMutexOwner(); + RecordMutex recordMutex; + (void)recordMutex.IsTimeout(); + + ffrt_queue_attr_destroy(&queue_attr); +} diff --git a/test/ut/testcase/ut_rtg.cpp b/test/ut/testcase/ut_rtg.cpp index b26107e..4a0b863 100644 --- a/test/ut/testcase/ut_rtg.cpp +++ b/test/ut/testcase/ut_rtg.cpp @@ -54,6 +54,7 @@ HWTEST_F(RTGTest, rtg_init_test, TestSize.Level1) { bool enabled = RTGCtrl::Instance().Enabled(); FFRT_LOGE("RTGCtrl Init %s", enabled ? "Success" : "Failed"); + EXPECT_EQ(enabled, false); } HWTEST_F(RTGTest, rtg_get_group_test, TestSize.Level1) @@ -62,11 +63,13 @@ HWTEST_F(RTGTest, rtg_get_group_test, TestSize.Level1) if (tgid < 0) { FFRT_LOGE("Failed to Get RTG id %d", tgid); } + EXPECT_LE(tgid, 0); bool ret = RTGCtrl::Instance().PutThreadGroup(tgid); if (!ret) { FFRT_LOGE("Failed to Put RTG id %d", tgid); } + EXPECT_EQ(ret, false); } HWTEST_F(RTGTest, rtg_set_window_size_test, TestSize.Level1) @@ -77,16 +80,19 @@ HWTEST_F(RTGTest, rtg_set_window_size_test, TestSize.Level1) if (tgid < 0) { FFRT_LOGE("Failed to Get RTG id %d", tgid); } + EXPECT_LE(tgid, 0); bool ret = RTGCtrl::Instance().SetGroupWindowSize(tgid, WINDOW_SIZE); if (!ret) { FFRT_LOGE("Failed to Set Window Size %d", WINDOW_SIZE); } + EXPECT_EQ(ret, false); ret = RTGCtrl::Instance().PutThreadGroup(tgid); if (!ret) { FFRT_LOGE("Failed to Put RTG id %d", tgid); } + EXPECT_EQ(ret, false); } HWTEST_F(RTGTest, rtg_set_invalid_interval_test, TestSize.Level1) @@ -97,16 +103,19 @@ HWTEST_F(RTGTest, rtg_set_invalid_interval_test, TestSize.Level1) if (tgid < 0) { FFRT_LOGE("Failed to Get RTG id %d", tgid); } + EXPECT_LE(tgid, 0); bool ret = RTGCtrl::Instance().SetInvalidInterval(tgid, INVALID_INTERVAL); if (!ret) { FFRT_LOGE("Failed to Set Invalid Interval %d", INVALID_INTERVAL); } + EXPECT_EQ(ret, false); ret = RTGCtrl::Instance().PutThreadGroup(tgid); if (!ret) { FFRT_LOGE("Failed to Put RTG id %d", tgid); } + EXPECT_EQ(ret, false); } HWTEST_F(RTGTest, rtg_set_preferred_cluster_test, TestSize.Level1) @@ -117,16 +126,19 @@ HWTEST_F(RTGTest, rtg_set_preferred_cluster_test, TestSize.Level1) if (tgid < 0) { FFRT_LOGE("Failed to Get RTG id %d", tgid); } + EXPECT_LE(tgid, 0); bool ret = RTGCtrl::Instance().SetPreferredCluster(tgid, CLUSTER_ID); if (!ret) { FFRT_LOGE("Failed to Set Preferred Cluster %d", CLUSTER_ID); } + EXPECT_EQ(ret, false); ret = RTGCtrl::Instance().PutThreadGroup(tgid); if (!ret) { FFRT_LOGE("Failed to Put RTG id %d", tgid); } + EXPECT_EQ(ret, false); } HWTEST_F(RTGTest, rtg_begin_end_test, TestSize.Level1) @@ -135,21 +147,25 @@ HWTEST_F(RTGTest, rtg_begin_end_test, TestSize.Level1) if (tgid < 0) { FFRT_LOGE("Failed to Get RTG id %d", tgid); } + EXPECT_LE(tgid, 0); bool ret = RTGCtrl::Instance().Begin(tgid); if (!ret) { FFRT_LOGE("Failed to Begin"); } + EXPECT_EQ(ret, false); ret = RTGCtrl::Instance().End(tgid); if (!ret) { FFRT_LOGE("Failed to End"); } + EXPECT_EQ(ret, false); ret = RTGCtrl::Instance().PutThreadGroup(tgid); if (!ret) { FFRT_LOGE("Failed to Put RTG id %d", tgid); } + EXPECT_EQ(ret, false); } HWTEST_F(RTGTest, rtg_add_tread_test, TestSize.Level1) diff --git a/test/ut/testcase/ut_scheduler.cpp b/test/ut/testcase/ut_scheduler.cpp index 5dce6f7..ebfe728 100644 --- a/test/ut/testcase/ut_scheduler.cpp +++ b/test/ut/testcase/ut_scheduler.cpp @@ -172,6 +172,7 @@ HWTEST_F(SchedulerTest, taskstateCount_test, TestSize.Level1) { SCPUEUTask* task1 = new SCPUEUTask(nullptr, nullptr, 0, QoS(static_cast(qos_user_interactive))); SCPUEUTask *task2 = new SCPUEUTask(nullptr, task1, 0, QoS()); + EXPECT_NE(task2, nullptr); TaskManager::Instance().TaskStateCount(task2); } diff --git a/test/ut/testcase/ut_thread.cpp b/test/ut/testcase/ut_thread.cpp index 04d8bd5..a94dc66 100644 --- a/test/ut/testcase/ut_thread.cpp +++ b/test/ut/testcase/ut_thread.cpp @@ -106,18 +106,21 @@ HWTEST_F(ThreadTest, SetExitedTest, TestSize.Level1) HWTEST_F(ThreadTest, GetQosTest, TestSize.Level1) { WorkerThread* wt = new WorkerThread(QoS(6)); + EXPECT_NE(wt, nullptr); QoS ret = wt->GetQos(); } HWTEST_F(ThreadTest, JoinTest, TestSize.Level1) { WorkerThread* wt = new WorkerThread(QoS(6)); + EXPECT_NE(wt, nullptr); wt->Join(); } HWTEST_F(ThreadTest, DetachTest, TestSize.Level1) { WorkerThread* wt = new WorkerThread(QoS(6)); + EXPECT_NE(wt, nullptr); wt->Detach(); } @@ -156,5 +159,8 @@ HWTEST_F(ThreadTest, c_api_thread_simple_test, TestSize.Level1) HWTEST_F(ThreadTest, wait_queue_test, TestSize.Level1) { - TaskWithNode node = TaskWithNode(); + ffrt::submit([]{ + TaskWithNode node = TaskWithNode(); + EXPECT_NE(node.task, nullptr); + }, {}, {}); } diff --git a/test/ut/worker_thread_test.cpp b/test/ut/worker_thread_test.cpp index debb29d..b26cd7a 100644 --- a/test/ut/worker_thread_test.cpp +++ b/test/ut/worker_thread_test.cpp @@ -110,6 +110,7 @@ HWTEST_F(WorkerThreadTest, SetExitedTest, TestSize.Level1) HWTEST_F(WorkerThreadTest, GetQosTest, TestSize.Level1) { WorkerThread* wt = new WorkerThread(QoS(6)); + EXPECT_NE(wt, nullptr); QoS ret = wt->GetQos(); } @@ -121,6 +122,7 @@ HWTEST_F(WorkerThreadTest, GetQosTest, TestSize.Level1) HWTEST_F(WorkerThreadTest, JoinTest, TestSize.Level1) { WorkerThread* wt = new WorkerThread(QoS(6)); + EXPECT_NE(wt, nullptr); wt->Join(); } @@ -132,5 +134,6 @@ HWTEST_F(WorkerThreadTest, JoinTest, TestSize.Level1) HWTEST_F(WorkerThreadTest, DetachTest, TestSize.Level1) { WorkerThread* wt = new WorkerThread(QoS(6)); + EXPECT_NE(wt, nullptr); wt->Detach(); }