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,
143 struct system_usage_report *report)
145 ON_NULL_RETURN_VAL(generator, -1);
146 ON_NULL_RETURN_VAL(report, -1);
149 struct stats_system current;
151 if (stats_update_system_stats(¤t) != 0) {
152 ERR("stats_update_system_stats failed.");
156 if (stats_get_system_cpu_usage_average(&generator->previous, ¤t, &usage))
158 ERR("stats_get_system_cpu_usage_average failed");
162 report->usage = usage;
163 report->time = clock_realtime_get();
165 generator->previous = current;
170 int report_generator_generate_system_memory_usage_report(
171 report_generator_system_t *generator,
172 struct system_usage_report *report) {
173 ON_NULL_RETURN_VAL(generator, -1);
174 ON_NULL_RETURN_VAL(report, -1);
178 if (stats_update_system_stats(&generator->previous) != 0) {
179 ERR("stats_update_system_stats failed.");
183 if (stats_get_system_memory_usage(&generator->previous, &usage) != 0) {
184 ERR("stats_get_system_memory_usage failed.");
188 report->time = clock_realtime_get();
189 report->usage = usage;
194 int report_generator_generate_process_cpu_usage_report(
195 report_generator_process_t *generator,
196 struct process_usage_report *report)
198 ON_NULL_RETURN_VAL(generator, -1);
199 ON_NULL_RETURN_VAL(report, -1);
201 struct stats_process current = {0,};
204 if (stats_update_process_stats(generator->pid, ¤t) != 0) {
205 ERR("stats_update_process_stats failed.");
209 if (stats_get_process_cpu_usage_average(&generator->previous, ¤t, &usage) ) {
210 ERR("stats_update_process_stats failed.");
214 report->time = clock_realtime_get();
215 report->pid = generator->pid;
216 report->usage = usage;
218 generator->previous = current;
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 (stats_get_process_memory_usage(generator->pid, &usage) != 0) {
233 ERR("stats_get_process_memory_usage 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 (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 (stats_update_system_stats(&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,};
392 unsigned long long ticks = 0;
394 if (closure->current_index >= closure->max_index)
397 if (process_get_cpu_usage(proc, &ticks) != 0) {
400 report.usage = stats_get_cpu_usage_percentage(ticks, closure->sys_stats.frame_time_inverted);
403 appid = process_get_appid(proc);
404 if (appid) strncpy(report.app_id, appid, sizeof(report.app_id));
405 report.pid = process_get_pid(proc);
406 report.time = clock_realtime_get();
407 closure->usage_report[closure->current_index++] = report;
412 static int _sort_by_cpu_usage(struct process *proc1, struct process *proc2)
414 unsigned long long usage1, usage2;
415 if (process_get_cpu_usage(proc1, &usage1) != 0) {
418 if (process_get_cpu_usage(proc2, &usage2) != 0) {
421 return usage2 - usage1;
424 static int _sort_by_memory_usage(struct process *proc1, struct process *proc2)
427 if (process_get_memory_usage(proc1, &usage1) != 0) {
430 if (process_get_memory_usage(proc2, &usage2) != 0) {
433 return usage2 - usage1;
436 static int _report_generator_top_report_generator_scan_apps(
437 report_generator_top_t *generator)
439 app_info_iterator_t *iter = app_info_provider_get_running_applications();
446 int count = app_info_iterator_get_count(iter);
448 app_info_iterator_free(iter);
452 int *pids = calloc(count, sizeof(int));
454 app_info_iterator_free(iter);
459 pids[i++] = app_info_iterator_get_pid(iter);
461 while (app_info_iterator_next(iter));
463 app_info_iterator_free(iter);
465 int ret = proc_scanner_scan_pids(generator->scanner, pids, i);
470 static int _report_generator_top_report_generator_scan_all(
471 report_generator_top_t *generator)
473 return proc_scanner_scan(generator->scanner);
476 static int _report_generator_top_report_generator_scan(
477 report_generator_top_t *generator)
479 switch (generator->type) {
480 case REPORT_GENERATOR_TOP_TYPE_APPS:
481 return _report_generator_top_report_generator_scan_apps(generator);
482 case REPORT_GENERATOR_TOP_TYPE_ALL:
483 return _report_generator_top_report_generator_scan_all(generator);
490 int report_generator_generate_top_cpu_report(
491 report_generator_top_t *generator,
492 struct process_usage_report **report,
495 ON_NULL_RETURN_VAL(generator, -1);
496 ON_NULL_RETURN_VAL(report, -1);
497 ON_NULL_RETURN_VAL(n_reports, -1);
499 struct report_generator_top_closure closure = {0,};
501 if (stats_update_system_stats(&generator->sys_stats) != 0) {
505 if (_report_generator_top_report_generator_scan(generator) != 0) {
509 if (proc_scanner_sort_processes(generator->scanner, _sort_by_cpu_usage) != 0) {
513 closure.max_index = generator->limit;
514 closure.sys_stats = generator->sys_stats;
515 closure.usage_report = calloc(generator->limit, sizeof(struct process_usage_report));
516 if (!closure.usage_report) {
520 if (proc_scanner_foreach_process(generator->scanner, _append_to_cpu_report, &closure) != 0) {
521 free(closure.usage_report);
525 *report = closure.usage_report;
526 *n_reports = closure.current_index;
531 int report_generator_generate_top_memory_report(
532 report_generator_top_t *generator,
533 struct process_usage_report **report,
536 ON_NULL_RETURN_VAL(generator, -1);
537 ON_NULL_RETURN_VAL(report, -1);
538 ON_NULL_RETURN_VAL(n_reports, -1);
540 struct report_generator_top_closure closure = {0,};
542 if (stats_update_system_stats(&generator->sys_stats) != 0) {
546 if (_report_generator_top_report_generator_scan(generator) != 0) {
550 if (proc_scanner_sort_processes(generator->scanner, _sort_by_memory_usage) != 0) {
554 closure.max_index = generator->limit;
555 closure.sys_stats = generator->sys_stats;
556 closure.usage_report = calloc(generator->limit, sizeof(struct process_usage_report));
557 if (!closure.usage_report) {
561 if (proc_scanner_foreach_process(generator->scanner, _append_to_mem_report, &closure) != 0) {
562 free(closure.usage_report);
566 *report = closure.usage_report;
567 *n_reports = closure.current_index;