#include <unistd.h>
#include "report-generator.h"
-#include "procfs.h"
#include "log.h"
#include "err-check.h"
#include "appinfo-provider.h"
+#include "stats.h"
struct report_generator_system {
- /** previous read from procfs */
- struct procfs_system_cpu_usage_info previous;
-};
-
-struct process_ticks_snapshot
-{
- unsigned long long system_ticks;
- unsigned long long process_ticks;
+ /** system cpu usage statistics */
+ struct stats_system previous;
};
struct report_generator_process
{
/** process pid */
int pid;
- /** previous process stats */
- struct process_ticks_snapshot previous;
+ /** process cpu usage statistics */
+ struct stats_process previous;
};
struct report_generator_app
report_generator_process_t *process_gen;
};
-static int _report_generator_read_process_ticks(int pid, struct process_ticks_snapshot *ticks);
int _app_report_generator_setup_process_generator(report_generator_app_t *generator);
static struct timespec clock_get_monotonic()
if (!ret)
return NULL;
- if (procfs_read_system_cpu_usage(&ret->previous) != 0) {
- ERR("procfs_read_system_cpu_usage failed");
+ if (stats_update_system_stats(&ret->previous) != 0) {
+ ERR("stats_update_system_stats failed");
free(ret);
return NULL;
}
if (!ret)
return NULL;
- if (_report_generator_read_process_ticks(pid, &ret->previous) != 0) {
- ERR("_report_generator_read_process_ticks failed.");
+ if (stats_update_process_stats(pid, &ret->previous) != 0) {
+ ERR("stats_update_process_stats failed.");
free(ret);
return NULL;
};
free(generator);
}
-static void _calculate_system_cpu_usage(
- struct procfs_system_cpu_usage_info *previous,
- struct procfs_system_cpu_usage_info *current,
- float *usage)
-{
- struct procfs_system_cpu_usage_info diff_ticks = { 0,};
-
- diff_ticks.user = current->user > previous->user ? current->user - previous->user : 0;
- diff_ticks.system = current->system > previous->system ? current->system - previous->system : 0;
- diff_ticks.nice = current->nice > previous->nice ? current->nice - previous->nice : 0;
- diff_ticks.idle = current->idle > previous->idle ? current->idle - previous->idle : 0;
- diff_ticks.iowait = current->iowait > previous->iowait ? current->iowait - previous->iowait : 0;
- diff_ticks.irq = current->irq > previous->irq ? current->irq - previous->irq : 0;
- diff_ticks.softirq = current->softirq > previous->softirq ? current->softirq - previous->softirq : 0;
-
- unsigned long long total = diff_ticks.user + diff_ticks.system + diff_ticks.nice +
- diff_ticks.idle + diff_ticks.iowait + diff_ticks.irq + diff_ticks.softirq;
-
- unsigned long long busy = diff_ticks.user + diff_ticks.system + diff_ticks.nice +
- diff_ticks.irq + diff_ticks.softirq;
-
- if (total == 0) {
- *usage = 0;
- } else {
- *usage = (float)busy / total;
- }
-}
-
int report_generator_generate_system_cpu_usage_report(
report_generator_system_t *generator,
int interval,
ON_TRUE_RETURN_VAL(interval < 0, -1);
ON_NULL_RETURN_VAL(report, -1);
- struct procfs_system_cpu_usage_info current = {0,};
float usage;
bool block = interval > 0;
+ struct stats_system current;
if (block) {
- if (procfs_read_system_cpu_usage(&generator->previous) != 0) {
- ERR("procfs_read_system_cpu_usage failed.");
+ if (stats_update_system_stats(&generator->previous) != 0) {
+ ERR("stats_update_system_stats failed.");
return -1;
}
sleep(interval);
}
- if (procfs_read_system_cpu_usage(¤t) != 0) {
- ERR("procfs_read_system_cpu_usage failed.");
+ if (stats_update_system_stats(¤t) != 0) {
+ ERR("stats_update_system_stats failed.");
return -1;
}
- _calculate_system_cpu_usage(&generator->previous, ¤t, &usage);
+ if (stats_get_system_cpu_usage_average(&generator->previous, ¤t, &usage))
+ {
+ ERR("stats_get_system_cpu_usage_average failed");
+ return -1;
+ }
report->usage = usage;
report->time = clock_get_monotonic().tv_sec;
ON_NULL_RETURN_VAL(generator, -1);
ON_NULL_RETURN_VAL(report, -1);
- struct procfs_system_memory_usage_info mem_usage;
+ float usage;
- if (procfs_read_system_memory_usage(&mem_usage) != 0) {
- ERR("procfs_read_system_memory_usage failed.");
+ if (stats_get_system_memory_usage(&usage) != 0) {
+ ERR("stats_get_system_memory_usage failed.");
return -1;
}
report->time = clock_get_monotonic().tv_sec;
- report->usage = (float)mem_usage.used / mem_usage.total;
-
- return 0;
-}
-
-/**
- * Calculates system average cpu usage between previous and current
- * snapshots.
- */
-static void _calculate_process_cpu_usage(struct process_ticks_snapshot *previous,
- struct process_ticks_snapshot *current, int ncpus, float *usage)
-{
- struct process_ticks_snapshot diff;
-
- diff.process_ticks = current->process_ticks > previous->process_ticks ? current->process_ticks - previous->process_ticks: 0;
- diff.system_ticks = current->system_ticks > previous->system_ticks ? current->system_ticks - previous->system_ticks : 0;
-
- if (diff.system_ticks == 0)
- *usage = 0;
- else
- *usage = (float)diff.process_ticks / diff.system_ticks * ncpus;
-}
-
-static unsigned long long
-_system_total_time(const struct procfs_system_cpu_usage_info *info)
-{
- return info->user + info->system + info->nice + info->idle;
-}
-
-static int
-_report_generator_read_process_ticks(int pid, struct process_ticks_snapshot *ticks)
-{
- struct procfs_system_cpu_usage_info system_ticks;
- struct procfs_process_cpu_usage_info process_ticks;
-
- if (procfs_read_process_cpu_usage(pid, &process_ticks) != 0) {
- ERR("procfs_read_process_cpu_usage failed.");
- return -1;
- }
-
- if (procfs_read_system_cpu_usage(&system_ticks) != 0) {
- ERR("procfs_read_system_cpu_usage failed.");
- return -1;
- }
-
- ticks->process_ticks = process_ticks.stime + process_ticks.utime;
- ticks->system_ticks = _system_total_time(&system_ticks);
+ report->usage = usage;
return 0;
}
ON_TRUE_RETURN_VAL(interval < 0, -1);
ON_NULL_RETURN_VAL(report, -1);
- struct process_ticks_snapshot current;
+ struct stats_process current = {0,};
bool block = interval > 0;
float usage;
- int ncpus;
if (block) {
- if (_report_generator_read_process_ticks(generator->pid, &generator->previous) != 0) {
- ERR("Unable to update process cpu ticks.");
+ if (stats_update_process_stats(generator->pid, &generator->previous) != 0) {
+ ERR("stats_update_process_stats failed.");
return -1;
}
sleep(interval);
}
- if (_report_generator_read_process_ticks(generator->pid, ¤t) != 0) {
- ERR("Unable to update process cpu ticks.");
+ if (stats_update_process_stats(generator->pid, ¤t) != 0) {
+ ERR("stats_update_process_stats failed.");
return -1;
}
- if (procfs_read_cpu_count(&ncpus) != 0) {
- ERR("procfs_read_cpu_count failed.");
+ if (stats_get_process_cpu_usage_average(&generator->previous, ¤t, &usage) ) {
+ ERR("stats_update_process_stats failed.");
return -1;
}
- _calculate_process_cpu_usage(&generator->previous, ¤t, ncpus, &usage);
-
report->time = clock_get_monotonic().tv_sec;
report->pid = generator->pid;
report->usage = usage;
ON_NULL_RETURN_VAL(generator, -1);
ON_NULL_RETURN_VAL(report, -1);
- struct procfs_process_memory_usage_info mem_info;
- struct procfs_system_memory_usage_info sys_info;
-
- if (procfs_read_process_memory_usage(generator->pid, &mem_info) != 0) {
- ERR("procfs_read_process_memory_usage failed.");
- return -1;
- }
+ float usage;
- if (procfs_read_system_memory_usage(&sys_info) != 0) {
- ERR("procfs_read_system_memory_usage failed.");
+ if (stats_get_process_memory_usage(generator->pid, &usage) != 0) {
+ ERR("stats_get_process_memory_usage failed.");
return -1;
}
report->time = clock_get_monotonic().tv_sec;
- report->usage = sys_info.total > 0 ? (float)mem_info.rss / sys_info.total : 0;
+ report->usage = usage;
return 0;
}
{
ON_NULL_RETURN_VAL(report, -1);
- struct procfs_load_average_info info = {0,};
+ float a1, a5, a15;
- if (procfs_read_system_load_average(&info) != 0) {
- ERR("procfs_read_system_load_average failed.");
+ if (stats_get_load_averages(&a1, &a5, &a15) != 0) {
+ ERR("stats_get_load_averages failed.");
return -1;
}
report->time = clock_get_monotonic().tv_sec;
- report->one_min_avg = info.one_min_avg;
- report->five_min_avg = info.five_min_avg;
- report->fifteen_min_avg = info.fifteen_min_avg;
+ report->one_min_avg = a1;
+ report->five_min_avg = a5;
+ report->fifteen_min_avg = a15;
return 0;
}
--- /dev/null
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Flora License, Version 1.1 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "stats.h"
+#include "procfs.h"
+#include "err-check.h"
+
+static int ncpus;
+
+int stats_get_system_cpu_usage_average(struct stats_system *previous, struct stats_system *current, float *usage)
+{
+ struct stats_system diff;
+
+ diff.busy_ticks = current->busy_ticks > previous->busy_ticks ? current->busy_ticks - previous->busy_ticks : 0;
+
+ diff.total_ticks = current->total_ticks > previous->total_ticks ? current->total_ticks - previous->total_ticks : 0;
+
+ if (diff.total_ticks == 0) {
+ *usage = 0;
+ } else {
+ *usage = (float)diff.busy_ticks / diff.total_ticks;
+ }
+
+ return 0;
+}
+
+int stats_update_system_stats(struct stats_system *sys)
+{
+ ON_NULL_RETURN_VAL(sys, -1);
+
+ struct procfs_system_cpu_usage_info info;
+
+ if (procfs_read_system_cpu_usage(&info) != 0) {
+ return -1;
+ }
+
+ sys->busy_ticks = info.user + info.system + info.nice + info.irq + info.softirq;
+ sys->total_ticks = info.user + info.system + info.nice + info.irq + info.softirq + info.idle + info.iowait;
+
+ return 0;
+}
+
+int stats_get_system_memory_usage(float *usage)
+{
+ ON_NULL_RETURN_VAL(usage, -1);
+
+ struct procfs_system_memory_usage_info info;
+
+ if (procfs_read_system_memory_usage(&info) != 0) {
+ ERR("procfs_read_system_memory_usage failed.");
+ return -1;
+ }
+
+ *usage = (float)info.used / info.total;
+
+ return 0;
+}
+
+int stats_update_process_stats(int pid, struct stats_process *stats)
+{
+ ON_TRUE_RETURN_VAL(pid < 0, -1);
+ ON_NULL_RETURN_VAL(stats, -1);
+
+ struct procfs_process_cpu_usage_info proc_info;
+ struct procfs_system_cpu_usage_info sys_info;
+
+ if (procfs_read_process_cpu_usage(pid, &proc_info) != 0) {
+ ERR("procfs_read_process_cpu_usage failed.");
+ return -1;
+ }
+
+ if (procfs_read_system_cpu_usage(&sys_info) != 0) {
+ ERR("procfs_read_system_cpu_usage failed.");
+ return -1;
+ }
+
+ stats->process_ticks = proc_info.stime + proc_info.utime;
+ stats->system_ticks = sys_info.user + sys_info.system + sys_info.nice + sys_info.idle;
+
+
+ return 0;
+}
+
+int stats_get_process_cpu_usage_average(struct stats_process *previous, struct stats_process *current, float *usage)
+{
+ struct stats_process diff;
+
+ diff.process_ticks = current->process_ticks > previous->process_ticks ? current->process_ticks - previous->process_ticks: 0;
+ diff.system_ticks = current->system_ticks > previous->system_ticks ? current->system_ticks - previous->system_ticks : 0;
+
+ if (diff.system_ticks == 0)
+ *usage = 0;
+ else
+ *usage = (float)diff.process_ticks / diff.system_ticks * ncpus;
+
+ return 0;
+}
+
+int stats_get_process_memory_usage(int pid, float *usage)
+{
+ ON_TRUE_RETURN_VAL(pid < 0, -1);
+ ON_NULL_RETURN_VAL(usage, -1);
+
+ struct procfs_process_memory_usage_info mem_info;
+ struct procfs_system_memory_usage_info sys_info;
+
+ if (procfs_read_process_memory_usage(pid, &mem_info) != 0) {
+ ERR("procfs_read_process_memory_usage failed.");
+ return -1;
+ }
+
+ if (procfs_read_system_memory_usage(&sys_info) != 0) {
+ ERR("procfs_read_system_memory_usage failed.");
+ return -1;
+ }
+
+ *usage = sys_info.total > 0 ? (float)mem_info.rss / sys_info.total : 0;
+
+ return 0;
+}
+
+int stats_get_load_averages(float *a1, float *a5, float *a15)
+{
+ struct procfs_load_average_info info;
+
+ if (procfs_read_system_load_average(&info) != 0) {
+ ERR("procfs_read_system_load_average failed.");
+ return -1;
+ }
+
+ if (a1) *a1 = info.one_min_avg;
+ if (a5) *a5 = info.five_min_avg;
+ if (a15) *a15 = info.fifteen_min_avg;
+
+ return 0;
+}
+
+int stats_init()
+{
+ if (procfs_read_cpu_count(&ncpus) != 0) {
+ ERR("procfs_read_cpu_count failed.");
+ return -1;
+ }
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Flora License, Version 1.1 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _STATS_H_
+#define _STATS_H_
+
+/**
+ * @brief System's statistics snapshot
+ */
+struct stats_system
+{
+ unsigned long long busy_ticks;
+ unsigned long long total_ticks;
+};
+
+/**
+ * @brief Process's statistics snapshot
+ */
+struct stats_process
+{
+ unsigned long long system_ticks;
+ unsigned long long process_ticks;
+};
+
+/**
+ * @brief Initializes stats module.
+ *
+ * @return: 0 on success, other value on error.
+ *
+ * @note function should be called before any other function call from this
+ * module.
+ */
+int stats_init();
+
+/**
+ * @brief Calculates average cpu usage between two stats snapshots.
+ *
+ * @param[in] previous the stats snapshots taken before current
+ * @param[in] current the stats snapshots taken after previous
+ * @param[out] usage the cpu usage as percent.
+ *
+ * @return: 0 on success, other value on error
+ */
+int stats_get_system_cpu_usage_average(struct stats_system *previous, struct stats_system *current, float *usage);
+
+/**
+ * @brief Takes system statistics snapshot.
+ *
+ * @param[out] stats System's statistics snapshot.
+ *
+ * @return: 0 on success, other value on error
+ */
+int stats_update_system_stats(struct stats_system *stats);
+
+/**
+ * @brief Calculates system memory usage.
+ *
+ * @param[out] usage the memory usage as percent.
+ *
+ * @return: 0 on success, other value on error
+ */
+int stats_get_system_memory_usage(float *usage);
+
+/**
+ * @brief Takes process statistics snapshot.
+ *
+ * @param[in] pid the process id.
+ * @param[out] stats process statistcs.
+ *
+ * @return: 0 on success, other value on error
+ */
+int stats_update_process_stats(int pid, struct stats_process *stats);
+
+/**
+ * @brief Calculates average process cpu usage between two stats snapshots.
+ *
+ * @param[in] previous the stats snapshots taken before current
+ * @param[in] current the stats snapshots taken after previous
+ * @param[out] usage the cpu usage as percent. It may be greater then 100% in
+ * case of multithreaded applications.
+ *
+ * @note in case when process has 2 threads which runs tight loop, the function
+ * will report 200% usage.
+ *
+ * @return: 0 on success, other value on error
+ */
+int stats_get_process_cpu_usage_average(struct stats_process *previous, struct stats_process *current, float *usage);
+
+/**
+ * @brief Calculates process memory usage.
+ *
+ * @param[in] pid the process id.
+ * @param[out] usage process memory usage.
+ *
+ * @return: 0 on success, other value on error
+ */
+int stats_get_process_memory_usage(int pid, float *usage);
+
+/**
+ * @brief Gets system load averages stats.
+ *
+ * @param[out] a1 one minute average.
+ * @param[out] a5 five minute average.
+ * @param[out] a15 fifteen minute average.
+ *
+ * @return: 0 on success, other value on error
+ */
+int stats_get_load_averages(float *a1, float *a5, float *a15);
+
+#endif
+
+