top generator related fixes
[apps/native/ttsd-worker-task.git] / src / report-generator.c
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://floralicense.org/license/
9  *
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.
15  */
16
17 #include <stdlib.h>
18 #include <string.h>
19 #include <stdbool.h>
20 #include <unistd.h>
21 #include <math.h>
22
23 #include "report-generator.h"
24 #include "log.h"
25 #include "err-check.h"
26 #include "appinfo-provider.h"
27 #include "stats.h"
28 #include "clock.h"
29 #include "proc-scanner.h"
30
31 struct report_generator_system {
32         /** system cpu usage statistics */
33         struct stats_system previous;
34 };
35
36 struct report_generator_process
37 {
38         /** process pid */
39         int pid;
40         /** process cpu usage statistics */
41         struct stats_process previous;
42 };
43
44 struct report_generator_app
45 {
46         char *app_id;
47         report_generator_process_t *process_gen;
48 };
49
50 struct report_generator_top
51 {
52         struct stats_system sys_stats;
53         proc_scanner_t *scanner;
54         report_generator_top_type_e type;
55         int limit;
56 };
57
58 struct report_generator_top_closure {
59         struct stats_system sys_stats;
60         int current_index;
61         int max_index;
62         struct process_usage_report *usage_report;
63 };
64
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);
67
68 report_generator_system_t *report_generator_new_system_report_generator()
69 {
70         report_generator_system_t *ret = calloc(1, sizeof(struct report_generator_system));
71         if (!ret)
72                 return NULL;
73
74         if (stats_update_system_stats(&ret->previous) != 0) {
75                 ERR("stats_update_system_stats failed");
76                 free(ret);
77                 return NULL;
78         }
79
80         return ret;
81 }
82
83 void report_generator_free_system_generator(report_generator_system_t *generator)
84 {
85         if (!generator)
86                 return;
87
88         free(generator);
89 }
90
91 report_generator_process_t *report_generator_new_process_report_generator(int pid)
92 {
93         ON_TRUE_RETURN_VAL(pid <= 0, NULL);
94
95         report_generator_process_t *ret = calloc(1, sizeof(struct report_generator_process));
96         if (!ret)
97                 return NULL;
98
99         if (stats_update_process_stats(pid, &ret->previous) != 0) {
100                 ERR("stats_update_process_stats failed.");
101                 free(ret);
102                 return NULL;
103         };
104
105         ret->pid = pid;
106
107         return ret;
108 }
109
110 void report_generator_free_process_generator(report_generator_process_t *generator)
111 {
112         if (!generator)
113                 return;
114
115         free(generator);
116 }
117
118 report_generator_app_t *report_generator_new_app_report_generator(const char *app_id)
119 {
120         ON_NULL_RETURN_VAL(app_id, NULL);
121
122         report_generator_app_t *ret = calloc(1, sizeof(struct report_generator_app));
123         if (!ret) {
124                 ERR("malloc failed");
125                 return NULL;
126         }
127
128         ret->app_id = strdup(app_id);
129         _app_report_generator_setup_process_generator(ret);
130         return ret;
131 }
132
133 void report_generator_free_app_generator(report_generator_app_t *generator)
134 {
135         if (!generator) return;
136         report_generator_free_process_generator(generator->process_gen);
137         free(generator->app_id);
138         free(generator);
139 }
140
141 int report_generator_generate_system_cpu_usage_report(
142                 report_generator_system_t *generator,
143                 int interval,
144                 struct system_usage_report *report)
145 {
146         ON_NULL_RETURN_VAL(generator, -1);
147         ON_TRUE_RETURN_VAL(interval < 0, -1);
148         ON_NULL_RETURN_VAL(report, -1);
149
150         float usage;
151         bool block = interval > 0;
152         struct stats_system current;
153
154         if (block) {
155                 if (stats_update_system_stats(&generator->previous) != 0) {
156                         ERR("stats_update_system_stats failed.");
157                         return -1;
158                 }
159                 sleep(interval);
160         }
161
162         if (stats_update_system_stats(&current) != 0) {
163                 ERR("stats_update_system_stats failed.");
164                 return -1;
165         }
166
167         if (stats_get_system_cpu_usage_average(&generator->previous, &current, &usage))
168         {
169                 ERR("stats_get_system_cpu_usage_average failed");
170                 return -1;
171         }
172
173         report->usage = usage;
174         report->time = clock_realtime_get();
175
176         generator->previous = current;
177
178         return 0;
179 }
180
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);
186
187         float usage;
188
189         if (stats_update_system_stats(&generator->previous) != 0) {
190                 ERR("stats_update_system_stats failed.");
191                 return -1;
192         }
193
194         if (stats_get_system_memory_usage(&generator->previous, &usage) != 0) {
195                 ERR("stats_get_system_memory_usage failed.");
196                 return -1;
197         }
198
199         report->time = clock_realtime_get();
200         report->usage = usage;
201
202         return 0;
203 }
204
205 int report_generator_generate_process_cpu_usage_report(
206                 report_generator_process_t *generator,
207                 int interval,
208                 struct process_usage_report *report)
209 {
210         ON_NULL_RETURN_VAL(generator, -1);
211         ON_TRUE_RETURN_VAL(interval < 0, -1);
212         ON_NULL_RETURN_VAL(report, -1);
213
214         struct stats_process current = {0,};
215         bool block = interval > 0;
216         float usage;
217
218         if (block) {
219                 if (stats_update_process_stats(generator->pid, &generator->previous) != 0) {
220                         ERR("stats_update_process_stats failed.");
221                         return -1;
222                 }
223                 sleep(interval);
224         }
225
226         if (stats_update_process_stats(generator->pid, &current) != 0) {
227                 ERR("stats_update_process_stats failed.");
228                 return -1;
229         }
230
231         if (stats_get_process_cpu_usage_average(&generator->previous, &current, &usage) ) {
232                 ERR("stats_update_process_stats failed.");
233                 return -1;
234         }
235
236         report->time = clock_realtime_get();
237         report->pid = generator->pid;
238         report->usage = usage;
239
240         generator->previous = current;
241
242         return 0;
243 }
244
245 int report_generator_generate_process_memory_usage_report(
246                 report_generator_process_t *generator,
247                 struct process_usage_report *report)
248 {
249         ON_NULL_RETURN_VAL(generator, -1);
250         ON_NULL_RETURN_VAL(report, -1);
251
252         float usage;
253
254         if (stats_get_process_memory_usage(generator->pid, &usage) != 0) {
255                 ERR("stats_get_process_memory_usage failed.");
256                 return -1;
257         }
258
259         report->time = clock_realtime_get();
260         report->usage = usage;
261
262         return 0;
263 }
264
265 int _app_report_generator_setup_process_generator(report_generator_app_t *generator)
266 {
267         int pid = app_info_provider_find_main_pid(generator->app_id);
268         if (pid < 0) {
269                 return -1;
270         }
271
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);
276         }
277         return 0;
278 }
279
280 int report_generator_generate_app_cpu_usage_report(
281                 report_generator_app_t *generator,
282                 int interval,
283                 struct process_usage_report *report)
284 {
285         ON_NULL_RETURN_VAL(generator, -1);
286         ON_TRUE_RETURN_VAL(interval < 0, -1);
287         ON_NULL_RETURN_VAL(report, -1);
288
289         if (_app_report_generator_setup_process_generator(generator) != 0) {
290                 ERR("_app_report_generator_setup_process_generator failed.");
291                 return -1;
292         }
293
294         if (report_generator_generate_process_cpu_usage_report(
295                                 generator->process_gen, interval, report) != 0)
296         {
297                 ERR("report_generator_generate_process_cpu_usage_report failed.");
298                 return 0;
299         }
300
301         strncpy(report->app_id, generator->app_id, sizeof(report->app_id));
302         report->pid = generator->process_gen->pid;
303
304         return 0;
305 }
306
307 int report_generator_generate_app_memory_usage_report(
308                 report_generator_app_t *generator,
309                 struct process_usage_report *report)
310 {
311         ON_NULL_RETURN_VAL(generator, -1);
312         ON_NULL_RETURN_VAL(report, -1);
313
314         if (_app_report_generator_setup_process_generator(generator)) {
315                 ERR("_app_report_generator_setup_process_generator failed.");
316                 return -1;
317         }
318
319         if (report_generator_generate_process_memory_usage_report(
320                                 generator->process_gen, report) != 0)
321         {
322                 ERR("report_generator_generate_process_memory_usage_report failed.");
323                 return 0;
324         }
325
326         strncpy(report->app_id, generator->app_id, sizeof(report->app_id));
327         report->pid = generator->process_gen->pid;
328
329         return 0;
330 }
331
332 int report_generator_generate_load_average_report(struct system_load_average_report *report)
333 {
334         ON_NULL_RETURN_VAL(report, -1);
335
336         float a1, a5, a15;
337
338         if (stats_get_load_averages(&a1, &a5, &a15) != 0) {
339                 ERR("stats_get_load_averages failed.");
340                 return -1;
341         }
342
343         report->time = clock_realtime_get();
344         report->one_min_avg = a1;
345         report->five_min_avg = a5;
346         report->fifteen_min_avg = a15;
347
348         return 0;
349 }
350
351 report_generator_top_t *report_generator_new_top_report_generator(report_generator_top_type_e type, int limit)
352 {
353         report_generator_top_t *gen = calloc(1, sizeof(report_generator_top_t));
354         if (!gen) {
355                 ERR("calloc failed.");
356                 return NULL;
357         }
358
359         gen->type = type;
360         gen->limit = limit;
361         gen->scanner = proc_scanner_new();
362         if (!gen->scanner) {
363                 report_generator_free_top_generator(gen);
364                 return NULL;
365         }
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);
369                 return NULL;
370         }
371         if (stats_update_system_stats(&gen->sys_stats) != 0) {
372                 report_generator_free_top_generator(gen);
373                 return NULL;
374         }
375
376         return gen;
377 }
378
379 void report_generator_free_top_generator(report_generator_top_t *generator)
380 {
381         if (!generator) return;
382         proc_scanner_free(generator->scanner);
383         free(generator);
384 }
385
386 static bool _append_to_mem_report(struct process *proc, void *data)
387 {
388         struct report_generator_top_closure *closure = data;
389         struct process_usage_report report = {0,};
390         const char *appid;
391         int mem;
392
393         if (closure->current_index >= closure->max_index)
394                 return false;
395
396         if (process_get_memory_usage(proc, &mem) != 0) {
397                 report.usage = NAN;
398         } else {
399                 report.usage = (float)mem / closure->sys_stats.total_memory;
400         }
401
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;
407
408         return true;
409 }
410
411 static bool _append_to_cpu_report(struct process *proc, void *data)
412 {
413         struct report_generator_top_closure *closure = data;
414         struct process_usage_report report = {0,};
415         const char *appid;
416         unsigned long long ticks = 0;
417
418         if (closure->current_index >= closure->max_index)
419                 return false;
420
421         if (process_get_cpu_usage(proc, &ticks) != 0) {
422                 report.usage = NAN;
423         } else {
424                 report.usage = stats_get_cpu_usage_percentage(ticks, closure->sys_stats.frame_time_inverted);
425         }
426
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;
432
433         return true;
434 }
435
436 static int _sort_by_cpu_usage(struct process *proc1, struct process *proc2)
437 {
438         unsigned long long usage1, usage2;
439         if (process_get_cpu_usage(proc1, &usage1) != 0) {
440                 return 1;
441         }
442         if (process_get_cpu_usage(proc2, &usage2) != 0) {
443                 return -1;
444         }
445         return usage2 - usage1;
446 }
447
448 static int _sort_by_memory_usage(struct process *proc1, struct process *proc2)
449 {
450         int usage1, usage2;
451         if (process_get_memory_usage(proc1, &usage1) != 0) {
452                 return 1;
453         }
454         if (process_get_memory_usage(proc2, &usage2) != 0) {
455                 return -1;
456         }
457         return usage2 - usage1;
458 }
459
460 static int _report_generator_top_report_generator_scan_apps(
461                 report_generator_top_t *generator)
462 {
463         app_info_iterator_t *iter = app_info_provider_get_running_applications();
464         int i = 0;
465
466         if (!iter) {
467                 return -1;
468         }
469
470         int count = app_info_iterator_get_count(iter);
471         if (count < 1) {
472                 app_info_iterator_free(iter);
473                 return -1;
474         }
475
476         int *pids = calloc(count, sizeof(int));
477         if (!pids) {
478                 app_info_iterator_free(iter);
479                 return -1;
480         }
481
482         do {
483                 pids[i++] = app_info_iterator_get_pid(iter);
484         }
485         while (app_info_iterator_next(iter));
486
487         app_info_iterator_free(iter);
488
489         int ret = proc_scanner_scan_pids(generator->scanner, pids, i);
490         free(pids);
491         return ret;
492 }
493
494 static int _report_generator_top_report_generator_scan_all(
495                 report_generator_top_t *generator)
496 {
497         return proc_scanner_scan(generator->scanner);
498 }
499
500 static int _report_generator_top_report_generator_scan(
501                 report_generator_top_t *generator)
502 {
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);
508                         break;
509         }
510
511         return -1;
512 }
513
514 int report_generator_generate_top_cpu_report(
515                 report_generator_top_t *generator,
516                 struct process_usage_report **report,
517                 int *n_reports)
518 {
519         ON_NULL_RETURN_VAL(generator, -1);
520         ON_NULL_RETURN_VAL(report, -1);
521         ON_NULL_RETURN_VAL(n_reports, -1);
522
523         struct report_generator_top_closure closure = {0,};
524
525         if (stats_update_system_stats(&generator->sys_stats) != 0) {
526                 return -1;
527         }
528
529         if (_report_generator_top_report_generator_scan(generator) != 0) {
530                 return -1;
531         }
532
533         if (proc_scanner_sort_processes(generator->scanner, _sort_by_cpu_usage) != 0) {
534                 return -1;
535         }
536
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) {
541                 return -1;
542         }
543
544         if (proc_scanner_foreach_process(generator->scanner, _append_to_cpu_report, &closure) != 0) {
545                 free(closure.usage_report);
546                 return -1;
547         }
548
549         *report = closure.usage_report;
550         *n_reports = closure.current_index;
551
552         return 0;
553 }
554
555 int report_generator_generate_top_memory_report(
556                 report_generator_top_t *generator,
557                 struct process_usage_report **report,
558                 int *n_reports)
559 {
560         ON_NULL_RETURN_VAL(generator, -1);
561         ON_NULL_RETURN_VAL(report, -1);
562         ON_NULL_RETURN_VAL(n_reports, -1);
563
564         struct report_generator_top_closure closure = {0,};
565
566         if (stats_update_system_stats(&generator->sys_stats) != 0) {
567                 return -1;
568         }
569
570         if (_report_generator_top_report_generator_scan(generator) != 0) {
571                 return -1;
572         }
573
574         if (proc_scanner_sort_processes(generator->scanner, _sort_by_memory_usage) != 0) {
575                 return -1;
576         }
577
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) {
582                 return -1;
583         }
584
585         if (proc_scanner_foreach_process(generator->scanner, _append_to_mem_report, &closure) != 0) {
586                 free(closure.usage_report);
587                 return -1;
588         }
589
590         *report = closure.usage_report;
591         *n_reports = closure.current_index;
592
593         return 0;
594 }