// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2023. Huawei Technologies Co., Ltd */
#include <vmlinux.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_helpers.h>
#include "bpf_experimental.h"
#include "bpf_misc.h"
struct generic_map_value {
void *data;
};
char _license[] SEC("license" ) = "GPL" ;
const unsigned int data_sizes[] = {16 , 32 , 64 , 96 , 128 , 192 , 256 , 512 , 1024 , 2048 , 4096 };
const volatile unsigned int data_btf_ids[ARRAY_SIZE(data_sizes)] = {};
const unsigned int percpu_data_sizes[] = {8 , 16 , 32 , 64 , 96 , 128 , 192 , 256 , 512 };
const volatile unsigned int percpu_data_btf_ids[ARRAY_SIZE(data_sizes)] = {};
int err = 0 ;
u32 pid = 0 ;
#define DEFINE_ARRAY_WITH_KPTR(_size) \
struct bin_data_## _size { \
char data[_size - sizeof (void *)]; \
}; \
/* See Commit 5d8d6634ccc, force btf generation for type bin_data_##_size */ \
struct bin_data_## _size *__bin_data_## _size; \
struct map_value_## _size { \
struct bin_data_## _size __kptr * data; \
}; \
struct { \
__uint(type, BPF_MAP_TYPE_ARRAY); \
__type(key, int ); \
__type(value, struct map_value_## _size); \
__uint(max_entries, 128 ); \
} array_## _size SEC(".maps" )
#define DEFINE_ARRAY_WITH_PERCPU_KPTR(_size) \
struct percpu_bin_data_## _size { \
char data[_size]; \
}; \
struct percpu_bin_data_## _size *__percpu_bin_data_## _size; \
struct map_value_percpu_## _size { \
struct percpu_bin_data_## _size __percpu_kptr * data; \
}; \
struct { \
__uint(type, BPF_MAP_TYPE_ARRAY); \
__type(key, int ); \
__type(value, struct map_value_percpu_## _size); \
__uint(max_entries, 128 ); \
} array_percpu_## _size SEC(".maps" )
static __always_inline void batch_alloc(struct bpf_map *map, unsigned int batch, unsigned int idx)
{
struct generic_map_value *value;
unsigned int i, key;
void *old, *new ;
for (i = 0 ; i < batch; i++) {
key = i;
value = bpf_map_lookup_elem(map, &key);
if (!value) {
err = 1 ;
return ;
}
new = bpf_obj_new_impl(data_btf_ids[idx], NULL);
if (!new ) {
err = 2 ;
return ;
}
old = bpf_kptr_xchg(&value->data, new );
if (old) {
bpf_obj_drop(old);
err = 3 ;
return ;
}
}
}
static __always_inline void batch_free(struct bpf_map *map, unsigned int batch, unsigned int idx)
{
struct generic_map_value *value;
unsigned int i, key;
void *old;
for (i = 0 ; i < batch; i++) {
key = i;
value = bpf_map_lookup_elem(map, &key);
if (!value) {
err = 4 ;
return ;
}
old = bpf_kptr_xchg(&value->data, NULL);
if (!old) {
err = 5 ;
return ;
}
bpf_obj_drop(old);
}
}
static __always_inline void batch_percpu_alloc(struct bpf_map *map, unsigned int batch,
unsigned int idx)
{
struct generic_map_value *value;
unsigned int i, key;
void *old, *new ;
for (i = 0 ; i < batch; i++) {
key = i;
value = bpf_map_lookup_elem(map, &key);
if (!value) {
err = 1 ;
return ;
}
/* per-cpu allocator may not be able to refill in time */
new = bpf_percpu_obj_new_impl(percpu_data_btf_ids[idx], NULL);
if (!new )
continue ;
old = bpf_kptr_xchg(&value->data, new );
if (old) {
bpf_percpu_obj_drop(old);
err = 2 ;
return ;
}
}
}
static __always_inline void batch_percpu_free(struct bpf_map *map, unsigned int batch,
unsigned int idx)
{
struct generic_map_value *value;
unsigned int i, key;
void *old;
for (i = 0 ; i < batch; i++) {
key = i;
value = bpf_map_lookup_elem(map, &key);
if (!value) {
err = 3 ;
return ;
}
old = bpf_kptr_xchg(&value->data, NULL);
if (!old)
continue ;
bpf_percpu_obj_drop(old);
}
}
#define CALL_BATCH_ALLOC(size, batch, idx) \
batch_alloc((struct bpf_map *)(&array_## size), batch, idx)
#define CALL_BATCH_ALLOC_FREE(size, batch, idx) \
do { \
batch_alloc((struct bpf_map *)(&array_## size), batch, idx); \
batch_free((struct bpf_map *)(&array_## size), batch, idx); \
} while (0 )
#define CALL_BATCH_PERCPU_ALLOC(size, batch, idx) \
batch_percpu_alloc((struct bpf_map *)(&array_percpu_## size), batch, idx)
#define CALL_BATCH_PERCPU_ALLOC_FREE(size, batch, idx) \
do { \
batch_percpu_alloc((struct bpf_map *)(&array_percpu_## size), batch, idx); \
batch_percpu_free((struct bpf_map *)(&array_percpu_## size), batch, idx); \
} while (0 )
/* kptr doesn't support bin_data_8 which is a zero-sized array */
DEFINE_ARRAY_WITH_KPTR(16 );
DEFINE_ARRAY_WITH_KPTR(32 );
DEFINE_ARRAY_WITH_KPTR(64 );
DEFINE_ARRAY_WITH_KPTR(96 );
DEFINE_ARRAY_WITH_KPTR(128 );
DEFINE_ARRAY_WITH_KPTR(192 );
DEFINE_ARRAY_WITH_KPTR(256 );
DEFINE_ARRAY_WITH_KPTR(512 );
DEFINE_ARRAY_WITH_KPTR(1024 );
DEFINE_ARRAY_WITH_KPTR(2048 );
DEFINE_ARRAY_WITH_KPTR(4096 );
DEFINE_ARRAY_WITH_PERCPU_KPTR(8 );
DEFINE_ARRAY_WITH_PERCPU_KPTR(16 );
DEFINE_ARRAY_WITH_PERCPU_KPTR(32 );
DEFINE_ARRAY_WITH_PERCPU_KPTR(64 );
DEFINE_ARRAY_WITH_PERCPU_KPTR(96 );
DEFINE_ARRAY_WITH_PERCPU_KPTR(128 );
DEFINE_ARRAY_WITH_PERCPU_KPTR(192 );
DEFINE_ARRAY_WITH_PERCPU_KPTR(256 );
DEFINE_ARRAY_WITH_PERCPU_KPTR(512 );
SEC("?fentry/" SYS_PREFIX "sys_nanosleep" )
int test_batch_alloc_free(void *ctx)
{
if ((u32)bpf_get_current_pid_tgid() != pid)
return 0 ;
/* Alloc 128 16-bytes objects in batch to trigger refilling,
* then free 128 16-bytes objects in batch to trigger freeing.
*/
CALL_BATCH_ALLOC_FREE(16 , 128 , 0 );
CALL_BATCH_ALLOC_FREE(32 , 128 , 1 );
CALL_BATCH_ALLOC_FREE(64 , 128 , 2 );
CALL_BATCH_ALLOC_FREE(96 , 128 , 3 );
CALL_BATCH_ALLOC_FREE(128 , 128 , 4 );
CALL_BATCH_ALLOC_FREE(192 , 128 , 5 );
CALL_BATCH_ALLOC_FREE(256 , 128 , 6 );
CALL_BATCH_ALLOC_FREE(512 , 64 , 7 );
CALL_BATCH_ALLOC_FREE(1024 , 32 , 8 );
CALL_BATCH_ALLOC_FREE(2048 , 16 , 9 );
CALL_BATCH_ALLOC_FREE(4096 , 8 , 10 );
return 0 ;
}
SEC("?fentry/" SYS_PREFIX "sys_nanosleep" )
int test_free_through_map_free(void *ctx)
{
if ((u32)bpf_get_current_pid_tgid() != pid)
return 0 ;
/* Alloc 128 16-bytes objects in batch to trigger refilling,
* then free these objects through map free.
*/
CALL_BATCH_ALLOC(16 , 128 , 0 );
CALL_BATCH_ALLOC(32 , 128 , 1 );
CALL_BATCH_ALLOC(64 , 128 , 2 );
CALL_BATCH_ALLOC(96 , 128 , 3 );
CALL_BATCH_ALLOC(128 , 128 , 4 );
CALL_BATCH_ALLOC(192 , 128 , 5 );
CALL_BATCH_ALLOC(256 , 128 , 6 );
CALL_BATCH_ALLOC(512 , 64 , 7 );
CALL_BATCH_ALLOC(1024 , 32 , 8 );
CALL_BATCH_ALLOC(2048 , 16 , 9 );
CALL_BATCH_ALLOC(4096 , 8 , 10 );
return 0 ;
}
SEC("?fentry/" SYS_PREFIX "sys_nanosleep" )
int test_batch_percpu_alloc_free(void *ctx)
{
if ((u32)bpf_get_current_pid_tgid() != pid)
return 0 ;
/* Alloc 128 8-bytes per-cpu objects in batch to trigger refilling,
* then free 128 8-bytes per-cpu objects in batch to trigger freeing.
*/
CALL_BATCH_PERCPU_ALLOC_FREE(8 , 128 , 0 );
CALL_BATCH_PERCPU_ALLOC_FREE(16 , 128 , 1 );
CALL_BATCH_PERCPU_ALLOC_FREE(32 , 128 , 2 );
CALL_BATCH_PERCPU_ALLOC_FREE(64 , 128 , 3 );
CALL_BATCH_PERCPU_ALLOC_FREE(96 , 128 , 4 );
CALL_BATCH_PERCPU_ALLOC_FREE(128 , 128 , 5 );
CALL_BATCH_PERCPU_ALLOC_FREE(192 , 128 , 6 );
CALL_BATCH_PERCPU_ALLOC_FREE(256 , 128 , 7 );
CALL_BATCH_PERCPU_ALLOC_FREE(512 , 64 , 8 );
return 0 ;
}
SEC("?fentry/" SYS_PREFIX "sys_nanosleep" )
int test_percpu_free_through_map_free(void *ctx)
{
if ((u32)bpf_get_current_pid_tgid() != pid)
return 0 ;
/* Alloc 128 8-bytes per-cpu objects in batch to trigger refilling,
* then free these object through map free.
*/
CALL_BATCH_PERCPU_ALLOC(8 , 128 , 0 );
CALL_BATCH_PERCPU_ALLOC(16 , 128 , 1 );
CALL_BATCH_PERCPU_ALLOC(32 , 128 , 2 );
CALL_BATCH_PERCPU_ALLOC(64 , 128 , 3 );
CALL_BATCH_PERCPU_ALLOC(96 , 128 , 4 );
CALL_BATCH_PERCPU_ALLOC(128 , 128 , 5 );
CALL_BATCH_PERCPU_ALLOC(192 , 128 , 6 );
CALL_BATCH_PERCPU_ALLOC(256 , 128 , 7 );
CALL_BATCH_PERCPU_ALLOC(512 , 64 , 8 );
return 0 ;
}
Messung V0.5 in Prozent C=97 H=92 G=94
¤ Dauer der Verarbeitung: 0.9 Sekunden
(vorverarbeitet am 2026-06-07)
¤
*© Formatika GbR, Deutschland