report-generator: implement generator functions 85/181285/9
authorLukasz Stanislawski <l.stanislaws@samsung.com>
Mon, 11 Jun 2018 08:53:28 +0000 (10:53 +0200)
committerLukasz Stanislawski <l.stanislaws@samsung.com>
Thu, 21 Jun 2018 12:42:18 +0000 (14:42 +0200)
Change-Id: I25f955a06d0ffbf0ecbb7bdeb77dc19cc15cad24

src/report-generator.c
src/report.h
src/task.h

index 0bfb232..bf1881d 100644 (file)
  * limitations under the License.
  */
 
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <stdbool.h>
+#include <unistd.h>
+
 #include "report-generator.h"
+#include "procfs.h"
+#include "log.h"
+#include "err-check.h"
+
+struct report_generator_system
+{
+       /** previous read from procfs */
+       struct procfs_system_cpu_usage_info previous;
+};
+
+struct process_ticks_snapshot
+{
+       unsigned long long system_ticks;
+       unsigned long long process_ticks;
+};
+
+struct report_generator_process
+{
+       /** process pid */
+       int pid;
+       /** previous process stats */
+       struct process_ticks_snapshot previous;
+};
+
+static int _report_generator_read_process_ticks(int pid, struct process_ticks_snapshot *ticks);
+
+static struct timespec clock_get_monotonic()
+{
+       struct timespec ret = {0,};
+
+       if (clock_gettime(CLOCK_MONOTONIC, &ret) != 0) {
+               ERR("Platform do not support monotonic clock type");
+               //TODO consider adding first init function to evaluate
+               //if clock_gettime can be used, so calling module could
+               //handle cases without monotonic clock gracefully.
+               abort();
+       }
+
+       return ret;
+}
 
 report_generator_system_t *report_generator_new_system_report_generator()
 {
-       return NULL;
+       report_generator_system_t *ret = calloc(1, sizeof(struct report_generator_system));
+       if (!ret)
+               return NULL;
+
+       if (procfs_read_system_cpu_usage(&ret->previous) != 0) {
+               ERR("procfs_read_system_cpu_usage failed");
+               free(ret);
+               return NULL;
+       }
+
+       return ret;
 }
 
 void report_generator_free_system_generator(report_generator_system_t *generator)
 {
+       if (!generator)
+               return;
+
+       free(generator);
 }
 
 report_generator_process_t *report_generator_new_process_report_generator(int pid)
 {
-       return NULL;
+       ON_TRUE_RETURN_VAL(pid <= 0, NULL);
+
+       report_generator_process_t *ret = calloc(1, sizeof(struct report_generator_process));
+       if (!ret)
+               return NULL;
+
+       if (_report_generator_read_process_ticks(pid, &ret->previous) != 0) {
+               ERR("_report_generator_read_process_ticks failed.");
+               free(ret);
+               return NULL;
+       };
+
+       ret->pid = pid;
+
+       return ret;
 }
 
 void report_generator_free_process_generator(report_generator_process_t *generator)
 {
+       if (!generator)
+               return;
+
+       free(generator);
+}
+
+static void _calculate_system_cpu_usage(
+               struct procfs_system_cpu_usage_info *previous,
+               struct procfs_system_cpu_usage_info *current,
+               float *usage)
+{
+       struct procfs_system_cpu_usage_info diff_ticks = { 0,};
+
+       diff_ticks.user = current->user > previous->user ? current->user - previous->user : 0;
+       diff_ticks.system = current->system > previous->system ? current->system - previous->system : 0;
+       diff_ticks.nice = current->nice > previous->nice ? current->nice - previous->nice : 0;
+       diff_ticks.idle = current->idle > previous->idle ? current->idle - previous->idle : 0;
+       diff_ticks.iowait = current->iowait > previous->iowait ? current->iowait - previous->iowait : 0;
+       diff_ticks.irq = current->irq > previous->irq ? current->irq - previous->irq : 0;
+       diff_ticks.softirq = current->softirq > previous->softirq ? current->softirq - previous->softirq : 0;
+
+       unsigned long long total = diff_ticks.user + diff_ticks.system + diff_ticks.nice +
+               diff_ticks.idle + diff_ticks.iowait + diff_ticks.irq + diff_ticks.softirq;
+
+       unsigned long long busy = diff_ticks.user + diff_ticks.system + diff_ticks.nice +
+               diff_ticks.irq + diff_ticks.softirq;
+
+       if (total == 0) {
+               *usage = 0;
+       } else {
+               *usage = (float)busy / total;
+       }
 }
 
 int report_generator_generate_system_cpu_usage_report(
@@ -39,22 +145,102 @@ int report_generator_generate_system_cpu_usage_report(
                int interval,
                struct system_cpu_usage_report *report)
 {
-       return -1;
+       ON_NULL_RETURN_VAL(generator, -1);
+       ON_TRUE_RETURN_VAL(interval < 0, -1);
+       ON_NULL_RETURN_VAL(report, -1);
+
+       struct procfs_system_cpu_usage_info current = {0,};
+       float usage;
+       bool block = interval > 0;
+
+       if (block) {
+               if (procfs_read_system_cpu_usage(&generator->previous) != 0) {
+                       ERR("procfs_read_system_cpu_usage failed.");
+                       return -1;
+               }
+               sleep(interval);
+       }
+
+       if (procfs_read_system_cpu_usage(&current) != 0) {
+               ERR("procfs_read_system_cpu_usage failed.");
+               return -1;
+       }
+
+       _calculate_system_cpu_usage(&generator->previous, &current, &usage);
+
+       report->usage = usage;
+       report->time = clock_get_monotonic().tv_sec;
+
+       generator->previous = current;
+
+       return 0;
 }
 
-int report_generator_generate_percpu_usage_report(
+int report_generator_generate_system_memory_usage_report(
                report_generator_system_t *generator,
-               int interval,
-               struct system_percpu_usage_report **report)
+               struct system_memory_usage_report *report) {
+       ON_NULL_RETURN_VAL(generator, -1);
+       ON_NULL_RETURN_VAL(report, -1);
+
+       struct procfs_system_memory_usage_info mem_usage;
+
+       if (procfs_read_system_memory_usage(&mem_usage) != 0) {
+               ERR("procfs_read_system_memory_usage failed.");
+               return -1;
+       }
+
+       report->time = clock_get_monotonic().tv_sec;
+       report->total = mem_usage.total;
+       report->used = mem_usage.used;
+       report->free = mem_usage.free;
+
+       return 0;
+}
+
+/**
+ * Calculates system average cpu usage between previous and current
+ * snapshots.
+ */
+static void _calculate_process_cpu_usage(struct process_ticks_snapshot *previous,
+               struct process_ticks_snapshot *current, int ncpus, float *usage)
+{
+       struct process_ticks_snapshot diff;
+
+       diff.process_ticks = current->process_ticks > previous->process_ticks ? current->process_ticks - previous->process_ticks: 0;
+       diff.system_ticks = current->system_ticks > previous->system_ticks ? current->system_ticks - previous->system_ticks : 0;
+
+       if (diff.system_ticks == 0)
+               *usage = 0;
+       else
+               *usage = (float)diff.process_ticks / diff.system_ticks * ncpus;
+}
+
+static unsigned long long
+_system_total_time(const struct procfs_system_cpu_usage_info *info)
 {
-       return -1;
+       return info->user + info->system + info->nice + info->idle;
 }
 
-int report_generator_generate_system_memory_usage_report(
-               report_generator_system_t *generator,
-               struct system_memory_usage_report *report)
+static int
+_report_generator_read_process_ticks(int pid, struct process_ticks_snapshot *ticks)
 {
-       return -1;
+       struct procfs_system_cpu_usage_info system_ticks;
+       struct procfs_process_cpu_usage_info process_ticks;
+
+       if (procfs_read_process_cpu_usage(pid, &process_ticks) != 0) {
+               ERR("procfs_read_process_cpu_usage failed.");
+               return -1;
+       }
+
+       if (procfs_read_system_cpu_usage(&system_ticks) != 0) {
+               ERR("procfs_read_system_cpu_usage failed.");
+               return -1;
+       }
+
+       ticks->process_ticks = process_ticks.stime + process_ticks.utime;
+       ticks->system_ticks = _system_total_time(&system_ticks);
+
+       return 0;
 }
 
 int report_generator_generate_process_cpu_usage_report(
@@ -62,18 +248,86 @@ int report_generator_generate_process_cpu_usage_report(
                int interval,
                struct process_cpu_usage_report *report)
 {
-       return -1;
+       ON_NULL_RETURN_VAL(generator, -1);
+       ON_TRUE_RETURN_VAL(interval < 0, -1);
+       ON_NULL_RETURN_VAL(report, -1);
+
+       struct process_ticks_snapshot current;
+       bool block = interval > 0;
+       float usage;
+       int ncpus;
+
+       if (block) {
+               if (_report_generator_read_process_ticks(generator->pid, &generator->previous) != 0) {
+                       ERR("Unable to update process cpu ticks.");
+                       return -1;
+               }
+               sleep(interval);
+       }
+
+       if (_report_generator_read_process_ticks(generator->pid, &current) != 0) {
+               ERR("Unable to update process cpu ticks.");
+               return -1;
+       }
+
+       if (procfs_read_cpu_count(&ncpus) != 0) {
+               ERR("procfs_read_cpu_count failed.");
+               return -1;
+       }
+
+       _calculate_process_cpu_usage(&generator->previous, &current, ncpus, &usage);
+
+       report->time = clock_get_monotonic().tv_sec;
+       report->pid = generator->pid;
+       report->usage = usage;
+
+       generator->previous = current;
+
+       return 0;
 }
 
 int report_generator_generate_proccess_memory_usage_report(
                report_generator_process_t *generator,
                struct process_memory_usage_report *report)
 {
-       return -1;
+       ON_NULL_RETURN_VAL(generator, -1);
+       ON_NULL_RETURN_VAL(report, -1);
+
+       struct procfs_process_memory_usage_info mem_info;
+       struct procfs_system_memory_usage_info sys_info;
+
+       if (procfs_read_process_memory_usage(generator->pid, &mem_info) != 0) {
+               ERR("procfs_read_process_memory_usage failed.");
+               return -1;
+       }
+
+       if (procfs_read_system_memory_usage(&sys_info) != 0) {
+               ERR("procfs_read_system_memory_usage failed.");
+               return -1;
+       }
+
+       report->time = clock_get_monotonic().tv_sec;
+       report->usage = sys_info.total > 0 ? (float)mem_info.rss / sys_info.total : 0;
+
+       return 0;
 }
 
 int report_generator_generate_load_average_report(struct system_load_average_report *report)
 {
-       return -1;
+       ON_NULL_RETURN_VAL(report, -1);
+
+       struct procfs_load_average_info info = {0,};
+
+       if (procfs_read_system_load_average(&info) != 0) {
+               ERR("procfs_read_system_load_average failed.");
+               return -1;
+       }
+
+       report->time = clock_get_monotonic().tv_sec;
+       report->one_min_avg = info.one_min_avg;
+       report->five_min_avg = info.five_min_avg;
+       report->fifteen_min_avg = info.fifteen_min_avg;
+
+       return 0;
 }
 
index 9081f00..c27dacb 100644 (file)
@@ -34,11 +34,9 @@ struct system_load_average_report {
  */
 struct system_memory_usage_report {
        time_t time; /** Number of seconds after the Epoch */
-       int total;   /** Total memory (KiB) */
+       int total;   /** Total memory available (KiB) */
        int used;    /** Used memory (KiB) */
        int free;    /** Free memory (KiB) */
-       int cache;   /** Cache memory (KiB) */
-       int swap;    /** Swap memory (KiB) */
 };
 
 /**
@@ -53,8 +51,9 @@ struct system_cpu_usage_report {
  * @brief System CPU usage report per core.
  */
 struct system_percpu_usage_report {
-       unsigned int cpu_count;
-       struct system_cpu_usage_report cpus[];
+       time_t time;              /** Number of seconds after the Epoch */
+       unsigned int cpu_count;   /** Number of logical cpus (cores) */
+       float usage[];            /** Utilization of each logical cpu (core) */
 };
 
 /**
@@ -72,13 +71,7 @@ struct process_cpu_usage_report {
 struct process_memory_usage_report {
        time_t time;       /** Number of seconds after the Epoch */
        int pid;           /** Process Pid */
-       int vsz;           /** Virtual memory size (KiB) */
-       int rss;           /** Resident set size (KiB) */
-       int pss;           /** Proportional set size (KiB) */
-       int shared_clean;  /** Not modified and mapped by other processes (KiB) */
-       int shared_dirty;  /** Modified and mapped by other processes (KiB) */
-       int private_clean; /** Not modified and available only to that process (KiB) */
-       int private_dirty; /** Modified and available only to that process (KiB) */
+       float usage;       /** System's memory utilization of process (Percent) */
 };
 
 /**
index 35662b1..c8aea9c 100644 (file)
@@ -59,7 +59,6 @@ typedef struct system_task
 typedef struct app_task
 {
     task_t task;
-    report_generator_app_t *report_generator;
 } app_task_t;
 
 /**
@@ -84,4 +83,4 @@ void task_release(task_t *task);
  */
 void task_execute(task_t *task);
 
-#endif
\ No newline at end of file
+#endif