tools: Add resource-monitor monitoring tool 76/278876/10 accepted/tizen/unified/20220805.131714 submit/tizen/20220805.024015
authorChanwoo Choi <cw00.choi@samsung.com>
Fri, 25 Feb 2022 10:29:06 +0000 (19:29 +0900)
committerChanwoo Choi <cw00.choi@samsung.com>
Thu, 4 Aug 2022 09:13:01 +0000 (18:13 +0900)
The resource-monitor monitors the available all resource attribute
on device and print them.

- Monitoring sequence as following:
1. Get resource count of each resource type
2. Set resource attributes of each resource
3. Update resource attributes to get value
4. Get value from resources
5. Print value of resources

- Usage
resource-monitor -h | -d secs -n max -p pid -g ppid | --pid pid --ppid ppid

- For example on rpi4 board,
$ resource-monitor --pid 1 --ppid 1
-------------------------------------------------------------------------------------------------------------------------------
  :  |             Resource Attribute Name |                 Resource Attribute Value | Unit  | Resource Attribute Description
-------------------------------------------------------------------------------------------------------------------------------
 0: 0|                SYSTEM_ATTR_CPU_UTIL |                                     4.96 | %     | CPU average utilization
 0: 1|           SYSTEM_ATTR_CPU_USER_UTIL |                                     0.65 | %     | CPU average utilization on user
 0: 2|            SYSTEM_ATTR_CPU_SYS_UTIL |                                     4.31 | %     | CPU average utilization on system
 0: 3|            SYSTEM_ATTR_PER_CPU_UTIL |                    1.72 1.71 13.91 1.72  | %     | Per-CPU utilization
 0: 4|       SYSTEM_ATTR_PER_CPU_USER_UTIL |                     0.00 0.00 1.74 0.00  | %     | Per-CPU utilization on user
 0: 5|        SYSTEM_ATTR_PER_CPU_SYS_UTIL |                    1.72 1.71 12.17 1.72  | %     | Per-CPU utilization on system
 0: 6|            SYSTEM_ATTR_POSSIBLE_CPU |                                        4 | ea    | Number of possible CPU
 0: 7|              SYSTEM_ATTR_ONLINE_CPU |                                        4 | ea    | Number of online CPU

 1: 0|                   MEMORY_ATTR_TOTAL |                               3974103040 | byte  | Memory total size
 1: 1|               MEMORY_ATTR_AVAILABLE |                               3560730624 | byte  | Memory available size
 1: 2|                    MEMORY_ATTR_FREE |                               3405287424 | byte  | Memory free size
 1: 3|                  MEMORY_ATTR_BUFFER |                                 20500480 | byte  | Memorry buffer size
 1: 4|                  MEMORY_ATTR_CACHED |                                220078080 | byte  | Memory cached size
 1: 5|               MEMORY_ATTR_CMA_TOTAL |                                419430400 | byte  | CMA memory total size
 1: 6|                MEMORY_ATTR_CMA_FREE |                                381743104 | byte  | CMA memory free size
 1: 7|              MEMORY_ATTR_SWAP_TOTAL |                               1589637120 | byte  | Swap memory total size
 1: 8|               MEMORY_ATTR_SWAP_FREE |                               1495789568 | byte  | Swap memory free size

 2: 0|                   DISPLAY_ATTR_NAME |                                    hdmi0 |       | Display device name
 2: 1|                    DISPLAY_ATTR_FPS |                                     0.00 | fps   | Frame per second (fps)

 3: 0|                       CPU_ATTR_NAME |                                     cpu0 |       | CPU cluster name
 3: 1|                   CPU_ATTR_CUR_FREQ |                                   600000 | kHz   | Current CPU frequency
 3: 2|                   CPU_ATTR_MIN_FREQ |                                   600000 | kHz   | Current CPU minimum frequency
 3: 3|                   CPU_ATTR_MAX_FREQ |                                  1500000 | kHz   | Current CPU maximum frequency
 3: 4|         CPU_ATTR_AVAILABLE_MIN_FREQ |                                   600000 | kHz   | Available CPU minimum frequency
 3: 5|         CPU_ATTR_AVAILABLE_MAX_FREQ |                                  1500000 | kHz   | Available CPU maximum frequency
 3: 6|               CPU_ATTR_CUR_GOVERNOR |                                schedutil |       | Current CPU frequency governor name

 4: 0|                      DISK_ATTR_NAME |                                    zram0 |       | Disk device name
 4: 1|              DISK_ATTR_READ_PER_SEC |                                     0.00 | kB/s  | Disk read per second
 4: 2|             DISK_ATTR_WRITE_PER_SEC |                                     0.00 | kB/s  | Disk write per second
 4: 3|                DISK_ATTR_READ_TOTAL |                                    46496 | kB    | Disk read total size
 4: 4|               DISK_ATTR_WRITE_TOTAL |                                   230640 | kB    | Disk write total size

 5: 0|                      DISK_ATTR_NAME |                                  mmcblk0 |       | Disk device name
 5: 1|              DISK_ATTR_READ_PER_SEC |                                     0.00 | kB/s  | Disk read per second
 5: 2|             DISK_ATTR_WRITE_PER_SEC |                                     0.00 | kB/s  | Disk write per second
 5: 3|                DISK_ATTR_READ_TOTAL |                                  1041514 | kB    | Disk read total size
 5: 4|               DISK_ATTR_WRITE_TOTAL |                                   388458 | kB    | Disk write total size

 6: 0|                   NETWORK_ATTR_NAME |                                     eth0 |       | Network device name

 7: 0|                   PROCESS_ATTR_NAME |                                  systemd |       | Process name
 7: 1|               PROCESS_ATTR_CPU_UTIL |                                     0.00 | %     | Process CPU utilization
 7: 2|               PROCESS_ATTR_MEM_VIRT |                                 15183377 | byte  | Process VIRT memory size
 7: 3|                PROCESS_ATTR_MEM_RSS |                                  6216822 | byte  | Process RSS(Resident Set Size) memory size
 7: 4|        PROCESS_ATTR_MEM_RSS_PERCENT |                                     0.00 | %     | Process RSS(Resident Set Size) memory percent
 7: 5|          PROCESS_ATTR_DISK_READ_BPS |                                        0 | b/s   | Process disk read per second
 7: 6|         PROCESS_ATTR_DISK_WRITE_BPS |                                        0 | b/s   | Process disk write per second
 7: 7|                   PROCESS_ATTR_PGID |                                        1 |       | Process group ID
 7: 8|                   PROCESS_ATTR_PPID |                                        0 |       | Process parent PID(Process ID)
 7: 9|                PROCESS_ATTR_MEM_PSS |                                  3757056 | byte  | Process PSS(Propotional Set Size) memory size
 7:10|               PROCESS_ATTR_MEM_SWAP |                                   311296 | byte  | Process Swap memory size
 7:11|           PROCESS_ATTR_MEM_SWAP_PSS |                                   186368 | byte  | Process Swap PSS(Propotional Set Size) memory size
 7:12|                PROCESS_ATTR_MEM_GPU |                            Not Supported | byte  | Process GPU memory size

 8: 0|         PROCESS_GROUP_ATTR_PID_LIST |                          Not Implemented |       | Process-group PID(Process ID) list
 8: 1|        PROCESS_GROUP_ATTR_NAME_LIST |                          Not Implemented |       | Process-group name list
 8: 2|         PROCESS_GROUP_ATTR_CPU_UTIL |                                     0.23 | %     | Process-group CPU utilization
 8: 3|    PROCESS_GROUP_ATTR_DISK_READ_BPS |                                        0 | b/s   | Process-group disk read per second
 8: 4|   PROCESS_GROUP_ATTR_DISK_WRITE_BPS |                                    31743 | b/s   | Process-group disk write per second
 8: 5|         PROCESS_GROUP_ATTR_MEM_VIRT |                             140541707212 | byte  | Process-group VIRT memory size
 8: 6|          PROCESS_GROUP_ATTR_MEM_RSS |                               1378679318 | byte  | Process-group RSS(Resident Set Size) memory size
 8: 7|          PROCESS_GROUP_ATTR_MEM_PSS |                                188443648 | byte  | Process-group PSS(Propotional Set Size) memory size
 8: 8|         PROCESS_GROUP_ATTR_MEM_SWAP |                                 93335552 | byte  | Process-group Swap memory size
 8: 9|     PROCESS_GROUP_ATTR_MEM_SWAP_PSS |                                 92164096 | byte  | Process-group Swap PSS(Propotional Set Size) memory size
 8:10|          PROCESS_GROUP_ATTR_MEM_GPU |                            Not Supported | byte  | Process-group GPU memory size

Change-Id: I4e227fe451108b51f0a2371ad7104a54e36bb6a8
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
CMakeLists.txt
packaging/pass.spec
tools/resource-monitor/CMakeLists.txt [new file with mode: 0644]
tools/resource-monitor/resource-monitor.c [new file with mode: 0644]

index aada2f3..81bcff5 100644 (file)
@@ -137,3 +137,5 @@ ADD_SUBDIRECTORY(tests/haltest)
 ADD_SUBDIRECTORY(tests/unittest)
 
 ADD_SUBDIRECTORY(lib)
+
+ADD_SUBDIRECTORY(tools/resource-monitor)
index 0168238..e50b60f 100644 (file)
@@ -115,6 +115,7 @@ systemctl daemon-reload
 %config %{_sysconfdir}/pass/pass-pmqos.json
 %config %{_sysconfdir}/pass/pass-thermal.json
 %{_bindir}/%{daemon_name}
+%{_bindir}/resource-monitor
 %{_unitdir}/delayed.target.wants/%{daemon_name}.service
 %{_unitdir}/%{daemon_name}.service
 %{_datadir}/dbus-1/system-services/org.tizen.system.pass.service
@@ -142,3 +143,4 @@ systemctl daemon-reload
 %{_includedir}/%{name}/*.h
 %{_libdir}/pkgconfig/%{libpass_resource_monitor_name}.pc
 %{_libdir}/*.so*
+
diff --git a/tools/resource-monitor/CMakeLists.txt b/tools/resource-monitor/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3e28063
--- /dev/null
@@ -0,0 +1,36 @@
+PROJECT(pass C CXX)
+
+SET(SRCS
+       ${CMAKE_SOURCE_DIR}/src/util/common.c
+       ${CMAKE_SOURCE_DIR}/lib/resource-monitor/resource-monitor.c
+)
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR})
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src)
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/pass)
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include)
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/lib/resource-monitor)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(gtest_pkgs REQUIRED
+       glib-2.0
+       gio-2.0
+       dlog
+       json-c
+)
+
+FOREACH(flag ${gtest_pkgs_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wall -fPIE")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -pie")
+
+SET(src ${CMAKE_SOURCE_DIR}/tools/resource-monitor/resource-monitor.c)
+GET_FILENAME_COMPONENT(src_name ${src} NAME_WE)
+MESSAGE("${src_name}")
+ADD_EXECUTABLE(${src_name} ${SRCS} ${src})
+TARGET_LINK_LIBRARIES(${src_name} ${gtest_LDFLAGS} ${gtest_pkgs_LDFLAGS} -ldl -L${LIBDIR}/hal)
+INSTALL(TARGETS ${src_name} DESTINATION /usr/bin/)
diff --git a/tools/resource-monitor/resource-monitor.c b/tools/resource-monitor/resource-monitor.c
new file mode 100644 (file)
index 0000000..cb44a5a
--- /dev/null
@@ -0,0 +1,585 @@
+/*
+ * 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;
+}