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"
29 #include "proc-scanner.h"
31 struct report_generator_system {
32 /** system cpu usage statistics */
33 struct stats_system previous;
36 struct report_generator_process
40 /** process cpu usage statistics */
41 struct stats_process previous;
44 struct report_generator_app
47 report_generator_process_t *process_gen;
50 struct report_generator_top
52 struct stats_system sys_stats;
53 proc_scanner_t *scanner;
54 report_generator_top_type_e type;
58 struct report_generator_top_closure {
59 struct stats_system sys_stats;
62 struct process_usage_report *usage_report;
65 int _app_report_generator_setup_process_generator(report_generator_app_t *generator);
66 static int _report_generator_top_report_generator_scan(report_generator_top_t *generator);
68 report_generator_system_t *report_generator_new_system_report_generator()
70 report_generator_system_t *ret = calloc(1, sizeof(struct report_generator_system));
74 if (stats_update_system_stats(&ret->previous) != 0) {
75 ERR("stats_update_system_stats failed");
83 void report_generator_free_system_generator(report_generator_system_t *generator)
91 report_generator_process_t *report_generator_new_process_report_generator(int pid)
93 ON_TRUE_RETURN_VAL(pid <= 0, NULL);
95 report_generator_process_t *ret = calloc(1, sizeof(struct report_generator_process));
99 if (stats_update_process_stats(pid, &ret->previous) != 0) {
100 ERR("stats_update_process_stats failed.");
110 void report_generator_free_process_generator(report_generator_process_t *generator)
118 report_generator_app_t *report_generator_new_app_report_generator(const char *app_id)
120 ON_NULL_RETURN_VAL(app_id, NULL);
122 report_generator_app_t *ret = calloc(1, sizeof(struct report_generator_app));
124 ERR("malloc failed");
128 ret->app_id = strdup(app_id);
129 _app_report_generator_setup_process_generator(ret);
133 void report_generator_free_app_generator(report_generator_app_t *generator)
135 if (!generator) return;
136 report_generator_free_process_generator(generator->process_gen);
137 free(generator->app_id);
141 int report_generator_generate_system_cpu_usage_report(
142 report_generator_system_t *generator,
144 struct system_usage_report *report)
146 ON_NULL_RETURN_VAL(generator, -1);
147 ON_TRUE_RETURN_VAL(interval < 0, -1);
148 ON_NULL_RETURN_VAL(report, -1);
151 bool block = interval > 0;
152 struct stats_system current;
155 if (stats_update_system_stats(&generator->previous) != 0) {
156 ERR("stats_update_system_stats failed.");
162 if (stats_update_system_stats(¤t) != 0) {
163 ERR("stats_update_system_stats failed.");
167 if (stats_get_system_cpu_usage_average(&generator->previous, ¤t, &usage))
169 ERR("stats_get_system_cpu_usage_average failed");
173 report->usage = usage;
174 report->time = clock_realtime_get();
176 generator->previous = current;
181 int report_generator_generate_system_memory_usage_report(
182 report_generator_system_t *generator,
183 struct system_usage_report *report) {
184 ON_NULL_RETURN_VAL(generator, -1);
185 ON_NULL_RETURN_VAL(report, -1);
189 if (stats_update_system_stats(&generator->previous) != 0) {
190 ERR("stats_update_system_stats failed.");
194 if (stats_get_system_memory_usage(&generator->previous, &usage) != 0) {
195 ERR("stats_get_system_memory_usage failed.");
199 report->time = clock_realtime_get();
200 report->usage = usage;
205 int report_generator_generate_process_cpu_usage_report(
206 report_generator_process_t *generator,
208 struct process_usage_report *report)
210 ON_NULL_RETURN_VAL(generator, -1);
211 ON_TRUE_RETURN_VAL(interval < 0, -1);
212 ON_NULL_RETURN_VAL(report, -1);
214 struct stats_process current = {0,};
215 bool block = interval > 0;
219 if (stats_update_process_stats(generator->pid, &generator->previous) != 0) {
220 ERR("stats_update_process_stats failed.");
226 if (stats_update_process_stats(generator->pid, ¤t) != 0) {
227 ERR("stats_update_process_stats failed.");
231 if (stats_get_process_cpu_usage_average(&generator->previous, ¤t, &usage) ) {
232 ERR("stats_update_process_stats failed.");
236 report->time = clock_realtime_get();
237 report->pid = generator->pid;
238 report->usage = usage;
240 generator->previous = current;
245 int report_generator_generate_process_memory_usage_report(
246 report_generator_process_t *generator,
247 struct process_usage_report *report)
249 ON_NULL_RETURN_VAL(generator, -1);
250 ON_NULL_RETURN_VAL(report, -1);
254 if (stats_get_process_memory_usage(generator->pid, &usage) != 0) {
255 ERR("stats_get_process_memory_usage failed.");
259 report->time = clock_realtime_get();
260 report->usage = usage;
265 int _app_report_generator_setup_process_generator(report_generator_app_t *generator)
267 int pid = app_info_provider_find_main_pid(generator->app_id);
272 if (!generator->process_gen || generator->process_gen->pid != pid) {
273 if (generator->process_gen)
274 report_generator_free_process_generator(generator->process_gen);
275 generator->process_gen = report_generator_new_process_report_generator(pid);
280 int report_generator_generate_app_cpu_usage_report(
281 report_generator_app_t *generator,
283 struct process_usage_report *report)
285 ON_NULL_RETURN_VAL(generator, -1);
286 ON_TRUE_RETURN_VAL(interval < 0, -1);
287 ON_NULL_RETURN_VAL(report, -1);
289 if (_app_report_generator_setup_process_generator(generator) != 0) {
290 ERR("_app_report_generator_setup_process_generator failed.");
294 if (report_generator_generate_process_cpu_usage_report(
295 generator->process_gen, interval, report) != 0)
297 ERR("report_generator_generate_process_cpu_usage_report failed.");
301 strncpy(report->app_id, generator->app_id, sizeof(report->app_id));
302 report->pid = generator->process_gen->pid;
307 int report_generator_generate_app_memory_usage_report(
308 report_generator_app_t *generator,
309 struct process_usage_report *report)
311 ON_NULL_RETURN_VAL(generator, -1);
312 ON_NULL_RETURN_VAL(report, -1);
314 if (_app_report_generator_setup_process_generator(generator)) {
315 ERR("_app_report_generator_setup_process_generator failed.");
319 if (report_generator_generate_process_memory_usage_report(
320 generator->process_gen, report) != 0)
322 ERR("report_generator_generate_process_memory_usage_report failed.");
326 strncpy(report->app_id, generator->app_id, sizeof(report->app_id));
327 report->pid = generator->process_gen->pid;
332 int report_generator_generate_load_average_report(struct system_load_average_report *report)
334 ON_NULL_RETURN_VAL(report, -1);
338 if (stats_get_load_averages(&a1, &a5, &a15) != 0) {
339 ERR("stats_get_load_averages failed.");
343 report->time = clock_realtime_get();
344 report->one_min_avg = a1;
345 report->five_min_avg = a5;
346 report->fifteen_min_avg = a15;
351 report_generator_top_t *report_generator_new_top_report_generator(report_generator_top_type_e type, int limit)
353 report_generator_top_t *gen = calloc(1, sizeof(report_generator_top_t));
355 ERR("calloc failed.");
361 gen->scanner = proc_scanner_new();
363 report_generator_free_top_generator(gen);
366 // run initial scan, so other next report will have valid data.
367 if (_report_generator_top_report_generator_scan(gen) != 0) {
368 report_generator_free_top_generator(gen);
371 if (stats_update_system_stats(&gen->sys_stats) != 0) {
372 report_generator_free_top_generator(gen);
379 void report_generator_free_top_generator(report_generator_top_t *generator)
381 if (!generator) return;
382 proc_scanner_free(generator->scanner);
386 static bool _append_to_mem_report(struct process *proc, void *data)
388 struct report_generator_top_closure *closure = data;
389 struct process_usage_report report = {0,};
393 if (closure->current_index >= closure->max_index)
396 if (process_get_memory_usage(proc, &mem) != 0) {
399 report.usage = (float)mem / closure->sys_stats.total_memory;
402 appid = process_get_appid(proc);
403 if (appid) strncpy(report.app_id, appid, sizeof(report.app_id));
404 report.pid = process_get_pid(proc);
405 report.time = clock_realtime_get();
406 closure->usage_report[closure->current_index++] = report;
411 static bool _append_to_cpu_report(struct process *proc, void *data)
413 struct report_generator_top_closure *closure = data;
414 struct process_usage_report report = {0,};
416 unsigned long long ticks = 0;
418 if (closure->current_index >= closure->max_index)
421 if (process_get_cpu_usage(proc, &ticks) != 0) {
424 report.usage = stats_get_cpu_usage_percentage(ticks, closure->sys_stats.frame_time_inverted);
427 appid = process_get_appid(proc);
428 if (appid) strncpy(report.app_id, appid, sizeof(report.app_id));
429 report.pid = process_get_pid(proc);
430 report.time = clock_realtime_get();
431 closure->usage_report[closure->current_index++] = report;
436 static int _sort_by_cpu_usage(struct process *proc1, struct process *proc2)
438 unsigned long long usage1, usage2;
439 if (process_get_cpu_usage(proc1, &usage1) != 0) {
442 if (process_get_cpu_usage(proc2, &usage2) != 0) {
445 return usage2 - usage1;
448 static int _sort_by_memory_usage(struct process *proc1, struct process *proc2)
451 if (process_get_memory_usage(proc1, &usage1) != 0) {
454 if (process_get_memory_usage(proc2, &usage2) != 0) {
457 return usage2 - usage1;
460 static int _report_generator_top_report_generator_scan_apps(
461 report_generator_top_t *generator)
463 app_info_iterator_t *iter = app_info_provider_get_running_applications();
470 int count = app_info_iterator_get_count(iter);
472 app_info_iterator_free(iter);
476 int *pids = calloc(count, sizeof(int));
478 app_info_iterator_free(iter);
483 pids[i++] = app_info_iterator_get_pid(iter);
485 while (app_info_iterator_next(iter));
487 app_info_iterator_free(iter);
489 int ret = proc_scanner_scan_pids(generator->scanner, pids, i);
494 static int _report_generator_top_report_generator_scan_all(
495 report_generator_top_t *generator)
497 return proc_scanner_scan(generator->scanner);
500 static int _report_generator_top_report_generator_scan(
501 report_generator_top_t *generator)
503 switch (generator->type) {
504 case REPORT_GENERATOR_TOP_TYPE_APPS:
505 return _report_generator_top_report_generator_scan_apps(generator);
506 case REPORT_GENERATOR_TOP_TYPE_ALL:
507 return _report_generator_top_report_generator_scan_all(generator);
514 int report_generator_generate_top_cpu_report(
515 report_generator_top_t *generator,
516 struct process_usage_report **report,
519 ON_NULL_RETURN_VAL(generator, -1);
520 ON_NULL_RETURN_VAL(report, -1);
521 ON_NULL_RETURN_VAL(n_reports, -1);
523 struct report_generator_top_closure closure = {0,};
525 if (stats_update_system_stats(&generator->sys_stats) != 0) {
529 if (_report_generator_top_report_generator_scan(generator) != 0) {
533 if (proc_scanner_sort_processes(generator->scanner, _sort_by_cpu_usage) != 0) {
537 closure.max_index = generator->limit;
538 closure.sys_stats = generator->sys_stats;
539 closure.usage_report = calloc(generator->limit, sizeof(struct process_usage_report));
540 if (!closure.usage_report) {
544 if (proc_scanner_foreach_process(generator->scanner, _append_to_cpu_report, &closure) != 0) {
545 free(closure.usage_report);
549 *report = closure.usage_report;
550 *n_reports = closure.current_index;
555 int report_generator_generate_top_memory_report(
556 report_generator_top_t *generator,
557 struct process_usage_report **report,
560 ON_NULL_RETURN_VAL(generator, -1);
561 ON_NULL_RETURN_VAL(report, -1);
562 ON_NULL_RETURN_VAL(n_reports, -1);
564 struct report_generator_top_closure closure = {0,};
566 if (stats_update_system_stats(&generator->sys_stats) != 0) {
570 if (_report_generator_top_report_generator_scan(generator) != 0) {
574 if (proc_scanner_sort_processes(generator->scanner, _sort_by_memory_usage) != 0) {
578 closure.max_index = generator->limit;
579 closure.sys_stats = generator->sys_stats;
580 closure.usage_report = calloc(generator->limit, sizeof(struct process_usage_report));
581 if (!closure.usage_report) {
585 if (proc_scanner_foreach_process(generator->scanner, _append_to_mem_report, &closure) != 0) {
586 free(closure.usage_report);
590 *report = closure.usage_report;
591 *n_reports = closure.current_index;