Files
2026-02-25 11:07:15 -08:00

154 lines
5.1 KiB
Go

// Copyright 2023 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package secbenchdef contains struct definitions for secbench benchmarks.
// All structs in this package need to be JSON-serializable.
package secbenchdef
import (
"fmt"
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/bpf"
"gvisor.dev/gvisor/pkg/seccomp"
)
// Bench represents a benchmark to run.
type Bench struct {
// Name is the name of the benchmark.
Name string `json:"name"`
// Profile represents the syscall pattern profile being benchmarked.
Profile Profile `json:"profile"`
// Instructions is the seccomp-bpf program to run the benchmark with.
Instructions []bpf.Instruction `json:"instructions"`
// BuildStats contains information on timing and size of the program.
BuildStats seccomp.BuildStats `json:"buildStats"`
// AllowRejected can be set to true if some sequences in the application
// profile are expected to not be allowed.
// If this is the case, the program's overall performance will not be
// reported.
AllowRejected bool `json:"allowRejected"`
}
// Profile represents an application's syscall profile.
type Profile struct {
// Arch is the architecture of the application.
// Should be an AUDIT_ARCH_* value.
Arch uint32 `json:"arch"`
// Sequences is a set of weighted syscall sequences.
// A benchmark with a given Profile will run these sequences
// picked by weighted random choice.
Sequences []Sequence `json:"sequences"`
}
// Sequence is a syscall sequence that the benchmark will make.
type Sequence struct {
// Name is the name of the sequence.
Name string `json:"name"`
// Weight is the weight of the sequence relative to all others within the
// same Profile.
Weight int `json:"weight"`
// Syscalls is the set of syscalls of the sequence.
Syscalls []Syscall `json:"syscalls"`
}
// String returns the name of the Sequence.
func (s Sequence) String() string {
return s.Name
}
const (
// NonExistentFD is an FD that is overwhelmingly likely to not exist,
// because it would mean that the application has opened 2^31-1 FDs.
// Useful to make sure syscalls involving FDs don't actually
// do anything serious.
NonExistentFD = uintptr(0x7fffffff)
// BadFD can be used as an invalid FD in syscall arguments.
BadFD = uintptr(0x80000000)
)
// Syscall is a single syscall within a Sequence.
type Syscall struct {
// Special may be set for syscalls with special handling.
// If set, this takes precedence over the other fields.
Special SpecialSyscall `json:"special,omitempty"`
// Sysno is the syscall number.
Sysno uintptr `json:"sysno"`
// Args is the syscall arguments.
Args [6]uintptr `json:"args"`
}
// Sys is a helper function to create a Syscall struct.
func Sys(sysno uintptr, args ...uintptr) Syscall {
if len(args) > 6 {
panic(fmt.Sprintf("cannot pass more than 6 syscall arguments, got: %v", args))
}
var sixArgs [6]uintptr
copy(sixArgs[:], args)
return Syscall{
Sysno: sysno,
Args: sixArgs,
}
}
// Single takes in a single syscall data and returns a one-item Syscall slice.
func Single(sysno uintptr, args ...uintptr) []Syscall {
return []Syscall{Sys(sysno, args...)}
}
// Call calls the system call.
//
//go:nosplit
func (s *Syscall) Call() (r1 uintptr, r2 uintptr, err error) {
if s.Special != "" {
return s.Special.Call()
}
return unix.Syscall6(s.Sysno, s.Args[0], s.Args[1], s.Args[2], s.Args[3], s.Args[4], s.Args[5])
}
// BenchRunRequest encodes a request sent to the benchmark runner binary.
type BenchRunRequest struct {
// Bench is the benchmark being run.
Bench Bench `json:"bench"`
// Iterations is the number of iterations to do (b.N).
Iterations uint64 `json:"iterations"`
// RandomSeed is the random seed to use to pick sequences.
RandomSeed int64 `json:"randomSeed"`
// ActiveSequences[i] is true if Bench.Profile.Sequences[i] should be
// run.
ActiveSequences []bool `json:"activeSequences"`
// InstallFilter is true if the seccomp-bpf filter should be actually
// installed. Setting this to false allows measuring the filter-less
// performance, so that it can be subtracted from performance with the
// filter.
InstallFilter bool `json:"installFilter"`
}
// SequenceMetrics is the per-sequence part of BenchRunResponse.
type SequenceMetrics struct {
Iterations uint64 `json:"iterations"`
TotalNanos uint64 `json:"totalNanos"`
}
// BenchRunResponse encodes a response from the runner binary.
type BenchRunResponse struct {
// TotalNanos is the number of nanoseconds that the whole run took.
TotalNanos uint64 `json:"totalNanos"`
// SequenceMetrics is the per-sequence metrics, mapped by index against
// the sequences in the Profile.
SequenceMetrics []SequenceMetrics `json:"sequenceMetrics"`
}