2 * Copyright (c) 2018 Samsung Electronics Co., Ltd.
4 * Licensed under the Flora License, Version 1.1 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://floralicense.org/license/
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
23 #include "report-generator.h"
25 #include "err-check.h"
26 #include "appinfo-provider.h"
27 #include "sys-stats.h"
29 #include "proc-scanner.h"
31 #include "json-schema-defs.h"
33 struct report_generator_system {
34 /** system cpu usage statistics */
35 struct sys_stats stats;
38 struct report_generator_process
40 proc_scanner_t *scanner;
41 report_generator_filter_cb filter;
43 JsonBuilder *current_builder;
46 struct report_generator_top
48 struct sys_stats sys_stats;
49 proc_scanner_t *scanner;
50 report_generator_top_type_e type;
54 struct report_generator_top_closure {
55 struct sys_stats sys_stats;
56 int current_index; int max_index;
57 struct process_usage_report *usage_report;
60 static int _report_generator_top_report_generator_scan(report_generator_top_t *generator);
62 report_generator_system_t *report_generator_new_system_report_generator()
64 report_generator_system_t *ret = calloc(1, sizeof(struct report_generator_system));
68 if (sys_stats_update(&ret->stats) != 0) {
69 ERR("stats_update_system_stats failed");
77 void report_generator_free_system_generator(report_generator_system_t *generator)
85 report_generator_process_t *report_generator_new_process_report_generator()
87 report_generator_process_t *ret = calloc(1, sizeof(struct report_generator_process));
91 ret->scanner = proc_scanner_new();
92 if (!ret->scanner) goto err;
94 if (proc_scanner_scan(ret->scanner) != 0) {
95 ERR("proc_scanner_scan failed");
102 proc_scanner_free(ret->scanner);
107 void report_generator_free_process_generator(report_generator_process_t *generator)
109 if (!generator) return;
110 proc_scanner_free(generator->scanner);
114 static bool _match_proc_and_append(struct process *proc, void *data)
116 report_generator_process_t *gen = data;
118 if (gen->filter && gen->filter(proc, gen->user_data)) {
119 process_serialize(proc, gen->current_builder);
125 int report_generator_generate_process_report(
126 report_generator_process_t *generator,
127 JsonBuilder *builder)
129 ON_NULL_RETURN_VAL(generator, -1);
130 ON_NULL_RETURN_VAL(builder, -1);
133 if (proc_scanner_scan(generator->scanner) != 0) {
134 ERR("proc_scanner_scan failed");
138 generator->current_builder = builder;
139 json_builder_begin_object(builder);
141 json_builder_set_member_name(builder, SCHEMA_TYPE);
142 json_builder_add_string_value(builder, SCHEMA_TYPE_PROCESS);
144 json_builder_set_member_name(builder, "time");
145 json_builder_add_int_value(builder, clock_realtime_get());
147 json_builder_set_member_name(builder, SCHEMA_RESULT_DATA_PROCESS);
148 json_builder_begin_array(builder);
150 proc_scanner_foreach_process(generator->scanner, _match_proc_and_append, generator);
151 json_builder_end_array(builder);
153 json_builder_end_object(builder); // end report
155 generator->current_builder = NULL;
159 void report_generator_set_filter(
160 report_generator_process_t *generator,
161 report_generator_filter_cb cb, const void *user_data)
163 ON_NULL_RETURN(generator);
166 generator->filter = cb;
167 generator->user_data = (void*)user_data;
170 int report_generator_generate_system_report(
171 report_generator_system_t *generator,
172 struct system_report *report)
174 ON_NULL_RETURN_VAL(generator, -1);
175 ON_NULL_RETURN_VAL(report, -1);
177 if (sys_stats_update(&generator->stats) != 0) {
178 ERR("stats_update_system_stats failed.");
182 if (sys_stats_get_cpu_usage_percentage(&generator->stats, &report->cpu))
184 ERR("stats_get_system_cpu_usage_average failed");
188 if (sys_stats_get_memory_usage_percentage(&generator->stats, &report->memory) != 0) {
189 ERR("stats_get_system_memory_usage failed.");
193 report->time = clock_realtime_get();
198 int report_generator_generate_load_average_report(struct system_load_average_report *report)
200 ON_NULL_RETURN_VAL(report, -1);
204 if (sys_stats_get_load_averages(&a1, &a5, &a15) != 0) {
205 ERR("stats_get_load_averages failed.");
209 report->time = clock_realtime_get();
210 report->one_min_avg = a1;
211 report->five_min_avg = a5;
212 report->fifteen_min_avg = a15;
217 report_generator_top_t *report_generator_new_top_report_generator(report_generator_top_type_e type, int limit)
219 report_generator_top_t *gen = calloc(1, sizeof(report_generator_top_t));
221 ERR("calloc failed.");
227 gen->scanner = proc_scanner_new();
229 report_generator_free_top_generator(gen);
232 // run initial scan, so other next report will have valid data.
233 if (_report_generator_top_report_generator_scan(gen) != 0) {
234 report_generator_free_top_generator(gen);
237 if (sys_stats_update(&gen->sys_stats) != 0) {
238 report_generator_free_top_generator(gen);
245 void report_generator_free_top_generator(report_generator_top_t *generator)
247 if (!generator) return;
248 proc_scanner_free(generator->scanner);
252 static bool _append_to_mem_report(struct process *proc, void *data)
254 struct report_generator_top_closure *closure = data;
255 struct process_usage_report report = {0,};
259 if (closure->current_index >= closure->max_index)
262 if (process_get_memory_usage(proc, &mem) != 0) {
265 report.usage = (float)mem / closure->sys_stats.total_memory;
268 appid = process_get_appid(proc);
269 if (appid) strncpy(report.app_id, appid, sizeof(report.app_id));
270 report.pid = process_get_pid(proc);
271 report.time = clock_realtime_get();
272 closure->usage_report[closure->current_index++] = report;
277 static bool _append_to_cpu_report(struct process *proc, void *data)
279 struct report_generator_top_closure *closure = data;
280 struct process_usage_report report = {0,};
283 if (closure->current_index >= closure->max_index)
286 if (process_get_cpu_usage_percentage(proc, &report.usage) != 0) {
290 appid = process_get_appid(proc);
291 if (appid) strncpy(report.app_id, appid, sizeof(report.app_id));
292 report.pid = process_get_pid(proc);
293 report.time = clock_realtime_get();
294 closure->usage_report[closure->current_index++] = report;
299 static int _sort_by_cpu_usage(struct process *proc1, struct process *proc2)
301 unsigned long long usage1, usage2;
302 if (process_get_cpu_usage(proc1, &usage1) != 0) {
305 if (process_get_cpu_usage(proc2, &usage2) != 0) {
308 return usage2 - usage1;
311 static int _sort_by_memory_usage(struct process *proc1, struct process *proc2)
314 if (process_get_memory_usage(proc1, &usage1) != 0) {
317 if (process_get_memory_usage(proc2, &usage2) != 0) {
320 return usage2 - usage1;
323 static int _report_generator_top_report_generator_scan_apps(
324 report_generator_top_t *generator)
326 app_info_iterator_t *iter = app_info_provider_get_running_applications();
333 int count = app_info_iterator_get_count(iter);
335 app_info_iterator_free(iter);
339 int *pids = calloc(count, sizeof(int));
341 app_info_iterator_free(iter);
346 pids[i++] = app_info_iterator_get_pid(iter);
348 while (app_info_iterator_next(iter));
350 app_info_iterator_free(iter);
352 int ret = proc_scanner_scan_pids(generator->scanner, pids, i);
357 static int _report_generator_top_report_generator_scan_all(
358 report_generator_top_t *generator)
360 return proc_scanner_scan(generator->scanner);
363 static int _report_generator_top_report_generator_scan(
364 report_generator_top_t *generator)
366 switch (generator->type) {
367 case REPORT_GENERATOR_TOP_TYPE_APPS:
368 return _report_generator_top_report_generator_scan_apps(generator);
369 case REPORT_GENERATOR_TOP_TYPE_ALL:
370 return _report_generator_top_report_generator_scan_all(generator);
377 int report_generator_generate_top_cpu_report(
378 report_generator_top_t *generator,
379 struct process_usage_report **report,
382 ON_NULL_RETURN_VAL(generator, -1);
383 ON_NULL_RETURN_VAL(report, -1);
384 ON_NULL_RETURN_VAL(n_reports, -1);
386 struct report_generator_top_closure closure = {0,};
388 if (sys_stats_update(&generator->sys_stats) != 0) {
392 if (_report_generator_top_report_generator_scan(generator) != 0) {
396 if (proc_scanner_sort_processes(generator->scanner, _sort_by_cpu_usage) != 0) {
400 closure.max_index = generator->limit;
401 closure.sys_stats = generator->sys_stats;
402 closure.usage_report = calloc(generator->limit, sizeof(struct process_usage_report));
403 if (!closure.usage_report) {
407 if (proc_scanner_foreach_process(generator->scanner, _append_to_cpu_report, &closure) != 0) {
408 free(closure.usage_report);
412 *report = closure.usage_report;
413 *n_reports = closure.current_index;
418 int report_generator_generate_top_memory_report(
419 report_generator_top_t *generator,
420 struct process_usage_report **report,
423 ON_NULL_RETURN_VAL(generator, -1);
424 ON_NULL_RETURN_VAL(report, -1);
425 ON_NULL_RETURN_VAL(n_reports, -1);
427 struct report_generator_top_closure closure = {0,};
429 if (sys_stats_update(&generator->sys_stats) != 0) {
433 if (_report_generator_top_report_generator_scan(generator) != 0) {
437 if (proc_scanner_sort_processes(generator->scanner, _sort_by_memory_usage) != 0) {
441 closure.max_index = generator->limit;
442 closure.sys_stats = generator->sys_stats;
443 closure.usage_report = calloc(generator->limit, sizeof(struct process_usage_report));
444 if (!closure.usage_report) {
448 if (proc_scanner_foreach_process(generator->scanner, _append_to_mem_report, &closure) != 0) {
449 free(closure.usage_report);
453 *report = closure.usage_report;
454 *n_reports = closure.current_index;