summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChanwoo Choi <cw00.choi@samsung.com>2022-07-25 12:44:02 +0900
committerChanwoo Choi <cw00.choi@samsung.com>2022-08-02 11:32:49 +0900
commitb3308132cbfbc2de1b74c07842bbba18a12c0063 (patch)
treec394984993040960a52abb58776da7735df77e6a
parentfbf292ad884a71023554bef0d4858dbad0208d24 (diff)
downloadpass-b3308132cbfbc2de1b74c07842bbba18a12c0063.tar.gz
pass-b3308132cbfbc2de1b74c07842bbba18a12c0063.tar.bz2
pass-b3308132cbfbc2de1b74c07842bbba18a12c0063.zip
resource: Add disk and network resource driversubmit/tizen/20220805.011932
Add disk and network resource driver to provide monitoring data. 1. Add disk resource driver to provide the disk bandwidth and usage with following resource attributes: - DISK_ATTR_NAME indicates the disk device name - DISK_ATTR_READ_PER_SEC indicates read bandwidth of specific block like zram0 - DISK_ATTR_WRITE_PER_SEC indicates write bandwidth of specific block like mmcblk0 - DISK_ATTR_READ_TOTAL indicates read kB size of specific block - DISK_ATTR_WRITE_TOTAL indicates write kB size of specific block The detailed description[1] of data are from /proc/diskstats and /sys/class/block/[block name]/stats: [1] https://www.kernel.org/doc/Documentation/ABI/testing/procfs-diskstats 2. Add skeleton of network resource driver with resource name attribute. - NETWORK_ATTR_NAME indicates the network device name Change-Id: Ib440ab628ad1edc5a24378b9c18b80b7c9a8367e Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
-rw-r--r--CMakeLists.txt2
-rw-r--r--lib/resource-monitor/resource-monitor.h16
-rw-r--r--src/resource/resource-disk.c410
-rw-r--r--src/resource/resource-network.c162
4 files changed, 590 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 71ab2c3..aada2f3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -49,6 +49,8 @@ SET(SRCS
src/resource/resource-battery.c
src/resource/resource-process.c
src/resource/resource-process-group.c
+ src/resource/resource-disk.c
+ src/resource/resource-network.c
src/monitor/monitor.c
src/monitor/monitor-thread.c
src/monitor/monitor-command.c
diff --git a/lib/resource-monitor/resource-monitor.h b/lib/resource-monitor/resource-monitor.h
index 08d7d11..1a97cb6 100644
--- a/lib/resource-monitor/resource-monitor.h
+++ b/lib/resource-monitor/resource-monitor.h
@@ -42,6 +42,8 @@ extern "C" {
#define RESOURCE_TYPE_DISPLAY 7
#define RESOURCE_TYPE_SYSTEM 8
#define RESOURCE_TYPE_PROCESS_GROUP 9
+#define RESOURCE_TYPE_DISK 10
+#define RESOURCE_TYPE_NETWORK 11
#define RESOURCE_TYPE_NONSTANDARD 99
/**
@@ -149,6 +151,20 @@ extern "C" {
#define PROCESS_GROUP_CTRL_ROOT_PID BIT(0)
+/* Disk Resource */
+#define DISK_ATTR_NAME BIT(0) /* DATA_TYPE_STRING */
+#define DISK_ATTR_READ_PER_SEC BIT(1) /* DATA_TYPE_DOUBLE */
+#define DISK_ATTR_WRITE_PER_SEC BIT(2) /* DATA_TYPE_DOUBLE */
+#define DISK_ATTR_READ_TOTAL BIT(3) /* DATA_TYPE_UINT64 */
+#define DISK_ATTR_WRITE_TOTAL BIT(4) /* DATA_TYPE_UINT64 */
+
+#define DISK_CTRL_DEVICE_ID BIT(0)
+
+/* Network Resource */
+#define NETWORK_ATTR_NAME BIT(0) /* DATA_TYPE_STRING */
+
+#define NETWORK_CTRL_DEVICE_ID BIT(0)
+
/**
* @brief Initialize the resource monitor
* @return @c positive integer as resource monitor id on success, otherwise a negative error value
diff --git a/src/resource/resource-disk.c b/src/resource/resource-disk.c
new file mode 100644
index 0000000..3493241
--- /dev/null
+++ b/src/resource/resource-disk.c
@@ -0,0 +1,410 @@
+/*
+ * PASS (Power Aware System Service) - Disk 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-disk.c
+ * @brief Provide disk resource driver supporting the various resource
+ * attributes. It supports the disk attributes such as disk
+ * read/write bandwidth, disk size and so on.
+ * @ingroup RESOURCE_MONITOR
+ */
+
+#include <glib.h>
+
+#include <util/common.h>
+#include <util/log.h>
+#include <util/resource.h>
+
+#include <resource-monitor/resource-monitor.h>
+
+enum {
+ PREV_IDX = 0,
+ CURR_IDX = 1,
+};
+
+/* Return interval of time (@p) is given in 1/100th of a second */
+#define GET_BPS(m, n, p) (((double) ((n) - (m))) / (p) * 100)
+
+struct io_stats {
+ unsigned long rd_sectors; /* Number of sectors read */
+ unsigned long wr_sectors; /* Number of sectors written */
+ unsigned long dc_sectors; /* Number of sectors discarded */
+ unsigned long rd_ios; /* Number of read operations issued to the device */
+ unsigned long rd_merges; /* Number of read requests merged */
+ unsigned long wr_ios; /* Number of write operations issued to the device */
+ unsigned long wr_merges; /* Number of write requests merged */
+ unsigned long dc_ios; /* Number of discard operations issued to the device */
+ unsigned long dc_merges; /* Number of discard requests merged */
+ unsigned long fl_ios; /* Number of flush requests issued to the device */
+ unsigned int rd_ticks; /* Time of read requests in queue */
+ unsigned int wr_ticks; /* Time of write requests in queue */
+ unsigned int dc_ticks; /* Time of discard requests in queue */
+ unsigned int fl_ticks; /* Time of flush requests in queue */
+ unsigned int ios_pgr; /* Number of I/Os in progress */
+ unsigned int tot_ticks; /* Number of ticks total (for this device) for I/O */
+ unsigned int rq_ticks; /* Number of ticks requests spent in queue */
+};
+
+struct disk_context {
+ char *device_name;
+ int index;
+
+ unsigned long long uptime_cs[2];
+ struct io_stats stats[2];
+
+ double read_per_sec;
+ double write_per_sec;
+ u_int32_t read_total;
+ u_int32_t write_total;
+};
+
+static int disk_get_value(struct resource *res,
+ const struct resource_attribute *attr,
+ void *data)
+{
+ struct disk_context *ctx;
+
+ if (!res || !attr || !data)
+ return -EINVAL;
+
+ ctx = get_resource_privdata(res);
+ if (!ctx)
+ return -EINVAL;
+
+ if (!ctx->device_name) {
+ _E("DISK_CTRL_DEVICE_ID is not yet initialized, res:name(%s)id(%d) | attr:name(%s)id(%"PRId64")\n",
+ get_resource_name(res), get_resource_id(res),
+ get_resource_attr_name(res, attr->id), attr->id);
+ return -EINVAL;
+ }
+
+ switch (attr->id) {
+ case DISK_ATTR_NAME:
+ strncpy((char *)data, ctx->device_name, BUFF_MAX);
+ break;
+ case DISK_ATTR_READ_PER_SEC:
+ *(double *)data = ctx->read_per_sec;
+ break;
+ case DISK_ATTR_WRITE_PER_SEC:
+ *(double *)data = ctx->write_per_sec;
+ break;
+ case DISK_ATTR_READ_TOTAL:
+ *(u_int64_t *)data = ctx->read_total;
+ break;
+ case DISK_ATTR_WRITE_TOTAL:
+ *(u_int64_t *)data = ctx->write_total;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct resource_attribute disk_attrs[] = {
+ {
+ .name = "DISK_ATTR_NAME",
+ .id = DISK_ATTR_NAME,
+ .type = DATA_TYPE_STRING,
+ .ops = {
+ .get = disk_get_value,
+ },
+ }, {
+ .name = "DISK_ATTR_READ_PER_SEC",
+ .id = DISK_ATTR_READ_PER_SEC,
+ .type = DATA_TYPE_DOUBLE,
+ .ops = {
+ .get = disk_get_value,
+ },
+ }, {
+ .name = "DISK_ATTR_WRITE_PER_SEC",
+ .id = DISK_ATTR_WRITE_PER_SEC,
+ .type = DATA_TYPE_DOUBLE,
+ .ops = {
+ .get = disk_get_value,
+ },
+ }, {
+ .name = "DISK_ATTR_READ_TOTAL",
+ .id = DISK_ATTR_READ_TOTAL,
+ .type = DATA_TYPE_UINT64,
+ .ops = {
+ .get = disk_get_value,
+ },
+ }, {
+ .name = "DISK_ATTR_WRITE_TOTAL",
+ .id = DISK_ATTR_WRITE_TOTAL,
+ .type = DATA_TYPE_UINT64,
+ .ops = {
+ .get = disk_get_value,
+ },
+ },
+};
+
+static int disk_setup_device_id(struct resource *res,
+ const struct resource_control *ctrl,
+ const void *data)
+{
+ struct disk_context *ctx;
+ const struct resource_device *device;
+ int resource_index = (int)(intptr_t)data;
+
+ if (!res || !ctrl)
+ return -EINVAL;
+
+ ctx = get_resource_privdata(res);
+ if (!ctx)
+ return -EINVAL;
+
+ device = find_resource_device(get_resource_type(res), resource_index);
+ if (!device) {
+ _E("Not available resource: type: %s, index: %d\n",
+ get_resource_name(res), resource_index);
+ return -EINVAL;
+ }
+
+ if (ctx->device_name)
+ free(ctx->device_name);
+
+ ctx->device_name = g_strdup(device->name);
+ ctx->index = resource_index;
+
+ return 0;
+}
+
+static const struct resource_control disk_ctrls[] = {
+ {
+ .name = "DISK_CTRL_DEVICE_ID",
+ .id = DISK_CTRL_DEVICE_ID,
+ .ops = {
+ .set = disk_setup_device_id,
+ },
+ },
+};
+
+static int read_uptime(unsigned long long *uptime)
+{
+ FILE *fp = NULL;
+ char line[BUFF_MAX];
+ unsigned long up_sec, up_cent;
+ int ret = 0;
+
+ if ((fp = fopen("/proc/uptime", "r")) == NULL) {
+ ret = -ENOENT;
+ } else if (fgets(line, sizeof(line), fp) == NULL) {
+ ret = -ENOENT;
+ } else if (sscanf(line, "%lu.%lu", &up_sec, &up_cent) == 2) {
+ *uptime = (unsigned long long) up_sec * 100 +
+ (unsigned long long) up_cent;
+ } else {
+ ret = -EINVAL;
+ }
+
+ if (fp != NULL)
+ fclose(fp);
+
+ return ret;
+}
+
+static int read_disk_stats(char *device_name, struct io_stats *ios)
+{
+ char filename[BUFF_MAX];
+ FILE *fp;
+ int i;
+ unsigned int ios_pgr, tot_ticks, rq_ticks, wr_ticks, dc_ticks, fl_ticks;
+ unsigned long rd_ios, rd_merges_or_rd_sec, wr_ios, wr_merges;
+ unsigned long rd_sec_or_wr_ios, wr_sec, rd_ticks_or_wr_sec;
+ unsigned long dc_ios, dc_merges, dc_sec, fl_ios;
+
+ if (!device_name || !ios)
+ return -EINVAL;
+
+ snprintf(filename, BUFF_MAX, "/sys/class/block/%s/stat", device_name);
+
+ if (access(filename, F_OK) == -1) {
+ _E("There is no block device(%s)\n", device_name);
+ return -ENOENT;
+ } else if ((fp = fopen(filename, "r")) == NULL) {
+ _E("failed to open block device(%s)\n", device_name);
+ return -ENOENT;
+ }
+
+ i = fscanf(fp, "%lu %lu %lu %lu %lu %lu %lu %u %u %u %u %lu %lu %lu %u %lu %u",
+ &rd_ios, &rd_merges_or_rd_sec, &rd_sec_or_wr_ios, &rd_ticks_or_wr_sec,
+ &wr_ios, &wr_merges, &wr_sec, &wr_ticks, &ios_pgr, &tot_ticks, &rq_ticks,
+ &dc_ios, &dc_merges, &dc_sec, &dc_ticks,
+ &fl_ios, &fl_ticks);
+
+ memset(ios, 0, sizeof(*ios));
+
+ if (i >= 11) {
+ /* Device or partition */
+ ios->rd_ios = rd_ios;
+ ios->rd_merges = rd_merges_or_rd_sec;
+ ios->rd_sectors = rd_sec_or_wr_ios;
+ ios->rd_ticks = (unsigned int) rd_ticks_or_wr_sec;
+ ios->wr_ios = wr_ios;
+ ios->wr_merges = wr_merges;
+ ios->wr_sectors = wr_sec;
+ ios->wr_ticks = wr_ticks;
+ ios->ios_pgr = ios_pgr;
+ ios->tot_ticks = tot_ticks;
+ ios->rq_ticks = rq_ticks;
+
+ if (i >= 15) {
+ /* Discard I/O */
+ ios->dc_ios = dc_ios;
+ ios->dc_merges = dc_merges;
+ ios->dc_sectors = dc_sec;
+ ios->dc_ticks = dc_ticks;
+ }
+
+ if (i >= 17) {
+ /* Flush I/O */
+ ios->fl_ios = fl_ios;
+ ios->fl_ticks = fl_ticks;
+ }
+ }
+ else if (i == 4) {
+ /* Partition without extended statistics */
+ ios->rd_ios = rd_ios;
+ ios->rd_sectors = rd_merges_or_rd_sec;
+ ios->wr_ios = rd_sec_or_wr_ios;
+ ios->wr_sectors = rd_ticks_or_wr_sec;
+ }
+
+ fclose(fp);
+
+ return 0;
+}
+
+static unsigned long long get_interval(unsigned long long prev_uptime,
+ unsigned long long curr_uptime)
+{
+ unsigned long long interval = curr_uptime - prev_uptime;
+ return (interval == 0) ? 1 : interval;
+}
+
+static int calculate_disk_stats(struct disk_context *ctx)
+{
+ struct io_stats *curr, *prev;
+ unsigned long long interval;
+
+ if (!ctx)
+ return -EINVAL;
+
+ /* Calculate time interval in 1/100th of a second */
+ interval = get_interval(ctx->uptime_cs[PREV_IDX], ctx->uptime_cs[CURR_IDX]);
+
+ curr = &ctx->stats[CURR_IDX];
+ prev = &ctx->stats[PREV_IDX];
+
+ ctx->read_per_sec = GET_BPS(prev->rd_sectors, curr->rd_sectors, interval);
+ ctx->write_per_sec = GET_BPS(prev->wr_sectors, curr->wr_sectors, interval);
+ ctx->read_total = curr->rd_sectors;
+ ctx->write_total = curr->wr_sectors;
+
+ return 0;
+}
+
+static int disk_init(struct resource *res)
+{
+ struct disk_context *ctx;
+
+ ctx = calloc(1, sizeof(struct disk_context));
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->index = -1;
+
+ set_resource_privdata(res, ctx);
+
+ return 0;
+}
+
+static void disk_exit(struct resource *res)
+{
+ struct disk_context *ctx;
+
+ if (!res)
+ return;
+
+ ctx = get_resource_privdata(res);
+ if (!ctx)
+ return;
+
+ if (ctx->device_name)
+ free(ctx->device_name);
+
+ free(ctx);
+ set_resource_privdata(res, NULL);
+}
+
+static int disk_prepare_update(struct resource *res)
+{
+ struct disk_context *ctx;
+ int ret;
+
+ if (!res)
+ return -EINVAL;
+
+ ctx = get_resource_privdata(res);
+ if (!ctx)
+ return -EINVAL;
+
+ if (!ctx->device_name) {
+ _E("%s: DISK_CTRL_DEVICE_ID is not yet initialized\n",
+ get_resource_name(res));
+ return -EINVAL;
+ }
+
+ /* Backup current disk stats */
+ memcpy(&ctx->stats[PREV_IDX], &ctx->stats[CURR_IDX], sizeof(ctx->stats[CURR_IDX]));
+ ctx->uptime_cs[PREV_IDX] = ctx->uptime_cs[CURR_IDX];
+
+ /* Read system uptime */
+ ret = read_uptime(&(ctx->uptime_cs[CURR_IDX]));
+ if (ret < 0)
+ return ret;
+
+ /* Read disk stats */
+ ret = read_disk_stats(ctx->device_name, &ctx->stats[CURR_IDX]);
+ if (ret < 0)
+ return ret;
+
+ /* Calculate disk stats */
+ ret = calculate_disk_stats(ctx);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static const struct resource_driver disk_resource_driver = {
+ .name = "DISK",
+ .type = RESOURCE_TYPE_DISK,
+ .attrs = disk_attrs,
+ .num_attrs = ARRAY_SIZE(disk_attrs),
+ .ctrls = disk_ctrls,
+ .num_ctrls = ARRAY_SIZE(disk_ctrls),
+ .ops = {
+ .init = disk_init,
+ .exit = disk_exit,
+ .prepare_update = disk_prepare_update,
+ },
+};
+RESOURCE_DRIVER_REGISTER(&disk_resource_driver)
diff --git a/src/resource/resource-network.c b/src/resource/resource-network.c
new file mode 100644
index 0000000..cfc4887
--- /dev/null
+++ b/src/resource/resource-network.c
@@ -0,0 +1,162 @@
+/*
+ * PASS (Power Aware System Service) - Network 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-network.c
+ * @brief Provide network resource driver supporting the various resource
+ * attributes. It supports the network attributes such as network
+ * bandwidth and so on.
+ * @ingroup RESOURCE_MONITOR
+ */
+
+#include <glib.h>
+
+#include <util/common.h>
+#include <util/log.h>
+#include <util/resource.h>
+
+#include <resource-monitor/resource-monitor.h>
+
+struct network_context {
+ char *device_name;
+ int index;
+};
+
+static int network_get_name(struct resource *res,
+ const struct resource_attribute *attr,
+ void *data)
+{
+ struct network_context *ctx;
+ char *buf = (char *)data;
+
+ if (!res || !attr || !data)
+ return -EINVAL;
+
+ ctx = get_resource_privdata(res);
+ if (!ctx)
+ return -EINVAL;
+
+ if (!ctx->device_name) {
+ _E("%s: NETWORK_CTRL_DEVICE_ID is not yet initialized\n",
+ get_resource_name(res));
+ return -EINVAL;
+ }
+
+ strncpy(buf, ctx->device_name, BUFF_MAX);
+
+ return 0;
+}
+
+static const struct resource_attribute network_attrs[] = {
+ {
+ .name = "NETWORK_ATTR_NAME",
+ .id = NETWORK_ATTR_NAME,
+ .type = DATA_TYPE_STRING,
+ .ops = {
+ .get = network_get_name,
+ },
+ },
+};
+
+static int network_setup_device_id(struct resource *res,
+ const struct resource_control *ctrl,
+ const void *data)
+{
+ struct network_context *ctx;
+ const struct resource_device *device;
+ int resource_index = (int)(intptr_t)data;
+
+ if (!res || !ctrl)
+ return -EINVAL;
+
+ ctx = get_resource_privdata(res);
+ if (!ctx)
+ return -EINVAL;
+
+ device = find_resource_device(get_resource_type(res), resource_index);
+ if (!device) {
+ _E("Not available resource: type: %s, index: %d\n",
+ get_resource_name(res), resource_index);
+ return -EINVAL;
+ }
+
+ if (ctx->device_name)
+ free(ctx->device_name);
+
+ ctx->device_name = g_strdup(device->name);
+ ctx->index = resource_index;
+
+ return 0;
+}
+
+static const struct resource_control network_ctrls[] = {
+ {
+ .name = "NETWORK_CTRL_DEVICE_ID",
+ .id = NETWORK_CTRL_DEVICE_ID,
+ .ops = {
+ .set = network_setup_device_id,
+ },
+ },
+};
+
+static int network_init(struct resource *res)
+{
+ struct network_context *ctx;
+
+ ctx = calloc(1, sizeof(struct network_context));
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->index = -1;
+
+ set_resource_privdata(res, ctx);
+
+ return 0;
+}
+
+static void network_exit(struct resource *res)
+{
+ struct network_context *ctx;
+
+ if (!res)
+ return;
+
+ ctx = get_resource_privdata(res);
+ if (!ctx)
+ return;
+
+ if (ctx->device_name)
+ free(ctx->device_name);
+
+ free(ctx);
+ set_resource_privdata(res, NULL);
+}
+
+static const struct resource_driver network_resource_driver = {
+ .name = "NETWORK",
+ .type = RESOURCE_TYPE_NETWORK,
+ .attrs = network_attrs,
+ .num_attrs = ARRAY_SIZE(network_attrs),
+ .ctrls = network_ctrls,
+ .num_ctrls = ARRAY_SIZE(network_ctrls),
+ .ops = {
+ .init = network_init,
+ .exit = network_exit,
+ },
+};
+RESOURCE_DRIVER_REGISTER(&network_resource_driver)