report-generator: refactor
[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 <assert.h>
19 #include <string.h>
20 #include <stdbool.h>
21 #include <unistd.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
29 struct report_generator_system {
30         /** system cpu usage statistics */
31         struct stats_system previous;
32 };
33
34 struct report_generator_process
35 {
36         /** process pid */
37         int pid;
38         /** process cpu usage statistics */
39         struct stats_process previous;
40 };
41
42 struct report_generator_app
43 {
44         char *app_id;
45         report_generator_process_t *process_gen;
46 };
47
48 int _app_report_generator_setup_process_generator(report_generator_app_t *generator);
49
50 static struct timespec clock_get_monotonic()
51 {
52         struct timespec ret = {0,};
53
54         if (clock_gettime(CLOCK_MONOTONIC, &ret) != 0) {
55                 ERR("Platform do not support monotonic clock type");
56                 //TODO consider adding first init function to evaluate
57                 //if clock_gettime can be used, so calling module could
58                 //handle cases without monotonic clock gracefully.
59                 abort();
60         }
61
62         return ret;
63 }
64
65 report_generator_system_t *report_generator_new_system_report_generator()
66 {
67         report_generator_system_t *ret = calloc(1, sizeof(struct report_generator_system));
68         if (!ret)
69                 return NULL;
70
71         if (stats_update_system_stats(&ret->previous) != 0) {
72                 ERR("stats_update_system_stats failed");
73                 free(ret);
74                 return NULL;
75         }
76
77         return ret;
78 }
79
80 void report_generator_free_system_generator(report_generator_system_t *generator)
81 {
82         if (!generator)
83                 return;
84
85         free(generator);
86 }
87
88 report_generator_process_t *report_generator_new_process_report_generator(int pid)
89 {
90         ON_TRUE_RETURN_VAL(pid <= 0, NULL);
91
92         report_generator_process_t *ret = calloc(1, sizeof(struct report_generator_process));
93         if (!ret)
94                 return NULL;
95
96         if (stats_update_process_stats(pid, &ret->previous) != 0) {
97                 ERR("stats_update_process_stats failed.");
98                 free(ret);
99                 return NULL;
100         };
101
102         ret->pid = pid;
103
104         return ret;
105 }
106
107 void report_generator_free_process_generator(report_generator_process_t *generator)
108 {
109         if (!generator)
110                 return;
111
112         free(generator);
113 }
114
115 report_generator_app_t *report_generator_new_app_report_generator(const char *app_id)
116 {
117         ON_NULL_RETURN_VAL(app_id, NULL);
118
119         report_generator_app_t *ret = malloc(sizeof(struct report_generator_app));
120         if (!ret) {
121                 ERR("malloc failed");
122                 return NULL;
123         }
124
125         ret->app_id = strdup(app_id);
126         _app_report_generator_setup_process_generator(ret);
127         return ret;
128 }
129
130 void report_generator_free_app_generator(report_generator_app_t *generator)
131 {
132         if (!generator) return;
133         report_generator_free_process_generator(generator->process_gen);
134         free(generator->app_id);
135         free(generator);
136 }
137
138 int report_generator_generate_system_cpu_usage_report(
139                 report_generator_system_t *generator,
140                 int interval,
141                 struct system_cpu_usage_report *report)
142 {
143         ON_NULL_RETURN_VAL(generator, -1);
144         ON_TRUE_RETURN_VAL(interval < 0, -1);
145         ON_NULL_RETURN_VAL(report, -1);
146
147         float usage;
148         bool block = interval > 0;
149         struct stats_system current;
150
151         if (block) {
152                 if (stats_update_system_stats(&generator->previous) != 0) {
153                         ERR("stats_update_system_stats failed.");
154                         return -1;
155                 }
156                 sleep(interval);
157         }
158
159         if (stats_update_system_stats(&current) != 0) {
160                 ERR("stats_update_system_stats failed.");
161                 return -1;
162         }
163
164         if (stats_get_system_cpu_usage_average(&generator->previous, &current, &usage))
165         {
166                 ERR("stats_get_system_cpu_usage_average failed");
167                 return -1;
168         }
169
170         report->usage = usage;
171         report->time = clock_get_monotonic().tv_sec;
172
173         generator->previous = current;
174
175         return 0;
176 }
177
178 int report_generator_generate_system_memory_usage_report(
179                 report_generator_system_t *generator,
180                 struct system_memory_usage_report *report) {
181         ON_NULL_RETURN_VAL(generator, -1);
182         ON_NULL_RETURN_VAL(report, -1);
183
184         float usage;
185
186         if (stats_get_system_memory_usage(&usage) != 0) {
187                 ERR("stats_get_system_memory_usage failed.");
188                 return -1;
189         }
190
191         report->time = clock_get_monotonic().tv_sec;
192         report->usage = usage;
193
194         return 0;
195 }
196
197 int report_generator_generate_process_cpu_usage_report(
198                 report_generator_process_t *generator,
199                 int interval,
200                 struct process_cpu_usage_report *report)
201 {
202         ON_NULL_RETURN_VAL(generator, -1);
203         ON_TRUE_RETURN_VAL(interval < 0, -1);
204         ON_NULL_RETURN_VAL(report, -1);
205
206         struct stats_process current = {0,};
207         bool block = interval > 0;
208         float usage;
209
210         if (block) {
211                 if (stats_update_process_stats(generator->pid, &generator->previous) != 0) {
212                         ERR("stats_update_process_stats failed.");
213                         return -1;
214                 }
215                 sleep(interval);
216         }
217
218         if (stats_update_process_stats(generator->pid, &current) != 0) {
219                 ERR("stats_update_process_stats failed.");
220                 return -1;
221         }
222
223         if (stats_get_process_cpu_usage_average(&generator->previous, &current, &usage) ) {
224                 ERR("stats_update_process_stats failed.");
225                 return -1;
226         }
227
228         report->time = clock_get_monotonic().tv_sec;
229         report->pid = generator->pid;
230         report->usage = usage;
231
232         generator->previous = current;
233
234         return 0;
235 }
236
237 int report_generator_generate_process_memory_usage_report(
238                 report_generator_process_t *generator,
239                 struct process_memory_usage_report *report)
240 {
241         ON_NULL_RETURN_VAL(generator, -1);
242         ON_NULL_RETURN_VAL(report, -1);
243
244         float usage;
245
246         if (stats_get_process_memory_usage(generator->pid, &usage) != 0) {
247                 ERR("stats_get_process_memory_usage failed.");
248                 return -1;
249         }
250
251         report->time = clock_get_monotonic().tv_sec;
252         report->usage = usage;
253
254         return 0;
255 }
256
257 int _app_report_generator_setup_process_generator(report_generator_app_t *generator)
258 {
259         int pid = app_info_provider_find_main_pid(generator->app_id);
260         if (pid < 0) {
261                 return -1;
262         }
263
264         if (!generator->process_gen || generator->process_gen->pid != pid) {
265                 if (generator->process_gen)
266                         report_generator_free_process_generator(generator->process_gen);
267                 generator->process_gen = report_generator_new_process_report_generator(pid);
268         }
269         return 0;
270 }
271
272 int report_generator_generate_app_cpu_usage_report(
273                 report_generator_app_t *generator,
274                 int interval,
275                 struct app_cpu_usage_report *report)
276 {
277         ON_NULL_RETURN_VAL(generator, -1);
278         ON_TRUE_RETURN_VAL(interval < 0, -1);
279         ON_NULL_RETURN_VAL(report, -1);
280
281         if (_app_report_generator_setup_process_generator(generator) != 0) {
282                 ERR("_app_report_generator_setup_process_generator failed.");
283                 return -1;
284         }
285
286         if (report_generator_generate_process_cpu_usage_report(
287                                 generator->process_gen, interval, &report->process_report) != 0)
288         {
289                 ERR("report_generator_generate_process_cpu_usage_report failed.");
290                 return 0;
291         }
292
293         strncpy(report->app_id, generator->app_id, sizeof(report->app_id));
294
295         return 0;
296 }
297
298 int report_generator_generate_app_memory_usage_report(
299                 report_generator_app_t *generator,
300                 struct app_memory_usage_report *report)
301 {
302         ON_NULL_RETURN_VAL(generator, -1);
303         ON_NULL_RETURN_VAL(report, -1);
304
305         if (_app_report_generator_setup_process_generator(generator)) {
306                 ERR("_app_report_generator_setup_process_generator failed.");
307                 return -1;
308         }
309
310         if (report_generator_generate_process_memory_usage_report(
311                                 generator->process_gen, &report->process_report) != 0)
312         {
313                 ERR("report_generator_generate_process_memory_usage_report failed.");
314                 return 0;
315         }
316
317         strncpy(report->app_id, generator->app_id, sizeof(report->app_id));
318
319         return 0;
320 }
321
322 int report_generator_generate_load_average_report(struct system_load_average_report *report)
323 {
324         ON_NULL_RETURN_VAL(report, -1);
325
326         float a1, a5, a15;
327
328         if (stats_get_load_averages(&a1, &a5, &a15) != 0) {
329                 ERR("stats_get_load_averages failed.");
330                 return -1;
331         }
332
333         report->time = clock_get_monotonic().tv_sec;
334         report->one_min_avg = a1;
335         report->five_min_avg = a5;
336         report->fifteen_min_avg = a15;
337
338         return 0;
339 }
340