#include <device/battery.h>
#include <device/callback.h>
+#include <runtime_info.h>
#include "bm_power_engine.h"
#include "bm_dbg.h"
}
}
- /* parse data which is received through handles */
- ret_val = bm_get_data_from_handles();
- BM_RETURN_VAL((ret_val == BATTERY_MONITOR_ERROR_NONE), {},
- BATTERY_MONITOR_ERROR_INTERNAL, "error in parsing data from handles");
-
EXIT;
return ret_val;
}
return ret_val;
}
+#define DEFAULT_USAGE_RATIO 0.60
+#define MINIMUM_USAGE_RATIO 0.50
+#define REDUCTION_USAGE_RATIO 0.00
+
+#define ACCEPT_COUNT 5
+
+/**
+ * We don't use idle time because it can be decreased
+ * when CPU core is inactive.
+ *
+ * Instead, we will use uptime to calculate CPU usage
+ * CPU_USAGE = (CT_USER + CT_NICE + CT_SYSTEM) / (NUM_CORE * UPTIME)
+ */
+enum cpu_time {
+ CT_USER = 0,
+ CT_NICE,
+ CT_SYSTEM,
+// CT_IDLE,
+ CT_NUM
+};
+
+static int num_cpu_core;
+static double up_time_last;
+static unsigned long long cpu_time_last[CT_NUM];
+
+int bm_get_cpu_time(unsigned long long cpu_time[CT_NUM])
+{
+ int ret_val = 0;
+ FILE *fp = NULL;
+
+ fp = fopen("/proc/stat", "r");
+ if (!fp) {
+ _ERR("fopen failed : %m");
+ return BATTERY_MONITOR_ERROR_NO_DATA;
+ }
+
+ ret_val = fscanf(fp, "%*s %llu %llu %llu", &cpu_time[CT_USER], &cpu_time[CT_NICE], &cpu_time[CT_SYSTEM]);
+ fclose(fp);
+
+ if (ret_val < CT_NUM) {
+ _ERR("fscanf failed : %m");
+ return BATTERY_MONITOR_ERROR_NO_DATA;
+ }
+
+ return BATTERY_MONITOR_ERROR_NONE;
+}
+
+int bm_get_up_time(double *up_time)
+{
+ int ret_val = 0;
+ FILE *fp = NULL;
+
+ fp = fopen("/proc/uptime", "r");
+ if (!fp) {
+ _ERR("fopen failed : %m");
+ return BATTERY_MONITOR_ERROR_NO_DATA;
+ }
+
+ ret_val = fscanf(fp, "%lf", up_time);
+ fclose(fp);
+
+ if (ret_val < 1) {
+ _ERR("fscanf failed : %m");
+ return BATTERY_MONITOR_ERROR_NO_DATA;
+ }
+
+ return BATTERY_MONITOR_ERROR_NONE;
+}
+
+gboolean is_cpu_idle(void)
+{
+ ENTER;
+
+ static int remaining_timeout = BATTERY_MONITOR_MAXIMUM_TRY_PERIOD;
+ static double usage_ratio_threshold = DEFAULT_USAGE_RATIO;
+ int try, idx;
+ unsigned long long cpu_time_cur[CT_NUM];
+ unsigned long long cpu_time_diff[CT_NUM];
+ double up_time_cur;
+ double up_time_diff;
+ double usage_ratio;
+
+ if (remaining_timeout <= 0) {
+ remaining_timeout = BATTERY_MONITOR_MAXIMUM_TRY_PERIOD;
+ _DBG("timeout!");
+ goto satisfy;
+ }
+
+ for (try = 1; try <= ACCEPT_COUNT; try++) {
+ // Get CPU time
+ if (bm_get_cpu_time(cpu_time_cur) != BATTERY_MONITOR_ERROR_NONE) {
+ _ERR("error getting CPU time");
+ goto unsatisfy;
+ }
+
+ for (idx = 0; idx < CT_NUM; idx++) {
+ if (cpu_time_last[idx] > cpu_time_cur[idx]) {
+ _ERR("error invalid CPU time");
+ goto unsatisfy;
+ }
+ cpu_time_diff[idx] = cpu_time_cur[idx] - cpu_time_last[idx];
+ }
+
+ for (idx = 0; idx < CT_NUM; idx++)
+ cpu_time_last[idx] = cpu_time_cur[idx];
+
+ // Get uptime
+ if (bm_get_up_time(&up_time_cur) != BATTERY_MONITOR_ERROR_NONE) {
+ _ERR("error getting uptime");
+ goto unsatisfy;
+ }
+
+ if (up_time_last >= up_time_cur) {
+ _ERR("error invalid uptime");
+ goto unsatisfy;
+ }
+
+ up_time_diff = up_time_cur - up_time_last;
+ up_time_last = up_time_cur;
+
+ // Calculate CPU usage
+ usage_ratio = ((double)cpu_time_diff[CT_USER] + cpu_time_diff[CT_NICE] + cpu_time_diff[CT_SYSTEM]) / (up_time_diff * num_cpu_core * 100);
+ if (usage_ratio > 1.0)
+ usage_ratio = 1.0;
+
+ if (usage_ratio > usage_ratio_threshold) {
+ _WARN("CPU usage = %.2lf%% (BUSY, criteria[%.2lf%%])", usage_ratio * 100, usage_ratio_threshold * 100);
+ goto unsatisfy;
+ }
+
+ _DBG("CPU usage = %.2lf%% (IDLE, count[%d/%d])", usage_ratio * 100, try, ACCEPT_COUNT);
+
+ usleep(BATTERY_MONITOR_TRY_DATA_JOB_PERIOD * 1000);
+ }
+
+satisfy:
+ remaining_timeout = BATTERY_MONITOR_MAXIMUM_TRY_PERIOD;
+ usage_ratio_threshold = DEFAULT_USAGE_RATIO;
+
+ EXIT;
+ return TRUE;
+
+unsatisfy:
+ remaining_timeout -= (try * BATTERY_MONITOR_TRY_DATA_JOB_PERIOD);
+ if (usage_ratio_threshold > MINIMUM_USAGE_RATIO)
+ usage_ratio_threshold -= REDUCTION_USAGE_RATIO;
+
+ EXIT;
+ return FALSE;
+}
+
+gboolean bm_try_request_feature_data(gpointer data)
+{
+ ENTER;
+
+ enum status {
+ GET_DATA = 0,
+ CALC_AND_STORE,
+ };
+
+ static enum status status = GET_DATA;
+ int ret_val;
+
+ if (!is_cpu_idle()) {
+ EXIT;
+ return G_SOURCE_CONTINUE;
+ }
+
+ if (status == GET_DATA) {
+ // Request data to plugin
+ ret_val = bm_start_getting_feature_data();
+ if (ret_val != BATTERY_MONITOR_ERROR_NONE) {
+ _ERR("error requesting feature data");
+ EXIT;
+ return G_SOURCE_CONTINUE;
+ }
+
+ status = CALC_AND_STORE;
+
+ if (!is_cpu_idle()) {
+ EXIT;
+ return G_SOURCE_CONTINUE;
+ }
+ }
+
+ // Calculate power consumption and restore to DB
+ ret_val = bm_get_data_from_handles();
+ if (ret_val != BATTERY_MONITOR_ERROR_NONE) {
+ _ERR("error in parsing data from handles");
+ EXIT;
+ return G_SOURCE_CONTINUE;
+ }
+
+ status = GET_DATA;
+
+ EXIT;
+ return G_SOURCE_REMOVE;
+}
+
gboolean bm_request_feature_data(gpointer data)
{
ENTER;
- int ret_val = BATTERY_MONITOR_ERROR_NONE;
+ int ret_val = bm_get_cpu_time(cpu_time_last);
+ if (ret_val != BATTERY_MONITOR_ERROR_NONE) {
+ _ERR("error getting cpu time");
+ return G_SOURCE_CONTINUE;
+ }
- ret_val = bm_start_getting_feature_data();
- if (ret_val != BATTERY_MONITOR_ERROR_NONE)
- _ERR("error requesting feature data");
+ if (bm_get_up_time(&up_time_last) != BATTERY_MONITOR_ERROR_NONE) {
+ _ERR("error getting uptime");
+ return G_SOURCE_CONTINUE;
+ }
+
+ if (num_cpu_core <= 0) {
+ ret_val = runtime_info_get_processor_count(&num_cpu_core);
+ if (ret_val != RUNTIME_INFO_ERROR_NONE) {
+ _ERR("error getting the number of cpu core");
+ return G_SOURCE_CONTINUE;
+ }
+ }
+
+ g_timeout_add(BATTERY_MONITOR_TRY_DATA_JOB_PERIOD, bm_try_request_feature_data, NULL);
EXIT;
- return true;
+ return G_SOURCE_CONTINUE;
}
gboolean bm_delete_data_from_db(gpointer data)
_ERR("error cleaning database");
EXIT;
- return true;
+ return G_SOURCE_CONTINUE;
}
int initialize_power_engine(void)