Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b061017f authored by Alexei Starovoitov's avatar Alexei Starovoitov Committed by Daniel Borkmann
Browse files

selftests/bpf: add realistic loop tests



Add a bunch of loop tests. Most of them are created by replacing
'#pragma unroll' with '#pragma clang loop unroll(disable)'

Several tests are artificially large:
  /* partial unroll. llvm will unroll loop ~150 times.
   * C loop count -> 600.
   * Asm loop count -> 4.
   * 16k insns in loop body.
   * Total of 5 such loops. Total program size ~82k insns.
   */
  "./pyperf600.o",

  /* no unroll at all.
   * C loop count -> 600.
   * ASM loop count -> 600.
   * ~110 insns in loop body.
   * Total of 5 such loops. Total program size ~1500 insns.
   */
  "./pyperf600_nounroll.o",

  /* partial unroll. 19k insn in a loop.
   * Total program size 20.8k insn.
   * ~350k processed_insns
   */
  "./strobemeta.o",

Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
Acked-by: default avatarAndrii Nakryiko <andriin@fb.com>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
parent 0d3679e9
Loading
Loading
Loading
Loading
+56 −11
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@ static int libbpf_debug_print(enum libbpf_print_level level,
			      const char *format, va_list args)
{
	if (level != LIBBPF_DEBUG)
		return 0;
		return vfprintf(stderr, format, args);

	if (!strstr(format, "verifier log"))
		return 0;
@@ -32,24 +32,69 @@ static int check_load(const char *file, enum bpf_prog_type type)

void test_bpf_verif_scale(void)
{
	const char *scale[] = {
		"./test_verif_scale1.o", "./test_verif_scale2.o", "./test_verif_scale3.o"
	const char *sched_cls[] = {
		"./test_verif_scale1.o", "./test_verif_scale2.o", "./test_verif_scale3.o",
	};
	const char *pyperf[] = {
		"./pyperf50.o",	"./pyperf100.o", "./pyperf180.o"
	const char *raw_tp[] = {
		/* full unroll by llvm */
		"./pyperf50.o",	"./pyperf100.o", "./pyperf180.o",

		/* partial unroll. llvm will unroll loop ~150 times.
		 * C loop count -> 600.
		 * Asm loop count -> 4.
		 * 16k insns in loop body.
		 * Total of 5 such loops. Total program size ~82k insns.
		 */
		"./pyperf600.o",

		/* no unroll at all.
		 * C loop count -> 600.
		 * ASM loop count -> 600.
		 * ~110 insns in loop body.
		 * Total of 5 such loops. Total program size ~1500 insns.
		 */
		"./pyperf600_nounroll.o",

		"./loop1.o", "./loop2.o",

		/* partial unroll. 19k insn in a loop.
		 * Total program size 20.8k insn.
		 * ~350k processed_insns
		 */
		"./strobemeta.o",

		/* no unroll, tiny loops */
		"./strobemeta_nounroll1.o",
		"./strobemeta_nounroll2.o",
	};
	const char *cg_sysctl[] = {
		"./test_sysctl_loop1.o", "./test_sysctl_loop2.o",
	};
	int err, i;

	if (verifier_stats)
		libbpf_set_print(libbpf_debug_print);

	for (i = 0; i < ARRAY_SIZE(scale); i++) {
		err = check_load(scale[i], BPF_PROG_TYPE_SCHED_CLS);
		printf("test_scale:%s:%s\n", scale[i], err ? "FAIL" : "OK");
	err = check_load("./loop3.o", BPF_PROG_TYPE_RAW_TRACEPOINT);
	printf("test_scale:loop3:%s\n", err ? (error_cnt--, "OK") : "FAIL");

	for (i = 0; i < ARRAY_SIZE(sched_cls); i++) {
		err = check_load(sched_cls[i], BPF_PROG_TYPE_SCHED_CLS);
		printf("test_scale:%s:%s\n", sched_cls[i], err ? "FAIL" : "OK");
	}

	for (i = 0; i < ARRAY_SIZE(pyperf); i++) {
		err = check_load(pyperf[i], BPF_PROG_TYPE_RAW_TRACEPOINT);
		printf("test_scale:%s:%s\n", pyperf[i], err ? "FAIL" : "OK");
	for (i = 0; i < ARRAY_SIZE(raw_tp); i++) {
		err = check_load(raw_tp[i], BPF_PROG_TYPE_RAW_TRACEPOINT);
		printf("test_scale:%s:%s\n", raw_tp[i], err ? "FAIL" : "OK");
	}

	for (i = 0; i < ARRAY_SIZE(cg_sysctl); i++) {
		err = check_load(cg_sysctl[i], BPF_PROG_TYPE_CGROUP_SYSCTL);
		printf("test_scale:%s:%s\n", cg_sysctl[i], err ? "FAIL" : "OK");
	}
	err = check_load("./test_xdp_loop.o", BPF_PROG_TYPE_XDP);
	printf("test_scale:test_xdp_loop:%s\n", err ? "FAIL" : "OK");

	err = check_load("./test_seg6_loop.o", BPF_PROG_TYPE_LWT_SEG6LOCAL);
	printf("test_scale:test_seg6_loop:%s\n", err ? "FAIL" : "OK");
}
+28 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019 Facebook
#include <linux/sched.h>
#include <linux/ptrace.h>
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <linux/bpf.h>
#include "bpf_helpers.h"

char _license[] SEC("license") = "GPL";

SEC("raw_tracepoint/kfree_skb")
int nested_loops(volatile struct pt_regs* ctx)
{
	int i, j, sum = 0, m;

	for (j = 0; j < 300; j++)
		for (i = 0; i < j; i++) {
			if (j & 1)
				m = ctx->rax;
			else
				m = j;
			sum += i * m;
		}

	return sum;
}
+28 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019 Facebook
#include <linux/sched.h>
#include <linux/ptrace.h>
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <linux/bpf.h>
#include "bpf_helpers.h"

char _license[] SEC("license") = "GPL";

SEC("raw_tracepoint/consume_skb")
int while_true(volatile struct pt_regs* ctx)
{
	int i = 0;

	while (true) {
		if (ctx->rax & 1)
			i += 3;
		else
			i += 7;
		if (i > 40)
			break;
	}

	return i;
}
+22 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019 Facebook
#include <linux/sched.h>
#include <linux/ptrace.h>
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <linux/bpf.h>
#include "bpf_helpers.h"

char _license[] SEC("license") = "GPL";

SEC("raw_tracepoint/consume_skb")
int while_true(volatile struct pt_regs* ctx)
{
	__u64 i = 0, sum = 0;
	do {
		i++;
		sum += ctx->rax;
	} while (i < 0x100000000ULL);
	return sum;
}
+5 −1
Original line number Diff line number Diff line
@@ -220,7 +220,11 @@ static inline __attribute__((__always_inline__)) int __on_event(struct pt_regs *
		int32_t* symbol_counter = bpf_map_lookup_elem(&symbolmap, &sym);
		if (symbol_counter == NULL)
			return 0;
#pragma unroll
#ifdef NO_UNROLL
#pragma clang loop unroll(disable)
#else
#pragma clang loop unroll(full)
#endif
		/* Unwind python stack */
		for (int i = 0; i < STACK_MAX_LEN; ++i) {
			if (frame_ptr && get_frame_data(frame_ptr, pidData, &frame, &sym)) {
Loading