From 0781d86a2b651615530dca0a615f6181f3b117d7 Mon Sep 17 00:00:00 2001 From: jp9000 Date: Fri, 4 Jul 2014 22:20:20 -0700 Subject: [PATCH] Implement CPU usage monitoring functions --- libobs/util/platform-cocoa.m | 98 ++++++++++++++++++++++++++++++++++ libobs/util/platform-nix.c | 59 ++++++++++++++++++++ libobs/util/platform-windows.c | 56 +++++++++++++++++++ libobs/util/platform.h | 7 +++ 4 files changed, 220 insertions(+) diff --git a/libobs/util/platform-cocoa.m b/libobs/util/platform-cocoa.m index 207456cc6..334702512 100644 --- a/libobs/util/platform-cocoa.m +++ b/libobs/util/platform-cocoa.m @@ -93,3 +93,101 @@ char *os_get_config_path(const char *name) dstr_cat(&path, name); return path.array; } + +struct os_cpu_usage_info { + int64_t last_cpu_time; + int64_t last_sys_time; + int core_count; +}; + +static inline void convert_time_value(struct timeval *dst, time_value_t *src) +{ + dst->tv_sec = src->seconds; + dst->tv_usec = src->microseconds; +} + +static inline void add_time_value(time_value_t *dst, time_value_t *a, + time_value_t *b) +{ + dst->microseconds = a->microseconds + b->microseconds; + dst->seconds = a->seconds + b->seconds; + + if (dst->microseconds >= 1000000) { + dst->seconds += dst->microseconds / 1000000; + dst->microseconds %= 1000000; + } +} + +static bool get_time_info(int64_t *cpu_time, int64_t *sys_time) +{ + mach_port_t task = mach_task_self(); + struct task_thread_times_info thread_data; + struct task_basic_info_64 task_data; + mach_msg_type_number_t count; + kern_return_t kern_ret; + time_value_t cur_time; + + *cpu_time = 0; + *sys_time = 0; + + count = TASK_THREAD_TIMES_INFO_COUNT; + kern_ret = task_info(task, TASK_THREAD_TIMES_INFO, + (task_info_t)&thread_data, &count); + if (kern_ret != KERN_SUCCESS) + return false; + + count = TASK_BASIC_INFO_64_COUNT; + kern_ret = task_info(task, TASK_BASIC_INFO_64, + (task_info_t)&task_data, &count); + if (kern_ret != KERN_SUCCESS) + return false; + + add_time_value(&cur_time, &thread_data.user_time, + &thread_data.system_time); + add_time_value(&cur_time, &cur_time, &task_data.user_time); + add_time_value(&cur_time, &cur_time, &task_data.system_time); + + *cpu_time = os_gettime_ns() / 1000; + *sys_time = cur_time.seconds * 1000000 + cur_time.microseconds; + return true; +} + +os_cpu_usage_info_t os_cpu_usage_info_start(void) +{ + struct os_cpu_usage_info *info = bmalloc(sizeof(*info)); + + if (!get_time_info(&info->last_cpu_time, &info->last_sys_time)) { + bfree(info); + return NULL; + } + + info->core_count = sysconf(_SC_NPROCESSORS_ONLN); + return info; +} + +double os_cpu_usage_info_query(os_cpu_usage_info_t info) +{ + int64_t sys_time, cpu_time; + int64_t sys_time_delta, cpu_time_delta; + + if (!info || !get_time_info(&cpu_time, &sys_time)) + return 0.0; + + sys_time_delta = sys_time - info->last_sys_time; + cpu_time_delta = cpu_time - info->last_cpu_time; + + if (cpu_time_delta == 0) + return 0.0; + + info->last_sys_time = sys_time; + info->last_cpu_time = cpu_time; + + return (double)sys_time_delta * 100.0 / (double)cpu_time_delta / + (double)info->core_count; +} + +void os_cpu_usage_info_destroy(os_cpu_usage_info_t info) +{ + if (info) + bfree(info); +} diff --git a/libobs/util/platform-nix.c b/libobs/util/platform-nix.c index e0c497c5f..0f3839217 100644 --- a/libobs/util/platform-nix.c +++ b/libobs/util/platform-nix.c @@ -23,6 +23,11 @@ #include #include +#if !defined(__APPLE__) +#include +#include +#endif + #include "dstr.h" #include "platform.h" @@ -56,6 +61,60 @@ void os_dlclose(void *module) dlclose(module); } +#if !defined(__APPLE__) + +struct os_cpu_usage_info { + clock_t last_cpu_time, last_sys_time, last_user_time; + int core_count; +}; + +os_cpu_usage_info_t os_cpu_usage_info_start(void) +{ + struct os_cpu_usage_info *info = bmalloc(sizeof(*info)); + struct tms time_sample; + + info->last_cpu_time = times(&time_sample); + info->last_sys_time = time_sample.tms_stime; + info->last_user_time = time_sample.tms_utime; + info->core_count = sysconf(_SC_NPROCESSORS_ONLN); + return info; +} + +double os_cpu_usage_info_query(os_cpu_usage_info_t info) +{ + struct tms time_sample; + clock_t cur_cpu_time; + double percent; + + if (!info) + return 0.0; + + cur_cpu_time = times(&time_sample); + if (cur_cpu_time <= info->last_cpu_time || + time_sample.tms_stime < info->last_sys_time || + time_sample.tms_utime < info->last_user_time) + return 0.0; + + percent = (double)(time_sample.tms_stime - info->last_sys_time + + (time_sample.tms_utime - info->last_user_time)); + percent /= (double)(cur_cpu_time - info->last_cpu_time); + percent /= (double)info->core_count; + + info->last_cpu_time = cur_cpu_time; + info->last_sys_time = time_sample.tms_stime; + info->last_user_time = time_sample.tms_utime; + + return percent * 100.0; +} + +void os_cpu_usage_info_destroy(os_cpu_usage_info_t info) +{ + if (info) + bfree(info); +} + +#endif + bool os_sleepto_ns(uint64_t time_target) { uint64_t current = os_gettime_ns(); diff --git a/libobs/util/platform-windows.c b/libobs/util/platform-windows.c index e995677cb..94f6e614d 100644 --- a/libobs/util/platform-windows.c +++ b/libobs/util/platform-windows.c @@ -86,6 +86,62 @@ void os_dlclose(void *module) FreeLibrary(module); } +union time_data { + FILETIME ft; + unsigned long long val; +}; + +struct os_cpu_usage_info { + union time_data last_time, last_sys_time, last_user_time; + DWORD core_count; +}; + +os_cpu_usage_info_t os_cpu_usage_info_start(void) +{ + struct os_cpu_usage_info *info = bzalloc(sizeof(*info)); + SYSTEM_INFO si; + FILETIME dummy; + + GetSystemInfo(&si); + GetSystemTimeAsFileTime(&info->last_time.ft); + GetProcessTimes(GetCurrentProcess(), &dummy, &dummy, + &info->last_sys_time.ft, &info->last_user_time.ft); + info->core_count = si.dwNumberOfProcessors; + + return info; +} + +double os_cpu_usage_info_query(os_cpu_usage_info_t info) +{ + union time_data cur_time, cur_sys_time, cur_user_time; + FILETIME dummy; + double percent; + + if (!info) + return 0.0; + + GetSystemTimeAsFileTime(&cur_time.ft); + GetProcessTimes(GetCurrentProcess(), &dummy, &dummy, + &cur_sys_time.ft, &cur_user_time.ft); + + percent = (double)(cur_sys_time.val - info->last_sys_time.val + + (cur_user_time.val - info->last_user_time.val)); + percent /= (double)(cur_time.val - info->last_time.val); + percent /= (double)info->core_count; + + info->last_time.val = cur_time.val; + info->last_sys_time.val = cur_sys_time.val; + info->last_user_time.val = cur_user_time.val; + + return percent * 100.0; +} + +void os_cpu_usage_info_destroy(os_cpu_usage_info_t info) +{ + if (info) + bfree(info); +} + bool os_sleepto_ns(uint64_t time_target) { uint64_t t = os_gettime_ns(); diff --git a/libobs/util/platform.h b/libobs/util/platform.h index 3a09ed42e..ad58d0946 100644 --- a/libobs/util/platform.h +++ b/libobs/util/platform.h @@ -69,6 +69,13 @@ EXPORT void *os_dlopen(const char *path); EXPORT void *os_dlsym(void *module, const char *func); EXPORT void os_dlclose(void *module); +struct os_cpu_usage_info; +typedef struct os_cpu_usage_info *os_cpu_usage_info_t; + +EXPORT os_cpu_usage_info_t os_cpu_usage_info_start(void); +EXPORT double os_cpu_usage_info_query(os_cpu_usage_info_t info); +EXPORT void os_cpu_usage_info_destroy(os_cpu_usage_info_t info); + /** * Sleeps to a specific time (in nanoseconds). Doesn't have to be super * accurate in terms of actual slept time because the target time is ensured.