Commit 52dbd67d authored by Jose E. Marchesi's avatar Jose E. Marchesi Committed by Andrii Nakryiko
Browse files

bpf: Abstract loop unrolling pragmas in BPF selftests



[Changes from V1:
- Avoid conflict by rebasing with latest master.]

Some BPF tests use loop unrolling compiler pragmas that are clang
specific and not supported by GCC.  These pragmas, along with their
GCC equivalences are:

  #pragma clang loop unroll_count(N)
  #pragma GCC unroll N

  #pragma clang loop unroll(full)
  #pragma GCC unroll 65534

  #pragma clang loop unroll(disable)
  #pragma GCC unroll 1

  #pragma unroll [aka #pragma clang loop unroll(enable)]
  There is no GCC equivalence to this pragma.  It enables unrolling on
  loops that the compiler would not ordinarily unroll even with
  -O2|-funroll-loops, but it is not equivalent to full unrolling
  either.

This patch adds a new header progs/bpf_compiler.h that defines the
following macros, which correspond to each pair of compiler-specific
pragmas above:

  __pragma_loop_unroll_count(N)
  __pragma_loop_unroll_full
  __pragma_loop_no_unroll
  __pragma_loop_unroll

The selftests using loop unrolling pragmas are then changed to include
the header and use these macros in place of the explicit pragmas.

Tested in bpf-next master.
No regressions.

Signed-off-by: default avatarJose E. Marchesi <jose.marchesi@oracle.com>
Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Acked-by: default avatarYonghong Song <yonghong.song@linux.dev>
Link: https://lore.kernel.org/bpf/20240208203612.29611-1-jose.marchesi@oracle.com
parent fc1c9e40
Loading
Loading
Loading
Loading
+33 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __BPF_COMPILER_H__
#define __BPF_COMPILER_H__

#define DO_PRAGMA_(X) _Pragma(#X)

#if __clang__
#define __pragma_loop_unroll DO_PRAGMA_(clang loop unroll(enable))
#else
/* In GCC -funroll-loops, which is enabled with -O2, should have the
   same impact than the loop-unroll-enable pragma above.  */
#define __pragma_loop_unroll
#endif

#if __clang__
#define __pragma_loop_unroll_count(N) DO_PRAGMA_(clang loop unroll_count(N))
#else
#define __pragma_loop_unroll_count(N) DO_PRAGMA_(GCC unroll N)
#endif

#if __clang__
#define __pragma_loop_unroll_full DO_PRAGMA_(clang loop unroll(full))
#else
#define __pragma_loop_unroll_full DO_PRAGMA_(GCC unroll 65534)
#endif

#if __clang__
#define __pragma_loop_no_unroll DO_PRAGMA_(clang loop unroll(disable))
#else
#define __pragma_loop_no_unroll DO_PRAGMA_(GCC unroll 1)
#endif

#endif
+3 −2
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include "bpf_misc.h"
#include "bpf_compiler.h"

#define ARRAY_SIZE(x) (int)(sizeof(x) / sizeof((x)[0]))

@@ -183,7 +184,7 @@ int iter_pragma_unroll_loop(const void *ctx)
	MY_PID_GUARD();

	bpf_iter_num_new(&it, 0, 2);
