mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
tools/sched_ext: add arena based scheduler
Add a scheduler that uses BPF arenas to manage task context data. Signed-off-by: Emil Tsalapatis <emil@etsalapatis.com> Signed-off-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
committed by
Tejun Heo
parent
f0262b102c
commit
36929ebd17
@@ -189,7 +189,7 @@ $(INCLUDE_DIR)/%.bpf.skel.h: $(SCXOBJ_DIR)/%.bpf.o $(INCLUDE_DIR)/vmlinux.h $(BP
|
||||
|
||||
SCX_COMMON_DEPS := include/scx/common.h include/scx/user_exit_info.h | $(BINDIR)
|
||||
|
||||
c-sched-targets = scx_simple scx_cpu0 scx_qmap scx_central scx_flatcg scx_userland scx_pair
|
||||
c-sched-targets = scx_simple scx_cpu0 scx_qmap scx_central scx_flatcg scx_userland scx_pair scx_sdt
|
||||
|
||||
$(addprefix $(BINDIR)/,$(c-sched-targets)): \
|
||||
$(BINDIR)/%: \
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,101 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2024 Meta Platforms, Inc. and affiliates.
|
||||
* Copyright (c) 2024 Emil Tsalapatis <etsal@meta.com>
|
||||
* Copyright (c) 2024 Tejun Heo <tj@kernel.org>
|
||||
* Copyright (c) 2022 David Vernet <dvernet@meta.com>
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <libgen.h>
|
||||
#include <bpf/bpf.h>
|
||||
#include <scx/common.h>
|
||||
|
||||
#include "scx_sdt.h"
|
||||
#include "scx_sdt.bpf.skel.h"
|
||||
|
||||
const char help_fmt[] =
|
||||
"A simple arena-based sched_ext scheduler.\n"
|
||||
"\n"
|
||||
"Modified version of scx_simple that demonstrates arena-based data structures.\n"
|
||||
"\n"
|
||||
"Usage: %s [-f] [-v]\n"
|
||||
"\n"
|
||||
" -v Print libbpf debug messages\n"
|
||||
" -h Display this help and exit\n";
|
||||
|
||||
static bool verbose;
|
||||
static volatile int exit_req;
|
||||
|
||||
static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
|
||||
{
|
||||
if (level == LIBBPF_DEBUG && !verbose)
|
||||
return 0;
|
||||
return vfprintf(stderr, format, args);
|
||||
}
|
||||
|
||||
static void sigint_handler(int sig)
|
||||
{
|
||||
exit_req = 1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct scx_sdt *skel;
|
||||
struct bpf_link *link;
|
||||
__u32 opt;
|
||||
__u64 ecode;
|
||||
|
||||
libbpf_set_print(libbpf_print_fn);
|
||||
signal(SIGINT, sigint_handler);
|
||||
signal(SIGTERM, sigint_handler);
|
||||
restart:
|
||||
skel = SCX_OPS_OPEN(sdt_ops, scx_sdt);
|
||||
|
||||
while ((opt = getopt(argc, argv, "fvh")) != -1) {
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
verbose = true;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, help_fmt, basename(argv[0]));
|
||||
return opt != 'h';
|
||||
}
|
||||
}
|
||||
|
||||
SCX_OPS_LOAD(skel, sdt_ops, scx_sdt, uei);
|
||||
link = SCX_OPS_ATTACH(skel, sdt_ops, scx_sdt);
|
||||
|
||||
while (!exit_req && !UEI_EXITED(skel, uei)) {
|
||||
printf("====SCHEDULING STATS====\n");
|
||||
printf("enqueues=%llu\t", skel->bss->stat_enqueue);
|
||||
printf("inits=%llu\t", skel->bss->stat_init);
|
||||
printf("exits=%llu\t", skel->bss->stat_exit);
|
||||
printf("\n");
|
||||
|
||||
printf("select_idle_cpu=%llu\t", skel->bss->stat_select_idle_cpu);
|
||||
printf("select_busy_cpu=%llu\t", skel->bss->stat_select_busy_cpu);
|
||||
printf("\n");
|
||||
|
||||
printf("====ALLOCATION STATS====\n");
|
||||
printf("chunk allocs=%llu\t", skel->bss->alloc_stats.chunk_allocs);
|
||||
printf("data_allocs=%llu\n", skel->bss->alloc_stats.data_allocs);
|
||||
printf("alloc_ops=%llu\t", skel->bss->alloc_stats.alloc_ops);
|
||||
printf("free_ops=%llu\t", skel->bss->alloc_stats.free_ops);
|
||||
printf("active_allocs=%llu\t", skel->bss->alloc_stats.active_allocs);
|
||||
printf("arena_pages_used=%llu\t", skel->bss->alloc_stats.arena_pages_used);
|
||||
printf("\n\n");
|
||||
|
||||
fflush(stdout);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
bpf_link__destroy(link);
|
||||
ecode = UEI_REPORT(skel, uei);
|
||||
scx_sdt__destroy(skel);
|
||||
|
||||
if (UEI_ECODE_RESTART(ecode))
|
||||
goto restart;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
* Copyright (c) 2025 Meta Platforms, Inc. and affiliates.
|
||||
* Copyright (c) 2025 Tejun Heo <tj@kernel.org>
|
||||
* Copyright (c) 2025 Emil Tsalapatis <etsal@meta.com>
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifndef __BPF__
|
||||
#define __arena
|
||||
#endif /* __BPF__ */
|
||||
|
||||
struct scx_alloc_stats {
|
||||
__u64 chunk_allocs;
|
||||
__u64 data_allocs;
|
||||
__u64 alloc_ops;
|
||||
__u64 free_ops;
|
||||
__u64 active_allocs;
|
||||
__u64 arena_pages_used;
|
||||
};
|
||||
|
||||
struct sdt_pool {
|
||||
void __arena *slab;
|
||||
__u64 elem_size;
|
||||
__u64 max_elems;
|
||||
__u64 idx;
|
||||
};
|
||||
|
||||
#ifndef div_round_up
|
||||
#define div_round_up(a, b) (((a) + (b) - 1) / (b))
|
||||
#endif
|
||||
|
||||
#ifndef round_up
|
||||
#define round_up(a, b) (div_round_up((a), (b)) * (b))
|
||||
#endif
|
||||
|
||||
typedef struct sdt_desc __arena sdt_desc_t;
|
||||
|
||||
enum sdt_consts {
|
||||
SDT_TASK_ENTS_PER_PAGE_SHIFT = 9,
|
||||
SDT_TASK_LEVELS = 3,
|
||||
SDT_TASK_ENTS_PER_CHUNK = 1 << SDT_TASK_ENTS_PER_PAGE_SHIFT,
|
||||
SDT_TASK_CHUNK_BITMAP_U64S = div_round_up(SDT_TASK_ENTS_PER_CHUNK, 64),
|
||||
SDT_TASK_MIN_ELEM_PER_ALLOC = 8,
|
||||
};
|
||||
|
||||
union sdt_id {
|
||||
__s64 val;
|
||||
struct {
|
||||
__s32 idx; /* index in the radix tree */
|
||||
__s32 genn; /* ++'d on recycle so that it forms unique'ish 64bit ID */
|
||||
};
|
||||
};
|
||||
|
||||
struct sdt_chunk;
|
||||
|
||||
/*
|
||||
* Each index page is described by the following descriptor which carries the
|
||||
* bitmap. This way the actual index can host power-of-two numbers of entries
|
||||
* which makes indexing cheaper.
|
||||
*/
|
||||
struct sdt_desc {
|
||||
__u64 allocated[SDT_TASK_CHUNK_BITMAP_U64S];
|
||||
__u64 nr_free;
|
||||
struct sdt_chunk __arena *chunk;
|
||||
};
|
||||
|
||||
/*
|
||||
* Leaf node containing per-task data.
|
||||
*/
|
||||
struct sdt_data {
|
||||
union sdt_id tid;
|
||||
__u64 payload[];
|
||||
};
|
||||
|
||||
/*
|
||||
* Intermediate node pointing to another intermediate node or leaf node.
|
||||
*/
|
||||
struct sdt_chunk {
|
||||
union {
|
||||
sdt_desc_t * descs[SDT_TASK_ENTS_PER_CHUNK];
|
||||
struct sdt_data __arena *data[SDT_TASK_ENTS_PER_CHUNK];
|
||||
};
|
||||
};
|
||||
|
||||
struct scx_allocator {
|
||||
struct sdt_pool pool;
|
||||
sdt_desc_t *root;
|
||||
};
|
||||
|
||||
struct scx_stats {
|
||||
int seq;
|
||||
pid_t pid;
|
||||
__u64 enqueue;
|
||||
__u64 exit;
|
||||
__u64 init;
|
||||
__u64 select_busy_cpu;
|
||||
__u64 select_idle_cpu;
|
||||
};
|
||||
|
||||
#ifdef __BPF__
|
||||
|
||||
void __arena *scx_task_data(struct task_struct *p);
|
||||
int scx_task_init(__u64 data_size);
|
||||
void __arena *scx_task_alloc(struct task_struct *p);
|
||||
void scx_task_free(struct task_struct *p);
|
||||
void scx_arena_subprog_init(void);
|
||||
|
||||
int scx_alloc_init(struct scx_allocator *alloc, __u64 data_size);
|
||||
u64 scx_alloc_internal(struct scx_allocator *alloc);
|
||||
int scx_alloc_free_idx(struct scx_allocator *alloc, __u64 idx);
|
||||
|
||||
#endif /* __BPF__ */
|
||||
Reference in New Issue
Block a user