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_cpu_usage_report(
148 report_generator_system_t *generator,
149 struct system_usage_report *report)
151 ON_NULL_RETURN_VAL(generator, -1);
152 ON_NULL_RETURN_VAL(report, -1);
156 if (sys_stats_update(&generator->stats) != 0) {
157 ERR("stats_update_system_stats failed.");
161 if (sys_stats_get_cpu_usage_percentage(&generator->stats, &usage))
163 ERR("stats_get_system_cpu_usage_average failed");
167 report->usage = usage;
168 report->time = clock_realtime_get();
173 int report_generator_generate_system_memory_usage_report(
174 report_generator_system_t *generator,
175 struct system_usage_report *report) {
176 ON_NULL_RETURN_VAL(generator, -1);
177 ON_NULL_RETURN_VAL(report, -1);
181 if (sys_stats_update(&generator->stats) != 0) {
182 ERR("stats_update_system_stats failed.");
186 if (sys_stats_get_memory_usage_percentage(&generator->stats, &usage) != 0) {
187 ERR("stats_get_system_memory_usage failed.");
191 report->time = clock_realtime_get();
192 report->usage = usage;
197 int report_generator_generate_process_cpu_usage_report(
198 report_generator_process_t *generator,
199 struct process_usage_report *report)
201 ON_NULL_RETURN_VAL(generator, -1);
202 ON_NULL_RETURN_VAL(report, -1);
206 if (process_update(&generator->proc) != 0) {
207 ERR("process_update failed.");
211 if (process_get_cpu_usage_percentage(&generator->proc, &usage) != 0) {
212 ERR("process_get_cpu_usage_percentage failed.");
216 report->time = clock_realtime_get();
217 report->pid = generator->pid;
218 report->usage = usage;
223 int report_generator_generate_process_memory_usage_report(
224 report_generator_process_t *generator,
225 struct process_usage_report *report)
227 ON_NULL_RETURN_VAL(generator, -1);
228 ON_NULL_RETURN_VAL(report, -1);
232 if (process_get_memory_usage_percentage(&generator->proc, &usage) != 0) {
233 ERR("process_get_memory_usage_percentage failed.");
237 report->time = clock_realtime_get();
238 report->usage = usage;
243 int _app_report_generator_setup_process_generator(report_generator_app_t *generator)
245 int pid = app_info_provider_find_main_pid(generator->app_id);
250 if (!generator->process_gen || generator->process_gen->pid != pid) {
251 if (generator->process_gen)
252 report_generator_free_process_generator(generator->process_gen);
253 generator->process_gen = report_generator_new_process_report_generator(pid);
258 int report_generator_generate_app_cpu_usage_report(
259 report_generator_app_t *generator,
260 struct process_usage_report *report)
262 ON_NULL_RETURN_VAL(generator, -1);
263 ON_NULL_RETURN_VAL(report, -1);
265 if (_app_report_generator_setup_process_generator(generator) != 0) {
266 ERR("_app_report_generator_setup_process_generator failed.");
270 if (report_generator_generate_process_cpu_usage_report(
271 generator->process_gen, report) != 0)
273 ERR("report_generator_generate_process_cpu_usage_report failed.");
277 strncpy(report->app_id, generator->app_id, sizeof(report->app_id));
278 report->pid = generator->process_gen->pid;
283 int report_generator_generate_app_memory_usage_report(
284 report_generator_app_t *generator,
285 struct process_usage_report *report)
287 ON_NULL_RETURN_VAL(generator, -1);
288 ON_NULL_RETURN_VAL(report, -1);
290 if (_app_report_generator_setup_process_generator(generator)) {
291 ERR("_app_report_generator_setup_process_generator failed.");
295 if (report_generator_generate_process_memory_usage_report(
296 generator->process_gen, report) != 0)
298 ERR("report_generator_generate_process_memory_usage_report failed.");
302 strncpy(report->app_id, generator->app_id, sizeof(report->app_id));
303 report->pid = generator->process_gen->pid;
308 int report_generator_generate_load_average_report(struct system_load_average_report *report)
310 ON_NULL_RETURN_VAL(report, -1);
314 if (sys_stats_get_load_averages(&a1, &a5, &a15) != 0) {
315 ERR("stats_get_load_averages failed.");
319 report->time = clock_realtime_get();
320 report->one_min_avg = a1;
321 report->five_min_avg = a5;
322 report->fifteen_min_avg = a15;
327 report_generator_top_t *report_generator_new_top_report_generator(report_generator_top_type_e type, int limit)
329 report_generator_top_t *gen = calloc(1, sizeof(report_generator_top_t));
331 ERR("calloc failed.");
337 gen->scanner = proc_scanner_new();
339 report_generator_free_top_generator(gen);
342 // run initial scan, so other next report will have valid data.
343 if (_report_generator_top_report_generator_scan(gen) != 0) {
344 report_generator_free_top_generator(gen);
347 if (sys_stats_update(&gen->sys_stats) != 0) {
348 report_generator_free_top_generator(gen);
355 void report_generator_free_top_generator(report_generator_top_t *generator)
357 if (!generator) return;
358 proc_scanner_free(generator->scanner);
362 static bool _append_to_mem_report(struct process *proc, void *data)
364 struct report_generator_top_closure *closure = data;
365 struct process_usage_report report = {0,};
369 if (closure->current_index >= closure->max_index)
372 if (process_get_memory_usage(proc, &mem) != 0) {
375 report.usage = (float)mem / closure->sys_stats.total_memory;
378 appid = process_get_appid(proc);
379 if (appid) strncpy(report.app_id, appid, sizeof(report.app_id));
380 report.pid = process_get_pid(proc);
381 report.time = clock_realtime_get();
382 closure->usage_report[closure->current_index++] = report;
387 static bool _append_to_cpu_report(struct process *proc, void *data)
389 struct report_generator_top_closure *closure = data;
390 struct process_usage_report report = {0,};
393 if (closure->current_index >= closure->max_index)
396 if (process_get_cpu_usage_percentage(proc, &report.usage) != 0) {
400 appid = process_get_appid(proc);
401 if (appid) strncpy(report.app_id, appid, sizeof(report.app_id));
402 report.pid = process_get_pid(proc);
403 report.time = clock_realtime_get();
404 closure->usage_report[closure->current_index++] = report;
409 static int _sort_by_cpu_usage(struct process *proc1, struct process *proc2)
411 unsigned long long usage1, usage2;
412 if (process_get_cpu_usage(proc1, &usage1) != 0) {
415 if (process_get_cpu_usage(proc2, &usage2) != 0) {
418 return usage2 - usage1;
421 static int _sort_by_memory_usage(struct process *proc1, struct process *proc2)
424 if (process_get_memory_usage(proc1, &usage1) != 0) {
427 if (process_get_memory_usage(proc2, &usage2) != 0) {
430 return usage2 - usage1;
433 static int _report_generator_top_report_generator_scan_apps(
434 report_generator_top_t *generator)
436 app_info_iterator_t *iter = app_info_provider_get_running_applications();
443 int count = app_info_iterator_get_count(iter);
445 app_info_iterator_free(iter);
449 int *pids = calloc(count, sizeof(int));
451 app_info_iterator_free(iter);
456 pids[i++] = app_info_iterator_get_pid(iter);
458 while (app_info_iterator_next(iter));
460 app_info_iterator_free(iter);
462 int ret = proc_scanner_scan_pids(generator->scanner, pids, i);
467 static int _report_generator_top_report_generator_scan_all(
468 report_generator_top_t *generator)
470 return proc_scanner_scan(generator->scanner);
473 static int _report_generator_top_report_generator_scan(
474 report_generator_top_t *generator)
476 switch (generator->type) {
477 case REPORT_GENERATOR_TOP_TYPE_APPS:
478 return _report_generator_top_report_generator_scan_apps(generator);
479 case REPORT_GENERATOR_TOP_TYPE_ALL:
480 return _report_generator_top_report_generator_scan_all(generator);
487 int report_generator_generate_top_cpu_report(
488 report_generator_top_t *generator,
489 struct process_usage_report **report,
492 ON_NULL_RETURN_VAL(generator, -1);
493 ON_NULL_RETURN_VAL(report, -1);
494 ON_NULL_RETURN_VAL(n_reports, -1);
496 struct report_generator_top_closure closure = {0,};
498 if (sys_stats_update(&generator->sys_stats) != 0) {
502 if (_report_generator_top_report_generator_scan(generator) != 0) {
506 if (proc_scanner_sort_processes(generator->scanner, _sort_by_cpu_usage) != 0) {
510 closure.max_index = generator->limit;
511 closure.sys_stats = generator->sys_stats;
512 closure.usage_report = calloc(generator->limit, sizeof(struct process_usage_report));
513 if (!closure.usage_report) {
517 if (proc_scanner_foreach_process(generator->scanner, _append_to_cpu_report, &closure) != 0) {
518 free(closure.usage_report);
522 *report = closure.usage_report;
523 *n_reports = closure.current_index;
528 int report_generator_generate_top_memory_report(
529 report_generator_top_t *generator,
530 struct process_usage_report **report,
533 ON_NULL_RETURN_VAL(generator, -1);
534 ON_NULL_RETURN_VAL(report, -1);
535 ON_NULL_RETURN_VAL(n_reports, -1);
537 struct report_generator_top_closure closure = {0,};
539 if (sys_stats_update(&generator->sys_stats) != 0) {
543 if (_report_generator_top_report_generator_scan(generator) != 0) {
547 if (proc_scanner_sort_processes(generator->scanner, _sort_by_memory_usage) != 0) {
551 closure.max_index = generator->limit;
552 closure.sys_stats = generator->sys_stats;
553 closure.usage_report = calloc(generator->limit, sizeof(struct process_usage_report));
554 if (!closure.usage_report) {
558 if (proc_scanner_foreach_process(generator->scanner, _append_to_mem_report, &closure) != 0) {
559 free(closure.usage_report);
563 *report = closure.usage_report;
564 *n_reports = closure.current_index;