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 }