From: Lukasz Stanislawski Date: Wed, 27 Jun 2018 14:33:02 +0000 (+0200) Subject: report-generator: refactor X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F55%2F182755%2F8;p=apps%2Fnative%2Fttsd-worker-task.git report-generator: refactor Move the statistic calculation logic out-of report-generator. Change-Id: I4993271bc9e0dbb0dd665f48f6fe66933e7b8bc3 --- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6b258d0..37806ba 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -25,6 +25,7 @@ SET(SRCS config-deserializer.c appinfo-provider.c report-json-serializer.c + stats.c ) ADD_EXECUTABLE(${PROJECT_NAME} ${SRCS}) diff --git a/src/report-generator.c b/src/report-generator.c index 3b24dbf..a763e91 100644 --- a/src/report-generator.c +++ b/src/report-generator.c @@ -21,28 +21,22 @@ #include #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 @@ -51,7 +45,6 @@ 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() @@ -75,8 +68,8 @@ report_generator_system_t *report_generator_new_system_report_generator() 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; } @@ -100,8 +93,8 @@ report_generator_process_t *report_generator_new_process_report_generator(int pi 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; }; @@ -142,34 +135,6 @@ void report_generator_free_app_generator(report_generator_app_t *generator) 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, @@ -179,24 +144,28 @@ int report_generator_generate_system_cpu_usage_report( 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; @@ -212,61 +181,15 @@ int report_generator_generate_system_memory_usage_report( 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; } @@ -280,31 +203,28 @@ int report_generator_generate_process_cpu_usage_report( 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; @@ -321,21 +241,15 @@ int report_generator_generate_process_memory_usage_report( 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; } @@ -409,17 +323,17 @@ int report_generator_generate_load_average_report(struct system_load_average_rep { 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; } diff --git a/src/stats.c b/src/stats.c new file mode 100644 index 0000000..275e860 --- /dev/null +++ b/src/stats.c @@ -0,0 +1,158 @@ +/* + * 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; +} diff --git a/src/stats.h b/src/stats.h new file mode 100644 index 0000000..0382cf8 --- /dev/null +++ b/src/stats.h @@ -0,0 +1,125 @@ +/* + * 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 + +