From d6547c7f818b7dcae431c55162c7e407f34926c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Tue, 1 Apr 2025 23:19:53 +0200 Subject: [PATCH] kernel & libbsd.so: add getloadavg() and _user_get_loadavg() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit the algorithm and reference values are from FreeBSD. Change-Id: Ia74a796e13adce6a70434c7546c25ca3d553f11f Reviewed-on: https://review.haiku-os.org/c/haiku/+/9150 Reviewed-by: waddlesplash Reviewed-by: Jérôme Duval Tested-by: Commit checker robot --- headers/compatibility/bsd/stdlib.h | 2 + headers/private/kernel/kscheduler.h | 4 ++ headers/private/system/scheduler_defs.h | 6 ++ headers/private/system/syscalls.h | 2 + src/libs/bsd/Jamfile | 1 + src/libs/bsd/getloadavg.cpp | 25 ++++++++ src/system/kernel/Jamfile | 1 + src/system/kernel/main.cpp | 2 + .../kernel/scheduler/scheduler_load.cpp | 62 +++++++++++++++++++ src/tests/libs/bsd/Jamfile | 1 + src/tests/libs/bsd/getloadavg_test.cpp | 23 +++++++ 11 files changed, 129 insertions(+) create mode 100644 src/libs/bsd/getloadavg.cpp create mode 100644 src/system/kernel/scheduler/scheduler_load.cpp create mode 100644 src/tests/libs/bsd/getloadavg_test.cpp diff --git a/headers/compatibility/bsd/stdlib.h b/headers/compatibility/bsd/stdlib.h index f9a8bc48c7..6b2a105aaf 100644 --- a/headers/compatibility/bsd/stdlib.h +++ b/headers/compatibility/bsd/stdlib.h @@ -30,6 +30,8 @@ int mkstemps(char *templat, int slen); long long strtonum(const char *numstr, long long minval, long long maxval, const char **errstrp); +int getloadavg(double array[], int size); + #ifdef __cplusplus } #endif diff --git a/headers/private/kernel/kscheduler.h b/headers/private/kernel/kscheduler.h index df8a71e551..9b53067401 100644 --- a/headers/private/kernel/kscheduler.h +++ b/headers/private/kernel/kscheduler.h @@ -85,6 +85,7 @@ void scheduler_add_listener(struct SchedulerListener* listener); void scheduler_remove_listener(struct SchedulerListener* listener); void scheduler_init(void); +status_t scheduler_loadavg_init(); void scheduler_enable_scheduling(void); void scheduler_update_policy(void); @@ -95,6 +96,9 @@ status_t _user_analyze_scheduling(bigtime_t from, bigtime_t until, void* buffer, status_t _user_set_scheduler_mode(int32 mode); int32 _user_get_scheduler_mode(void); +status_t _user_get_loadavg(struct loadavg* info, size_t size); + + #ifdef __cplusplus } #endif diff --git a/headers/private/system/scheduler_defs.h b/headers/private/system/scheduler_defs.h index c17bf43414..ecd0692092 100644 --- a/headers/private/system/scheduler_defs.h +++ b/headers/private/system/scheduler_defs.h @@ -62,4 +62,10 @@ struct scheduling_analysis { }; +struct loadavg { + uint32 ldavg[3]; + long fscale; +}; + + #endif /* _SYSTEM_SCHEDULER_DEFS_H */ diff --git a/headers/private/system/syscalls.h b/headers/private/system/syscalls.h index b80ee04774..8793ca687e 100644 --- a/headers/private/system/syscalls.h +++ b/headers/private/system/syscalls.h @@ -28,6 +28,7 @@ struct fd_info; struct fd_set; struct fs_info; struct iovec; +struct loadavg; struct msqid_ds; struct net_stat; struct pollfd; @@ -212,6 +213,7 @@ extern bigtime_t _kern_estimate_max_scheduling_latency(thread_id thread); extern status_t _kern_set_scheduler_mode(int32 mode); extern int32 _kern_get_scheduler_mode(void); +extern status_t _kern_get_loadavg(struct loadavg* info, size_t size); // user/group functions extern gid_t _kern_getgid(bool effective); diff --git a/src/libs/bsd/Jamfile b/src/libs/bsd/Jamfile index cbc8972a74..d0dac23f74 100644 --- a/src/libs/bsd/Jamfile +++ b/src/libs/bsd/Jamfile @@ -19,6 +19,7 @@ for architectureObject in [ MultiArchSubDirSetup ] { explicit_bzero.c fgetln.c fts.c + getloadavg.cpp getpass.c issetugid.c kqueue.cpp diff --git a/src/libs/bsd/getloadavg.cpp b/src/libs/bsd/getloadavg.cpp new file mode 100644 index 0000000000..f2ac718dc7 --- /dev/null +++ b/src/libs/bsd/getloadavg.cpp @@ -0,0 +1,25 @@ +/* + * Copyright 2025, Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include +#include + + +extern "C" int +getloadavg(double loadavg[], int count) +{ + struct loadavg info; + + if (_kern_get_loadavg(&info, sizeof(info)) != B_OK) + return -1; + + size_t size = min_c((size_t)count, B_COUNT_OF(info.ldavg)); + for (size_t i = 0; i < size; i++) + loadavg[i] = (double)info.ldavg[i] / info.fscale; + return count; +} diff --git a/src/system/kernel/Jamfile b/src/system/kernel/Jamfile index b5b0761c32..e23b095f15 100644 --- a/src/system/kernel/Jamfile +++ b/src/system/kernel/Jamfile @@ -70,6 +70,7 @@ KernelMergeObject kernel_core.o : power_saving.cpp scheduler.cpp scheduler_cpu.cpp + scheduler_load.cpp scheduler_profiler.cpp scheduler_thread.cpp scheduler_tracing.cpp diff --git a/src/system/kernel/main.cpp b/src/system/kernel/main.cpp index 2669b95996..d81ab0203d 100644 --- a/src/system/kernel/main.cpp +++ b/src/system/kernel/main.cpp @@ -313,6 +313,8 @@ main2(void* /*unused*/) TRACE("init system notifications\n"); system_notifications_init(); + scheduler_loadavg_init(); + TRACE("Init modules\n"); boot_splash_set_stage(BOOT_SPLASH_STAGE_1_INIT_MODULES); module_init_post_threads(); diff --git a/src/system/kernel/scheduler/scheduler_load.cpp b/src/system/kernel/scheduler/scheduler_load.cpp new file mode 100644 index 0000000000..5b1985fa04 --- /dev/null +++ b/src/system/kernel/scheduler/scheduler_load.cpp @@ -0,0 +1,62 @@ +/* + * Copyright 2025, Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT license. + */ + + +#include "scheduler_cpu.h" + +#include +#include + + +using namespace Scheduler; + +// load average algorithm from FreeBSD, see kern_sync.c +const static int kFShift = 11; +const static long kFScale = 1 << kFShift; +static struct loadavg sAverageRunnable = {{0, 0, 0}, kFScale}; +const static uint64 sCExp[3] = {(uint64)(0.9200444146293232 * kFScale), + (uint64)(0.9834714538216174 * kFScale), (uint64)(0.9944598480048967 * kFScale)}; + + +static void +_LoadavgUpdate(void *data, int iteration) +{ + uint64 threadCount = 0; + for (int i = 0; i < gCoreCount; i++) + threadCount += gCoreEntries[i].ThreadCount(); + threadCount--; + for (int i = 0; i < 3; i++) { + sAverageRunnable.ldavg[i] + = (sCExp[i] * sAverageRunnable.ldavg[i] + threadCount * kFScale * (kFScale - sCExp[i])) + >> kFShift; + } +} + + +status_t +scheduler_loadavg_init() +{ + register_kernel_daemon(_LoadavgUpdate, NULL, 50); + // run the daemon once five second + + return B_OK; +} + + +// #pragma mark - Syscalls + + +status_t +_user_get_loadavg(struct loadavg* userInfo, size_t size) +{ + if (userInfo == NULL || !IS_USER_ADDRESS(userInfo)) + return B_BAD_ADDRESS; + if (size != sizeof(struct loadavg)) + return B_BAD_VALUE; + if (user_memcpy(userInfo, &sAverageRunnable, sizeof(struct loadavg)) < B_OK) + return B_BAD_ADDRESS; + + return B_OK; +} diff --git a/src/tests/libs/bsd/Jamfile b/src/tests/libs/bsd/Jamfile index ccb6c111b4..f626cec70e 100644 --- a/src/tests/libs/bsd/Jamfile +++ b/src/tests/libs/bsd/Jamfile @@ -3,6 +3,7 @@ SubDir HAIKU_TOP src tests libs bsd ; UseHeaders [ FDirName $(HAIKU_TOP) headers compatibility bsd ] : true ; SimpleTest forkpty_test : forkpty.c : libbsd.so ; +SimpleTest getloadavg_test : getloadavg_test.cpp : libbsd.so ; SimpleTest wait4_test : wait4_test.cpp : libbsd.so ; diff --git a/src/tests/libs/bsd/getloadavg_test.cpp b/src/tests/libs/bsd/getloadavg_test.cpp new file mode 100644 index 0000000000..620f83dccf --- /dev/null +++ b/src/tests/libs/bsd/getloadavg_test.cpp @@ -0,0 +1,23 @@ +/* + * Copyright 2025, Jérôme Duval, jerome.duval@gmail.com. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include +#include +#include + + +int +main(int argc, char** argv) +{ + double loadavg[3]; + int count = getloadavg(loadavg, 3); + if (count == -1) + return 1; + printf("getloadavg() returned %" PRId32 ", values %f %f %f\n", count, loadavg[0], loadavg[1], + loadavg[2]); + + return 0; +}