/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. * Copyright (c) 2022 Tejun Heo <tj@kernel.org> * Copyright (c) 2022 David Vernet <dvernet@meta.com>
*/ #ifndef __SCX_COMMON_BPF_H #define __SCX_COMMON_BPF_H
/* * The generated kfunc prototypes in vmlinux.h are missing address space * attributes which cause build failures. For now, suppress the generated * prototypes. See https://github.com/sched-ext/scx/issues/1111.
*/ #define BPF_NO_KFUNC_PROTOTYPES
/* * Earlier versions of clang/pahole lost upper 32bits in 64bit enums which can * lead to really confusing misbehaviors. Let's trigger a build failure.
*/ staticinlinevoid ___vmlinux_h_sanity_check___(void)
{
_Static_assert(SCX_DSQ_FLAG_BUILTIN, "bpftool generated vmlinux.h is missing high bits for 64bit enums, upgrade clang and pahole");
}
/* * Helper macro for initializing the fmt and variadic argument inputs to both * bstr exit kfuncs. Callers to this function should use ___fmt and ___param to * refer to the initialized list of inputs to the bstr kfunc.
*/ #define scx_bpf_bstr_preamble(fmt, args...) \ staticchar ___fmt[] = fmt; \ /* \ * Note that __param[] must have at least one \ * element to keep the verifier happy. \
*/ unsignedlonglong ___param[___bpf_narg(args) ?: 1] = {}; \
\
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \
___bpf_fill(___param, args); \
_Pragma("GCC diagnostic pop")
/* * scx_bpf_exit() wraps the scx_bpf_exit_bstr() kfunc with variadic arguments * instead of an array of u64. Using this macro will cause the scheduler to * exit cleanly with the specified exit code being passed to user space.
*/ #define scx_bpf_exit(code, fmt, args...) \
({ \
scx_bpf_bstr_preamble(fmt, args) \
scx_bpf_exit_bstr(code, ___fmt, ___param, sizeof(___param)); \
___scx_bpf_bstr_format_checker(fmt, ##args); \
})
/* * scx_bpf_error() wraps the scx_bpf_error_bstr() kfunc with variadic arguments * instead of an array of u64. Invoking this macro will cause the scheduler to * exit in an erroneous state, with diagnostic information being passed to the * user.
*/ #define scx_bpf_error(fmt, args...) \
({ \
scx_bpf_bstr_preamble(fmt, args) \
scx_bpf_error_bstr(___fmt, ___param, sizeof(___param)); \
___scx_bpf_bstr_format_checker(fmt, ##args); \
})
/* * scx_bpf_dump() wraps the scx_bpf_dump_bstr() kfunc with variadic arguments * instead of an array of u64. To be used from ops.dump() and friends.
*/ #define scx_bpf_dump(fmt, args...) \
({ \
scx_bpf_bstr_preamble(fmt, args) \
scx_bpf_dump_bstr(___fmt, ___param, sizeof(___param)); \
___scx_bpf_bstr_format_checker(fmt, ##args); \
})
/* * scx_bpf_dump_header() is a wrapper around scx_bpf_dump that adds a header * of system information for debugging.
*/ #define scx_bpf_dump_header() \
({ \
scx_bpf_dump("kernel: %d.%d.%d %s\ncc: %s\n", \
LINUX_KERNEL_VERSION >> 16, \
LINUX_KERNEL_VERSION >> 8 & 0xFF, \
LINUX_KERNEL_VERSION & 0xFF, \
CONFIG_LOCALVERSION, \
CONFIG_CC_VERSION_TEXT); \
})
/** * RESIZABLE_ARRAY - Generates annotations for an array that may be resized * @elfsec: the data section of the BPF program in which to place the array * @arr: the name of the array * * libbpf has an API for setting map value sizes. Since data sections (i.e. * bss, data, rodata) themselves are maps, a data section can be resized. If * a data section has an array as its last element, the BTF info for that * array will be adjusted so that length of the array is extended to meet the * new length of the data section. This macro annotates an array to have an * element count of one with the assumption that this array can be resized * within the userspace program. It also annotates the section specifier so * this array exists in a custom sub data section which can be resized * independently. * * See RESIZE_ARRAY() for the userspace convenience macro for resizing an * array declared with RESIZABLE_ARRAY().
*/ #define RESIZABLE_ARRAY(elfsec, arr) arr[1] SEC("."#elfsec"."#arr)
/** * MEMBER_VPTR - Obtain the verified pointer to a struct or array member * @base: struct or array to index * @member: dereferenced member (e.g. .field, [idx0][idx1], .field[idx0] ...) * * The verifier often gets confused by the instruction sequence the compiler * generates for indexing struct fields or arrays. This macro forces the * compiler to generate a code sequence which first calculates the byte offset, * checks it against the struct or array size and add that byte offset to * generate the pointer to the member to help the verifier. * * Ideally, we want to abort if the calculated offset is out-of-bounds. However, * BPF currently doesn't support abort, so evaluate to %NULL instead. The caller * must check for %NULL and take appropriate action to appease the verifier. To * avoid confusing the verifier, it's best to check for %NULL and dereference * immediately. * * vptr = MEMBER_VPTR(my_array, [i][j]); * if (!vptr) * return error; * *vptr = new_value; * * sizeof(@base) should encompass the memory area to be accessed and thus can't * be a pointer to the area. Use `MEMBER_VPTR(*ptr, .member)` instead of * `MEMBER_VPTR(ptr, ->member)`.
*/ #define MEMBER_VPTR(base, member) (typeof((base) member) *) \
({ \
u64 __base = (u64)&(base); \
u64 __addr = (u64)&((base) member) - __base; \
_Static_assert(sizeof(base) >= sizeof((base) member), \ "@base is smaller than @member, is @base a pointer?"); \ asmvolatile ( \ "if %0 <= %[max] goto +2\n" \ "%0 = 0\n" \ "goto +1\n" \ "%0 += %1\n" \
: "+r"(__addr) \
: "r"(__base), \
[max]"i"(sizeof(base) - sizeof((base) member))); \
__addr; \
})
/** * ARRAY_ELEM_PTR - Obtain the verified pointer to an array element * @arr: array to index into * @i: array index * @n: number of elements in array * * Similar to MEMBER_VPTR() but is intended for use with arrays where the * element count needs to be explicit. * It can be used in cases where a global array is defined with an initial * size but is intended to be be resized before loading the BPF program. * Without this version of the macro, MEMBER_VPTR() will use the compile time * size of the array to compute the max, which will result in rejection by * the verifier.
*/ #define ARRAY_ELEM_PTR(arr, i, n) (typeof(arr[i]) *) \
({ \
u64 __base = (u64)arr; \
u64 __addr = (u64)&(arr[i]) - __base; \ asmvolatile ( \ "if %0 <= %[max] goto +2\n" \ "%0 = 0\n" \ "goto +1\n" \ "%0 += %1\n" \
: "+r"(__addr) \
: "r"(__base), \
[max]"r"(sizeof(arr[0]) * ((n) - 1))); \
__addr; \
})
/* * BPF declarations and helpers
*/
/* list and rbtree */ #define __contains(name, node) __attribute__((btf_decl_tag("contains:"#name":"#node))) #defineprivate(name) SEC(".data."#name) __hidden __attribute__((aligned(8)))
/* * Time helpers, most of which are from jiffies.h.
*/
/** * time_delta - Calculate the delta between new and old time stamp * @after: first comparable as u64 * @before: second comparable as u64 * * Return: the time difference, which is >= 0
*/ staticinline s64 time_delta(u64 after, u64 before)
{ return (s64)(after - before) > 0 ? (s64)(after - before) : 0;
}
/** * time_after - returns true if the time a is after time b. * @a: first comparable as u64 * @b: second comparable as u64 * * Do this with "<0" and ">=0" to only test the sign of the result. A * good compiler would generate better code (and a really good compiler * wouldn't care). Gcc is currently neither. * * Return: %true is time a is after time b, otherwise %false.
*/ staticinlinebool time_after(u64 a, u64 b)
{ return (s64)(b - a) < 0;
}
/** * time_before - returns true if the time a is before time b. * @a: first comparable as u64 * @b: second comparable as u64 * * Return: %true is time a is before time b, otherwise %false.
*/ staticinlinebool time_before(u64 a, u64 b)
{ return time_after(b, a);
}
/** * time_after_eq - returns true if the time a is after or the same as time b. * @a: first comparable as u64 * @b: second comparable as u64 * * Return: %true is time a is after or the same as time b, otherwise %false.
*/ staticinlinebool time_after_eq(u64 a, u64 b)
{ return (s64)(a - b) >= 0;
}
/** * time_before_eq - returns true if the time a is before or the same as time b. * @a: first comparable as u64 * @b: second comparable as u64 * * Return: %true is time a is before or the same as time b, otherwise %false.
*/ staticinlinebool time_before_eq(u64 a, u64 b)
{ return time_after_eq(b, a);
}
/** * time_in_range - Calculate whether a is in the range of [b, c]. * @a: time to test * @b: beginning of the range * @c: end of the range * * Return: %true is time a is in the range [b, c], otherwise %false.
*/ staticinlinebool time_in_range(u64 a, u64 b, u64 c)
{ return time_after_eq(a, b) && time_before_eq(a, c);
}
/** * time_in_range_open - Calculate whether a is in the range of [b, c). * @a: time to test * @b: beginning of the range * @c: end of the range * * Return: %true is time a is in the range [b, c), otherwise %false.
*/ staticinlinebool time_in_range_open(u64 a, u64 b, u64 c)
{ return time_after_eq(a, b) && time_before(a, c);
}
/* * READ/WRITE_ONCE() are from kernel (include/asm-generic/rwonce.h). They * prevent compiler from caching, redoing or reordering reads or writes.
*/ typedef __u8 __attribute__((__may_alias__)) __u8_alias_t; typedef __u16 __attribute__((__may_alias__)) __u16_alias_t; typedef __u32 __attribute__((__may_alias__)) __u32_alias_t; typedef __u64 __attribute__((__may_alias__)) __u64_alias_t;
static __always_inline void __read_once_size(constvolatilevoid *p, void *res, int size)
{ switch (size) { case 1: *(__u8_alias_t *) res = *(volatile __u8_alias_t *) p; break; case 2: *(__u16_alias_t *) res = *(volatile __u16_alias_t *) p; break; case 4: *(__u32_alias_t *) res = *(volatile __u32_alias_t *) p; break; case 8: *(__u64_alias_t *) res = *(volatile __u64_alias_t *) p; break; default:
barrier();
__builtin_memcpy((void *)res, (constvoid *)p, size);
barrier();
}
}
static __always_inline void __write_once_size(volatilevoid *p, void *res, int size)
{ switch (size) { case 1: *(volatile __u8_alias_t *) p = *(__u8_alias_t *) res; break; case 2: *(volatile __u16_alias_t *) p = *(__u16_alias_t *) res; break; case 4: *(volatile __u32_alias_t *) p = *(__u32_alias_t *) res; break; case 8: *(volatile __u64_alias_t *) p = *(__u64_alias_t *) res; break; default:
barrier();
__builtin_memcpy((void *)p, (constvoid *)res, size);
barrier();
}
}
/* * __unqual_typeof(x) - Declare an unqualified scalar type, leaving * non-scalar types unchanged, * * Prefer C11 _Generic for better compile-times and simpler code. Note: 'char' * is not type-compatible with 'signed char', and we define a separate case. * * This is copied verbatim from kernel's include/linux/compiler_types.h, but * with default expression (for pointers) changed from (x) to (typeof(x)0). * * This is because LLVM has a bug where for lvalue (x), it does not get rid of * an extra address_space qualifier, but does in case of rvalue (typeof(x)0). * Hence, for pointers, we need to create an rvalue expression to get the * desired type. See https://github.com/llvm/llvm-project/issues/53400.
*/ #define __scalar_type_to_expr_cases(type) \ unsigned type : (unsigned type)0, signed type : (signed type)0
/* * log2_u32 - Compute the base 2 logarithm of a 32-bit exponential value. * @v: The value for which we're computing the base 2 logarithm.
*/ staticinline u32 log2_u32(u32 v)
{
u32 r;
u32 shift;
r = (v > 0xFFFF) << 4; v >>= r;
shift = (v > 0xFF) << 3; v >>= shift; r |= shift;
shift = (v > 0xF) << 2; v >>= shift; r |= shift;
shift = (v > 0x3) << 1; v >>= shift; r |= shift;
r |= (v >> 1); return r;
}
/* * log2_u64 - Compute the base 2 logarithm of a 64-bit exponential value. * @v: The value for which we're computing the base 2 logarithm.
*/ staticinline u32 log2_u64(u64 v)
{
u32 hi = v >> 32; if (hi) return log2_u32(hi) + 32 + 1; else return log2_u32(v) + 1;
}
/* * Return a value proportionally scaled to the task's weight.
*/ staticinline u64 scale_by_task_weight(conststruct task_struct *p, u64 value)
{ return (value * p->scx.weight) / 100;
}
/* * Return a value inversely proportional to the task's weight.
*/ staticinline u64 scale_by_task_weight_inverse(conststruct task_struct *p, u64 value)
{ return value * 100 / p->scx.weight;
}
#include"compat.bpf.h" #include"enums.bpf.h"
#endif/* __SCX_COMMON_BPF_H */
Messung V0.5
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.