--- /dev/null
+/*
+ * PASS (Power Aware System Service) - Resource Monitor Tool
+ *
+ * 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.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <util/common.h>
+
+#include "resource-monitor.h"
+
+#define BUFF_MAX 255
+#define MAX_RESOURCE 100
+#define MAX_ATTR 64
+
+struct resource_attr_data {
+ const u_int64_t id;
+ const int type;
+ const int array_type;
+ const char *name;
+ const char *unit;
+ const char *desc;
+
+ u_int32_t value_uint32;
+ u_int64_t value_uint64;
+ int32_t value_int32;
+ int64_t value_int64;
+ double value_double;
+ char value_string[BUFF_MAX];
+};
+
+static struct resource_attr_data cpu_attrs[] = {
+ { .id = CPU_ATTR_NAME, .type = DATA_TYPE_STRING, .name = "CPU_ATTR_NAME", .unit = "", .desc = "CPU cluster name", },
+ { .id = CPU_ATTR_CUR_FREQ, .type = DATA_TYPE_INT, .name = "CPU_ATTR_CUR_FREQ", .unit = "kHz", .desc = "Current CPU frequency", },
+ { .id = CPU_ATTR_MIN_FREQ, .type = DATA_TYPE_INT, .name = "CPU_ATTR_MIN_FREQ", .unit = "kHz", .desc = "Current CPU minimum frequency", },
+ { .id = CPU_ATTR_MAX_FREQ, .type = DATA_TYPE_INT, .name = "CPU_ATTR_MAX_FREQ", .unit = "kHz", .desc = "Current CPU maximum frequency", },
+ { .id = CPU_ATTR_AVAILABLE_MIN_FREQ, .type = DATA_TYPE_INT, .name = "CPU_ATTR_AVAILABLE_MIN_FREQ", .unit = "kHz", .desc = "Available CPU minimum frequency", },
+ { .id = CPU_ATTR_AVAILABLE_MAX_FREQ, .type = DATA_TYPE_INT, .name = "CPU_ATTR_AVAILABLE_MAX_FREQ", .unit = "kHz", .desc = "Available CPU maximum frequency", },
+ { .id = CPU_ATTR_CUR_GOVERNOR, .type = DATA_TYPE_STRING, .name = "CPU_ATTR_CUR_GOVERNOR", .unit = "", .desc = "Current CPU frequency governor name", },
+};
+
+static struct resource_attr_data bus_attrs[] = {
+ { .id = BUS_ATTR_NAME, .type = DATA_TYPE_STRING, .name = "BUS_ATTR_NAME", .unit = "", .desc = "Bus device name", },
+ { .id = BUS_ATTR_CUR_FREQ, .type = DATA_TYPE_INT, .name = "BUS_ATTR_CUR_FREQ", .unit = "kHz", .desc = "Current bus frequency", },
+ { .id = BUS_ATTR_MIN_FREQ, .type = DATA_TYPE_INT, .name = "BUS_ATTR_MIN_FREQ", .unit = "kHz", .desc = "Current bus minimum frequency", },
+ { .id = BUS_ATTR_MAX_FREQ, .type = DATA_TYPE_INT, .name = "BUS_ATTR_MAX_FREQ", .unit = "kHz", .desc = "Current bus maximum frequency", },
+ { .id = BUS_ATTR_AVAILABLE_MIN_FREQ, .type = DATA_TYPE_INT, .name = "BUS_ATTR_AVAILABLE_MIN_FREQ", .unit = "kHz", .desc = "Available bus minimum frequency", },
+ { .id = BUS_ATTR_AVAILABLE_MAX_FREQ, .type = DATA_TYPE_INT, .name = "BUS_ATTR_AVAILABLE_MAX_FREQ", .unit = "kHz", .desc = "Available bus maximum frequency", },
+ { .id = BUS_ATTR_CUR_GOVERNOR, .type = DATA_TYPE_STRING, .name = "BUS_ATTR_CUR_GOVERNOR", .unit = "", .desc = "Current bus frequency governor name", },
+};
+
+static struct resource_attr_data gpu_attrs[] = {
+ { .id = GPU_ATTR_NAME, .type = DATA_TYPE_STRING, .name = "GPU_ATTR_NAME", .unit = "", .desc = "GPU device name", },
+ { .id = GPU_ATTR_CUR_FREQ, .type = DATA_TYPE_INT, .name = "GPU_ATTR_CUR_FREQ", .unit = "kHz", .desc = "Current GPU frequency", },
+ { .id = GPU_ATTR_MIN_FREQ, .type = DATA_TYPE_INT, .name = "GPU_ATTR_MIN_FREQ", .unit = "kHz", .desc = "Current GPU minimum frequency", },
+ { .id = GPU_ATTR_MAX_FREQ, .type = DATA_TYPE_INT, .name = "GPU_ATTR_MAX_FREQ", .unit = "kHz", .desc = "Current GPU maximum frequency", },
+ { .id = GPU_ATTR_AVAILABLE_MIN_FREQ, .type = DATA_TYPE_INT, .name = "GPU_ATTR_AVAILABLE_MIN_FREQ", .unit = "kHz", .desc = "Available GPU minimum frequency", },
+ { .id = GPU_ATTR_AVAILABLE_MAX_FREQ, .type = DATA_TYPE_INT, .name = "GPU_ATTR_AVAILABLE_MAX_FREQ", .unit = "kHz", .desc = "Available GPU maximum frequency", },
+ { .id = GPU_ATTR_CUR_GOVERNOR, .type = DATA_TYPE_STRING, .name = "GPU_ATTR_CUR_GOVERNOR", .unit = "", .desc = "Current GPU frequency governor name", },
+};
+
+static struct resource_attr_data memory_attrs[] = {
+ { .id = MEMORY_ATTR_TOTAL, .type = DATA_TYPE_UINT64, .name = "MEMORY_ATTR_TOTAL", .unit = "byte", .desc = "Memory total size", },
+ { .id = MEMORY_ATTR_AVAILABLE, .type = DATA_TYPE_UINT64, .name = "MEMORY_ATTR_AVAILABLE", .unit = "byte", .desc = "Memory available size", },
+ { .id = MEMORY_ATTR_FREE, .type = DATA_TYPE_UINT64, .name = "MEMORY_ATTR_FREE", .unit = "byte", .desc = "Memory free size", },
+ { .id = MEMORY_ATTR_BUFFER, .type = DATA_TYPE_UINT64, .name = "MEMORY_ATTR_BUFFER", .unit = "byte", .desc = "Memorry buffer size", },
+ { .id = MEMORY_ATTR_CACHED, .type = DATA_TYPE_UINT64, .name = "MEMORY_ATTR_CACHED", .unit = "byte", .desc = "Memory cached size", },
+ { .id = MEMORY_ATTR_CMA_TOTAL, .type = DATA_TYPE_UINT64, .name = "MEMORY_ATTR_CMA_TOTAL", .unit = "byte", .desc = "CMA memory total size", },
+ { .id = MEMORY_ATTR_CMA_FREE, .type = DATA_TYPE_UINT64, .name = "MEMORY_ATTR_CMA_FREE", .unit = "byte", .desc = "CMA memory free size", },
+ { .id = MEMORY_ATTR_SWAP_TOTAL, .type = DATA_TYPE_UINT64, .name = "MEMORY_ATTR_SWAP_TOTAL", .unit = "byte", .desc = "Swap memory total size", },
+ { .id = MEMORY_ATTR_SWAP_FREE, .type = DATA_TYPE_UINT64, .name = "MEMORY_ATTR_SWAP_FREE", .unit = "byte", .desc = "Swap memory free size", },
+};
+
+static struct resource_attr_data battery_attrs[] = {
+ { .id = BATTERY_ATTR_CAPACITY, .type = DATA_TYPE_INT, .name = "BATTERY_ATTR_CAPACITY", .unit = "%", .desc = "Battery capacity", },
+ { .id = BATTERY_ATTR_STATUS, .type = DATA_TYPE_STRING, .name = "BATTERY_ATTR_STATUS", .unit = "", .desc = "Battery status", },
+ { .id = BATTERY_ATTR_TEMPERATURE, .type = DATA_TYPE_INT, .name = "BATTERY_ATTR_TEMPERATURE", .unit = "", .desc = "Battery temperature", },
+ { .id = BATTERY_ATTR_VOLTAGE_NOW, .type = DATA_TYPE_INT, .name = "BATTERY_ATTR_VOLTAGE_NOW", .unit = "uV", .desc = "Battery voltage figure", },
+ { .id = BATTERY_ATTR_CURRENT_NOW, .type = DATA_TYPE_INT, .name = "BATTERY_ATTR_CURRENT_NOW", .unit = "uA", .desc = "Battery current figure", },
+ { .id = BATTERY_ATTR_PRESENT, .type = DATA_TYPE_INT, .name = "BATTERY_ATTR_PRESENT", .unit = "", .desc = "Battery connected status", },
+};
+
+static struct resource_attr_data display_attrs[] = {
+ { .id = DISPLAY_ATTR_NAME, .type = DATA_TYPE_STRING, .name = "DISPLAY_ATTR_NAME", .unit = "", .desc = "Display device name", },
+ { .id = DISPLAY_ATTR_FPS, .type = DATA_TYPE_DOUBLE, .name = "DISPLAY_ATTR_FPS", .unit = "fps", .desc = "Frame per second", },
+};
+
+static struct resource_attr_data system_attrs[] = {
+ { .id = SYSTEM_ATTR_CPU_UTIL, .type = DATA_TYPE_DOUBLE, .name = "SYSTEM_ATTR_CPU_UTIL", .unit = "%", .desc = "CPU average utilization", },
+ { .id = SYSTEM_ATTR_CPU_USER_UTIL, .type = DATA_TYPE_DOUBLE, .name = "SYSTEM_ATTR_CPU_USER_UTIL", .unit = "%", .desc = "CPU average utilization on user", },
+ { .id = SYSTEM_ATTR_CPU_SYS_UTIL, .type = DATA_TYPE_DOUBLE, .name = "SYSTEM_ATTR_CPU_SYS_UTIL", .unit = "%", .desc = "CPU average utilization on system", },
+ { .id = SYSTEM_ATTR_PER_CPU_UTIL, .type = DATA_TYPE_ARRAY, .name = "SYSTEM_ATTR_PER_CPU_UTIL", .unit = "%", .desc = "Per-CPU utilization", .array_type = DATA_TYPE_DOUBLE, },
+ { .id = SYSTEM_ATTR_PER_CPU_USER_UTIL, .type = DATA_TYPE_ARRAY, .name = "SYSTEM_ATTR_PER_CPU_USER_UTIL", .unit = "%", .desc = "Per-CPU utilization on user", .array_type = DATA_TYPE_DOUBLE, },
+ { .id = SYSTEM_ATTR_PER_CPU_SYS_UTIL, .type = DATA_TYPE_ARRAY, .name = "SYSTEM_ATTR_PER_CPU_SYS_UTIL", .unit = "%", .desc = "Per-CPU utilization on system", .array_type = DATA_TYPE_DOUBLE, },
+ { .id = SYSTEM_ATTR_POSSIBLE_CPU, .type = DATA_TYPE_INT, .name = "SYSTEM_ATTR_POSSIBLE_CPU", .unit = "ea", .desc = "Number of possible CPU", },
+ { .id = SYSTEM_ATTR_ONLINE_CPU, .type = DATA_TYPE_INT, .name = "SYSTEM_ATTR_ONLINE_CPU", .unit = "ea", .desc = "Number of online CPU", },
+};
+
+struct resource_attr_data process_attrs[] = {
+ { .id = PROCESS_ATTR_NAME, .type = DATA_TYPE_STRING, .name = "PROCESS_ATTR_NAME", .unit = "", .desc = "Process name", },
+ { .id = PROCESS_ATTR_CPU_UTIL, .type = DATA_TYPE_DOUBLE, .name = "PROCESS_ATTR_CPU_UTIL", .unit = "%", .desc = "Process CPU utilization", },
+ { .id = PROCESS_ATTR_MEM_VIRT, .type = DATA_TYPE_UINT64, .name = "PROCESS_ATTR_MEM_VIRT", .unit = "byte", .desc = "Process VIRT memory size", },
+ { .id = PROCESS_ATTR_MEM_RSS, .type = DATA_TYPE_UINT64, .name = "PROCESS_ATTR_MEM_RSS", .unit = "byte", .desc = "Process RSS(Resident Set Size) memory size", },
+ { .id = PROCESS_ATTR_MEM_RSS_PERCENT, .type = DATA_TYPE_DOUBLE, .name = "PROCESS_ATTR_MEM_RSS_PERCENT", .unit = "%", .desc = "Process RSS(Resident Set Size) memory percent", },
+ { .id = PROCESS_ATTR_DISK_READ_BPS, .type = DATA_TYPE_UINT, .name = "PROCESS_ATTR_DISK_READ_BPS", .unit = "b/s", .desc = "Process disk read per second", },
+ { .id = PROCESS_ATTR_DISK_WRITE_BPS, .type = DATA_TYPE_UINT, .name = "PROCESS_ATTR_DISK_WRITE_BPS", .unit = "b/s", .desc = "Process disk write per second", },
+ { .id = PROCESS_ATTR_PGID, .type = DATA_TYPE_INT, .name = "PROCESS_ATTR_PGID", .unit = "", .desc = "Process group ID", },
+ { .id = PROCESS_ATTR_PPID, .type = DATA_TYPE_INT, .name = "PROCESS_ATTR_PPID", .unit = "", .desc = "Process parent PID(Process ID)", },
+ { .id = PROCESS_ATTR_MEM_PSS, .type = DATA_TYPE_UINT64, .name = "PROCESS_ATTR_MEM_PSS", .unit = "byte", .desc = "Process PSS(Propotional Set Size) memory size", },
+ { .id = PROCESS_ATTR_MEM_SWAP, .type = DATA_TYPE_UINT64, .name = "PROCESS_ATTR_MEM_SWAP", .unit = "byte", .desc = "Process Swap memory size", },
+ { .id = PROCESS_ATTR_MEM_SWAP_PSS, .type = DATA_TYPE_UINT64, .name = "PROCESS_ATTR_MEM_SWAP_PSS", .unit = "byte", .desc = "Process Swap PSS(Propotional Set Size) memory size", },
+ { .id = PROCESS_ATTR_MEM_GPU, .type = DATA_TYPE_UINT64, .name = "PROCESS_ATTR_MEM_GPU", .unit = "byte", .desc = "Process GPU memory size", },
+};
+
+struct resource_attr_data process_group_attrs[] = {
+ { .id = PROCESS_GROUP_ATTR_PID_LIST, .type = DATA_TYPE_ARRAY, .name = "PROCESS_GROUP_ATTR_PID_LIST", .unit = "", .desc = "Process-group PID(Process ID) list", .array_type = DATA_TYPE_INT, },
+ { .id = PROCESS_GROUP_ATTR_NAME_LIST, .type = DATA_TYPE_ARRAY, .name = "PROCESS_GROUP_ATTR_NAME_LIST", .unit = "", .desc = "Process-group name list", .array_type = DATA_TYPE_STRING, },
+ { .id = PROCESS_GROUP_ATTR_CPU_UTIL, .type = DATA_TYPE_DOUBLE, .name = "PROCESS_GROUP_ATTR_CPU_UTIL", .unit = "%", .desc = "Process-group CPU utilization", },
+ { .id = PROCESS_GROUP_ATTR_DISK_READ_BPS, .type = DATA_TYPE_UINT, .name = "PROCESS_GROUP_ATTR_DISK_READ_BPS", .unit = "b/s", .desc = "Process-group disk read per second", },
+ { .id = PROCESS_GROUP_ATTR_DISK_WRITE_BPS, .type = DATA_TYPE_UINT, .name = "PROCESS_GROUP_ATTR_DISK_WRITE_BPS", .unit = "b/s", .desc = "Process-group disk write per second", },
+ { .id = PROCESS_GROUP_ATTR_MEM_VIRT, .type = DATA_TYPE_UINT64, .name = "PROCESS_GROUP_ATTR_MEM_VIRT", .unit = "byte", .desc = "Process-group VIRT memory size", },
+ { .id = PROCESS_GROUP_ATTR_MEM_RSS, .type = DATA_TYPE_UINT64, .name = "PROCESS_GROUP_ATTR_MEM_RSS", .unit = "byte", .desc = "Process-group RSS(Resident Set Size) memory size", },
+ { .id = PROCESS_GROUP_ATTR_MEM_PSS, .type = DATA_TYPE_UINT64, .name = "PROCESS_GROUP_ATTR_MEM_PSS", .unit = "byte", .desc = "Process-group PSS(Propotional Set Size) memory size", },
+ { .id = PROCESS_GROUP_ATTR_MEM_SWAP, .type = DATA_TYPE_UINT64, .name = "PROCESS_GROUP_ATTR_MEM_SWAP", .unit = "byte", .desc = "Process-group Swap memory size", },
+ { .id = PROCESS_GROUP_ATTR_MEM_SWAP_PSS, .type = DATA_TYPE_UINT64, .name = "PROCESS_GROUP_ATTR_MEM_SWAP_PSS", .unit = "byte", .desc = "Process-group Swap PSS(Propotional Set Size) memory size", },
+ { .id = PROCESS_GROUP_ATTR_MEM_GPU, .type = DATA_TYPE_UINT64, .name = "PROCESS_GROUP_ATTR_MEM_GPU", .unit = "byte", .desc = "Process-group GPU memory size", },
+};
+
+struct resource_attr_data disk_attrs[] = {
+ { .id = DISK_ATTR_NAME, .type = DATA_TYPE_STRING, .name = "DISK_ATTR_NAME", .unit = "", .desc = "Disk device name", },
+ { .id = DISK_ATTR_READ_PER_SEC, .type = DATA_TYPE_DOUBLE, .name = "DISK_ATTR_READ_PER_SEC", .unit = "kB/s", .desc = "Disk read per second", },
+ { .id = DISK_ATTR_WRITE_PER_SEC, .type = DATA_TYPE_DOUBLE, .name = "DISK_ATTR_WRITE_PER_SEC", .unit = "kB/s", .desc = "Disk write per second", },
+ { .id = DISK_ATTR_READ_TOTAL, .type = DATA_TYPE_UINT64, .name = "DISK_ATTR_READ_TOTAL", .unit = "kB", .desc = "Disk read total size", },
+ { .id = DISK_ATTR_WRITE_TOTAL, .type = DATA_TYPE_UINT64, .name = "DISK_ATTR_WRITE_TOTAL", .unit = "kB", .desc = "Disk write total size", },
+};
+
+struct resource_attr_data network_attrs[] = {
+ { .id = NETWORK_ATTR_NAME, .type =DATA_TYPE_STRING, .name = "NETWORK_ATTR_NAME", .unit = "", .desc = "Network device name", },
+};
+
+struct resource_data {
+ int mon_id;
+ int res_index;
+ int res_id;
+ u_int64_t mask;
+
+ /* Copy data from g_resource_type */
+ int type;
+ u_int64_t ctrl_id;
+ int ctrl_val;
+ int num_attrs;
+ struct resource_attr_data attrs[MAX_ATTR];
+};
+
+struct resource_monitor_data {
+ unsigned int pid;
+ unsigned int ppid;
+ unsigned int secs;
+ unsigned int max;
+
+ int mon_id;
+ int num_res;
+ struct resource_data res[MAX_RESOURCE];
+} g_data;
+
+struct __resource_type {
+ int type;
+ u_int64_t ctrl_id;
+ int ctrl_val;
+ int num_attrs;
+ struct resource_attr_data *attrs;
+
+ int res_count;
+} g_resource_type[] = {
+ {
+ .type = RESOURCE_TYPE_SYSTEM,
+ .ctrl_id = 0,
+ .attrs = system_attrs,
+ .num_attrs = ARRAY_SIZE(system_attrs),
+ .res_count = 1,
+ }, {
+ .type = RESOURCE_TYPE_MEMORY,
+ .ctrl_id = 0,
+ .attrs = memory_attrs,
+ .num_attrs = ARRAY_SIZE(memory_attrs),
+ }, {
+ .type = RESOURCE_TYPE_DISPLAY,
+ .ctrl_id = DISPLAY_CTRL_DEVICE_ID,
+ .attrs = display_attrs,
+ .num_attrs = ARRAY_SIZE(display_attrs),
+ }, {
+ .type = RESOURCE_TYPE_BATTERY,
+ .ctrl_id = 0,
+ .attrs = battery_attrs,
+ .num_attrs = ARRAY_SIZE(battery_attrs),
+ }, {
+ .type = RESOURCE_TYPE_CPU,
+ .ctrl_id = CPU_CTRL_CLUSTER_ID,
+ .attrs = cpu_attrs,
+ .num_attrs = ARRAY_SIZE(cpu_attrs),
+ }, {
+ .type = RESOURCE_TYPE_BUS,
+ .ctrl_id = BUS_CTRL_DEVICE_ID,
+ .attrs = bus_attrs,
+ .num_attrs = ARRAY_SIZE(bus_attrs),
+ }, {
+ .type = RESOURCE_TYPE_GPU,
+ .ctrl_id = GPU_CTRL_DEVICE_ID,
+ .attrs = gpu_attrs,
+ .num_attrs = ARRAY_SIZE(gpu_attrs),
+ }, {
+ .type = RESOURCE_TYPE_DISK,
+ .ctrl_id = DISK_CTRL_DEVICE_ID,
+ .attrs = disk_attrs,
+ .num_attrs = ARRAY_SIZE(disk_attrs),
+ }, {
+ .type = RESOURCE_TYPE_NETWORK,
+ .ctrl_id = NETWORK_CTRL_DEVICE_ID,
+ .attrs = network_attrs,
+ .num_attrs = ARRAY_SIZE(network_attrs),
+ }, {
+ .type = RESOURCE_TYPE_PROCESS,
+ .ctrl_id = PROCESS_CTRL_TGID,
+ .attrs = process_attrs,
+ .num_attrs = ARRAY_SIZE(process_attrs),
+ .res_count = 1,
+ }, {
+ .type = RESOURCE_TYPE_PROCESS_GROUP,
+ .ctrl_id = PROCESS_GROUP_CTRL_ROOT_PID,
+ .attrs = process_group_attrs,
+ .num_attrs = ARRAY_SIZE(process_group_attrs),
+ .res_count = 1,
+ },
+};
+
+static inline void create_resource_and_set_attrs(struct resource_data *res, int ctrl_val)
+{
+ int i;
+
+ if (!res)
+ return;
+
+ res->res_id = pass_resource_monitor_create_resource(res->mon_id, res->type);
+
+ if (res->ctrl_id)
+ pass_resource_monitor_set_resource_ctrl(
+ res->mon_id, res->res_id, res->ctrl_id, ctrl_val);
+
+ for (i = 0; i < res->num_attrs; i++) {
+ if (pass_resource_monitor_is_resource_attr_supported(
+ res->mon_id, res->res_id, res->attrs[i].id))
+ res->mask |= res->attrs[i].id;
+ }
+
+ pass_resource_monitor_set_resource_attr(res->mon_id, res->res_id, res->mask);
+}
+
+static inline void unset_attrs_and_delete_resource(struct resource_data *res)
+{
+ if (!res)
+ return;
+
+ pass_resource_monitor_unset_resource_attr(res->mon_id, res->res_id, res->mask);
+ pass_resource_monitor_delete_resource(res->mon_id, res->res_id);
+}
+
+static inline int get_resource_attr_array_value(struct resource_data *res, int idx)
+{
+ int i;
+ int ret = 0;
+ int length;
+ double *array = NULL;
+ char buf[BUFF_MAX];
+ char temp[10];
+
+ if (!res)
+ return -1;
+
+ switch (res->attrs[idx].array_type) {
+ case DATA_TYPE_DOUBLE:
+ ret = pass_resource_monitor_get_array_double(
+ res->mon_id, res->res_id,
+ res->attrs[idx].id, &array, &length);
+
+ if (ret < 0) break;
+
+ memset(buf, 0, BUFF_MAX);
+ for (i = 0; i < length; i++) {
+ snprintf(temp, 10, "%2.2f ", array[i]);
+ strcat(buf, temp);
+ }
+
+ printf("%40s | %-5s | %s", buf, res->attrs[idx].unit, res->attrs[idx].desc);
+
+ free(array);
+ break;
+ case DATA_TYPE_INT:
+ case DATA_TYPE_INT64:
+ case DATA_TYPE_UINT:
+ case DATA_TYPE_UINT64:
+ case DATA_TYPE_STRING:
+ printf("%40s | %-5s | %s", "Not Implemented",
+ res->attrs[idx].unit, res->attrs[idx].desc);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static inline void get_resource_attr_value(struct resource_data *res, int i)
+{
+ bool supported;
+ int ret = 0;
+
+ supported = pass_resource_monitor_is_resource_attr_supported(
+ res->mon_id, res->res_id,
+ res->attrs[i].id);
+ if (!supported) {
+ printf("%40s | %-5s | %s", "Not Supported",
+ res->attrs[i].unit, res->attrs[i].desc);
+ return;
+ }
+
+ switch (res->attrs[i].type) {
+ case DATA_TYPE_INT:
+ ret = pass_resource_monitor_get_value_int(
+ res->mon_id, res->res_id,
+ res->attrs[i].id,
+ &(res->attrs[i].value_int32));
+ if (ret < 0) break;
+
+ printf("%40d | %-5s | %s",
+ res->attrs[i].value_int32,
+ res->attrs[i].unit, res->attrs[i].desc);
+ break;
+ case DATA_TYPE_INT64:
+ ret = pass_resource_monitor_get_value_int64(
+ res->mon_id, res->res_id,
+ res->attrs[i].id,
+ &(res->attrs[i].value_int64));
+ if (ret < 0) break;
+
+ printf("%40"PRId64" | %-5s | %s",
+ res->attrs[i].value_int64,
+ res->attrs[i].unit, res->attrs[i].desc);
+ break;
+ case DATA_TYPE_UINT:
+ ret = pass_resource_monitor_get_value_uint(
+ res->mon_id, res->res_id,
+ res->attrs[i].id,
+ &(res->attrs[i].value_uint32));
+ if (ret < 0) break;
+
+ printf("%40u | %-5s | %s",
+ res->attrs[i].value_uint32,
+ res->attrs[i].unit, res->attrs[i].desc);
+ break;
+ case DATA_TYPE_UINT64:
+ ret = pass_resource_monitor_get_value_uint64(
+ res->mon_id, res->res_id,
+ res->attrs[i].id,
+ &(res->attrs[i].value_uint64));
+ if (ret < 0) break;
+
+ printf("%40"PRId64" | %-5s | %s",
+ res->attrs[i].value_uint64,
+ res->attrs[i].unit, res->attrs[i].desc);
+ break;
+ case DATA_TYPE_DOUBLE:
+ ret = pass_resource_monitor_get_value_double(
+ res->mon_id, res->res_id,
+ res->attrs[i].id,
+ &(res->attrs[i].value_double));
+ if (ret < 0) break;
+
+ printf("%40.2f | %-5s | %s",
+ res->attrs[i].value_double,
+ res->attrs[i].unit, res->attrs[i].desc);
+ break;
+ case DATA_TYPE_STRING:
+ ret = pass_resource_monitor_get_value_string(
+ res->mon_id, res->res_id,
+ res->attrs[i].id,
+ res->attrs[i].value_string);
+ if (ret < 0) break;
+
+ printf("%40s | %-5s | %s",
+ res->attrs[i].value_string,
+ res->attrs[i].unit, res->attrs[i].desc);
+ break;
+ case DATA_TYPE_ARRAY:
+ ret = get_resource_attr_array_value(res, i);
+ break;
+ case DATA_TYPE_PTR:
+ case DATA_TYPE_BOOLEAN:
+ printf("(%40s) | %-5s | %s", "Not Implemented",
+ res->attrs[i].unit, res->attrs[i].desc);
+ break;
+ default:
+ printf("(%40s)", "Unknown Data Type");
+ break;
+ }
+
+ if (ret < 0)
+ printf("%40s | %-5s | %s", "Failed to Get Value",
+ res->attrs[i].unit, res->attrs[i].desc);
+}
+
+static void resource_monitor_exit(int signal)
+{
+ int i;
+
+ for (i = 0; i < g_data.num_res; i++)
+ unset_attrs_and_delete_resource(&g_data.res[i]);
+
+ pass_resource_monitor_exit(g_data.mon_id);
+
+ printf("Exit resource-monitor\n");
+ exit(0);
+}
+
+static int resource_monitor_init(void)
+{
+ int id, i, j, count;
+
+ /* 1. Initialize resource-monitor */
+ id = pass_resource_monitor_init();
+ g_data.mon_id = id;
+
+ /* 2. Get resource count */
+ for (i = 0; i < ARRAY_SIZE(g_resource_type); i++) {
+ if (g_resource_type[i].res_count)
+ count = g_resource_type[i].res_count;
+ else
+ count = pass_resource_monitor_get_resource_count(id, g_resource_type[i].type);
+
+ if (g_resource_type[i].ctrl_val < 0)
+ continue;
+
+ for (j = 0; j < count; j++) {
+ struct resource_data *res = &g_data.res[g_data.num_res++];
+
+ res->mon_id = g_data.mon_id;
+ res->res_index = j;
+ res->type = g_resource_type[i].type;
+ res->ctrl_id = g_resource_type[i].ctrl_id;
+ res->num_attrs = g_resource_type[i].num_attrs;
+ memcpy(res->attrs, g_resource_type[i].attrs, sizeof(struct resource_attr_data) * res->num_attrs);
+ res->ctrl_val = g_resource_type[i].ctrl_val;
+ }
+ }
+
+ for (i = 0; i < g_data.num_res; i++) {
+ struct resource_data *res = &g_data.res[i];
+
+ if (res->ctrl_val > 0)
+ create_resource_and_set_attrs(res, res->ctrl_val);
+ else
+ create_resource_and_set_attrs(res, res->res_index);
+ }
+
+ return 0;
+}
+
+static void resource_monitor(void)
+{
+ int id = g_data.mon_id;
+ int count = 0;
+ int i, j;
+
+ while (1) {
+ if (g_data.max != -1 && g_data.max <= count++)
+ break;
+
+ /* 4. Update resource attribute value */
+ pass_resource_monitor_update(id);
+
+ printf("-------------------------------------------------------------------------------------------------------------------------------\n");
+ printf("%2s:%2s| %35s | %40s | %-5s | %s\n",
+ "", "", "Resource Attribute Name", "Resource Attribute Value", "Unit", "Resource Attribute Description");
+ printf("-------------------------------------------------------------------------------------------------------------------------------\n");
+
+ for (i = 0; i < g_data.num_res; i++) {
+ struct resource_data *res = &g_data.res[i];
+
+ for (j = 0; j < res->num_attrs; j++) {
+ printf("%2d:%2d| %35s | ", i, j, res->attrs[j].name);
+ get_resource_attr_value(res, j);
+ printf("\n");
+ }
+ printf("\n");
+ }
+ sleep(g_data.secs);
+ }
+ resource_monitor_exit(0);
+}
+
+static void usage()
+{
+ printf("Usage:\n");
+ printf(" resource-moniotr -h | -d secs -n max -p pid -g ppid | --pid pid --ppid ppid\n");
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+ int opt = 1;
+
+ /* Initialize default value and parse command line */
+ g_data.secs = 1; /* default sampling rate is 1 second. */
+ g_data.max = -1; /* default count is infinite. */
+ g_data.pid = -1;
+ g_data.ppid = -1;
+
+ while (opt < argc) {
+ if (!strncmp(argv[opt], "--pid", 5)) {
+ g_data.pid = atoi(argv[opt + 1]);
+ } else if (!strncmp(argv[opt], "--ppid", 6)) {
+ g_data.ppid = atoi(argv[opt + 1]);
+ } else if (!strncmp(argv[opt], "-", 1)) {
+ for (i = 1; *(argv[opt] + i); i++) {
+ switch (*(argv[opt] + i)) {
+ case 'd':
+ g_data.secs = atoi(argv[opt + 1]);
+ break;
+ case 'n':
+ g_data.max = atoi(argv[opt + 1]);
+ break;
+ case 'p':
+ g_data.pid = atoi(argv[opt + 1]);
+ break;
+ case 'g':
+ g_data.ppid = atoi(argv[opt + 1]);
+ break;
+ case 'h':
+ usage();
+ exit(0);
+ default:
+ usage();
+ }
+ }
+ }
+ opt++;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(g_resource_type); i++) {
+ if (g_resource_type[i].type == RESOURCE_TYPE_PROCESS)
+ g_resource_type[i].ctrl_val = g_data.pid;
+
+ if (g_resource_type[i].type == RESOURCE_TYPE_PROCESS_GROUP)
+ g_resource_type[i].ctrl_val = g_data.ppid;
+ }
+
+ /* Register signal handler for freeing resources */
+ signal(SIGINT, resource_monitor_exit);
+
+ /* Initialize available resources and resource attributes */
+ resource_monitor_init();
+
+ /* Start resource monitor */
+ resource_monitor();
+
+ return 0;
+}