Support gpu, gem, swap memory usage information
[platform/core/api/runtime-info.git] / src / runtime_info_usage.c
index 19f6320..dacf4a5 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <stdarg.h>
 
 #include <dlog.h>
 
 #include <runtime_info.h>
 #include <runtime_info_private.h>
+#include <runtime_info-internal.h>
 
 #include <gio/gio.h>
 #include <glib.h>
 
+#include <hal/device/hal-memory.h>
+
 #define RESOURCED_BUS_NAME "org.tizen.resourced"
 #define RESOURCED_USAGE_OBJECT_NAME "/Org/Tizen/ResourceD/Process"
 #define RESOURCED_USAGE_INTERFACE_NAME "org.tizen.resourced.process"
@@ -38,6 +42,7 @@ typedef enum {
        USAGE_TYPE_PROCESS_CPU,
        USAGE_TYPE_APP_MEMORY,
        USAGE_TYPE_APP_CPU,
+       USAGE_TYPE_PROCESS_SWAP,
 } runtime_info_usage_type_e;
 
 typedef struct {
@@ -51,6 +56,7 @@ static const runtime_info_dbus_info_s dbus_info[] = {
        { "ProcCpuUsage", "process cpu" },
        { "GetMemoryList", "all apps memory" },
        { "GetCpuList", "all apps cpu" },
+       { "ProcSwapUsage", "process swap" },
 };
 
 #define ULONGtoINT(ulong)      (int)(MIN((ulong), INT_MAX))
@@ -93,6 +99,7 @@ static GVariant *runtime_info_dbus_request_usage_info(runtime_info_usage_type_e
        switch (type) {
        case USAGE_TYPE_PROCESS_MEMORY:
        case USAGE_TYPE_PROCESS_CPU:
+       case USAGE_TYPE_PROCESS_SWAP:
                if (!pid || size <= 0) {
                        //LCOV_EXCL_START : system error
                        _E("INVALID_PARAMETER(0x%08x): pid list cannot be null",
@@ -126,6 +133,7 @@ static GVariant *runtime_info_dbus_request_usage_info(runtime_info_usage_type_e
        switch (type) {
        case USAGE_TYPE_PROCESS_MEMORY:
        case USAGE_TYPE_PROCESS_CPU:
+       case USAGE_TYPE_PROCESS_SWAP:
                _D("Process %d: received query to get %s usage of %d processes",
                                getpid(), dbus_info[type].caption, size);
                args_in = runtime_info_append_args(pid, size);
@@ -382,6 +390,221 @@ API int runtime_info_get_process_memory_info(int *pid, int size, process_memory_
        return RUNTIME_INFO_ERROR_NONE;
 }
 
+static runtime_info_error_e hal_error_to_runtime_info_error(int err)
+{
+       switch (err) {
+       case 0:
+               return RUNTIME_INFO_ERROR_NONE;
+       case -EINVAL:
+               return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
+       case -ENOMEM:
+               return RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
+       case -EIO:
+       case -ENOENT:
+               return RUNTIME_INFO_ERROR_IO_ERROR;
+       case -EPERM:
+       case -EACCES:
+               return RUNTIME_INFO_ERROR_PERMISSION_DENIED;
+       case -ENOTSUP:
+               return RUNTIME_INFO_ERROR_NOT_SUPPORTED;
+       default:
+               // TODO: what is the runtime-info error for this default case?
+               return RUNTIME_INFO_ERROR_NO_DATA;
+       }
+}
+
+static int get_process_memory_info_direct(int *pid, int size, process_memory_info_key_e key, int **info)
+{
+       int ret, i;
+       struct gpu_info gpu_info;
+       struct gem_info gem_info;
+       int *result;
+       int err = RUNTIME_INFO_ERROR_NONE;
+
+       result = (int *)calloc(size, sizeof(int));
+       if (!result) {
+               err = RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
+               goto out;
+       }
+
+       switch (key) {
+       case RUNTIME_INFO_PROC_MEMORY_GPU:
+               for (i = 0; i < size; ++i) {
+                       ret = hal_device_memory_get_gpu_info(pid[i], &gpu_info);
+                       if (ret != 0) {
+                               err = hal_error_to_runtime_info_error(ret);
+                               goto out;
+                       }
+                       result[i] = gpu_info.used_pages;
+               }
+               *info = result;
+               break;
+       case RUNTIME_INFO_PROC_MEMORY_GEM_RSS:
+               for (i = 0; i < size; ++i) {
+                       ret = hal_device_memory_get_gem_info(pid[i], &gem_info);
+                       if (ret != 0) {
+                               err = hal_error_to_runtime_info_error(ret);
+                               goto out;
+                       }
+                       result[i] = gem_info.rss;
+               }
+               *info = result;
+               break;
+       default:
+               err = RUNTIME_INFO_ERROR_INVALID_PARAMETER;
+               break;
+       }
+
+out:
+       if (err != RUNTIME_INFO_ERROR_NONE)
+               free(result);
+
+       return err;
+}
+
+static int get_process_memory_swap_info(int *pid, int size, int **info)
+{
+    int i, temp;
+    int error;
+    GVariant *usages;
+    GVariantIter iter;
+
+    if (!pid || size <= 0) {
+        _E("INVALID_PARAMETER(0x%08x) : invalid input param",
+                RUNTIME_INFO_ERROR_INVALID_PARAMETER);
+        return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
+    }
+
+    if (!info) {
+        _E("INVALID_PARAMETER(0x%08x) : invalid output param",
+                RUNTIME_INFO_ERROR_INVALID_PARAMETER);
+        return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
+    }
+
+    *info = NULL;
+
+    /* Get the needed information from resourced daemon using dbus */
+    usages = runtime_info_dbus_request_usage_info(USAGE_TYPE_PROCESS_SWAP, pid, size, &error);
+    if (!usages) {
+        //LCOV_EXCL_START : system error
+        _E("DBUS_METHOD_CALL: call to resourced not successful");
+        return error;
+        //LCOV_EXCL_STOP
+    }
+
+    /* Check whether the received usage has expected format or not */
+    if (g_strcmp0(g_variant_get_type_string(usages), "a(i)") ||
+            g_variant_n_children(usages) != size) {
+        //LCOV_EXCL_START : system error
+        _E("DBUS_METHOD_CALL: received dbus message is not in expected format");
+        g_variant_unref(usages);
+        return RUNTIME_INFO_ERROR_REMOTE_IO;
+        //LCOV_EXCL_STOP
+    }
+
+    /* Populate the entries of info array using the data received from resourced */
+       *info = (int *)malloc(size * sizeof(int));
+    if (!(*info)) {
+        _E("OUT_OF_MEMORY(0x%08x)", RUNTIME_INFO_ERROR_OUT_OF_MEMORY);
+        g_variant_unref(usages);
+        return RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
+    }
+
+    g_variant_iter_init(&iter, usages);
+    for (i = 0; i < size; i++) {
+        g_variant_iter_next(&iter, "(i)", &temp);
+               (*info)[i] = temp;
+       }
+
+    g_variant_unref(usages);
+
+    return RUNTIME_INFO_ERROR_NONE;
+}
+
+static int get_process_memory_info(int *pid, int size, process_memory_info_key_e key, int **info)
+{
+       int i;
+       int ret;
+       int *result;
+       process_memory_info_s *base = NULL;
+
+       ret = RUNTIME_INFO_ERROR_NONE;
+
+       result = (int *)calloc(size, sizeof(int));
+       if (!result) {
+               ret = RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
+               goto out;
+       }
+
+       ret = runtime_info_get_process_memory_info(pid, size, &base);
+       if (ret != RUNTIME_INFO_ERROR_NONE)
+               goto out;
+
+       switch (key) {
+       case RUNTIME_INFO_PROC_MEMORY_VSZ:
+               for (i = 0; i < size; ++i)
+                       result[i] = base[i].vsz;
+               break;
+       case RUNTIME_INFO_PROC_MEMORY_RSS:
+               for (i = 0; i < size; ++i)
+                       result[i] = base[i].rss;
+               break;
+       case RUNTIME_INFO_PROC_MEMORY_PSS:
+               for (i = 0; i < size; ++i)
+                       result[i] = base[i].pss;
+               break;
+       case RUNTIME_INFO_PROC_MEMORY_SHARED_CLEAN:
+               for (i = 0; i < size; ++i)
+                       result[i] = base[i].shared_clean;
+               break;
+       case RUNTIME_INFO_PROC_MEMORY_SHARED_DIRTY:
+               for (i = 0; i < size; ++i)
+                       result[i] = base[i].shared_dirty;
+               break;
+       case RUNTIME_INFO_PROC_MEMORY_PRIVATE_CLEAN:
+               for (i = 0; i < size; ++i)
+                       result[i] = base[i].private_clean;
+               break;
+       case RUNTIME_INFO_PROC_MEMORY_PRIVATE_DIRTY:
+               for (i = 0; i < size; ++i)
+                       result[i] = base[i].private_dirty;
+               break;
+       default:
+               ret = RUNTIME_INFO_ERROR_INVALID_PARAMETER;
+               goto out;
+       }
+
+       *info = result;
+
+out:
+       if (ret != RUNTIME_INFO_ERROR_NONE)
+               free(result);
+       free(base);
+
+       return ret;
+}
+
+API int runtime_info_get_process_memory_value_int(int *pid, int size, process_memory_info_key_e key, int **info)
+{
+       switch (key) {
+       case RUNTIME_INFO_PROC_MEMORY_GPU:
+       case RUNTIME_INFO_PROC_MEMORY_GEM_RSS:
+               return get_process_memory_info_direct(pid, size, key, info);
+       case RUNTIME_INFO_PROC_MEMORY_SWAP:
+               return get_process_memory_swap_info(pid, size, info);
+       case RUNTIME_INFO_PROC_MEMORY_VSZ:
+       case RUNTIME_INFO_PROC_MEMORY_RSS:
+       case RUNTIME_INFO_PROC_MEMORY_PSS:
+       case RUNTIME_INFO_PROC_MEMORY_SHARED_CLEAN:
+       case RUNTIME_INFO_PROC_MEMORY_SHARED_DIRTY:
+       case RUNTIME_INFO_PROC_MEMORY_PRIVATE_CLEAN:
+       case RUNTIME_INFO_PROC_MEMORY_PRIVATE_DIRTY:
+               return get_process_memory_info(pid, size, key, info);
+       default:
+               return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
+       }
+}
+
 API int runtime_info_get_cpu_usage(runtime_cpu_usage_s *usage)
 {
        FILE *cpuinfo_fp;