gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/secbench/secbenchdef/secbenchdef.go (about)

     1  // Copyright 2023 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package secbenchdef contains struct definitions for secbench benchmarks.
    16  // All structs in this package need to be JSON-serializable.
    17  package secbenchdef
    18  
    19  import (
    20  	"fmt"
    21  
    22  	"golang.org/x/sys/unix"
    23  	"gvisor.dev/gvisor/pkg/bpf"
    24  	"gvisor.dev/gvisor/pkg/seccomp"
    25  )
    26  
    27  // Bench represents a benchmark to run.
    28  type Bench struct {
    29  	// Name is the name of the benchmark.
    30  	Name string `json:"name"`
    31  	// Profile represents the syscall pattern profile being benchmarked.
    32  	Profile Profile `json:"profile"`
    33  	// Instructions is the seccomp-bpf program to run the benchmark with.
    34  	Instructions []bpf.Instruction `json:"instructions"`
    35  	// BuildStats contains information on timing and size of the program.
    36  	BuildStats seccomp.BuildStats `json:"buildStats"`
    37  	// AllowRejected can be set to true if some sequences in the application
    38  	// profile are expected to not be allowed.
    39  	// If this is the case, the program's overall performance will not be
    40  	// reported.
    41  	AllowRejected bool `json:"allowRejected"`
    42  }
    43  
    44  // Profile represents an application's syscall profile.
    45  type Profile struct {
    46  	// Arch is the architecture of the application.
    47  	// Should be an AUDIT_ARCH_* value.
    48  	Arch uint32 `json:"arch"`
    49  	// Sequences is a set of weighted syscall sequences.
    50  	// A benchmark with a given Profile will run these sequences
    51  	// picked by weighted random choice.
    52  	Sequences []Sequence `json:"sequences"`
    53  }
    54  
    55  // Sequence is a syscall sequence that the benchmark will make.
    56  type Sequence struct {
    57  	// Name is the name of the sequence.
    58  	Name string `json:"name"`
    59  	// Weight is the weight of the sequence relative to all others within the
    60  	// same Profile.
    61  	Weight int `json:"weight"`
    62  	// Syscalls is the set of syscalls of the sequence.
    63  	Syscalls []Syscall `json:"syscalls"`
    64  }
    65  
    66  // String returns the name of the Sequence.
    67  func (s Sequence) String() string {
    68  	return s.Name
    69  }
    70  
    71  const (
    72  	// NonExistentFD is an FD that is overwhelmingly likely to not exist,
    73  	// because it would mean that the application has opened 2^31-1 FDs.
    74  	// Useful to make sure syscalls involving FDs don't actually
    75  	// do anything serious.
    76  	NonExistentFD = uintptr(0x7fffffff)
    77  
    78  	// BadFD can be used as an invalid FD in syscall arguments.
    79  	BadFD = uintptr(0x80000000)
    80  )
    81  
    82  // Syscall is a single syscall within a Sequence.
    83  type Syscall struct {
    84  	// Special may be set for syscalls with special handling.
    85  	// If set, this takes precedence over the other fields.
    86  	Special SpecialSyscall `json:"special,omitempty"`
    87  	// Sysno is the syscall number.
    88  	Sysno uintptr `json:"sysno"`
    89  	// Args is the syscall arguments.
    90  	Args [6]uintptr `json:"args"`
    91  }
    92  
    93  // Sys is a helper function to create a Syscall struct.
    94  func Sys(sysno uintptr, args ...uintptr) Syscall {
    95  	if len(args) > 6 {
    96  		panic(fmt.Sprintf("cannot pass more than 6 syscall arguments, got: %v", args))
    97  	}
    98  	var sixArgs [6]uintptr
    99  	for i := 0; i < len(args); i++ {
   100  		sixArgs[i] = args[i]
   101  	}
   102  	return Syscall{
   103  		Sysno: sysno,
   104  		Args:  sixArgs,
   105  	}
   106  }
   107  
   108  // Single takes in a single syscall data and returns a one-item Syscall slice.
   109  func Single(sysno uintptr, args ...uintptr) []Syscall {
   110  	return []Syscall{Sys(sysno, args...)}
   111  }
   112  
   113  // Call calls the system call.
   114  //
   115  //go:nosplit
   116  func (s *Syscall) Call() (r1 uintptr, r2 uintptr, err error) {
   117  	if s.Special != "" {
   118  		return s.Special.Call()
   119  	}
   120  	return unix.Syscall6(s.Sysno, s.Args[0], s.Args[1], s.Args[2], s.Args[3], s.Args[4], s.Args[5])
   121  }
   122  
   123  // BenchRunRequest encodes a request sent to the benchmark runner binary.
   124  type BenchRunRequest struct {
   125  	// Bench is the benchmark being run.
   126  	Bench Bench `json:"bench"`
   127  	// Iterations is the number of iterations to do (b.N).
   128  	Iterations uint64 `json:"iterations"`
   129  	// RandomSeed is the random seed to use to pick sequences.
   130  	RandomSeed int64 `json:"randomSeed"`
   131  	// ActiveSequences[i] is true if Bench.Profile.Sequences[i] should be
   132  	// run.
   133  	ActiveSequences []bool `json:"activeSequences"`
   134  	// InstallFilter is true if the seccomp-bpf filter should be actually
   135  	// installed. Setting this to false allows measuring the filter-less
   136  	// performance, so that it can be subtracted from performance with the
   137  	// filter.
   138  	InstallFilter bool `json:"installFilter"`
   139  }
   140  
   141  // SequenceMetrics is the per-sequence part of BenchRunResponse.
   142  type SequenceMetrics struct {
   143  	Iterations uint64 `json:"iterations"`
   144  	TotalNanos uint64 `json:"totalNanos"`
   145  }
   146  
   147  // BenchRunResponse encodes a response from the runner binary.
   148  type BenchRunResponse struct {
   149  	// TotalNanos is the number of nanoseconds that the whole run took.
   150  	TotalNanos uint64 `json:"totalNanos"`
   151  
   152  	// SequenceMetrics is the per-sequence metrics, mapped by index against
   153  	// the sequences in the Profile.
   154  	SequenceMetrics []SequenceMetrics `json:"sequenceMetrics"`
   155  }