#pragma nounroll
	__pragma_loop_no_unroll
	for (i = 0; i < 3; i++) {
		v = bpf_iter_num_next(&it);
		bpf_printk("ITER_BASIC: E3 VAL: i=%d v=%d", i, v ? *v : -1);
@@ -238,7 +239,7 @@ int iter_multiple_sequential_loops(const void *ctx)
	bpf_iter_num_destroy(&it);

	bpf_iter_num_new(&it, 0, 2);
#pragma nounroll
	__pragma_loop_no_unroll
	for (i = 0; i < 3; i++) {
		v = bpf_iter_num_next(&it);
		bpf_printk("ITER_BASIC: E3 VAL: i=%d v=%d", i, v ? *v : -1);
+3 −1
Original line number Diff line number Diff line
@@ -3,6 +3,8 @@
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>

#include "bpf_compiler.h"

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

SEC("socket")
@@ -10,7 +12,7 @@ int combinations(volatile struct __sk_buff* skb)
{
	int ret = 0, i;

#pragma nounroll
	__pragma_loop_no_unroll
	for (i = 0; i < 20; i++)
		if (skb->len)
			ret |= 1 << i;
+9 −8
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
#include "profiler.h"
#include "err.h"
#include "bpf_experimental.h"
#include "bpf_compiler.h"

#ifndef NULL
#define NULL 0
@@ -169,7 +170,7 @@ static INLINE int get_var_spid_index(struct var_kill_data_arr_t* arr_struct,
				     int spid)
{
#ifdef UNROLL
#pragma unroll
	__pragma_loop_unroll
#endif
	for (int i = 0; i < ARRAY_SIZE(arr_struct->array); i++)
		if (arr_struct->array[i].meta.pid == spid)
@@ -185,7 +186,7 @@ static INLINE void populate_ancestors(struct task_struct* task,

	ancestors_data->num_ancestors = 0;
#ifdef UNROLL
#pragma unroll
	__pragma_loop_unroll
#endif
	for (num_ancestors = 0; num_ancestors < MAX_ANCESTORS; num_ancestors++) {
		parent = BPF_CORE_READ(parent, real_parent);
@@ -212,7 +213,7 @@ static INLINE void* read_full_cgroup_path(struct kernfs_node* cgroup_node,
	size_t filepart_length;

#ifdef UNROLL
#pragma unroll
	__pragma_loop_unroll
#endif
	for (int i = 0; i < MAX_CGROUPS_PATH_DEPTH; i++) {
		filepart_length =
@@ -261,7 +262,7 @@ static INLINE void* populate_cgroup_info(struct cgroup_data_t* cgroup_data,
		int cgrp_id = bpf_core_enum_value(enum cgroup_subsys_id___local,
						  pids_cgrp_id___local);
#ifdef UNROLL
#pragma unroll
		__pragma_loop_unroll
#endif
		for (int i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
			struct cgroup_subsys_state* subsys =
@@ -402,7 +403,7 @@ static INLINE int trace_var_sys_kill(void* ctx, int tpid, int sig)
			if (kill_data == NULL)
				return 0;
#ifdef UNROLL
#pragma unroll
			__pragma_loop_unroll
#endif
			for (int i = 0; i < ARRAY_SIZE(arr_struct->array); i++)
				if (arr_struct->array[i].meta.pid == 0) {
@@ -482,7 +483,7 @@ read_absolute_file_path_from_dentry(struct dentry* filp_dentry, void* payload)
	struct dentry* parent_dentry;

#ifdef UNROLL
#pragma unroll
	__pragma_loop_unroll
#endif
	for (int i = 0; i < MAX_PATH_DEPTH; i++) {
		filepart_length =
@@ -508,7 +509,7 @@ is_ancestor_in_allowed_inodes(struct dentry* filp_dentry)
{
	struct dentry* parent_dentry;
#ifdef UNROLL
#pragma unroll
	__pragma_loop_unroll
#endif
	for (int i = 0; i < MAX_PATH_DEPTH; i++) {
		u64 dir_ino = BPF_CORE_READ(filp_dentry, d_inode, i_ino);
@@ -629,7 +630,7 @@ int raw_tracepoint__sched_process_exit(void* ctx)
	struct kernfs_node* proc_kernfs = BPF_CORE_READ(task, cgroups, dfl_cgrp, kn);

#ifdef UNROLL
#pragma unroll
	__pragma_loop_unroll
#endif
	for (int i = 0; i < ARRAY_SIZE(arr_struct->array); i++) {
		struct var_kill_data_t* past_kill_data = &arr_struct->array[i];
+4 −3
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include "bpf_misc.h"
#include "bpf_compiler.h"

#define FUNCTION_NAME_LEN 64
#define FILE_NAME_LEN 128
@@ -298,11 +299,11 @@ int __on_event(struct bpf_raw_tracepoint_args *ctx)
#if defined(USE_ITER)
/* no for loop, no unrolling */
#elif defined(NO_UNROLL)
#pragma clang loop unroll(disable)
	__pragma_loop_no_unroll
#elif defined(UNROLL_COUNT)
#pragma clang loop unroll_count(UNROLL_COUNT)
	__pragma_loop_unroll_count(UNROLL_COUNT)
#else
#pragma clang loop unroll(full)
	__pragma_loop_unroll_full
#endif /* NO_UNROLL */
		/* Unwind python stack */
#ifdef USE_ITER
Loading