Help us shape the future of Go! Take the 2026 Go Developer Survey

perfharness

package
v0.3.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 3, 2026 License: GPL-3.0 Imports: 28 Imported by: 0

Documentation

Index

Constants

View Source
const Password = "etherperf-password"

Credentials minted into the throwaway copy. Every viewer signs in with Password through the real protocol sign-in routes; Plex and the owner console use a minted Plex token; Stremio uses a minted surface grant.

View Source
const RestrictedViewer = 2

RestrictedViewer is the fixture viewer with a rating cap and a plex.tv share filter, so restricted listings are measured on a full library.

Variables

View Source
var Budgets = map[string]Budget{
	// contains filtered or unexported fields
}
View Source
var LargeScale = Scale{Movies: 250_000, Shows: 10_000, SeasonsPerShow: 4, EpisodesPerSeason: 6, Viewers: 2, HistoryPerViewer: 20_000, InProgressPerViewer: 40}

LargeScale is the CI gate's library: 500k+ catalogue rows and a household with deep watch history.

View Source
var SmallScale = LargeScale.Divide(10)

SmallScale is LargeScale's household over a tenth of its library; the gate compares the two, so only the library differs.

Functions

func Audit

func Audit(ctx context.Context, dbPath string, trace map[string]TraceRecord, w io.Writer) error

audit runs EXPLAIN QUERY PLAN for every statement the trace attributes to a request and ranks them by the time they cost, flagging full scans of large tables, temporary sort trees, automatic indexes, correlated subqueries and statements repeated within one request.

func AuditPostgres

func AuditPostgres(ctx context.Context, url string, trace map[string]TraceRecord, w io.Writer) error

