Try to handle plugin data when CPU is idle 03/230203/4
authorKichan Kwon <k_c.kwon@samsung.com>
Wed, 8 Apr 2020 11:24:40 +0000 (20:24 +0900)
committerKichan Kwon <k_c.kwon@samsung.com>
Fri, 17 Apr 2020 02:18:51 +0000 (11:18 +0900)
- Separate getting plugin data with calculating and DB restoring
- Period : 3 minutes -> 10 minutes
- Check whether CPU is idle before working
  - If CPU is busy, try on next time

Change-Id: I5c27880ad01c0f1142db4d1b804a4088770f95d5
Signed-off-by: Kichan Kwon <k_c.kwon@samsung.com>
CMakeLists.txt
include/bm_common.h
packaging/batterymonitor.spec
src/bm_power_engine.c

index 10299eb..3ed25fd 100644 (file)
@@ -12,6 +12,7 @@ pkg_check_modules(pkgs REQUIRED
        sqlite3
        db-util
        capi-system-info
+       capi-system-runtime-info
        cynara-client
        cynara-session
        cynara-creds-gdbus
index 1907181..035ac99 100644 (file)
@@ -74,7 +74,9 @@ typedef enum {
 #define BM_RESOURCE_ID_TO_STR(x, y)            case (x): EXIT; return (y);
 
 /* job-scheduler macros */
-#define BATTERY_MONITOR_GET_DATA_JOB_PERIOD    180000          /* (3*60*1000) interval of 3mins */
+#define BATTERY_MONITOR_TRY_DATA_JOB_PERIOD    1000            /* (1*1000) interval of 1sec */
+#define BATTERY_MONITOR_GET_DATA_JOB_PERIOD    600000          /* (10*60*1000) interval of 10mins */
+#define BATTERY_MONITOR_MAXIMUM_TRY_PERIOD (BATTERY_MONITOR_GET_DATA_JOB_PERIOD / 10)
 #define BATTERY_MONITOR_DELETE_DB_JOB_PERIOD   86400000        /* (24*60*60*1000) interval of 24hrs */
 
 #define BM_PLUGIN_CONST_BATTERY                        7
index 437aef7..9ce4b32 100644 (file)
@@ -12,6 +12,7 @@ Source4:      batterymonitor.manifest
 BuildRequires:  cmake
 BuildRequires:  pkgconfig(dlog)
 BuildRequires:  pkgconfig(capi-system-info)
+BuildRequires:  pkgconfig(capi-system-runtime-info)
 BuildRequires:  pkgconfig(glib-2.0) >= 2.26
 BuildRequires:  pkgconfig(gio-2.0)
 BuildRequires:  pkgconfig(gio-unix-2.0)
index 96888fa..84c14bd 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <device/battery.h>
 #include <device/callback.h>
+#include <runtime_info.h>
 
 #include "bm_power_engine.h"
 #include "bm_dbg.h"
@@ -1978,11 +1979,6 @@ int bm_start_getting_feature_data(void)
                }
        }
 
-       /* 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;
 }
@@ -2002,18 +1998,232 @@ int bm_clean_db_table_for_job_id(void)
        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)
@@ -2027,7 +2237,7 @@ gboolean bm_delete_data_from_db(gpointer data)
                _ERR("error cleaning database");
 
        EXIT;
-       return true;
+       return G_SOURCE_CONTINUE;
 }
 
 int initialize_power_engine(void)