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 static void _calculate_system_cpu_usage(
116 struct procfs_system_cpu_usage_info *previous,
117 struct procfs_system_cpu_usage_info *current,
120 struct procfs_system_cpu_usage_info diff_ticks = { 0,};
122 diff_ticks.user = current->user > previous->user ? current->user - previous->user : 0;
123 diff_ticks.system = current->system > previous->system ? current->system - previous->system : 0;
124 diff_ticks.nice = current->nice > previous->nice ? current->nice - previous->nice : 0;
125 diff_ticks.idle = current->idle > previous->idle ? current->idle - previous->idle : 0;
126 diff_ticks.iowait = current->iowait > previous->iowait ? current->iowait - previous->iowait : 0;
127 diff_ticks.irq = current->irq > previous->irq ? current->irq - previous->irq : 0;
128 diff_ticks.softirq = current->softirq > previous->softirq ? current->softirq - previous->softirq : 0;
130 unsigned long long total = diff_ticks.user + diff_ticks.system + diff_ticks.nice +
131 diff_ticks.idle + diff_ticks.iowait + diff_ticks.irq + diff_ticks.softirq;
133 unsigned long long busy = diff_ticks.user + diff_ticks.system + diff_ticks.nice +
134 diff_ticks.irq + diff_ticks.softirq;
139 *usage = (float)busy / total;
143 int report_generator_generate_system_cpu_usage_report(
144 report_generator_system_t *generator,
146 struct system_cpu_usage_report *report)
148 ON_NULL_RETURN_VAL(generator, -1);
149 ON_TRUE_RETURN_VAL(interval < 0, -1);
150 ON_NULL_RETURN_VAL(report, -1);
152 struct procfs_system_cpu_usage_info current = {0,};
154 bool block = interval > 0;
157 if (procfs_read_system_cpu_usage(&generator->previous) != 0) {
158 ERR("procfs_read_system_cpu_usage failed.");
164 if (procfs_read_system_cpu_usage(¤t) != 0) {
165 ERR("procfs_read_system_cpu_usage failed.");
169 _calculate_system_cpu_usage(&generator->previous, ¤t, &usage);
171 report->usage = usage;
172 report->time = clock_get_monotonic().tv_sec;
174 generator->previous = current;
179 int report_generator_generate_system_memory_usage_report(
180 report_generator_system_t *generator,
181 struct system_memory_usage_report *report) {
182 ON_NULL_RETURN_VAL(generator, -1);
183 ON_NULL_RETURN_VAL(report, -1);
185 struct procfs_system_memory_usage_info mem_usage;
187 if (procfs_read_system_memory_usage(&mem_usage) != 0) {
188 ERR("procfs_read_system_memory_usage failed.");
192 report->time = clock_get_monotonic().tv_sec;
193 report->total = mem_usage.total;
194 report->used = mem_usage.used;
195 report->free = mem_usage.free;
201 * Calculates system average cpu usage between previous and current
204 static void _calculate_process_cpu_usage(struct process_ticks_snapshot *previous,
205 struct process_ticks_snapshot *current, int ncpus, float *usage)
207 struct process_ticks_snapshot diff;
209 diff.process_ticks = current->process_ticks > previous->process_ticks ? current->process_ticks - previous->process_ticks: 0;
210 diff.system_ticks = current->system_ticks > previous->system_ticks ? current->system_ticks - previous->system_ticks : 0;
212 if (diff.system_ticks == 0)
215 *usage = (float)diff.process_ticks / diff.system_ticks * ncpus;
218 static unsigned long long
219 _system_total_time(const struct procfs_system_cpu_usage_info *info)
221 return info->user + info->system + info->nice + info->idle;
225 _report_generator_read_process_ticks(int pid, struct process_ticks_snapshot *ticks)
227 struct procfs_system_cpu_usage_info system_ticks;
228 struct procfs_process_cpu_usage_info process_ticks;
230 if (procfs_read_process_cpu_usage(pid, &process_ticks) != 0) {
231 ERR("procfs_read_process_cpu_usage failed.");
235 if (procfs_read_system_cpu_usage(&system_ticks) != 0) {
236 ERR("procfs_read_system_cpu_usage failed.");
240 ticks->process_ticks = process_ticks.stime + process_ticks.utime;
241 ticks->system_ticks = _system_total_time(&system_ticks);
246 int report_generator_generate_process_cpu_usage_report(
247 report_generator_process_t *generator,
249 struct process_cpu_usage_report *report)
251 ON_NULL_RETURN_VAL(generator, -1);
252 ON_TRUE_RETURN_VAL(interval < 0, -1);
253 ON_NULL_RETURN_VAL(report, -1);
255 struct process_ticks_snapshot current;
256 bool block = interval > 0;
261 if (_report_generator_read_process_ticks(generator->pid, &generator->previous) != 0) {
262 ERR("Unable to update process cpu ticks.");
268 if (_report_generator_read_process_ticks(generator->pid, ¤t) != 0) {
269 ERR("Unable to update process cpu ticks.");
273 if (procfs_read_cpu_count(&ncpus) != 0) {
274 ERR("procfs_read_cpu_count failed.");
278 _calculate_process_cpu_usage(&generator->previous, ¤t, ncpus, &usage);
280 report->time = clock_get_monotonic().tv_sec;
281 report->pid = generator->pid;
282 report->usage = usage;
284 generator->previous = current;
289 int report_generator_generate_proccess_memory_usage_report(
290 report_generator_process_t *generator,
291 struct process_memory_usage_report *report)
293 ON_NULL_RETURN_VAL(generator, -1);
294 ON_NULL_RETURN_VAL(report, -1);
296 struct procfs_process_memory_usage_info mem_info;
297 struct procfs_system_memory_usage_info sys_info;
299 if (procfs_read_process_memory_usage(generator->pid, &mem_info) != 0) {
300 ERR("procfs_read_process_memory_usage failed.");
304 if (procfs_read_system_memory_usage(&sys_info) != 0) {
305 ERR("procfs_read_system_memory_usage failed.");
309 report->time = clock_get_monotonic().tv_sec;
310 report->usage = sys_info.total > 0 ? (float)mem_info.rss / sys_info.total : 0;
315 int report_generator_generate_load_average_report(struct system_load_average_report *report)
317 ON_NULL_RETURN_VAL(report, -1);
319 struct procfs_load_average_info info = {0,};
321 if (procfs_read_system_load_average(&info) != 0) {
322 ERR("procfs_read_system_load_average failed.");
326 report->time = clock_get_monotonic().tv_sec;
327 report->one_min_avg = info.one_min_avg;
328 report->five_min_avg = info.five_min_avg;
329 report->fifteen_min_avg = info.fifteen_min_avg;