AuditPostgres audits the same statements against a PostgreSQL database (a cluster node's, or a copy of one) with EXPLAIN (GENERIC_PLAN), which plans a parameterized statement without values (PostgreSQL 16+). It flags sequential scans of large tables, sorts and correlated subplans.

func Generate

func Generate(ctx context.Context, db *sql.DB, s Scale, now time.Time) error

Generate fills an empty, migrated database with a synthetic library and household at scale s. The output is deterministic for a given scale and now.

func WriteReport

func WriteReport(w io.Writer, title string, meta []string, rows []*Row) (failed int)

Types

type BackgroundWriter

type BackgroundWriter struct {
	// contains filtered or unexported fields
}

backgroundWriter imitates a catalogue refresh against the same database: write transactions of 500 title rows, back to back with a short pause, so request paths meet a busy writer the way they do while the mirror syncs.

func StartBackgroundWriter

func StartBackgroundWriter(dbPath string) (*BackgroundWriter, error)

func (*BackgroundWriter) Close

func (w *BackgroundWriter) Close() string

type Budget

type Budget struct {
	Warm, Cold, Loaded time.Duration
	Gated              bool
}

budget is the latency a class must meet: p95 of the warm phase, the single cold request, and p95 under concurrent viewers or a busy writer.

type Client

type Client struct {
	Name    string
	Surface string
	// Port offset from the base port (0 main, 1 Jellyfin, 2 Emby, 3 Silo),
	// or SharedPrefix on the main port when the runner shares one port.
	Port         int
	SharedPrefix string
	Prefix       string
	Headers      func(s *session) http.Header
	SignIn       *Step
	Steps        []Step
}

client is one real client's request sequence against one protocol.

func Clients

func Clients() []Client

Clients is every replayed client, in report order.

func Only

func Only(cs []Client, names []string) []Client

Only keeps the clients named in names (all of them when names is empty).

func OnlySteps

func OnlySteps(cs []Client, names []string) []Client

OnlySteps keeps the steps whose name contains one of names (case insensitive); clients left with no steps are dropped. Sign-in always runs.

type Result

type Result struct {
	Phase   string        `json:"phase"`
	Client  string        `json:"client"`
	Surface string        `json:"surface"`
	Step    string        `json:"step"`
	Class   string        `json:"class"`
	Viewer  string        `json:"viewer"`
	Tag     string        `json:"tag"`
	Status  int           `json:"status"`
	Bytes   int           `json:"bytes"`
	Dur     time.Duration `json:"dur"`
	Err     string        `json:"err,omitempty"`
	Skipped string        `json:"skipped,omitempty"`
}

result is one timed request.

type Row

type Row struct {
	Client, Step, Class                    string
	RowsBound                              int
	Cold, WarmP50, WarmP95, ConcP95, BgP95 time.Duration
	Queries, Writes, Rows                  int64
	// The fewest and most statements and rows over the cold and warm
	// passes. A pass may or may not be answered by a cache, so the gate
	// compares the large library's least work with the small one's most.
	QueriesMin, QueriesMax, RowsMin, RowsMax int64
	DBTime, LockWait                         time.Duration
	Status                                   string
	Fails                                    []string
	Skipped                                  string
	Errors                                   []string
	// contains filtered or unexported fields
}

row is one endpoint's line in the report.

func Summarize

func Summarize(results []Result, trace map[string]TraceRecord, order []Client) []*Row

summarize groups results by client and step and checks each against its class budget. A step with no samples in a phase is not judged for it.

type Runner

type Runner struct {
	// contains filtered or unexported fields
}

func NewRunner

func NewRunner(basePort int, shared bool, viewers []Viewer) *Runner

NewRunner drives a server whose main port is basePort. With shared set, Jellyfin, Emby and Silo are reached under their path prefixes on that port; otherwise on basePort+1, +2 and +3.

func (*Runner) Concurrent

func (r *Runner) Concurrent(ctx context.Context, phase string, n, rounds int, cs []Client)

concurrent runs n workers, each a viewer working through every client in its own order, rounds times.

func (*Runner) Results

func (r *Runner) Results() []Result

Results returns every timed request so far.

func (*Runner) Sequential

func (r *Runner) Sequential(ctx context.Context, phase string, viewers []Viewer, cs []Client)

sequential runs every client for each viewer, one request at a time.

func (*Runner) SetTimeout

func (r *Runner) SetTimeout(d time.Duration)

SetTimeout caps each request (60 s by default).

type Scale

type Scale struct {
	Movies            int
	Shows             int
	SeasonsPerShow    int
	EpisodesPerSeason int
	// Viewers beyond the owner, each with HistoryPerViewer watched titles
	// and InProgressPerViewer partly watched ones.
	Viewers             int
	HistoryPerViewer    int
	InProgressPerViewer int
}

Scale sizes a synthetic library. Every title is browsable, detailed and fresh, so a request never needs TMDB: the fixture measures Ether, not a provider.

func (Scale) Divide

func (s Scale) Divide(n int) Scale

Divide shrinks the library by n, keeping the household.

func (Scale) Rows

func (s Scale) Rows() int

Rows is the number of catalogue rows the scale produces.

type Step

type Step struct {
	Name  string
	Class string
	// RowsBound, when set, is a hard bound on the rows the step reads,
	// whatever the library's size: a search reads at most its candidate
	// window, so its rows grow with the matches only until the window
	// fills. The gate checks the bound instead of comparing scales.
	RowsBound int
	Method    string
	Path      string
	Body      string
	Discover  func(vars map[string]string, body []byte)
}

type TraceRecord

type TraceRecord struct {
	Tag        string          `json:"tag"`
	Surface    string          `json:"surface"`
	Method     string          `json:"method"`
	Path       string          `json:"path"`
	Status     int             `json:"status"`
	Duration   time.Duration   `json:"duration"`
	Queries    int64           `json:"queries"`
	Writes     int64           `json:"writes"`
	Rows       int64           `json:"rows"`
	DBTime     time.Duration   `json:"dbTime"`
	LockWait   time.Duration   `json:"lockWait"`
	Statements []statementStat `json:"statements"`
}

traceRecord mirrors app.PerfTraceRecord (one line of ETHER_PERF_TRACE).

func ReadTrace

func ReadTrace(path string) (map[string]TraceRecord, []TraceRecord, error)

type Viewer

type Viewer struct {
	ID         int64
	Username   string
	Owner      bool
	Restricted bool
	PlexToken  string
	Stremio    string
}

func MintCredentials

func MintCredentials(ctx context.Context, db *sql.DB, max int) ([]Viewer, error)

MintCredentials gives up to max active viewers of a throwaway database a known password, a Plex token and a Stremio grant. The owner comes first. Never run it against a real server's database.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL