resource: Add system resource driver 12/271212/16
authorChanwoo Choi <cw00.choi@samsung.com>
Thu, 10 Feb 2022 06:41:49 +0000 (15:41 +0900)
committerChanwoo Choi <cw00.choi@samsung.com>
Fri, 18 Feb 2022 07:52:00 +0000 (16:52 +0900)
The system resource driver provides the system attributes expressing
the whole system information.

[Detailed description of added system attributes]
- SYSTEM_CPU_UTIL : Average cpu utilization of all cpus
- SYSTEM_CPU_USER_UTIL : Average cpu utilization of all cpus on user
- SYSTEM_CPU_SYS_UTIL : Average cpu utilization of all cpus on system
- SYSTEM_PER_CPU_UTIL : Per-cpu utilization of all cpus
- SYSTEM_PER_CPU_USER_UTIL : Per-cpu utilization on user
- SYSTEM_PER_CPU_SYS_UTIL : Per-cpu utilization on system
- SYSTEM_POSSIBLE_CPU : the number of all cpus regardless cpu online status.
- SYSTEM_ONLINE_CPU : the number of online cpu.

Change-Id: Ide1673e8dae0076bb5dd47002457d0ff0e43649b
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
CMakeLists.txt
lib/tmonitor/tmonitor.h
src/resource/resource-system.c [new file with mode: 0644]

index 747f2f4..8cbd328 100644 (file)
@@ -45,6 +45,7 @@ SET(SRCS
        src/resource/resource-gpu.c
        src/resource/resource-memory.c
        src/resource/resource-display.c
+       src/resource/resource-system.c
        src/monitor/monitor.c
        src/monitor/monitor-thread.c
        src/monitor/monitor-command.c
index 59853b4..890f0b3 100644 (file)
@@ -36,6 +36,7 @@ extern "C" {
 #define RESOURCE_TYPE_BATTERY          5
 #define RESOURCE_TYPE_PROCESS          6
 #define RESOURCE_TYPE_DISPLAY          7
+#define RESOURCE_TYPE_SYSTEM           8
 #define RESOURCE_TYPE_NONSTANDARD      99
 
 /**
@@ -76,6 +77,15 @@ extern "C" {
 
 #define DISPLAY_FPS                    BIT(0)
 
+#define SYSTEM_CPU_UTIL                        BIT(0)
+#define SYSTEM_CPU_USER_UTIL           BIT(1)
+#define SYSTEM_CPU_SYS_UTIL            BIT(2)
+#define SYSTEM_PER_CPU_UTIL            BIT(3)
+#define SYSTEM_PER_CPU_USER_UTIL       BIT(4)
+#define SYSTEM_PER_CPU_SYS_UTIL                BIT(5)
+#define SYSTEM_POSSIBLE_CPU            BIT(6)
+#define SYSTEM_ONLINE_CPU              BIT(7)
+
 /**
  * @brief Initialize the tizen monitor
  * @param[in] Timer period (unit: millisecond, minimum value is 100ms)
diff --git a/src/resource/resource-system.c b/src/resource/resource-system.c
new file mode 100644 (file)
index 0000000..a96dd6b
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * PASS (Power Aware System Service) - System Resource Driver
+ *
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file       resource-system.c
+ * @brief      TBD
+ * @ingroup    TBD
+ */
+
+#include <glib.h>
+
+#include <hal/hal-power.h>
+
+#include <util/common.h>
+#include <util/log.h>
+#include <util/resource.h>
+#include <util/kernel.h>
+
+#include <tmonitor/tmonitor.h>
+
+struct system_resouce_data {
+       struct cpu_stat prev_avg;
+       struct cpu_stat curr_avg;
+
+       int num_possible_cpus;
+       int num_online_cpus;
+       struct cpu_stat *prev_cpus;
+       struct cpu_stat *curr_cpus;
+};
+
+static double __calculate_cpu_util(int64_t id, struct cpu_stat *prev,
+                                       struct cpu_stat *curr)
+{
+       struct cpu_stat diff;
+       int total;
+       double util;
+
+       diff.user = curr->user - prev->user;
+       diff.system = curr->system - prev->system;
+       diff.nice = curr->nice - prev->nice;
+       diff.idle = curr->idle - prev->idle;
+
+       total = (double)(diff.user + diff.system + diff.nice + diff.idle);
+
+       switch (id) {
+       case SYSTEM_CPU_UTIL:
+       case SYSTEM_PER_CPU_UTIL:
+               util = (double)((diff.user + diff.system + diff.nice) * 100) / total;
+               break;
+       case SYSTEM_CPU_USER_UTIL:
+       case SYSTEM_PER_CPU_USER_UTIL:
+               util = (double)((diff.user) * 100) / total;
+               break;
+       case SYSTEM_CPU_SYS_UTIL:
+       case SYSTEM_PER_CPU_SYS_UTIL:
+               util = (double)((diff.system + diff.nice) * 100) / total;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return util;
+}
+
+static int system_get_avg_cpu_util(const struct resource *res,
+                               const struct resource_attribute *attr,
+                               void **data)
+{
+       struct system_resouce_data *sysdata = (struct system_resouce_data *)res->priv;
+       double util;
+
+       if (!res || !attr || !data)
+               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.%d: %s)\n",
+                               res->name, res->index, attr->name);
+               util = 0;
+       }
+       *data = (void *)(intptr_t)util;
+
+       return 0;
+}
+
+static int system_get_per_cpu_util(const struct resource *res,
+                               const struct resource_attribute *attr,
+                               void **data)
+{
+       struct system_resouce_data *sysdata = (struct system_resouce_data *)res->priv;
+       struct array_value *array;
+       double *utils;
+       int i;
+
+       if (!res || !attr || !data)
+               return -EINVAL;
+       array = calloc(1, sizeof(*array));
+       if (!array)
+               return -ENOMEM;
+
+       array->type = DATA_TYPE_DOUBLE;
+       array->length = sysdata->num_possible_cpus;
+       array->data = calloc(sysdata->num_possible_cpus, sizeof(double));
+       if (!array->data) {
+               free(array);
+               return -ENOMEM;
+       }
+       utils = (double *)array->data;
+
+       for (i = 0; i < sysdata->num_possible_cpus; i++) {
+               utils[i] = __calculate_cpu_util(attr->id,
+                                       &sysdata->prev_cpus[i],
+                                       &sysdata->curr_cpus[i]);
+               if (utils[i] < 0) {
+                       _W("failed to calculate per-cpu util (%s.%d: %s)\n",
+                                       res->name, res->index, attr->name);
+                       utils[i] = 0;
+               }
+       }
+       *data = (void *)array;
+
+       return 0;
+}
+
+static int system_get_cpu_num(const struct resource *res,
+                               const struct resource_attribute *attr,
+                               void **data)
+{
+       int cpu_num;
+
+       if (!res || !attr || !data)
+               return -EINVAL;
+
+       switch (attr->id) {
+       case SYSTEM_POSSIBLE_CPU:
+               cpu_num = kernel_get_online_cpu_num();
+               break;
+       case SYSTEM_ONLINE_CPU:
+               cpu_num = kernel_get_possible_cpu_num();
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       *data = (void *)(intptr_t)cpu_num;
+
+       return 0;
+}
+
+static const struct resource_attribute system_attrs[] = {
+       {
+               .name   = "SYSTEM_CPU_UTIL",
+               .id     = SYSTEM_CPU_UTIL,
+               .type   = DATA_TYPE_DOUBLE,
+               .ops    = {
+                       .get = system_get_avg_cpu_util,
+               }
+       }, {
+               .name   = "SYSTEM_CPU_USER_UTIL",
+               .id     = SYSTEM_CPU_USER_UTIL,
+               .type   = DATA_TYPE_DOUBLE,
+               .ops    = {
+                       .get = system_get_avg_cpu_util,
+               }
+       }, {
+               .name   = "SYSTEM_CPU_SYS_UTIL",
+               .id     = SYSTEM_CPU_SYS_UTIL,
+               .type   = DATA_TYPE_DOUBLE,
+               .ops    = {
+                       .get = system_get_avg_cpu_util,
+               }
+       }, {
+               .name   = "SYSTEM_PER_CPU_UTIL",
+               .id     = SYSTEM_PER_CPU_UTIL,
+               .type   = DATA_TYPE_ARRAY,
+               .ops    = {
+                       .get = system_get_per_cpu_util,
+               }
+       }, {
+               .name   = "SYSTEM_PER_CPU_USER_UTIL",
+               .id     = SYSTEM_PER_CPU_USER_UTIL,
+               .type   = DATA_TYPE_ARRAY,
+               .ops    = {
+                       .get = system_get_per_cpu_util,
+               }
+       }, {
+               .name   = "SYSTEM_PER_CPU_SYS_UTIL",
+               .id     = SYSTEM_PER_CPU_SYS_UTIL,
+               .type   = DATA_TYPE_ARRAY,
+               .ops    = {
+                       .get = system_get_per_cpu_util,
+               }
+       }, {
+               .name   = "SYSTEM_POSSIBLE_CPU",
+               .id     = SYSTEM_POSSIBLE_CPU,
+               .type   = DATA_TYPE_INT,
+               .ops    = {
+                       .get = system_get_cpu_num,
+               }
+       }, {
+               .name   = "SYSTEM_ONLINE_CPU",
+               .id     = SYSTEM_ONLINE_CPU,
+               .type   = DATA_TYPE_INT,
+               .ops    = {
+                       .get = system_get_cpu_num,
+               }
+       },
+};
+
+static int system_driver_init(struct resource *res)
+{
+       struct system_resouce_data *sysdata;
+       int ret;
+
+       sysdata = calloc(1, sizeof(struct system_resouce_data));
+       if (!sysdata)
+               return -ENOMEM;
+       res->priv = (void *)sysdata;
+
+       ret = kernel_get_possible_cpu_num();
+       if (ret < 0) {
+               _I("failed to get possible cpu on system driver (%s.%d)\n",
+                               res->name, res->index);
+               goto err;
+       }
+       sysdata->num_possible_cpus = ret;
+
+       sysdata->prev_cpus = calloc(sysdata->num_possible_cpus,
+                                       sizeof(struct cpu_stat));
+       if (!sysdata->prev_cpus) {
+               _I("failed to allocate memory of prev_cpus (%s.%d)\n",
+                               res->name, res->index);
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       sysdata->curr_cpus = calloc(sysdata->num_possible_cpus,
+                                       sizeof(struct cpu_stat));
+       if (!sysdata->curr_cpus) {
+               _I("failed to allocate memory of curr_cpus (%s.%d)\n",
+                               res->name, res->index);
+               ret = -ENOMEM;
+               goto err_prev_cpus;
+       }
+
+       return 0;
+
+err_prev_cpus:
+       free(sysdata->prev_cpus);
+err:
+       sysdata->num_possible_cpus = 0;
+       free(sysdata);
+       sysdata = NULL;
+
+       return ret;
+}
+
+static void system_driver_exit(struct resource *res)
+{
+       struct system_resouce_data *sysdata
+                       = (struct system_resouce_data *)res->priv;
+
+       free(sysdata->prev_cpus);
+       free(sysdata->curr_cpus);
+       free(sysdata);
+       res->priv = NULL;
+}
+
+static int system_driver_prepare_update(struct resource *res)
+{
+       struct system_resouce_data *sysdata
+                       = (struct system_resouce_data *)res->priv;
+       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:%d)\n",
+                               res->name, res->index);
+               return ret;
+       }
+
+       /* Get the per-cpu utilization */
+       memcpy(sysdata->prev_cpus, sysdata->curr_cpus,
+                       sizeof(struct cpu_stat) * sysdata->num_possible_cpus);
+       ret = kernel_get_per_cpu_stat(sysdata->curr_cpus,
+                                       sysdata->num_possible_cpus,
+                                       &sysdata->num_online_cpus);
+       if (ret < 0) {
+               _I("failed to calculate per-cpu util (%s:%d)\n",
+                               res->name, res->index);
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct resource_driver system_resource_driver = {
+       .name           = "SYSTEM",
+       .type           = RESOURCE_TYPE_SYSTEM,
+       .attrs          = system_attrs,
+       .num_attrs      = ARRAY_SIZE(system_attrs),
+       .flags          = RESOURCE_DRIVER_NO_DEVICE,
+       .ops = {
+               .init           = system_driver_init,
+               .exit           = system_driver_exit,
+               .prepare_update = system_driver_prepare_update,
+       },
+};
+RESOURCE_DRIVER_REGISTER(&system_resource_driver)