diff options
author | Chanwoo Choi <cw00.choi@samsung.com> | 2022-07-25 12:44:02 +0900 |
---|---|---|
committer | Chanwoo Choi <cw00.choi@samsung.com> | 2022-08-02 11:32:49 +0900 |
commit | b3308132cbfbc2de1b74c07842bbba18a12c0063 (patch) | |
tree | c394984993040960a52abb58776da7735df77e6a | |
parent | fbf292ad884a71023554bef0d4858dbad0208d24 (diff) | |
download | pass-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.txt | 2 | ||||
-rw-r--r-- | lib/resource-monitor/resource-monitor.h | 16 | ||||
-rw-r--r-- | src/resource/resource-disk.c | 410 | ||||
-rw-r--r-- | src/resource/resource-network.c | 162 |
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) |