From cef1649ea7a4092e57cfffbaa54e79cc1912969f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Costa?= Date: Fri, 14 Feb 2025 04:49:19 +0100 Subject: [PATCH] feat(osal): add lv_os_get_idle_percent for linux (#7632) Co-authored-by: Liam <30486941+liamHowatt@users.noreply.github.com> --- lv_conf_template.h | 2 +- src/core/lv_global.h | 7 +++ src/lv_conf_internal.h | 2 +- src/osal/lv_cmsis_rtos2.c | 6 ++ src/osal/lv_freertos.h | 7 --- src/osal/lv_linux.c | 122 ++++++++++++++++++++++++++++++++++++ src/osal/lv_linux_private.h | 56 +++++++++++++++++ src/osal/lv_mqx.c | 6 ++ src/osal/lv_os.h | 6 ++ src/osal/lv_os_none.c | 50 +++++++++++++++ src/osal/lv_pthread.c | 21 +++++-- src/osal/lv_rtthread.c | 6 ++ src/osal/lv_sdl2.c | 11 ++++ src/osal/lv_windows.c | 6 ++ 14 files changed, 295 insertions(+), 13 deletions(-) create mode 100644 src/osal/lv_linux.c create mode 100644 src/osal/lv_linux_private.h create mode 100644 src/osal/lv_os_none.c diff --git a/lv_conf_template.h b/lv_conf_template.h index a52e2e187..af2f1d6e7 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -969,7 +969,7 @@ #define LV_USE_SYSMON 0 #if LV_USE_SYSMON /** Get the idle percentage. E.g. uint32_t my_get_idle(void); */ - #define LV_SYSMON_GET_IDLE lv_timer_get_idle + #define LV_SYSMON_GET_IDLE lv_os_get_idle_percent /** 1: Show CPU usage and FPS count. * - Requires `LV_USE_SYSMON = 1` */ diff --git a/src/core/lv_global.h b/src/core/lv_global.h index 9428dae2f..6a1089a0e 100644 --- a/src/core/lv_global.h +++ b/src/core/lv_global.h @@ -35,6 +35,10 @@ extern "C" { #include "../font/lv_font_fmt_txt_private.h" #endif +#if LV_USE_OS != LV_OS_NONE && defined(__linux__) +#include "../osal/lv_linux_private.h" +#endif + #include "../tick/lv_tick.h" #include "../layouts/lv_layout.h" @@ -224,6 +228,9 @@ typedef struct _lv_global_t { #if LV_USE_OS != LV_OS_NONE lv_mutex_t lv_general_mutex; +#if defined(__linux__) + lv_proc_stat_t linux_last_proc_stat; +#endif #endif #if LV_USE_OS == LV_OS_FREERTOS diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index dec5c4a07..435aba69f 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -3074,7 +3074,7 @@ #ifdef CONFIG_LV_SYSMON_GET_IDLE #define LV_SYSMON_GET_IDLE CONFIG_LV_SYSMON_GET_IDLE #else - #define LV_SYSMON_GET_IDLE lv_timer_get_idle + #define LV_SYSMON_GET_IDLE lv_os_get_idle_percent #endif #endif diff --git a/src/osal/lv_cmsis_rtos2.c b/src/osal/lv_cmsis_rtos2.c index 4a5628012..d2f89430b 100644 --- a/src/osal/lv_cmsis_rtos2.c +++ b/src/osal/lv_cmsis_rtos2.c @@ -17,6 +17,7 @@ #if LV_USE_OS == LV_OS_CMSIS_RTOS2 #include "../misc/lv_log.h" +#include "../misc/lv_timer.h" /********************* * DEFINES @@ -190,6 +191,11 @@ lv_result_t lv_thread_sync_delete(lv_thread_sync_t * sync) return LV_RESULT_OK; } +uint32_t lv_os_get_idle_percent(void) +{ + return lv_timer_get_idle(); +} + /********************** * STATIC FUNCTIONS **********************/ diff --git a/src/osal/lv_freertos.h b/src/osal/lv_freertos.h index 5c296bc8b..a3bafca74 100644 --- a/src/osal/lv_freertos.h +++ b/src/osal/lv_freertos.h @@ -84,13 +84,6 @@ void lv_freertos_task_switch_in(const char * name); */ void lv_freertos_task_switch_out(void); -/** - * Set it for `LV_SYSMON_GET_IDLE` to show the CPU usage - * as reported based the usage of FreeRTOS's idle task - * If it's important when a GPU is used. - * @return the idle percentage since the last call - */ -uint32_t lv_os_get_idle_percent(void); /********************** * MACROS diff --git a/src/osal/lv_linux.c b/src/osal/lv_linux.c new file mode 100644 index 000000000..baec0aa54 --- /dev/null +++ b/src/osal/lv_linux.c @@ -0,0 +1,122 @@ +/** + * @file lv_linux.c + * + */ + +/********************* + * INCLUDES + *********************/ + +#include "lv_os.h" + +#if LV_USE_OS != LV_OS_NONE && defined(__linux__) + +#include "../core/lv_global.h" +#include "../misc/lv_log.h" +#include "lv_linux_private.h" +#include + +/********************* + * DEFINES + *********************/ + +#define LV_UPTIME_MONITOR_FILE "/proc/stat" + +#define LV_PROC_STAT_VAR_FORMAT " %" PRIu32 +#define LV_PROC_STAT_IGNORE_VAR_FORMAT " %*" PRIu32 + +#define last_proc_stat LV_GLOBAL_DEFAULT()->linux_last_proc_stat + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +static lv_result_t lv_read_proc_stat(lv_proc_stat_t * result); +static uint32_t lv_proc_stat_get_total(const lv_proc_stat_t * p); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +uint32_t lv_os_get_idle_percent(void) +{ + lv_proc_stat_t proc_stat; + { + lv_result_t err = lv_read_proc_stat(&proc_stat); + + if(err == LV_RESULT_INVALID) { + return UINT32_MAX; + } + + for(size_t i = 0; i < LV_PROC_STAT_PARAMS_LEN; ++i) { + uint32_t delta = + proc_stat.buffer[i] - last_proc_stat.buffer[i]; + /* Update old for next call*/ + last_proc_stat.buffer[i] = proc_stat.buffer[i]; + /* Store delta in new */ + proc_stat.buffer[i] = delta; + } + } + + /* From here onwards, there's no risk of overflowing as long as we call this function regularly */ + const uint32_t total = lv_proc_stat_get_total(&proc_stat); + + if(total == 0) { + return 0; + } + + return (proc_stat.fields.idle * 100) / total; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static lv_result_t lv_read_proc_stat(lv_proc_stat_t * result) +{ + FILE * fp = fopen(LV_UPTIME_MONITOR_FILE, "r"); + + if(!fp) { + LV_LOG_ERROR("Failed to open " LV_UPTIME_MONITOR_FILE); + return LV_RESULT_INVALID; + } + const char * fmt = "cpu " LV_PROC_STAT_VAR_FORMAT LV_PROC_STAT_VAR_FORMAT + LV_PROC_STAT_VAR_FORMAT LV_PROC_STAT_VAR_FORMAT + LV_PROC_STAT_IGNORE_VAR_FORMAT LV_PROC_STAT_VAR_FORMAT + LV_PROC_STAT_VAR_FORMAT LV_PROC_STAT_VAR_FORMAT; + + int err = fscanf(fp, fmt, &result->fields.user, &result->fields.nice, + &result->fields.system, &result->fields.idle, + &result->fields.irq, &result->fields.softirq, + &result->fields.steal); + + fclose(fp); + + if(err != LV_PROC_STAT_PARAMS_LEN) { + LV_LOG_ERROR("Failed to parse " LV_UPTIME_MONITOR_FILE); + return LV_RESULT_INVALID; + } + return LV_RESULT_OK; +} +static uint32_t lv_proc_stat_get_total(const lv_proc_stat_t * p) +{ + uint32_t sum = 0; + for(size_t i = 0; i < LV_PROC_STAT_PARAMS_LEN; ++i) { + sum += p->buffer[i]; + } + return sum; +} + +#endif diff --git a/src/osal/lv_linux_private.h b/src/osal/lv_linux_private.h new file mode 100644 index 000000000..d6e43cbf7 --- /dev/null +++ b/src/osal/lv_linux_private.h @@ -0,0 +1,56 @@ + +/** + * @file lv_linux_private.h + * + */ + +#ifndef LV_LINUX_PRIVATE_H +#define LV_LINUX_PRIVATE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "../misc/lv_types.h" + +/********************* + * DEFINES + *********************/ + +#define LV_PROC_STAT_PARAMS_LEN 7 + +/********************** + * TYPEDEFS + **********************/ + + +typedef union { + struct { + /* + * We ignore the iowait column as it's not reliable + * We ignore the guest and guest_nice columns because they're accounted + * for in user and nice respectively + */ + uint32_t user, nice, system, idle, /*iowait,*/ irq, softirq, + steal /*, guest, guest_nice*/; + } fields; + uint32_t buffer[LV_PROC_STAT_PARAMS_LEN]; +} lv_proc_stat_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_LINUX_PRIVATE_H*/ diff --git a/src/osal/lv_mqx.c b/src/osal/lv_mqx.c index 7d27d752d..ffcf16332 100644 --- a/src/osal/lv_mqx.c +++ b/src/osal/lv_mqx.c @@ -11,6 +11,7 @@ #if LV_USE_OS == LV_OS_MQX #include "../misc/lv_log.h" +#include "../misc/lv_timer.h" #include "../stdlib/lv_string.h" /********************* @@ -163,6 +164,11 @@ lv_result_t lv_thread_sync_signal_isr(lv_thread_sync_t * sync) return LV_RESULT_INVALID; } +uint32_t lv_os_get_idle_percent(void) +{ + return lv_timer_get_idle(); +} + /********************** * STATIC FUNCTIONS **********************/ diff --git a/src/osal/lv_os.h b/src/osal/lv_os.h index d4e230603..47fd80108 100644 --- a/src/osal/lv_os.h +++ b/src/osal/lv_os.h @@ -60,6 +60,12 @@ typedef enum { * GLOBAL PROTOTYPES **********************/ +/** + * Set it for `LV_SYSMON_GET_IDLE` to show the CPU usage + * @return the idle percentage since the last call + */ +uint32_t lv_os_get_idle_percent(void); + #if LV_USE_OS != LV_OS_NONE /*---------------------------------------- diff --git a/src/osal/lv_os_none.c b/src/osal/lv_os_none.c new file mode 100644 index 000000000..9fe3cac63 --- /dev/null +++ b/src/osal/lv_os_none.c @@ -0,0 +1,50 @@ +/** + * @file lv_os_none.c + * + */ + +/********************* + * INCLUDES + *********************/ + +#include "../lv_conf_internal.h" +#if LV_USE_OS == LV_OS_NONE + +#include "lv_os.h" +#include "../misc/lv_timer.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +uint32_t lv_os_get_idle_percent(void) +{ + return lv_timer_get_idle(); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + + +#endif diff --git a/src/osal/lv_pthread.c b/src/osal/lv_pthread.c index 665efd2e3..52bd236de 100644 --- a/src/osal/lv_pthread.c +++ b/src/osal/lv_pthread.c @@ -10,9 +10,12 @@ #if LV_USE_OS == LV_OS_PTHREAD -#include #include "../misc/lv_log.h" +#ifndef __linux__ + #include "../misc/lv_timer.h" +#endif + /********************* * DEFINES *********************/ @@ -26,6 +29,7 @@ **********************/ static void * generic_callback(void * user_data); + /********************** * STATIC VARIABLES **********************/ @@ -38,9 +42,9 @@ static void * generic_callback(void * user_data); * GLOBAL FUNCTIONS **********************/ -lv_result_t lv_thread_init(lv_thread_t * thread, const char * const name, lv_thread_prio_t prio, - void (*callback)(void *), size_t stack_size, - void * user_data) +lv_result_t lv_thread_init(lv_thread_t * thread, const char * const name, + lv_thread_prio_t prio, void (*callback)(void *), + size_t stack_size, void * user_data) { LV_UNUSED(name); LV_UNUSED(prio); @@ -167,6 +171,14 @@ lv_result_t lv_thread_sync_signal_isr(lv_thread_sync_t * sync) return LV_RESULT_INVALID; } +#ifndef __linux__ +uint32_t lv_os_get_idle_percent(void) +{ + return lv_timer_get_idle(); +} +#endif + + /********************** * STATIC FUNCTIONS **********************/ @@ -178,4 +190,5 @@ static void * generic_callback(void * user_data) return NULL; } + #endif /*LV_USE_OS == LV_OS_PTHREAD*/ diff --git a/src/osal/lv_rtthread.c b/src/osal/lv_rtthread.c index b719152b5..1f2f9d80e 100644 --- a/src/osal/lv_rtthread.c +++ b/src/osal/lv_rtthread.c @@ -11,6 +11,7 @@ #if LV_USE_OS == LV_OS_RTTHREAD #include "../misc/lv_log.h" +#include "../misc/lv_timer.h" /********************* * DEFINES @@ -184,6 +185,11 @@ lv_result_t lv_thread_sync_signal_isr(lv_thread_sync_t * sync) return LV_RESULT_INVALID; } +uint32_t lv_os_get_idle_percent(void) +{ + return lv_timer_get_idle(); +} + /********************** * STATIC FUNCTIONS **********************/ diff --git a/src/osal/lv_sdl2.c b/src/osal/lv_sdl2.c index bfbeac0cd..50a589a01 100644 --- a/src/osal/lv_sdl2.c +++ b/src/osal/lv_sdl2.c @@ -13,6 +13,10 @@ #include #include "../misc/lv_log.h" +#ifndef __linux__ + #include "../misc/lv_timer.h" +#endif + /********************* * DEFINES *********************/ @@ -169,6 +173,13 @@ lv_result_t lv_thread_sync_signal_isr(lv_thread_sync_t * sync) return LV_RESULT_INVALID; } +#ifndef __linux__ +uint32_t lv_os_get_idle_percent(void) +{ + return lv_timer_get_idle(); +} +#endif + /********************** * STATIC FUNCTIONS **********************/ diff --git a/src/osal/lv_windows.c b/src/osal/lv_windows.c index 33822577c..8b28ab18a 100644 --- a/src/osal/lv_windows.c +++ b/src/osal/lv_windows.c @@ -12,6 +12,7 @@ #if LV_USE_OS == LV_OS_WINDOWS #include +#include "../misc/lv_timer.h" /********************* * DEFINES @@ -206,6 +207,11 @@ lv_result_t lv_thread_sync_signal_isr(lv_thread_sync_t * sync) return LV_RESULT_INVALID; } +uint32_t lv_os_get_idle_percent(void) +{ + return lv_timer_get_idle(); +} + /********************** * STATIC FUNCTIONS **********************/