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 app_cpu_usage_report *cpu_report;
63 struct app_memory_usage_report *mem_report;
66 int _app_report_generator_setup_process_generator(report_generator_app_t *generator);
67 static int _report_generator_top_report_generator_scan(report_generator_top_t *generator);
69 report_generator_system_t *report_generator_new_system_report_generator()
71 report_generator_system_t *ret = calloc(1, sizeof(struct report_generator_system));
75 if (stats_update_system_stats(&ret->previous) != 0) {
76 ERR("stats_update_system_stats failed");
84 void report_generator_free_system_generator(report_generator_system_t *generator)
92 report_generator_process_t *report_generator_new_process_report_generator(int pid)
94 ON_TRUE_RETURN_VAL(pid <= 0, NULL);
96 report_generator_process_t *ret = calloc(1, sizeof(struct report_generator_process));
100 if (stats_update_process_stats(pid, &ret->previous) != 0) {
101 ERR("stats_update_process_stats failed.");
111 void report_generator_free_process_generator(report_generator_process_t *generator)
119 report_generator_app_t *report_generator_new_app_report_generator(const char *app_id)
121 ON_NULL_RETURN_VAL(app_id, NULL);
123 report_generator_app_t *ret = calloc(1, sizeof(struct report_generator_app));
125 ERR("malloc failed");
129 ret->app_id = strdup(app_id);
130 _app_report_generator_setup_process_generator(ret);
134 void report_generator_free_app_generator(report_generator_app_t *generator)
136 if (!generator) return;
137 report_generator_free_process_generator(generator->process_gen);
138 free(generator->app_id);
142 int report_generator_generate_system_cpu_usage_report(
143 report_generator_system_t *generator,
145 struct system_cpu_usage_report *report)
147 ON_NULL_RETURN_VAL(generator, -1);
148 ON_TRUE_RETURN_VAL(interval < 0, -1);
149 ON_NULL_RETURN_VAL(report, -1);
152 bool block = interval > 0;
153 struct stats_system current;
156 if (stats_update_system_stats(&generator->previous) != 0) {
157 ERR("stats_update_system_stats failed.");
163 if (stats_update_system_stats(¤t) != 0) {
164 ERR("stats_update_system_stats failed.");
168 if (stats_get_system_cpu_usage_average(&generator->previous, ¤t, &usage))
170 ERR("stats_get_system_cpu_usage_average failed");
174 report->usage = usage;
175 report->time = clock_realtime_get().tv_sec;
177 generator->previous = current;
182 int report_generator_generate_system_memory_usage_report(
183 report_generator_system_t *generator,
184 struct system_memory_usage_report *report) {
185 ON_NULL_RETURN_VAL(generator, -1);
186 ON_NULL_RETURN_VAL(report, -1);
190 if (stats_update_system_stats(&generator->previous) != 0) {
191 ERR("stats_update_system_stats failed.");
195 if (stats_get_system_memory_usage(&generator->previous, &usage) != 0) {
196 ERR("stats_get_system_memory_usage failed.");
200 report->time = clock_realtime_get().tv_sec;
201 report->usage = usage;
206 int report_generator_generate_process_cpu_usage_report(
207 report_generator_process_t *generator,
209 struct process_cpu_usage_report *report)
211 ON_NULL_RETURN_VAL(generator, -1);
212 ON_TRUE_RETURN_VAL(interval < 0, -1);
213 ON_NULL_RETURN_VAL(report, -1);
215 struct stats_process current = {0,};
216 bool block = interval > 0;
220 if (stats_update_process_stats(generator->pid, &generator->previous) != 0) {
221 ERR("stats_update_process_stats failed.");
227 if (stats_update_process_stats(generator->pid, ¤t) != 0) {
228 ERR("stats_update_process_stats failed.");
232 if (stats_get_process_cpu_usage_average(&generator->previous, ¤t, &usage) ) {
233 ERR("stats_update_process_stats failed.");
237 report->time = clock_realtime_get().tv_sec;
238 report->pid = generator->pid;
239 report->usage = usage;
241 generator->previous = current;
246 int report_generator_generate_process_memory_usage_report(
247 report_generator_process_t *generator,
248 struct process_memory_usage_report *report)
250 ON_NULL_RETURN_VAL(generator, -1);
251 ON_NULL_RETURN_VAL(report, -1);
255 if (stats_get_process_memory_usage(generator->pid, &usage) != 0) {
256 ERR("stats_get_process_memory_usage failed.");
260 report->time = clock_realtime_get().tv_sec;
261 report->usage = usage;
266 int _app_report_generator_setup_process_generator(report_generator_app_t *generator)
268 int pid = app_info_provider_find_main_pid(generator->app_id);
273 if (!generator->process_gen || generator->process_gen->pid != pid) {
274 if (generator->process_gen)
275 report_generator_free_process_generator(generator->process_gen);
276 generator->process_gen = report_generator_new_process_report_generator(pid);
281 int report_generator_generate_app_cpu_usage_report(
282 report_generator_app_t *generator,
284 struct app_cpu_usage_report *report)
286 ON_NULL_RETURN_VAL(generator, -1);
287 ON_TRUE_RETURN_VAL(interval < 0, -1);
288 ON_NULL_RETURN_VAL(report, -1);
290 if (_app_report_generator_setup_process_generator(generator) != 0) {
291 ERR("_app_report_generator_setup_process_generator failed.");
295 if (report_generator_generate_process_cpu_usage_report(
296 generator->process_gen, interval, &report->process_report) != 0)
298 ERR("report_generator_generate_process_cpu_usage_report failed.");
302 strncpy(report->app_id, generator->app_id, sizeof(report->app_id));
303 report->process_report.pid = generator->process_gen->pid;
308 int report_generator_generate_app_memory_usage_report(
309 report_generator_app_t *generator,
310 struct app_memory_usage_report *report)
312 ON_NULL_RETURN_VAL(generator, -1);
313 ON_NULL_RETURN_VAL(report, -1);
315 if (_app_report_generator_setup_process_generator(generator)) {
316 ERR("_app_report_generator_setup_process_generator failed.");
320 if (report_generator_generate_process_memory_usage_report(
321 generator->process_gen, &report->process_report) != 0)
323 ERR("report_generator_generate_process_memory_usage_report failed.");
327 strncpy(report->app_id, generator->app_id, sizeof(report->app_id));
328 report->process_report.pid = generator->process_gen->pid;
333 int report_generator_generate_load_average_report(struct system_load_average_report *report)
335 ON_NULL_RETURN_VAL(report, -1);
339 if (stats_get_load_averages(&a1, &a5, &a15) != 0) {
340 ERR("stats_get_load_averages failed.");
344 report->time = clock_realtime_get().tv_sec;
345 report->one_min_avg = a1;
346 report->five_min_avg = a5;
347 report->fifteen_min_avg = a15;
352 report_generator_top_t *report_generator_new_top_report_generator(report_generator_top_type_e type, int limit)
354 report_generator_top_t *gen = calloc(1, sizeof(report_generator_top_t));
356 ERR("calloc failed.");
362 gen->scanner = proc_scanner_new();
364 report_generator_free_top_generator(gen);
367 // run initial scan, so other next report will have valid data.
368 if (_report_generator_top_report_generator_scan(gen) != 0) {
369 report_generator_free_top_generator(gen);
372 if (stats_update_system_stats(&gen->sys_stats) != 0) {
373 report_generator_free_top_generator(gen);
380 void report_generator_free_top_generator(report_generator_top_t *generator)
382 if (!generator) return;
383 proc_scanner_free(generator->scanner);
387 static bool _append_to_mem_report(struct process *proc, void *data)
389 struct report_generator_top_closure *closure = data;
390 struct app_memory_usage_report report = {0,};
394 if (closure->current_index >= closure->max_index)
397 if (process_get_memory_usage(proc, &mem) != 0) {
398 report.process_report.usage = NAN;
400 report.process_report.usage = (float)mem / closure->sys_stats.total_memory;
403 appid = process_get_appid(proc);
404 if (appid) strncpy(report.app_id, appid, sizeof(report.app_id));
405 report.process_report.pid = process_get_pid(proc);
406 report.process_report.time = clock_realtime_get().tv_sec;
407 closure->mem_report[closure->current_index++] = report;
412 static bool _append_to_cpu_report(struct process *proc, void *data)
414 struct report_generator_top_closure *closure = data;
415 struct app_cpu_usage_report report = {0,};
417 unsigned long long ticks = 0;
419 if (closure->current_index >= closure->max_index)
422 if (process_get_cpu_usage(proc, &ticks) != 0) {
423 report.process_report.usage = NAN;
425 report.process_report.usage = stats_get_cpu_usage_percentage(ticks, closure->sys_stats.frame_time);
428 appid = process_get_appid(proc);
429 if (appid) strncpy(report.app_id, appid, sizeof(report.app_id));
430 report.process_report.pid = process_get_pid(proc);
431 report.process_report.time = clock_realtime_get().tv_sec;
432 closure->cpu_report[closure->current_index++] = report;
437 static int _sort_by_cpu_usage(struct process *proc1, struct process *proc2)
439 unsigned long long usage1, usage2;
440 if (process_get_cpu_usage(proc1, &usage1) != 0) {
443 if (process_get_cpu_usage(proc2, &usage2) != 0) {
446 return usage2 - usage1;
449 static int _sort_by_memory_usage(struct process *proc1, struct process *proc2)
452 if (process_get_memory_usage(proc1, &usage1) != 0) {
455 if (process_get_memory_usage(proc2, &usage2) != 0) {
458 return usage2 - usage1;
461 static int _report_generator_top_report_generator_scan_apps(
462 report_generator_top_t *generator)
464 app_info_iterator_t *iter = app_info_provider_get_running_applications();
471 int count = app_info_iterator_get_count(iter);
473 app_info_iterator_free(iter);
477 int *pids = calloc(count, sizeof(int));
479 app_info_iterator_free(iter);
484 pids[i++] = app_info_iterator_get_pid(iter);
486 while (app_info_iterator_next(iter));
488 app_info_iterator_free(iter);
490 return proc_scanner_scan_pids(generator->scanner, pids, count);
493 static int _report_generator_top_report_generator_scan_all(
494 report_generator_top_t *generator)
496 return proc_scanner_scan(generator->scanner);
499 static int _report_generator_top_report_generator_scan(
500 report_generator_top_t *generator)
502 switch (generator->type) {
503 case REPORT_GENERATOR_TOP_TYPE_APPS:
504 return _report_generator_top_report_generator_scan_apps(generator);
505 case REPORT_GENERATOR_TOP_TYPE_ALL:
506 return _report_generator_top_report_generator_scan_all(generator);
513 int report_generator_generate_top_cpu_report(
514 report_generator_top_t *generator,
515 struct app_cpu_usage_report **report,
518 ON_NULL_RETURN_VAL(generator, -1);
519 ON_NULL_RETURN_VAL(report, -1);
520 ON_NULL_RETURN_VAL(n_reports, -1);
522 struct report_generator_top_closure closure = {0,};
524 if (stats_update_system_stats(&generator->sys_stats) != 0) {
528 if (_report_generator_top_report_generator_scan(generator) != 0) {
532 if (proc_scanner_sort_processes(generator->scanner, _sort_by_cpu_usage) != 0) {
536 closure.max_index = generator->limit;
537 closure.sys_stats = generator->sys_stats;
538 closure.cpu_report = calloc(generator->limit, sizeof(struct app_cpu_usage_report));
539 if (!closure.cpu_report) {
543 if (proc_scanner_foreach_process(generator->scanner, _append_to_cpu_report, &closure) != 0) {
544 free(closure.cpu_report);
548 *report = closure.cpu_report;
549 *n_reports = closure.current_index;
554 int report_generator_generate_top_memory_report(
555 report_generator_top_t *generator,
556 struct app_memory_usage_report **report,
559 ON_NULL_RETURN_VAL(generator, -1);
560 ON_NULL_RETURN_VAL(report, -1);
561 ON_NULL_RETURN_VAL(n_reports, -1);
563 struct report_generator_top_closure closure = {0,};
565 if (stats_update_system_stats(&generator->sys_stats) != 0) {
569 if (_report_generator_top_report_generator_scan(generator) != 0) {
573 if (proc_scanner_sort_processes(generator->scanner, _sort_by_memory_usage) != 0) {
577 closure.max_index = generator->limit;
578 closure.sys_stats = generator->sys_stats;
579 closure.mem_report = calloc(generator->limit, sizeof(struct app_memory_usage_report));
580 if (!closure.mem_report) {
584 if (proc_scanner_foreach_process(generator->scanner, _append_to_mem_report, &closure) != 0) {
585 free(closure.mem_report);
589 *report = closure.mem_report;
590 *n_reports = closure.current_index;