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->usage = (float)mem_usage.used / mem_usage.total;
199 * Calculates system average cpu usage between previous and current
202 static void _calculate_process_cpu_usage(struct process_ticks_snapshot *previous,
203 struct process_ticks_snapshot *current, int ncpus, float *usage)
205 struct process_ticks_snapshot diff;
207 diff.process_ticks = current->process_ticks > previous->process_ticks ? current->process_ticks - previous->process_ticks: 0;
208 diff.system_ticks = current->system_ticks > previous->system_ticks ? current->system_ticks - previous->system_ticks : 0;
210 if (diff.system_ticks == 0)
213 *usage = (float)diff.process_ticks / diff.system_ticks * ncpus;
216 static unsigned long long
217 _system_total_time(const struct procfs_system_cpu_usage_info *info)
219 return info->user + info->system + info->nice + info->idle;
223 _report_generator_read_process_ticks(int pid, struct process_ticks_snapshot *ticks)
225 struct procfs_system_cpu_usage_info system_ticks;
226 struct procfs_process_cpu_usage_info process_ticks;
228 if (procfs_read_process_cpu_usage(pid, &process_ticks) != 0) {
229 ERR("procfs_read_process_cpu_usage failed.");
233 if (procfs_read_system_cpu_usage(&system_ticks) != 0) {
234 ERR("procfs_read_system_cpu_usage failed.");
238 ticks->process_ticks = process_ticks.stime + process_ticks.utime;
239 ticks->system_ticks = _system_total_time(&system_ticks);
244 int report_generator_generate_process_cpu_usage_report(
245 report_generator_process_t *generator,
247 struct process_cpu_usage_report *report)
249 ON_NULL_RETURN_VAL(generator, -1);
250 ON_TRUE_RETURN_VAL(interval < 0, -1);
251 ON_NULL_RETURN_VAL(report, -1);
253 struct process_ticks_snapshot current;
254 bool block = interval > 0;
259 if (_report_generator_read_process_ticks(generator->pid, &generator->previous) != 0) {
260 ERR("Unable to update process cpu ticks.");
266 if (_report_generator_read_process_ticks(generator->pid, ¤t) != 0) {
267 ERR("Unable to update process cpu ticks.");
271 if (procfs_read_cpu_count(&ncpus) != 0) {
272 ERR("procfs_read_cpu_count failed.");
276 _calculate_process_cpu_usage(&generator->previous, ¤t, ncpus, &usage);
278 report->time = clock_get_monotonic().tv_sec;
279 report->pid = generator->pid;
280 report->usage = usage;
282 generator->previous = current;
287 int report_generator_generate_proccess_memory_usage_report(
288 report_generator_process_t *generator,
289 struct process_memory_usage_report *report)
291 ON_NULL_RETURN_VAL(generator, -1);
292 ON_NULL_RETURN_VAL(report, -1);
294 struct procfs_process_memory_usage_info mem_info;
295 struct procfs_system_memory_usage_info sys_info;
297 if (procfs_read_process_memory_usage(generator->pid, &mem_info) != 0) {
298 ERR("procfs_read_process_memory_usage failed.");
302 if (procfs_read_system_memory_usage(&sys_info) != 0) {
303 ERR("procfs_read_system_memory_usage failed.");
307 report->time = clock_get_monotonic().tv_sec;
308 report->usage = sys_info.total > 0 ? (float)mem_info.rss / sys_info.total : 0;
313 int report_generator_generate_load_average_report(struct system_load_average_report *report)
315 ON_NULL_RETURN_VAL(report, -1);
317 struct procfs_load_average_info info = {0,};
319 if (procfs_read_system_load_average(&info) != 0) {
320 ERR("procfs_read_system_load_average failed.");
324 report->time = clock_get_monotonic().tv_sec;
325 report->one_min_avg = info.one_min_avg;
326 report->five_min_avg = info.five_min_avg;
327 report->fifteen_min_avg = info.fifteen_min_avg;