/* * SPDX-License-Identifier: GPL-2.0 * Copyright (c) 2025 Meta Platforms, Inc. and affiliates. * Copyright (c) 2025 Tejun Heo * Copyright (c) 2025 Emil Tsalapatis */ #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__ */