kernel & libbsd.so: add getloadavg() and _user_get_loadavg()

the algorithm and reference values are from FreeBSD.

Change-Id: Ia74a796e13adce6a70434c7546c25ca3d553f11f
Reviewed-on: https://review.haiku-os.org/c/haiku/+/9150
Reviewed-by: waddlesplash <[email protected]>
Reviewed-by: Jérôme Duval <[email protected]>
Tested-by: Commit checker robot <[email protected]>
This commit is contained in:
Jérôme Duval
2025-04-21 18:43:29 +00:00
parent 14aded56ee
commit d6547c7f81
11 changed files with 129 additions and 0 deletions
+2
View File
@@ -30,6 +30,8 @@ int mkstemps(char *templat, int slen);
long long strtonum(const char *numstr, long long minval, long long strtonum(const char *numstr, long long minval,
long long maxval, const char **errstrp); long long maxval, const char **errstrp);
int getloadavg(double array[], int size);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
+4
View File
@@ -85,6 +85,7 @@ void scheduler_add_listener(struct SchedulerListener* listener);
void scheduler_remove_listener(struct SchedulerListener* listener); void scheduler_remove_listener(struct SchedulerListener* listener);
void scheduler_init(void); void scheduler_init(void);
status_t scheduler_loadavg_init();
void scheduler_enable_scheduling(void); void scheduler_enable_scheduling(void);
void scheduler_update_policy(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); status_t _user_set_scheduler_mode(int32 mode);
int32 _user_get_scheduler_mode(void); int32 _user_get_scheduler_mode(void);
status_t _user_get_loadavg(struct loadavg* info, size_t size);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
+6
View File
@@ -62,4 +62,10 @@ struct scheduling_analysis {
}; };
struct loadavg {
uint32 ldavg[3];
long fscale;
};
#endif /* _SYSTEM_SCHEDULER_DEFS_H */ #endif /* _SYSTEM_SCHEDULER_DEFS_H */
+2
View File
@@ -28,6 +28,7 @@ struct fd_info;
struct fd_set; struct fd_set;
struct fs_info; struct fs_info;
struct iovec; struct iovec;
struct loadavg;
struct msqid_ds; struct msqid_ds;
struct net_stat; struct net_stat;
struct pollfd; 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 status_t _kern_set_scheduler_mode(int32 mode);
extern int32 _kern_get_scheduler_mode(void); extern int32 _kern_get_scheduler_mode(void);
extern status_t _kern_get_loadavg(struct loadavg* info, size_t size);
// user/group functions // user/group functions
extern gid_t _kern_getgid(bool effective); extern gid_t _kern_getgid(bool effective);
+1
View File
@@ -19,6 +19,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
explicit_bzero.c explicit_bzero.c
fgetln.c fgetln.c
fts.c fts.c
getloadavg.cpp
getpass.c getpass.c
issetugid.c issetugid.c
kqueue.cpp kqueue.cpp
+25
View File
@@ -0,0 +1,25 @@
/*
* Copyright 2025, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include <stdlib.h>
#include <scheduler_defs.h>
#include <syscalls.h>
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;
}
+1
View File
@@ -70,6 +70,7 @@ KernelMergeObject kernel_core.o :
power_saving.cpp power_saving.cpp
scheduler.cpp scheduler.cpp
scheduler_cpu.cpp scheduler_cpu.cpp
scheduler_load.cpp
scheduler_profiler.cpp scheduler_profiler.cpp
scheduler_thread.cpp scheduler_thread.cpp
scheduler_tracing.cpp scheduler_tracing.cpp
+2
View File
@@ -313,6 +313,8 @@ main2(void* /*unused*/)
TRACE("init system notifications\n"); TRACE("init system notifications\n");
system_notifications_init(); system_notifications_init();
scheduler_loadavg_init();
TRACE("Init modules\n"); TRACE("Init modules\n");
boot_splash_set_stage(BOOT_SPLASH_STAGE_1_INIT_MODULES); boot_splash_set_stage(BOOT_SPLASH_STAGE_1_INIT_MODULES);
module_init_post_threads(); module_init_post_threads();
@@ -0,0 +1,62 @@
/*
* Copyright 2025, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT license.
*/
#include "scheduler_cpu.h"
#include <kernel.h>
#include <scheduler_defs.h>
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;
}
+1
View File
@@ -3,6 +3,7 @@ SubDir HAIKU_TOP src tests libs bsd ;
UseHeaders [ FDirName $(HAIKU_TOP) headers compatibility bsd ] : true ; UseHeaders [ FDirName $(HAIKU_TOP) headers compatibility bsd ] : true ;
SimpleTest forkpty_test : forkpty.c : libbsd.so ; SimpleTest forkpty_test : forkpty.c : libbsd.so ;
SimpleTest getloadavg_test : getloadavg_test.cpp : libbsd.so ;
SimpleTest wait4_test : wait4_test.cpp : libbsd.so ; SimpleTest wait4_test : wait4_test.cpp : libbsd.so ;
+23
View File
@@ -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 <cinttypes>
#include <stdio.h>
#include <stdlib.h>
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;
}