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"
28 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 static int _report_generator_read_process_ticks(int pid, struct process_ticks_snapshot *ticks);
50 static struct timespec clock_get_monotonic()
52 struct timespec ret = {0,};
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.
65 report_generator_system_t *report_generator_new_system_report_generator()
67 report_generator_system_t *ret = calloc(1, sizeof(struct report_generator_system));
71 if (procfs_read_system_cpu_usage(&ret->previous) != 0) {
72 ERR("procfs_read_system_cpu_usage failed");
80 void report_generator_free_system_generator(report_generator_system_t *generator)
88 report_generator_process_t *report_generator_new_process_report_generator(int pid)
90 ON_TRUE_RETURN_VAL(pid <= 0, NULL);
92 report_generator_process_t *ret = calloc(1, sizeof(struct report_generator_process));
96 if (_report_generator_read_process_ticks(pid, &ret->previous) != 0) {
97 ERR("_report_generator_read_process_ticks failed.");
107 void report_generator_free_process_generator(report_generator_process_t *generator)
115 report_generator_apps_t *report_generator_new_apps_report_generator(const char *app_id)
121 void report_generator_free_apps_generator(report_generator_apps_t *generator)
126 static void _calculate_system_cpu_usage(
127 struct procfs_system_cpu_usage_info *previous,
128 struct procfs_system_cpu_usage_info *current,
131 struct procfs_system_cpu_usage_info diff_ticks = { 0,};
133 diff_ticks.user = current->user > previous->user ? current->user - previous->user : 0;
134 diff_ticks.system = current->system > previous->system ? current->system - previous->system : 0;
135 diff_ticks.nice = current->nice > previous->nice ? current->nice - previous->nice : 0;
136 diff_ticks.idle = current->idle > previous->idle ? current->idle - previous->idle : 0;
137 diff_ticks.iowait = current->iowait > previous->iowait ? current->iowait - previous->iowait : 0;
138 diff_ticks.irq = current->irq > previous->irq ? current->irq - previous->irq : 0;
139 diff_ticks.softirq = current->softirq > previous->softirq ? current->softirq - previous->softirq : 0;
141 unsigned long long total = diff_ticks.user + diff_ticks.system + diff_ticks.nice +
142 diff_ticks.idle + diff_ticks.iowait + diff_ticks.irq + diff_ticks.softirq;
144 unsigned long long busy = diff_ticks.user + diff_ticks.system + diff_ticks.nice +
145 diff_ticks.irq + diff_ticks.softirq;
150 *usage = (float)busy / total;
154 int report_generator_generate_system_cpu_usage_report(
155 report_generator_system_t *generator,
157 struct system_cpu_usage_report *report)
159 ON_NULL_RETURN_VAL(generator, -1);
160 ON_TRUE_RETURN_VAL(interval < 0, -1);
161 ON_NULL_RETURN_VAL(report, -1);
163 struct procfs_system_cpu_usage_info current = {0,};
165 bool block = interval > 0;
168 if (procfs_read_system_cpu_usage(&generator->previous) != 0) {
169 ERR("procfs_read_system_cpu_usage failed.");
175 if (procfs_read_system_cpu_usage(¤t) != 0) {
176 ERR("procfs_read_system_cpu_usage failed.");
180 _calculate_system_cpu_usage(&generator->previous, ¤t, &usage);
182 report->usage = usage;
183 report->time = clock_get_monotonic().tv_sec;
185 generator->previous = current;
190 int report_generator_generate_system_memory_usage_report(
191 report_generator_system_t *generator,
192 struct system_memory_usage_report *report) {
193 ON_NULL_RETURN_VAL(generator, -1);
194 ON_NULL_RETURN_VAL(report, -1);
196 struct procfs_system_memory_usage_info mem_usage;
198 if (procfs_read_system_memory_usage(&mem_usage) != 0) {
199 ERR("procfs_read_system_memory_usage failed.");
203 report->time = clock_get_monotonic().tv_sec;
204 report->usage = (float)mem_usage.used / mem_usage.total;
210 * Calculates system average cpu usage between previous and current
213 static void _calculate_process_cpu_usage(struct process_ticks_snapshot *previous,
214 struct process_ticks_snapshot *current, int ncpus, float *usage)
216 struct process_ticks_snapshot diff;
218 diff.process_ticks = current->process_ticks > previous->process_ticks ? current->process_ticks - previous->process_ticks: 0;
219 diff.system_ticks = current->system_ticks > previous->system_ticks ? current->system_ticks - previous->system_ticks : 0;
221 if (diff.system_ticks == 0)
224 *usage = (float)diff.process_ticks / diff.system_ticks * ncpus;
227 static unsigned long long
228 _system_total_time(const struct procfs_system_cpu_usage_info *info)
230 return info->user + info->system + info->nice + info->idle;
234 _report_generator_read_process_ticks(int pid, struct process_ticks_snapshot *ticks)
236 struct procfs_system_cpu_usage_info system_ticks;
237 struct procfs_process_cpu_usage_info process_ticks;
239 if (procfs_read_process_cpu_usage(pid, &process_ticks) != 0) {
240 ERR("procfs_read_process_cpu_usage failed.");
244 if (procfs_read_system_cpu_usage(&system_ticks) != 0) {
245 ERR("procfs_read_system_cpu_usage failed.");
249 ticks->process_ticks = process_ticks.stime + process_ticks.utime;
250 ticks->system_ticks = _system_total_time(&system_ticks);
255 int report_generator_generate_process_cpu_usage_report(
256 report_generator_process_t *generator,
258 struct process_cpu_usage_report *report)
260 ON_NULL_RETURN_VAL(generator, -1);
261 ON_TRUE_RETURN_VAL(interval < 0, -1);
262 ON_NULL_RETURN_VAL(report, -1);
264 struct process_ticks_snapshot current;
265 bool block = interval > 0;
270 if (_report_generator_read_process_ticks(generator->pid, &generator->previous) != 0) {
271 ERR("Unable to update process cpu ticks.");
277 if (_report_generator_read_process_ticks(generator->pid, ¤t) != 0) {
278 ERR("Unable to update process cpu ticks.");
282 if (procfs_read_cpu_count(&ncpus) != 0) {
283 ERR("procfs_read_cpu_count failed.");
287 _calculate_process_cpu_usage(&generator->previous, ¤t, ncpus, &usage);
289 report->time = clock_get_monotonic().tv_sec;
290 report->pid = generator->pid;
291 report->usage = usage;
293 generator->previous = current;
298 int report_generator_generate_proccess_memory_usage_report(
299 report_generator_process_t *generator,
300 struct process_memory_usage_report *report)
302 ON_NULL_RETURN_VAL(generator, -1);
303 ON_NULL_RETURN_VAL(report, -1);
305 struct procfs_process_memory_usage_info mem_info;
306 struct procfs_system_memory_usage_info sys_info;
308 if (procfs_read_process_memory_usage(generator->pid, &mem_info) != 0) {
309 ERR("procfs_read_process_memory_usage failed.");
313 if (procfs_read_system_memory_usage(&sys_info) != 0) {
314 ERR("procfs_read_system_memory_usage failed.");
318 report->time = clock_get_monotonic().tv_sec;
319 report->usage = sys_info.total > 0 ? (float)mem_info.rss / sys_info.total : 0;
324 int report_generator_generate_apps_cpu_usage_report(
325 report_generator_apps_t *generator,
327 struct app_cpu_usage_report **reports)
334 int report_generator_generate_apps_memory_usage_report(
335 report_generator_apps_t *generator,
336 struct app_memory_usage_report **report)
342 int report_generator_generate_load_average_report(struct system_load_average_report *report)
344 ON_NULL_RETURN_VAL(report, -1);
346 struct procfs_load_average_info info = {0,};
348 if (procfs_read_system_load_average(&info) != 0) {
349 ERR("procfs_read_system_load_average failed.");
353 report->time = clock_get_monotonic().tv_sec;
354 report->one_min_avg = info.one_min_avg;
355 report->five_min_avg = info.five_min_avg;
356 report->fifteen_min_avg = info.fifteen_min_avg;