resource: system: Calculate average cpu utilization with per-cpu stat 84/279984/3
authorDongwoo Lee <dwoo08.lee@samsung.com>
Fri, 19 Aug 2022 10:05:05 +0000 (19:05 +0900)
committerDongwoo Lee <dwlee08@gmail.com>
Tue, 23 Aug 2022 00:04:34 +0000 (17:04 -0700)
In a situation where the number of online cpus is dynamically changed,
measuring the total system cpu usage by using the sum of the online
cpus usage time located at the top of '/proc/stat' will result in
inaccurate results. For example, suppose that the number of online
cpus changed from 2 to 1 between two time intervals. In this case, the
sum of the cpu time measured later is rather reduced than the sum of
the cpu time measured first, and if the cpu usage rate is calculated
using the difference between these two cpu times, a negative result
will come out. To prevent this situation, the average usage is
calculated by summing the usage time of each CPU; assuming that the
usage rate is 0% for offline CPUs.

Change-Id: I93e4561f525b54488df46bf0f895fa76b3b710ca
Signed-off-by: Dongwoo Lee <dwoo08.lee@samsung.com>
src/resource/resource-system.c

index 6343b11..cc2b8a6 100644 (file)
@@ -34,9 +34,6 @@
 #include <resource-monitor/resource-monitor.h>
 
 struct system_resource_data {
-       struct cpu_stat prev_avg;
-       struct cpu_stat curr_avg;
-
        int num_possible_cpus;
        int num_online_cpus;
        struct cpu_stat *prev_cpus;
@@ -57,6 +54,9 @@ static double __calculate_cpu_util(int64_t id, struct cpu_stat *prev,
 
        total = (double)(diff.user + diff.system + diff.nice + diff.idle);
 
+       if (total < 1E-6)
+               return 0.0;
+
        switch (id) {
        case SYSTEM_ATTR_CPU_UTIL:
        case SYSTEM_ATTR_PER_CPU_UTIL:
@@ -82,7 +82,8 @@ static int system_get_avg_cpu_util(struct resource *res,
                                void *data)
 {
        struct system_resource_data *sysdata;
-       double *util = (double *)data;
+       double util, sum = 0.0;
+       int i;
 
        if (!res || !attr || !data)
                return -EINVAL;
@@ -91,13 +92,27 @@ static int system_get_avg_cpu_util(struct resource *res,
        if (!sysdata)
                return -EINVAL;
 
-       *util = __calculate_cpu_util(attr->id, &sysdata->prev_avg, &sysdata->curr_avg);
-       if (*util < 0) {
-               _W("failed to calculate average cpu util (%s: %s)\n",
-                               get_resource_name(res), attr->name);
-               *util = 0.0;
+       for (i = 0; i < sysdata->num_possible_cpus; i++) {
+               util = __calculate_cpu_util(attr->id,
+                                       &sysdata->prev_cpus[i],
+                                       &sysdata->curr_cpus[i]);
+               if (util < 0.0) {
+                       _W("failed to calculate per-cpu util (%s: %s)\n",
+                                       get_resource_name(res), attr->name);
+                       continue;
+               }
+
+               sum += util;
        }
 
+       /*
+        * For offline cpus, it is reasonable to assume that the cpu utilization
+        * is 0%, so when calculating the average utilization, it is more
+        * accurate to average the number of possible cpus instead of the number
+        * of online cpus.
+        */
+       *(double *)data = sum / sysdata->num_possible_cpus;
+
        return 0;
 }
 
@@ -295,14 +310,6 @@ static int system_driver_prepare_update(struct resource *res)
        const char *res_name = get_resource_name(res);
        int ret;
 
-       /* Get the average cpu utilization of all cpus */
-       memcpy(&sysdata->prev_avg, &sysdata->curr_avg, sizeof(sysdata->prev_avg));
-       ret = kernel_get_total_cpu_stat(&sysdata->curr_avg);
-       if (ret < 0) {
-               _I("failed to calculate average cpu util (%s)\n", res_name);
-               return ret;
-       }
-
        /* Get the per-cpu utilization */
        memcpy(sysdata->prev_cpus, sysdata->curr_cpus,
                        sizeof(struct cpu_stat) * sysdata->num_possible_cpus);