Browse Source

Implement CPU usage monitoring functions

jp9000 11 years ago
parent
commit
0781d86a2b
4 changed files with 220 additions and 0 deletions
  1. 98 0
      libobs/util/platform-cocoa.m
  2. 59 0
      libobs/util/platform-nix.c
  3. 56 0
      libobs/util/platform-windows.c
  4. 7 0
      libobs/util/platform.h

+ 98 - 0
libobs/util/platform-cocoa.m

@@ -93,3 +93,101 @@ char *os_get_config_path(const char *name)
 	dstr_cat(&path, name);
 	dstr_cat(&path, name);
 	return path.array;
 	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);
+}

+ 59 - 0
libobs/util/platform-nix.c

@@ -23,6 +23,11 @@
 #include <unistd.h>
 #include <unistd.h>
 #include <time.h>
 #include <time.h>
 
 
+#if !defined(__APPLE__)
+#include <sys/times.h>
+#include <sys/vtimes.h>
+#endif
+
 #include "dstr.h"
 #include "dstr.h"
 #include "platform.h"
 #include "platform.h"
 
 
@@ -56,6 +61,60 @@ void os_dlclose(void *module)
 	dlclose(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)
 bool os_sleepto_ns(uint64_t time_target)
 {
 {
 	uint64_t current = os_gettime_ns();
 	uint64_t current = os_gettime_ns();

+ 56 - 0
libobs/util/platform-windows.c

@@ -86,6 +86,62 @@ void os_dlclose(void *module)
 	FreeLibrary(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)
 bool os_sleepto_ns(uint64_t time_target)
 {
 {
 	uint64_t t = os_gettime_ns();
 	uint64_t t = os_gettime_ns();

+ 7 - 0
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_dlsym(void *module, const char *func);
 EXPORT void os_dlclose(void *module);
 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
  * 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.
  * accurate in terms of actual slept time because the target time is ensured.