github.com/cilium/ebpf@v0.15.1-0.20240517100537-8079b37aa138/btf/traversal_test.go (about)

     1  package btf
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"github.com/go-quicktest/qt"
     8  )
     9  
    10  func TestPostorderTraversal(t *testing.T) {
    11  	ptr := newCyclicalType(2).(*Pointer)
    12  	cst := ptr.Target.(*Const)
    13  	str := cst.Type.(*Struct)
    14  
    15  	t.Logf("%3v", ptr)
    16  	pending := []Type{str, cst, ptr}
    17  	visitInPostorder(ptr, nil, func(typ Type) bool {
    18  		qt.Assert(t, qt.Equals(typ, pending[0]))
    19  		pending = pending[1:]
    20  		return true
    21  	})
    22  	qt.Assert(t, qt.HasLen(pending, 0))
    23  
    24  	i := &Int{Name: "foo"}
    25  	// i appears twice at the same nesting depth.
    26  	arr := &Array{Index: i, Type: i}
    27  	seen := make(map[Type]bool)
    28  	visitInPostorder(arr, nil, func(typ Type) bool {
    29  		qt.Assert(t, qt.IsFalse(seen[typ]))
    30  		seen[typ] = true
    31  		return true
    32  	})
    33  	qt.Assert(t, qt.IsTrue(seen[arr]))
    34  	qt.Assert(t, qt.IsTrue(seen[i]))
    35  }
    36  
    37  func TestPostorderTraversalVmlinux(t *testing.T) {
    38  	spec := vmlinuxTestdataSpec(t)
    39  
    40  	typ, err := spec.AnyTypeByName("gov_update_cpu_data")
    41  	if err != nil {
    42  		t.Fatal(err)
    43  	}
    44  
    45  	for _, typ := range []Type{typ} {
    46  		t.Run(fmt.Sprintf("%s", typ), func(t *testing.T) {
    47  			seen := make(map[Type]bool)
    48  			var last Type
    49  			visitInPostorder(typ, nil, func(typ Type) bool {
    50  				if seen[typ] {
    51  					t.Fatalf("%s visited twice", typ)
    52  				}
    53  				seen[typ] = true
    54  				last = typ
    55  				return true
    56  			})
    57  			if last != typ {
    58  				t.Fatalf("Expected %s got %s as last type", typ, last)
    59  			}
    60  
    61  			children(typ, func(child *Type) bool {
    62  				qt.Check(t, qt.IsTrue(seen[*child]), qt.Commentf("missing child %s", *child))
    63  				return true
    64  			})
    65  		})
    66  	}
    67  }
    68  
    69  func BenchmarkPostorderTraversal(b *testing.B) {
    70  	spec := vmlinuxTestdataSpec(b)
    71  
    72  	var fn *Func
    73  	err := spec.TypeByName("gov_update_cpu_data", &fn)
    74  	if err != nil {
    75  		b.Fatal(err)
    76  	}
    77  
    78  	for _, test := range []struct {
    79  		name string
    80  		typ  Type
    81  	}{
    82  		{"single type", &Int{}},
    83  		{"cycle(1)", newCyclicalType(1)},
    84  		{"cycle(10)", newCyclicalType(10)},
    85  		{"gov_update_cpu_data", fn},
    86  	} {
    87  		b.Logf("%10v", test.typ)
    88  
    89  		b.Run(test.name, func(b *testing.B) {
    90  			b.ReportAllocs()
    91  			for i := 0; i < b.N; i++ {
    92  				visitInPostorder(test.typ, nil, func(t Type) bool { return true })
    93  			}
    94  		})
    95  	}
    96  }