* limitations under the License.
*/
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <math.h>
+
#include "report-generator.h"
+#include "log.h"
+#include "err-check.h"
+#include "appinfo-provider.h"
+#include "sys-stats.h"
+#include "clock.h"
+#include "proc-scanner.h"
+#include "process.h"
+#include "json-schema-defs.h"
+
+struct report_generator_system {
+ /** system cpu usage statistics */
+ struct sys_stats stats;
+};
+
+struct report_generator_process
+{
+ proc_scanner_t *scanner;
+ report_generator_filter_cb filter;
+ void *user_data;
+ JsonBuilder *current_builder;
+};
+
+struct report_generator_top
+{
+ struct sys_stats sys_stats;
+ proc_scanner_t *scanner;
+ report_generator_top_type_e type;
+ int limit;
+};
+
+struct report_generator_top_closure {
+ struct sys_stats sys_stats;
+ int current_index; int max_index;
+ struct process_usage_report *usage_report;
+};
+
+static int _report_generator_top_report_generator_scan(report_generator_top_t *generator);
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 (sys_stats_update(&ret->stats) != 0) {
+ ERR("stats_update_system_stats 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)
+report_generator_process_t *report_generator_new_process_report_generator()
{
+ report_generator_process_t *ret = calloc(1, sizeof(struct report_generator_process));
+ if (!ret)
+ return NULL;
+
+ ret->scanner = proc_scanner_new();
+ if (!ret->scanner) goto err;
+
+ if (proc_scanner_scan(ret->scanner) != 0) {
+ ERR("proc_scanner_scan failed");
+ goto err;
+ }
+
+ return ret;
+
+err:
+ proc_scanner_free(ret->scanner);
+ free(ret);
return NULL;
}
void report_generator_free_process_generator(report_generator_process_t *generator)
{
+ if (!generator) return;
+ proc_scanner_free(generator->scanner);
+ free(generator);
}
-int report_generator_generate_system_cpu_usage_report(
- report_generator_system_t *generator,
- int interval,
- struct system_cpu_usage_report *report)
+static bool _match_proc_and_append(struct process *proc, void *data)
{
- return -1;
+ report_generator_process_t *gen = data;
+
+ if (gen->filter && gen->filter(proc, gen->user_data)) {
+ process_serialize(proc, gen->current_builder);
+ }
+
+ return true;
}
-int report_generator_generate_percpu_usage_report(
- report_generator_system_t *generator,
- int interval,
- struct system_percpu_usage_report **report)
+int report_generator_generate_process_report(
+ report_generator_process_t *generator,
+ JsonBuilder *builder)
{
- return -1;
+ ON_NULL_RETURN_VAL(generator, -1);
+ ON_NULL_RETURN_VAL(builder, -1);
+
+ // refresh data
+ if (proc_scanner_scan(generator->scanner) != 0) {
+ ERR("proc_scanner_scan failed");
+ return -1;
+ }
+
+ generator->current_builder = builder;
+ json_builder_begin_object(builder);
+
+ json_builder_set_member_name(builder, SCHEMA_TYPE);
+ json_builder_add_string_value(builder, SCHEMA_TYPE_PROCESS);
+
+ json_builder_set_member_name(builder, "time");
+ json_builder_add_int_value(builder, clock_realtime_get());
+
+ json_builder_set_member_name(builder, SCHEMA_RESULT_DATA_PROCESS);
+ json_builder_begin_array(builder);
+
+ proc_scanner_foreach_process(generator->scanner, _match_proc_and_append, generator);
+ json_builder_end_array(builder);
+
+ json_builder_end_object(builder); // end report
+
+ generator->current_builder = NULL;
+ return 0;
+}
+
+void report_generator_set_filter(
+ report_generator_process_t *generator,
+ report_generator_filter_cb cb, const void *user_data)
+{
+ ON_NULL_RETURN(generator);
+ ON_NULL_RETURN(cb);
+
+ generator->filter = cb;
+ generator->user_data = (void*)user_data;
}
-int report_generator_generate_system_memory_usage_report(
+int report_generator_generate_system_report(
report_generator_system_t *generator,
- struct system_memory_usage_report *report)
+ struct system_report *report)
{
- return -1;
+ ON_NULL_RETURN_VAL(generator, -1);
+ ON_NULL_RETURN_VAL(report, -1);
+
+ if (sys_stats_update(&generator->stats) != 0) {
+ ERR("stats_update_system_stats failed.");
+ return -1;
+ }
+
+ if (sys_stats_get_cpu_usage_percentage(&generator->stats, &report->cpu))
+ {
+ ERR("stats_get_system_cpu_usage_average failed");
+ return -1;
+ }
+
+ if (sys_stats_get_memory_usage_percentage(&generator->stats, &report->memory) != 0) {
+ ERR("stats_get_system_memory_usage failed.");
+ return -1;
+ }
+
+ report->time = clock_realtime_get();
+
+ return 0;
}
-int report_generator_generate_process_cpu_usage_report(
- report_generator_process_t *generator,
- int interval,
- struct process_cpu_usage_report *report)
+int report_generator_generate_load_average_report(struct system_load_average_report *report)
{
- return -1;
+ ON_NULL_RETURN_VAL(report, -1);
+
+ float a1, a5, a15;
+
+ if (sys_stats_get_load_averages(&a1, &a5, &a15) != 0) {
+ ERR("stats_get_load_averages failed.");
+ return -1;
+ }
+
+ report->time = clock_realtime_get();
+ report->one_min_avg = a1;
+ report->five_min_avg = a5;
+ report->fifteen_min_avg = a15;
+
+ return 0;
}
-int report_generator_generate_proccess_memory_usage_report(
- report_generator_process_t *generator,
- struct process_memory_usage_report *report)
+report_generator_top_t *report_generator_new_top_report_generator(report_generator_top_type_e type, int limit)
{
- return -1;
+ report_generator_top_t *gen = calloc(1, sizeof(report_generator_top_t));
+ if (!gen) {
+ ERR("calloc failed.");
+ return NULL;
+ }
+
+ gen->type = type;
+ gen->limit = limit;
+ gen->scanner = proc_scanner_new();
+ if (!gen->scanner) {
+ report_generator_free_top_generator(gen);
+ return NULL;
+ }
+ // run initial scan, so other next report will have valid data.
+ if (_report_generator_top_report_generator_scan(gen) != 0) {
+ report_generator_free_top_generator(gen);
+ return NULL;
+ }
+ if (sys_stats_update(&gen->sys_stats) != 0) {
+ report_generator_free_top_generator(gen);
+ return NULL;
+ }
+
+ return gen;
}
-int report_generator_generate_load_average_report(struct system_load_average_report *report)
+void report_generator_free_top_generator(report_generator_top_t *generator)
{
+ if (!generator) return;
+ proc_scanner_free(generator->scanner);
+ free(generator);
+}
+
+static bool _append_to_mem_report(struct process *proc, void *data)
+{
+ struct report_generator_top_closure *closure = data;
+ struct process_usage_report report = {0,};
+ const char *appid;
+ int mem;
+
+ if (closure->current_index >= closure->max_index)
+ return false;
+
+ if (process_get_memory_usage(proc, &mem) != 0) {
+ report.usage = NAN;
+ } else {
+ report.usage = (float)mem / closure->sys_stats.total_memory;
+ }
+
+ appid = process_get_appid(proc);
+ if (appid) strncpy(report.app_id, appid, sizeof(report.app_id));
+ report.pid = process_get_pid(proc);
+ report.time = clock_realtime_get();
+ closure->usage_report[closure->current_index++] = report;
+
+ return true;
+}
+
+static bool _append_to_cpu_report(struct process *proc, void *data)
+{
+ struct report_generator_top_closure *closure = data;
+ struct process_usage_report report = {0,};
+ const char *appid;
+
+ if (closure->current_index >= closure->max_index)
+ return false;
+
+ if (process_get_cpu_usage_percentage(proc, &report.usage) != 0) {
+ report.usage = NAN;
+ }
+
+ appid = process_get_appid(proc);
+ if (appid) strncpy(report.app_id, appid, sizeof(report.app_id));
+ report.pid = process_get_pid(proc);
+ report.time = clock_realtime_get();
+ closure->usage_report[closure->current_index++] = report;
+
+ return true;
+}
+
+static int _sort_by_cpu_usage(struct process *proc1, struct process *proc2)
+{
+ unsigned long long usage1, usage2;
+ if (process_get_cpu_usage(proc1, &usage1) != 0) {
+ return 1;
+ }
+ if (process_get_cpu_usage(proc2, &usage2) != 0) {
+ return -1;
+ }
+ return usage2 - usage1;
+}
+
+static int _sort_by_memory_usage(struct process *proc1, struct process *proc2)
+{
+ int usage1, usage2;
+ if (process_get_memory_usage(proc1, &usage1) != 0) {
+ return 1;
+ }
+ if (process_get_memory_usage(proc2, &usage2) != 0) {
+ return -1;
+ }
+ return usage2 - usage1;
+}
+
+static int _report_generator_top_report_generator_scan_apps(
+ report_generator_top_t *generator)
+{
+ app_info_iterator_t *iter = app_info_provider_get_running_applications();
+ int i = 0;
+
+ if (!iter) {
+ return -1;
+ }
+
+ int count = app_info_iterator_get_count(iter);
+ if (count < 1) {
+ app_info_iterator_free(iter);
+ return -1;
+ }
+
+ int *pids = calloc(count, sizeof(int));
+ if (!pids) {
+ app_info_iterator_free(iter);
+ return -1;
+ }
+
+ do {
+ pids[i++] = app_info_iterator_get_pid(iter);
+ }
+ while (app_info_iterator_next(iter));
+
+ app_info_iterator_free(iter);
+
+ int ret = proc_scanner_scan_pids(generator->scanner, pids, i);
+ free(pids);
+ return ret;
+}
+
+static int _report_generator_top_report_generator_scan_all(
+ report_generator_top_t *generator)
+{
+ return proc_scanner_scan(generator->scanner);
+}
+
+static int _report_generator_top_report_generator_scan(
+ report_generator_top_t *generator)
+{
+ switch (generator->type) {
+ case REPORT_GENERATOR_TOP_TYPE_APPS:
+ return _report_generator_top_report_generator_scan_apps(generator);
+ case REPORT_GENERATOR_TOP_TYPE_ALL:
+ return _report_generator_top_report_generator_scan_all(generator);
+ break;
+ }
+
return -1;
}
+int report_generator_generate_top_cpu_report(
+ report_generator_top_t *generator,
+ struct process_usage_report **report,
+ int *n_reports)
+{
+ ON_NULL_RETURN_VAL(generator, -1);
+ ON_NULL_RETURN_VAL(report, -1);
+ ON_NULL_RETURN_VAL(n_reports, -1);
+
+ struct report_generator_top_closure closure = {0,};
+
+ if (sys_stats_update(&generator->sys_stats) != 0) {
+ return -1;
+ }
+
+ if (_report_generator_top_report_generator_scan(generator) != 0) {
+ return -1;
+ }
+
+ if (proc_scanner_sort_processes(generator->scanner, _sort_by_cpu_usage) != 0) {
+ return -1;
+ }
+
+ closure.max_index = generator->limit;
+ closure.sys_stats = generator->sys_stats;
+ closure.usage_report = calloc(generator->limit, sizeof(struct process_usage_report));
+ if (!closure.usage_report) {
+ return -1;
+ }
+
+ if (proc_scanner_foreach_process(generator->scanner, _append_to_cpu_report, &closure) != 0) {
+ free(closure.usage_report);
+ return -1;
+ }
+
+ *report = closure.usage_report;
+ *n_reports = closure.current_index;
+
+ return 0;
+}
+
+int report_generator_generate_top_memory_report(
+ report_generator_top_t *generator,
+ struct process_usage_report **report,
+ int *n_reports)
+{
+ ON_NULL_RETURN_VAL(generator, -1);
+ ON_NULL_RETURN_VAL(report, -1);
+ ON_NULL_RETURN_VAL(n_reports, -1);
+
+ struct report_generator_top_closure closure = {0,};
+
+ if (sys_stats_update(&generator->sys_stats) != 0) {
+ return -1;
+ }
+
+ if (_report_generator_top_report_generator_scan(generator) != 0) {
+ return -1;
+ }
+
+ if (proc_scanner_sort_processes(generator->scanner, _sort_by_memory_usage) != 0) {
+ return -1;
+ }
+
+ closure.max_index = generator->limit;
+ closure.sys_stats = generator->sys_stats;
+ closure.usage_report = calloc(generator->limit, sizeof(struct process_usage_report));
+ if (!closure.usage_report) {
+ return -1;
+ }
+
+ if (proc_scanner_foreach_process(generator->scanner, _append_to_mem_report, &closure) != 0) {
+ free(closure.usage_report);
+ return -1;
+ }
+
+ *report = closure.usage_report;
+ *n_reports = closure.current_index;
+
+ return 0;
+}