To get the CPU usage of the specific process, new functions are added.
Change-Id: Ib3eadfe63e4da36464d9c4f52b4a742cad193715
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 "aul/include/aul_cpu_monitor.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <new>
+#include <string>
+
+#include "aul/aul_api.h"
+#include "aul/common/log_private.hh"
+#include "aul/include/aul.h"
+
+namespace {
+
+class CpuTimes {
+ public:
+ CpuTimes(pid_t pid) : pid_(pid) {}
+
+ ~CpuTimes() {}
+
+ int Update() {
+ if (UpdateTotalCpuTime() != 0)
+ return -1;
+
+ return UpdateProcessCpuTime();
+ }
+
+ double CalculateCpuUsage() {
+ auto total_diff = current_total_time_ - previous_total_time_;
+ if (total_diff == 0) return 0.0f;
+
+ auto process_diff = current_process_time_ - previous_process_time_;
+ return (static_cast<double>(process_diff) / total_diff) * 100.0;
+ }
+
+ pid_t GetPid() const { return pid_; }
+
+ private:
+ int UpdateTotalCpuTime() {
+ FILE* fp = fopen("/proc/stat", "r");
+ if (fp == nullptr) {
+ _E("Failed to open /proc/stat");
+ return -1;
+ }
+
+ unsigned long long user = 0;
+ unsigned long long nice = 0;
+ unsigned long long system = 0;
+ unsigned long long idle_time = 0;
+ unsigned long long iowait = 0;
+ unsigned long long irq = 0;
+ unsigned long long softirq = 0;
+ unsigned long long steal = 0;
+ int ret =
+ fscanf(fp, "cpu %llu %llu %llu %llu %llu %llu %llu %llu", &user, &nice,
+ &system, &idle_time, &iowait, &irq, &softirq, &steal);
+ fclose(fp);
+ if (ret != 8) {
+ _E("Failed to scan /proc/stat: %d", ret);
+ return -1;
+ }
+
+ previous_total_time_ = current_total_time_;
+ current_total_time_ =
+ user + nice + system + idle_time + iowait + irq + softirq + steal;
+ _D("previous_total_time=%llu, current_total_time=%llu",
+ previous_total_time_, current_total_time_);
+ return 0;
+ }
+
+ int UpdateProcessCpuTime() {
+ std::string path = "/proc/" + std::to_string(pid_) + "/stat";
+ FILE* fp = fopen(path.c_str(), "r");
+ if (fp == nullptr) {
+ _E("Failed to open %s", path.c_str());
+ return -1;
+ }
+
+ unsigned long long utime = 0;
+ unsigned long long stime = 0;
+ int ret = fscanf(
+ fp, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %llu %llu",
+ &utime, &stime);
+ fclose(fp);
+ if (ret != 2) {
+ _E("Failed to scan %s: %d", path.c_str(), ret);
+ return -1;
+ }
+
+ previous_process_time_ = current_process_time_;
+ current_process_time_ = utime + stime;
+ _W("previous_process_time=%llu, current_process_time=%llu",
+ previous_process_time_, current_process_time_);
+ return 0;
+ }
+
+ private:
+ pid_t pid_;
+ unsigned long long current_total_time_ = 0;
+ unsigned long long current_process_time_ = 0;
+ unsigned long long previous_total_time_ = 0;
+ unsigned long long previous_process_time_ = 0;
+};
+
+} // namespace
+
+extern "C" API int aul_cpu_times_create(pid_t pid, aul_cpu_times_h* cpu_times) {
+ if (pid < 1 || cpu_times == nullptr) {
+ _E("Invalid parameter");
+ return AUL_R_EINVAL;
+ }
+
+ auto* handle = new (std::nothrow) ::CpuTimes(pid);
+ if (handle == nullptr) {
+ _E("Out of memory");
+ return AUL_R_ENOMEM;
+ }
+
+ *cpu_times = static_cast<aul_cpu_times_h>(handle);
+ return AUL_R_OK;
+}
+
+extern "C" API int aul_cpu_times_destroy(aul_cpu_times_h cpu_times) {
+ if (cpu_times == nullptr) {
+ _E("Invalid parameter");
+ return AUL_R_EINVAL;
+ }
+
+ auto* handle = static_cast<::CpuTimes*>(cpu_times);
+ delete handle;
+ return AUL_R_OK;
+}
+
+extern "C" API int aul_cpu_times_update(aul_cpu_times_h cpu_times) {
+ if (cpu_times == nullptr) {
+ _E("Invalid parameter");
+ return AUL_R_EINVAL;
+ }
+
+ auto* handle = static_cast<::CpuTimes*>(cpu_times);
+ if (handle->Update() != 0) {
+ _E("Failed to update cpu times");
+ return AUL_R_ERROR;
+ }
+
+ return AUL_R_OK;
+}
+
+extern "C" API int aul_cpu_monitor_get_cpu_usage(
+ aul_cpu_times_h cpu_times, double* cpu_usage) {
+ if (cpu_times == nullptr || cpu_usage == nullptr) {
+ _E("Invalid parameter");
+ return AUL_R_EINVAL;
+ }
+
+ auto handle = static_cast<::CpuTimes*>(cpu_times);
+ *cpu_usage = handle->CalculateCpuUsage();
+ _D("Process=%d, CPU usage=%.4f%%", handle->GetPid(), *cpu_usage);
+ return AUL_R_OK;
+}
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 __AUL_CPU_MONITOR_H__
+#define __AUL_CPU_MONITOR_H__
+
+#include <sys/types.h>
+
+#include <aul.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief The handle of CPU times.
+ * @since_tizen 9.0
+ */
+typedef void *aul_cpu_times_h;
+
+/**
+ * @brief Creates a handle of CPU times.
+ * @since_tizen 9.0
+ * @param[in] pid The process ID
+ * @param[out] cpu_times The handle of CPU times
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #AUL_R_OK Successful
+ * @retval #AUL_R_EINVAL Invalid parameter
+ * @retval #AUL_R_ENOMEM Out of memory
+ * @see aul_cpu_times_destroy()
+ */
+int aul_cpu_times_create(pid_t pid, aul_cpu_times_h *cpu_times);
+
+/**
+ * @brief Destroys the handle of CPU times.
+ * @since_tizen 9.0
+ * @param[in] cpu_times The handle of CPU times
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #AUL_R_OK Successful
+ * @retval #AUL_R_EINVAL Invalid parameter
+ * @see aul_cpu_times_create()
+ */
+int aul_cpu_times_destroy(aul_cpu_times_h cpu_times);
+
+/**
+ * @brief Updates the handle of CPU times.
+ * @since_tizen 9.0
+ * @param[in] cpu_times The handle of CPU times
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #AUL_R_OK Successful
+ * @retval #AUL_R_EINVAL Invalid parameter
+ * @retval #AUL_R_ERROR Internal error occured
+ * @see aul_cpu_times_create()
+ */
+int aul_cpu_times_update(aul_cpu_times_h cpu_times);
+
+/**
+ * @brief Gets the cpu usage from the handle of CPU times.
+ * @since_tizen 9.0
+ * @param[in] cpu_times The handle of CPU times
+ * @param[out] cpu_usage The cpu usage
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #AUL_R_OK Successful
+ * @retval #AUL_R_EINVAL Invalid parameter
+ * @retval #AUL_R_ERROR Internal error occured
+ * @see aul_cpu_times_create()
+ * @code
+ * #include <stdio.h>
+ * #include <aul_cpu_monitor.h>
+ * int main(void) {
+ * aul_cpu_times_h cpu_times;
+ * if (aul_cpu_times_create(getpid(), &cpu_times)!= AUL_R_OK) {
+ * return -1;
+ * }
+ *
+ * if (aul_cpu_times_update(cpu_times)!= AUL_R_OK) {
+ * aul_cpu_times_destroy(cpu_times);
+ * return -1;
+ * }
+ *
+ * sleep(1);
+ *
+ * if (aul_cpu_times_update(cpu_times)!= AUL_R_OK) {
+ * aul_cpu_times_destroy(cpu_times);
+ * return -1;
+ * }
+ *
+ * double cpu_usage;
+ * if (aul_cpu_monitor_get_cpu_usage(cpu_times, &cpu_usage)!= AUL_R_OK) {
+ * aul_cpu_times_destroy(cpu_times);
+ * return -1;
+ * }
+ *
+ * printf("cpu usage: %f\n", cpu_usage);
+ * aul_cpu_times_destroy(cpu_times);
+ * return 0;
+ * }
+ * @endcode
+ */
+int aul_cpu_monitor_get_cpu_usage(aul_cpu_times_h cpu_times, double *cpu_usage);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __AUL_CPU_MONITOR_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "aul_test.hh"
+#include "include/aul_cpu_monitor.h"
+#include "log_private.hh"
+
+namespace aul_test {
+
+class AulCpuMonitorGetCpuUsageTest : public AulTest {
+ public:
+ AulCpuMonitorGetCpuUsageTest()
+ : AulTest("get_cpu_usage", "aul_cpu_monitor_get_cpu_usage",
+ "get_cpu_usage <pid>") {}
+
+ virtual ~AulCpuMonitorGetCpuUsageTest() {}
+
+ void SetUp() override {}
+
+ void TearDown() override {}
+
+ int Test(int argc, char** argv) override {
+ if (argc < 3) {
+ Usage();
+ return -1;
+ }
+
+ if (getuid() != 0) {
+ fprintf(stderr, "Permission denied\n");
+ return -EPERM;
+ }
+
+ unsigned int seconds = 1;
+ if (argc > 3)
+ seconds = atoi(argv[3]);
+
+ _D("[aul_cpu_monitor_get_cpu_usage test] %s", argv[2]);
+ pid_t pid = atoi(argv[2]);
+ aul_cpu_times_h cpu_times = nullptr;
+ int ret = aul_cpu_times_create(pid, &cpu_times);
+ ret |= aul_cpu_times_update(cpu_times);
+
+ sleep(seconds);
+
+ ret |= aul_cpu_times_update(cpu_times);
+
+ double cpu_usage = 0.0f;
+ ret |= aul_cpu_monitor_get_cpu_usage(cpu_times, &cpu_usage);
+ aul_cpu_times_destroy(cpu_times);
+
+ printf("Process=%d, CPU usage=%.4f%%\n", pid, cpu_usage);
+ return ret;
+ }
+};
+
+AUL_TEST_REGISTER(AulCpuMonitorGetCpuUsageTest, get_cpu_usage_test);
+
+} // namespace aul_test