From 941f2e20c1a38581864d9cb35279c8499731f8ec Mon Sep 17 00:00:00 2001 From: icexin Date: Thu, 5 Dec 2024 17:55:32 +0800 Subject: [PATCH] add support for bthread cpu usage --- src/bthread/bthread.cpp | 8 ++++++++ src/bthread/bthread.h | 18 ++++++++++++++++++ src/bthread/task_group.cpp | 19 ++++++++++++++++++- src/bthread/task_group.h | 11 +++++++++++ src/bthread/task_meta.h | 1 + src/butil/time.h | 8 ++++++++ 6 files changed, 64 insertions(+), 1 deletion(-) diff --git a/src/bthread/bthread.cpp b/src/bthread/bthread.cpp index bf2c24f819..b834b42af2 100644 --- a/src/bthread/bthread.cpp +++ b/src/bthread/bthread.cpp @@ -554,4 +554,12 @@ bthread_tag_t bthread_self_tag(void) { : BTHREAD_TAG_DEFAULT; } +uint64_t bthread_cpu_clock_ns(void) { + bthread::TaskGroup* g = bthread::tls_task_group; + if (g != NULL && !g->is_current_main_task()) { + return g->current_task_cpu_clock_ns(); + } + return 0; +} + } // extern "C" diff --git a/src/bthread/bthread.h b/src/bthread/bthread.h index 8532b3b322..72b32ad981 100644 --- a/src/bthread/bthread.h +++ b/src/bthread/bthread.h @@ -397,6 +397,24 @@ extern bthread_tag_t bthread_self_tag(void); // Returns 0 on success, error code otherwise. extern int bthread_once(bthread_once_t* once_control, void (*init_routine)()); + /** + * @brief Retrieves the CPU time consumed by the current bthread. + * + * This function returns the CPU time (in nanoseconds) used by the current + * bthread, excluding time spent in blocking I/O operations. The result + * provides an accurate measure of CPU time utilized by the bthread's + * execution. + * + * @note The functionality of this function depends on the + * `bthread_enable_cpu_clock_stat` flag. Ensure this flag is enabled + * for the function to provide meaningful results. If the flag is + * disabled, the function may return an invalid value or behave + * unexpectedly. + * + * @return int64_t The CPU time in nanoseconds consumed by the bthread. + */ +extern uint64_t bthread_cpu_clock_ns(void); + __END_DECLS #endif // BTHREAD_BTHREAD_H diff --git a/src/bthread/task_group.cpp b/src/bthread/task_group.cpp index bab6469001..f922050ef6 100644 --- a/src/bthread/task_group.cpp +++ b/src/bthread/task_group.cpp @@ -57,6 +57,11 @@ const bool ALLOW_UNUSED dummy_show_per_worker_usage_in_vars = ::GFLAGS_NS::RegisterFlagValidator(&FLAGS_show_per_worker_usage_in_vars, pass_bool); +DEFINE_bool(bthread_enable_cpu_clock_stat, false, + "Enable CPU clock statistics for bthread"); +const bool ALLOW_UNUSED dummy_bthread_enable_cpu_clock_stat = ::GFLAGS_NS::RegisterFlagValidator(&FLAGS_bthread_enable_cpu_clock_stat, + pass_bool); + BAIDU_VOLATILE_THREAD_LOCAL(TaskGroup*, tls_task_group, NULL); // Sync with TaskMeta::local_storage when a bthread is created or destroyed. // During running, the two fields may be inconsistent, use tls_bls as the @@ -70,7 +75,7 @@ extern void return_keytable(bthread_keytable_pool_t*, KeyTable*); // overhead of creation keytable, may be removed later. BAIDU_VOLATILE_THREAD_LOCAL(void*, tls_unique_user_ptr, NULL); -const TaskStatistics EMPTY_STAT = { 0, 0 }; +const TaskStatistics EMPTY_STAT = { 0, 0, 0 }; const size_t OFFSET_TABLE[] = { #include "bthread/offset_inl.list" @@ -255,6 +260,7 @@ int TaskGroup::init(size_t runqueue_capacity) { _main_tid = m->tid; _main_stack = stk; _last_run_ns = butil::cpuwide_time_ns(); + _last_cpu_clock_ns = 0; return 0; } @@ -602,6 +608,17 @@ void TaskGroup::sched_to(TaskGroup** pg, TaskMeta* next_meta) { const int64_t elp_ns = now - g->_last_run_ns; g->_last_run_ns = now; cur_meta->stat.cputime_ns += elp_ns; + + if (FLAGS_bthread_enable_cpu_clock_stat) { + const int64_t cpu_thread_time = butil::cputhread_time_ns(); + if (g->_last_cpu_clock_ns != 0) { + cur_meta->stat.cpu_usage_ns += cpu_thread_time - g->_last_cpu_clock_ns; + } + g->_last_cpu_clock_ns = cpu_thread_time; + } else { + g->_last_cpu_clock_ns = 0; + } + if (cur_meta->tid != g->main_tid()) { g->_cumulated_cputime_ns += elp_ns; } diff --git a/src/bthread/task_group.h b/src/bthread/task_group.h index a19bd023f7..7c197c011b 100644 --- a/src/bthread/task_group.h +++ b/src/bthread/task_group.h @@ -189,6 +189,15 @@ class TaskGroup { bthread_tag_t tag() const { return _tag; } + int64_t current_task_cpu_clock_ns() { + if (_last_cpu_clock_ns == 0) { + return 0; + } + int64_t total_ns = _cur_meta->stat.cpu_usage_ns; + total_ns += butil::cputhread_time_ns() - _last_cpu_clock_ns; + return total_ns; + } + private: friend class TaskControl; @@ -241,6 +250,8 @@ friend class TaskControl; // last scheduling time int64_t _last_run_ns; int64_t _cumulated_cputime_ns; + // last thread cpu clock + int64_t _last_cpu_clock_ns; size_t _nswitch; RemainedFn _last_context_remained; diff --git a/src/bthread/task_meta.h b/src/bthread/task_meta.h index 5e5c4541d1..3d9016336d 100644 --- a/src/bthread/task_meta.h +++ b/src/bthread/task_meta.h @@ -33,6 +33,7 @@ namespace bthread { struct TaskStatistics { int64_t cputime_ns; int64_t nswitch; + int64_t cpu_usage_ns; }; class KeyTable; diff --git a/src/butil/time.h b/src/butil/time.h index 005f551b1c..90378c5953 100644 --- a/src/butil/time.h +++ b/src/butil/time.h @@ -303,6 +303,14 @@ inline int64_t cpuwide_time_ns() { #endif // defined(BAIDU_INTERNAL) } +// Get cpu clock time of the current thread in nanoseconds without the time spent in blocking I/O operations. +// Cost ~200ns +inline int64_t cputhread_time_ns() { + timespec now; + clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now); + return now.tv_sec * 1000000000L + now.tv_nsec; +} + inline int64_t cpuwide_time_us() { return cpuwide_time_ns() / 1000L; }