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"
26 #include "err-check.h"
27 #include "appinfo-provider.h"
29 struct report_generator_system {
30 /** previous read from procfs */
31 struct procfs_system_cpu_usage_info previous;
34 struct process_ticks_snapshot
36 unsigned long long system_ticks;
37 unsigned long long process_ticks;
40 struct report_generator_process
44 /** previous process stats */
45 struct process_ticks_snapshot previous;
48 struct report_generator_app
51 report_generator_process_t *process_gen;
54 static int _report_generator_read_process_ticks(int pid, struct process_ticks_snapshot *ticks);
55 int _app_report_generator_setup_process_generator(report_generator_app_t *generator);
57 static struct timespec clock_get_monotonic()
59 struct timespec ret = {0,};
61 if (clock_gettime(CLOCK_MONOTONIC, &ret) != 0) {
62 ERR("Platform do not support monotonic clock type");
63 //TODO consider adding first init function to evaluate
64 //if clock_gettime can be used, so calling module could
65 //handle cases without monotonic clock gracefully.
72 report_generator_system_t *report_generator_new_system_report_generator()
74 report_generator_system_t *ret = calloc(1, sizeof(struct report_generator_system));
78 if (procfs_read_system_cpu_usage(&ret->previous) != 0) {
79 ERR("procfs_read_system_cpu_usage failed");
87 void report_generator_free_system_generator(report_generator_system_t *generator)
95 report_generator_process_t *report_generator_new_process_report_generator(int pid)
97 ON_TRUE_RETURN_VAL(pid <= 0, NULL);
99 report_generator_process_t *ret = calloc(1, sizeof(struct report_generator_process));
103 if (_report_generator_read_process_ticks(pid, &ret->previous) != 0) {
104 ERR("_report_generator_read_process_ticks failed.");
114 void report_generator_free_process_generator(report_generator_process_t *generator)
122 report_generator_app_t *report_generator_new_app_report_generator(const char *app_id)
124 ON_NULL_RETURN_VAL(app_id, NULL);
126 report_generator_app_t *ret = malloc(sizeof(struct report_generator_app));
128 ERR("malloc failed");
132 ret->app_id = strdup(app_id);
133 _app_report_generator_setup_process_generator(ret);
137 void report_generator_free_app_generator(report_generator_app_t *generator)
139 if (!generator) return;
140 report_generator_free_process_generator(generator->process_gen);
141 free(generator->app_id);
145 static void _calculate_system_cpu_usage(
146 struct procfs_system_cpu_usage_info *previous,
147 struct procfs_system_cpu_usage_info *current,
150 struct procfs_system_cpu_usage_info diff_ticks = { 0,};
152 diff_ticks.user = current->user > previous->user ? current->user - previous->user : 0;
153 diff_ticks.system = current->system > previous->system ? current->system - previous->system : 0;
154 diff_ticks.nice = current->nice > previous->nice ? current->nice - previous->nice : 0;
155 diff_ticks.idle = current->idle > previous->idle ? current->idle - previous->idle : 0;
156 diff_ticks.iowait = current->iowait > previous->iowait ? current->iowait - previous->iowait : 0;
157 diff_ticks.irq = current->irq > previous->irq ? current->irq - previous->irq : 0;
158 diff_ticks.softirq = current->softirq > previous->softirq ? current->softirq - previous->softirq : 0;
160 unsigned long long total = diff_ticks.user + diff_ticks.system + diff_ticks.nice +
161 diff_ticks.idle + diff_ticks.iowait + diff_ticks.irq + diff_ticks.softirq;
163 unsigned long long busy = diff_ticks.user + diff_ticks.system + diff_ticks.nice +
164 diff_ticks.irq + diff_ticks.softirq;
169 *usage = (float)busy / total;
173 int report_generator_generate_system_cpu_usage_report(
174 report_generator_system_t *generator,
176 struct system_cpu_usage_report *report)
178 ON_NULL_RETURN_VAL(generator, -1);
179 ON_TRUE_RETURN_VAL(interval < 0, -1);
180 ON_NULL_RETURN_VAL(report, -1);
182 struct procfs_system_cpu_usage_info current = {0,};
184 bool block = interval > 0;
187 if (procfs_read_system_cpu_usage(&generator->previous) != 0) {
188 ERR("procfs_read_system_cpu_usage failed.");
194 if (procfs_read_system_cpu_usage(¤t) != 0) {
195 ERR("procfs_read_system_cpu_usage failed.");
199 _calculate_system_cpu_usage(&generator->previous, ¤t, &usage);
201 report->usage = usage;
202 report->time = clock_get_monotonic().tv_sec;
204 generator->previous = current;
209 int report_generator_generate_system_memory_usage_report(
210 report_generator_system_t *generator,
211 struct system_memory_usage_report *report) {
212 ON_NULL_RETURN_VAL(generator, -1);
213 ON_NULL_RETURN_VAL(report, -1);
215 struct procfs_system_memory_usage_info mem_usage;
217 if (procfs_read_system_memory_usage(&mem_usage) != 0) {
218 ERR("procfs_read_system_memory_usage failed.");
222 report->time = clock_get_monotonic().tv_sec;
223 report->usage = (float)mem_usage.used / mem_usage.total;
229 * Calculates system average cpu usage between previous and current
232 static void _calculate_process_cpu_usage(struct process_ticks_snapshot *previous,
233 struct process_ticks_snapshot *current, int ncpus, float *usage)
235 struct process_ticks_snapshot diff;
237 diff.process_ticks = current->process_ticks > previous->process_ticks ? current->process_ticks - previous->process_ticks: 0;
238 diff.system_ticks = current->system_ticks > previous->system_ticks ? current->system_ticks - previous->system_ticks : 0;
240 if (diff.system_ticks == 0)
243 *usage = (float)diff.process_ticks / diff.system_ticks * ncpus;
246 static unsigned long long
247 _system_total_time(const struct procfs_system_cpu_usage_info *info)
249 return info->user + info->system + info->nice + info->idle;
253 _report_generator_read_process_ticks(int pid, struct process_ticks_snapshot *ticks)
255 struct procfs_system_cpu_usage_info system_ticks;
256 struct procfs_process_cpu_usage_info process_ticks;
258 if (procfs_read_process_cpu_usage(pid, &process_ticks) != 0) {
259 ERR("procfs_read_process_cpu_usage failed.");
263 if (procfs_read_system_cpu_usage(&system_ticks) != 0) {
264 ERR("procfs_read_system_cpu_usage failed.");
268 ticks->process_ticks = process_ticks.stime + process_ticks.utime;
269 ticks->system_ticks = _system_total_time(&system_ticks);
274 int report_generator_generate_process_cpu_usage_report(
275 report_generator_process_t *generator,
277 struct process_cpu_usage_report *report)
279 ON_NULL_RETURN_VAL(generator, -1);
280 ON_TRUE_RETURN_VAL(interval < 0, -1);
281 ON_NULL_RETURN_VAL(report, -1);
283 struct process_ticks_snapshot current;
284 bool block = interval > 0;
289 if (_report_generator_read_process_ticks(generator->pid, &generator->previous) != 0) {
290 ERR("Unable to update process cpu ticks.");
296 if (_report_generator_read_process_ticks(generator->pid, ¤t) != 0) {
297 ERR("Unable to update process cpu ticks.");
301 if (procfs_read_cpu_count(&ncpus) != 0) {
302 ERR("procfs_read_cpu_count failed.");
306 _calculate_process_cpu_usage(&generator->previous, ¤t, ncpus, &usage);
308 report->time = clock_get_monotonic().tv_sec;
309 report->pid = generator->pid;
310 report->usage = usage;
312 generator->previous = current;
317 int report_generator_generate_process_memory_usage_report(
318 report_generator_process_t *generator,
319 struct process_memory_usage_report *report)
321 ON_NULL_RETURN_VAL(generator, -1);
322 ON_NULL_RETURN_VAL(report, -1);
324 struct procfs_process_memory_usage_info mem_info;
325 struct procfs_system_memory_usage_info sys_info;
327 if (procfs_read_process_memory_usage(generator->pid, &mem_info) != 0) {
328 ERR("procfs_read_process_memory_usage failed.");
332 if (procfs_read_system_memory_usage(&sys_info) != 0) {
333 ERR("procfs_read_system_memory_usage failed.");
337 report->time = clock_get_monotonic().tv_sec;
338 report->usage = sys_info.total > 0 ? (float)mem_info.rss / sys_info.total : 0;
343 int _app_report_generator_setup_process_generator(report_generator_app_t *generator)
345 int pid = app_info_provider_find_main_pid(generator->app_id);
350 if (!generator->process_gen || generator->process_gen->pid != pid) {
351 if (generator->process_gen)
352 report_generator_free_process_generator(generator->process_gen);
353 generator->process_gen = report_generator_new_process_report_generator(pid);
358 int report_generator_generate_app_cpu_usage_report(
359 report_generator_app_t *generator,
361 struct app_cpu_usage_report *report)
363 ON_NULL_RETURN_VAL(generator, -1);
364 ON_TRUE_RETURN_VAL(interval < 0, -1);
365 ON_NULL_RETURN_VAL(report, -1);
367 if (_app_report_generator_setup_process_generator(generator) != 0) {
368 ERR("_app_report_generator_setup_process_generator failed.");
372 if (report_generator_generate_process_cpu_usage_report(
373 generator->process_gen, interval, &report->process_report) != 0)
375 ERR("report_generator_generate_process_cpu_usage_report failed.");
379 strncpy(report->app_id, generator->app_id, sizeof(report->app_id));
384 int report_generator_generate_app_memory_usage_report(
385 report_generator_app_t *generator,
386 struct app_memory_usage_report *report)
388 ON_NULL_RETURN_VAL(generator, -1);
389 ON_NULL_RETURN_VAL(report, -1);
391 if (_app_report_generator_setup_process_generator(generator)) {
392 ERR("_app_report_generator_setup_process_generator failed.");
396 if (report_generator_generate_process_memory_usage_report(
397 generator->process_gen, &report->process_report) != 0)
399 ERR("report_generator_generate_process_memory_usage_report failed.");
403 strncpy(report->app_id, generator->app_id, sizeof(report->app_id));
408 int report_generator_generate_load_average_report(struct system_load_average_report *report)
410 ON_NULL_RETURN_VAL(report, -1);
412 struct procfs_load_average_info info = {0,};
414 if (procfs_read_system_load_average(&info) != 0) {
415 ERR("procfs_read_system_load_average failed.");
419 report->time = clock_get_monotonic().tv_sec;
420 report->one_min_avg = info.one_min_avg;
421 report->five_min_avg = info.five_min_avg;
422 report->fifteen_min_avg = info.fifteen_min_avg;