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"
32 struct report_generator_system {
33 /** system cpu usage statistics */
34 struct sys_stats stats;
37 struct report_generator_process
41 /** process statistics */
44 float proc_update_time;
47 struct report_generator_app
50 report_generator_process_t *process_gen;
53 struct report_generator_top
55 struct sys_stats sys_stats;
56 proc_scanner_t *scanner;
57 report_generator_top_type_e type;
61 struct report_generator_top_closure {
62 struct sys_stats sys_stats;
65 struct process_usage_report *usage_report;
68 int _app_report_generator_setup_process_generator(report_generator_app_t *generator);
69 static int _report_generator_top_report_generator_scan(report_generator_top_t *generator);
71 report_generator_system_t *report_generator_new_system_report_generator()
73 report_generator_system_t *ret = calloc(1, sizeof(struct report_generator_system));
77 if (sys_stats_update(&ret->stats) != 0) {
78 ERR("stats_update_system_stats failed");
86 void report_generator_free_system_generator(report_generator_system_t *generator)
94 report_generator_process_t *report_generator_new_process_report_generator(int pid)
96 ON_TRUE_RETURN_VAL(pid <= 0, NULL);
98 report_generator_process_t *ret = calloc(1, sizeof(struct report_generator_process));
102 process_init(pid, &ret->proc);
104 if (process_update(&ret->proc) != 0) {
105 ERR("process_update failed.");
110 ret->proc_update_time = clock_monotonic_get();
116 void report_generator_free_process_generator(report_generator_process_t *generator)
124 report_generator_app_t *report_generator_new_app_report_generator(const char *app_id)
126 ON_NULL_RETURN_VAL(app_id, NULL);
128 report_generator_app_t *ret = calloc(1, sizeof(struct report_generator_app));
130 ERR("malloc failed");
134 ret->app_id = strdup(app_id);
135 _app_report_generator_setup_process_generator(ret);
139 void report_generator_free_app_generator(report_generator_app_t *generator)
141 if (!generator) return;
142 report_generator_free_process_generator(generator->process_gen);
143 free(generator->app_id);
147 int report_generator_generate_system_report(
148 report_generator_system_t *generator,
149 struct system_report *report)
151 ON_NULL_RETURN_VAL(generator, -1);
152 ON_NULL_RETURN_VAL(report, -1);
154 if (sys_stats_update(&generator->stats) != 0) {
155 ERR("stats_update_system_stats failed.");
159 if (sys_stats_get_cpu_usage_percentage(&generator->stats, &report->cpu))
161 ERR("stats_get_system_cpu_usage_average failed");
165 if (sys_stats_get_memory_usage_percentage(&generator->stats, &report->memory) != 0) {
166 ERR("stats_get_system_memory_usage failed.");
171 report->time = clock_realtime_get();
176 int report_generator_generate_process_cpu_usage_report(
177 report_generator_process_t *generator,
178 struct process_usage_report *report)
180 ON_NULL_RETURN_VAL(generator, -1);
181 ON_NULL_RETURN_VAL(report, -1);
185 if (process_update(&generator->proc) != 0) {
186 ERR("process_update failed.");
190 if (process_get_cpu_usage_percentage(&generator->proc, &usage) != 0) {
191 ERR("process_get_cpu_usage_percentage failed.");
195 report->time = clock_realtime_get();
196 report->pid = generator->pid;
197 report->usage = usage;
202 int report_generator_generate_process_memory_usage_report(
203 report_generator_process_t *generator,
204 struct process_usage_report *report)
206 ON_NULL_RETURN_VAL(generator, -1);
207 ON_NULL_RETURN_VAL(report, -1);
211 if (process_get_memory_usage_percentage(&generator->proc, &usage) != 0) {
212 ERR("process_get_memory_usage_percentage failed.");
216 report->time = clock_realtime_get();
217 report->usage = usage;
222 int _app_report_generator_setup_process_generator(report_generator_app_t *generator)
224 int pid = app_info_provider_find_main_pid(generator->app_id);
229 if (!generator->process_gen || generator->process_gen->pid != pid) {
230 if (generator->process_gen)
231 report_generator_free_process_generator(generator->process_gen);
232 generator->process_gen = report_generator_new_process_report_generator(pid);
237 int report_generator_generate_app_cpu_usage_report(
238 report_generator_app_t *generator,
239 struct process_usage_report *report)
241 ON_NULL_RETURN_VAL(generator, -1);
242 ON_NULL_RETURN_VAL(report, -1);
244 if (_app_report_generator_setup_process_generator(generator) != 0) {
245 ERR("_app_report_generator_setup_process_generator failed.");
249 if (report_generator_generate_process_cpu_usage_report(
250 generator->process_gen, report) != 0)
252 ERR("report_generator_generate_process_cpu_usage_report failed.");
256 strncpy(report->app_id, generator->app_id, sizeof(report->app_id));
257 report->pid = generator->process_gen->pid;
262 int report_generator_generate_app_memory_usage_report(
263 report_generator_app_t *generator,
264 struct process_usage_report *report)
266 ON_NULL_RETURN_VAL(generator, -1);
267 ON_NULL_RETURN_VAL(report, -1);
269 if (_app_report_generator_setup_process_generator(generator)) {
270 ERR("_app_report_generator_setup_process_generator failed.");
274 if (report_generator_generate_process_memory_usage_report(
275 generator->process_gen, report) != 0)
277 ERR("report_generator_generate_process_memory_usage_report failed.");
281 strncpy(report->app_id, generator->app_id, sizeof(report->app_id));
282 report->pid = generator->process_gen->pid;
287 int report_generator_generate_load_average_report(struct system_load_average_report *report)
289 ON_NULL_RETURN_VAL(report, -1);
293 if (sys_stats_get_load_averages(&a1, &a5, &a15) != 0) {
294 ERR("stats_get_load_averages failed.");
298 report->time = clock_realtime_get();
299 report->one_min_avg = a1;
300 report->five_min_avg = a5;
301 report->fifteen_min_avg = a15;
306 report_generator_top_t *report_generator_new_top_report_generator(report_generator_top_type_e type, int limit)
308 report_generator_top_t *gen = calloc(1, sizeof(report_generator_top_t));
310 ERR("calloc failed.");
316 gen->scanner = proc_scanner_new();
318 report_generator_free_top_generator(gen);
321 // run initial scan, so other next report will have valid data.
322 if (_report_generator_top_report_generator_scan(gen) != 0) {
323 report_generator_free_top_generator(gen);
326 if (sys_stats_update(&gen->sys_stats) != 0) {
327 report_generator_free_top_generator(gen);
334 void report_generator_free_top_generator(report_generator_top_t *generator)
336 if (!generator) return;
337 proc_scanner_free(generator->scanner);
341 static bool _append_to_mem_report(struct process *proc, void *data)
343 struct report_generator_top_closure *closure = data;
344 struct process_usage_report report = {0,};
348 if (closure->current_index >= closure->max_index)
351 if (process_get_memory_usage(proc, &mem) != 0) {
354 report.usage = (float)mem / closure->sys_stats.total_memory;
357 appid = process_get_appid(proc);
358 if (appid) strncpy(report.app_id, appid, sizeof(report.app_id));
359 report.pid = process_get_pid(proc);
360 report.time = clock_realtime_get();
361 closure->usage_report[closure->current_index++] = report;
366 static bool _append_to_cpu_report(struct process *proc, void *data)
368 struct report_generator_top_closure *closure = data;
369 struct process_usage_report report = {0,};
372 if (closure->current_index >= closure->max_index)
375 if (process_get_cpu_usage_percentage(proc, &report.usage) != 0) {
379 appid = process_get_appid(proc);
380 if (appid) strncpy(report.app_id, appid, sizeof(report.app_id));
381 report.pid = process_get_pid(proc);
382 report.time = clock_realtime_get();
383 closure->usage_report[closure->current_index++] = report;
388 static int _sort_by_cpu_usage(struct process *proc1, struct process *proc2)
390 unsigned long long usage1, usage2;
391 if (process_get_cpu_usage(proc1, &usage1) != 0) {
394 if (process_get_cpu_usage(proc2, &usage2) != 0) {
397 return usage2 - usage1;
400 static int _sort_by_memory_usage(struct process *proc1, struct process *proc2)
403 if (process_get_memory_usage(proc1, &usage1) != 0) {
406 if (process_get_memory_usage(proc2, &usage2) != 0) {
409 return usage2 - usage1;
412 static int _report_generator_top_report_generator_scan_apps(
413 report_generator_top_t *generator)
415 app_info_iterator_t *iter = app_info_provider_get_running_applications();
422 int count = app_info_iterator_get_count(iter);
424 app_info_iterator_free(iter);
428 int *pids = calloc(count, sizeof(int));
430 app_info_iterator_free(iter);
435 pids[i++] = app_info_iterator_get_pid(iter);
437 while (app_info_iterator_next(iter));
439 app_info_iterator_free(iter);
441 int ret = proc_scanner_scan_pids(generator->scanner, pids, i);
446 static int _report_generator_top_report_generator_scan_all(
447 report_generator_top_t *generator)
449 return proc_scanner_scan(generator->scanner);
452 static int _report_generator_top_report_generator_scan(
453 report_generator_top_t *generator)
455 switch (generator->type) {
456 case REPORT_GENERATOR_TOP_TYPE_APPS:
457 return _report_generator_top_report_generator_scan_apps(generator);
458 case REPORT_GENERATOR_TOP_TYPE_ALL:
459 return _report_generator_top_report_generator_scan_all(generator);
466 int report_generator_generate_top_cpu_report(
467 report_generator_top_t *generator,
468 struct process_usage_report **report,
471 ON_NULL_RETURN_VAL(generator, -1);
472 ON_NULL_RETURN_VAL(report, -1);
473 ON_NULL_RETURN_VAL(n_reports, -1);
475 struct report_generator_top_closure closure = {0,};
477 if (sys_stats_update(&generator->sys_stats) != 0) {
481 if (_report_generator_top_report_generator_scan(generator) != 0) {
485 if (proc_scanner_sort_processes(generator->scanner, _sort_by_cpu_usage) != 0) {
489 closure.max_index = generator->limit;
490 closure.sys_stats = generator->sys_stats;
491 closure.usage_report = calloc(generator->limit, sizeof(struct process_usage_report));
492 if (!closure.usage_report) {
496 if (proc_scanner_foreach_process(generator->scanner, _append_to_cpu_report, &closure) != 0) {
497 free(closure.usage_report);
501 *report = closure.usage_report;
502 *n_reports = closure.current_index;
507 int report_generator_generate_top_memory_report(
508 report_generator_top_t *generator,
509 struct process_usage_report **report,
512 ON_NULL_RETURN_VAL(generator, -1);
513 ON_NULL_RETURN_VAL(report, -1);
514 ON_NULL_RETURN_VAL(n_reports, -1);
516 struct report_generator_top_closure closure = {0,};
518 if (sys_stats_update(&generator->sys_stats) != 0) {
522 if (_report_generator_top_report_generator_scan(generator) != 0) {
526 if (proc_scanner_sort_processes(generator->scanner, _sort_by_memory_usage) != 0) {
530 closure.max_index = generator->limit;
531 closure.sys_stats = generator->sys_stats;
532 closure.usage_report = calloc(generator->limit, sizeof(struct process_usage_report));
533 if (!closure.usage_report) {
537 if (proc_scanner_foreach_process(generator->scanner, _append_to_mem_report, &closure) != 0) {
538 free(closure.usage_report);
542 *report = closure.usage_report;
543 *n_reports = closure.current_index;