report-generator: remove interval param
[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                 struct system_usage_report *report)
144 {
145         ON_NULL_RETURN_VAL(generator, -1);
146         ON_NULL_RETURN_VAL(report, -1);
147
148         float usage;
149         struct stats_system current;
150
151         if (stats_update_system_stats(&current) != 0) {
152                 ERR("stats_update_system_stats failed.");
153                 return -1;
154         }
155
156         if (stats_get_system_cpu_usage_average(&generator->previous, &current, &usage))
157         {
158                 ERR("stats_get_system_cpu_usage_average failed");
159                 return -1;
160         }
161
162         report->usage = usage;
163         report->time = clock_realtime_get();
164
165         generator->previous = current;
166
167         return 0;
168 }
169
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);
175
176         float usage;
177
178         if (stats_update_system_stats(&generator->previous) != 0) {
179                 ERR("stats_update_system_stats failed.");
180                 return -1;
181         }
182
183         if (stats_get_system_memory_usage(&generator->previous, &usage) != 0) {
184                 ERR("stats_get_system_memory_usage failed.");
185                 return -1;
186         }
187
188         report->time = clock_realtime_get();
189         report->usage = usage;
190
191         return 0;
192 }
193
194 int report_generator_generate_process_cpu_usage_report(
195                 report_generator_process_t *generator,
196                 struct process_usage_report *report)
197 {
198         ON_NULL_RETURN_VAL(generator, -1);
199         ON_NULL_RETURN_VAL(report, -1);
200
201         struct stats_process current = {0,};
202         float usage;
203
204         if (stats_update_process_stats(generator->pid, &current) != 0) {
205                 ERR("stats_update_process_stats failed.");
206                 return -1;
207         }
208
209         if (stats_get_process_cpu_usage_average(&generator->previous, &current, &usage) ) {
210                 ERR("stats_update_process_stats failed.");
211                 return -1;
212         }
213
214         report->time = clock_realtime_get();
215         report->pid = generator->pid;
216         report->usage = usage;
217
218         generator->previous = current;
219
220         return 0;
221 }
222
223 int report_generator_generate_process_memory_usage_report(
224                 report_generator_process_t *generator,
225                 struct process_usage_report *report)
226 {
227         ON_NULL_RETURN_VAL(generator, -1);
228         ON_NULL_RETURN_VAL(report, -1);
229
230         float usage;
231
232         if (stats_get_process_memory_usage(generator->pid, &usage) != 0) {
233                 ERR("stats_get_process_memory_usage failed.");
234                 return -1;
235         }
236
237         report->time = clock_realtime_get();
238         report->usage = usage;
239
240         return 0;
241 }
242
243 int _app_report_generator_setup_process_generator(report_generator_app_t *generator)
244 {
245         int pid = app_info_provider_find_main_pid(generator->app_id);
246         if (pid < 0) {
247                 return -1;
248         }
249
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);
254         }
255         return 0;
256 }
257
258 int report_generator_generate_app_cpu_usage_report(
259                 report_generator_app_t *generator,
260                 struct process_usage_report *report)
261 {
262         ON_NULL_RETURN_VAL(generator, -1);
263         ON_NULL_RETURN_VAL(report, -1);
264
265         if (_app_report_generator_setup_process_generator(generator) != 0) {
266                 ERR("_app_report_generator_setup_process_generator failed.");
267                 return -1;
268         }
269
270         if (report_generator_generate_process_cpu_usage_report(
271                                 generator->process_gen, report) != 0)
272         {
273                 ERR("report_generator_generate_process_cpu_usage_report failed.");
274                 return 0;
275         }
276
277         strncpy(report->app_id, generator->app_id, sizeof(report->app_id));
278         report->pid = generator->process_gen->pid;
279
280         return 0;
281 }
282
283 int report_generator_generate_app_memory_usage_report(
284                 report_generator_app_t *generator,
285                 struct process_usage_report *report)
286 {
287         ON_NULL_RETURN_VAL(generator, -1);
288         ON_NULL_RETURN_VAL(report, -1);
289
290         if (_app_report_generator_setup_process_generator(generator)) {
291                 ERR("_app_report_generator_setup_process_generator failed.");
292                 return -1;
293         }
294
295         if (report_generator_generate_process_memory_usage_report(
296                                 generator->process_gen, report) != 0)
297         {
298                 ERR("report_generator_generate_process_memory_usage_report failed.");
299                 return 0;
300         }
301
302         strncpy(report->app_id, generator->app_id, sizeof(report->app_id));
303         report->pid = generator->process_gen->pid;
304
305         return 0;
306 }
307
308 int report_generator_generate_load_average_report(struct system_load_average_report *report)
309 {
310         ON_NULL_RETURN_VAL(report, -1);
311
312         float a1, a5, a15;
313
314         if (stats_get_load_averages(&a1, &a5, &a15) != 0) {
315                 ERR("stats_get_load_averages failed.");
316                 return -1;
317         }
318
319         report->time = clock_realtime_get();
320         report->one_min_avg = a1;
321         report->five_min_avg = a5;
322         report->fifteen_min_avg = a15;
323
324         return 0;
325 }
326
327 report_generator_top_t *report_generator_new_top_report_generator(report_generator_top_type_e type, int limit)
328 {
329         report_generator_top_t *gen = calloc(1, sizeof(report_generator_top_t));
330         if (!gen) {
331                 ERR("calloc failed.");
332                 return NULL;
333         }
334
335         gen->type = type;
336         gen->limit = limit;
337         gen->scanner = proc_scanner_new();
338         if (!gen->scanner) {
339                 report_generator_free_top_generator(gen);
340                 return NULL;
341         }
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);
345                 return NULL;
346         }
347         if (stats_update_system_stats(&gen->sys_stats) != 0) {
348                 report_generator_free_top_generator(gen);
349                 return NULL;
350         }
351
352         return gen;
353 }
354
355 void report_generator_free_top_generator(report_generator_top_t *generator)
356 {
357         if (!generator) return;
358         proc_scanner_free(generator->scanner);
359         free(generator);
360 }
361
362 static bool _append_to_mem_report(struct process *proc, void *data)
363 {
364         struct report_generator_top_closure *closure = data;
365         struct process_usage_report report = {0,};
366         const char *appid;
367         int mem;
368
369         if (closure->current_index >= closure->max_index)
370                 return false;
371
372         if (process_get_memory_usage(proc, &mem) != 0) {
373                 report.usage = NAN;
374         } else {
375                 report.usage = (float)mem / closure->sys_stats.total_memory;
376         }
377
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;
383
384         return true;
385 }
386
387 static bool _append_to_cpu_report(struct process *proc, void *data)
388 {
389         struct report_generator_top_closure *closure = data;
390         struct process_usage_report report = {0,};
391         const char *appid;
392         unsigned long long ticks = 0;
393
394         if (closure->current_index >= closure->max_index)
395                 return false;
396
397         if (process_get_cpu_usage(proc, &ticks) != 0) {
398                 report.usage = NAN;
399         } else {
400                 report.usage = stats_get_cpu_usage_percentage(ticks, closure->sys_stats.frame_time_inverted);
401         }
402
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;
408
409         return true;
410 }
411
412 static int _sort_by_cpu_usage(struct process *proc1, struct process *proc2)
413 {
414         unsigned long long usage1, usage2;
415         if (process_get_cpu_usage(proc1, &usage1) != 0) {
416                 return 1;
417         }
418         if (process_get_cpu_usage(proc2, &usage2) != 0) {
419                 return -1;
420         }
421         return usage2 - usage1;
422 }
423
424 static int _sort_by_memory_usage(struct process *proc1, struct process *proc2)
425 {
426         int usage1, usage2;
427         if (process_get_memory_usage(proc1, &usage1) != 0) {
428                 return 1;
429         }
430         if (process_get_memory_usage(proc2, &usage2) != 0) {
431                 return -1;
432         }
433         return usage2 - usage1;
434 }
435
436 static int _report_generator_top_report_generator_scan_apps(
437                 report_generator_top_t *generator)
438 {
439         app_info_iterator_t *iter = app_info_provider_get_running_applications();
440         int i = 0;
441
442         if (!iter) {
443                 return -1;
444         }
445
446         int count = app_info_iterator_get_count(iter);
447         if (count < 1) {
448                 app_info_iterator_free(iter);
449                 return -1;
450         }
451
452         int *pids = calloc(count, sizeof(int));
453         if (!pids) {
454                 app_info_iterator_free(iter);
455                 return -1;
456         }
457
458         do {
459                 pids[i++] = app_info_iterator_get_pid(iter);
460         }
461         while (app_info_iterator_next(iter));
462
463         app_info_iterator_free(iter);
464
465         int ret = proc_scanner_scan_pids(generator->scanner, pids, i);
466         free(pids);
467         return ret;
468 }
469
470 static int _report_generator_top_report_generator_scan_all(
471                 report_generator_top_t *generator)
472 {
473         return proc_scanner_scan(generator->scanner);
474 }
475
476 static int _report_generator_top_report_generator_scan(
477                 report_generator_top_t *generator)
478 {
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);
484                         break;
485         }
486
487         return -1;
488 }
489
490 int report_generator_generate_top_cpu_report(
491                 report_generator_top_t *generator,
492                 struct process_usage_report **report,
493                 int *n_reports)
494 {
495         ON_NULL_RETURN_VAL(generator, -1);
496         ON_NULL_RETURN_VAL(report, -1);
497         ON_NULL_RETURN_VAL(n_reports, -1);
498
499         struct report_generator_top_closure closure = {0,};
500
501         if (stats_update_system_stats(&generator->sys_stats) != 0) {
502                 return -1;
503         }
504
505         if (_report_generator_top_report_generator_scan(generator) != 0) {
506                 return -1;
507         }
508
509         if (proc_scanner_sort_processes(generator->scanner, _sort_by_cpu_usage) != 0) {
510                 return -1;
511         }
512
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) {
517                 return -1;
518         }
519
520         if (proc_scanner_foreach_process(generator->scanner, _append_to_cpu_report, &closure) != 0) {
521                 free(closure.usage_report);
522                 return -1;
523         }
524
525         *report = closure.usage_report;
526         *n_reports = closure.current_index;
527
528         return 0;
529 }
530
531 int report_generator_generate_top_memory_report(
532                 report_generator_top_t *generator,
533                 struct process_usage_report **report,
534                 int *n_reports)
535 {
536         ON_NULL_RETURN_VAL(generator, -1);
537         ON_NULL_RETURN_VAL(report, -1);
538         ON_NULL_RETURN_VAL(n_reports, -1);
539
540         struct report_generator_top_closure closure = {0,};
541
542         if (stats_update_system_stats(&generator->sys_stats) != 0) {
543                 return -1;
544         }
545
546         if (_report_generator_top_report_generator_scan(generator) != 0) {
547                 return -1;
548         }
549
550         if (proc_scanner_sort_processes(generator->scanner, _sort_by_memory_usage) != 0) {
551                 return -1;
552         }
553
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) {
558                 return -1;
559         }
560
561         if (proc_scanner_foreach_process(generator->scanner, _append_to_mem_report, &closure) != 0) {
562                 free(closure.usage_report);
563                 return -1;
564         }
565
566         *report = closure.usage_report;
567         *n_reports = closure.current_index;
568
569         return 0;
570 }