scale

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Oct 9, 2026 License: MPL-2.0 Imports: 23 Imported by: 0

Documentation

Overview

Package scale is the reproducible scale acceptance harness. It generates deterministic fixtures, builds the real pdfconcat executable, runs it on large plans, measures wall time, peak resident memory, open descriptors and scratch disk, and then checks the output with qpdf and Poppler.

Run it with

export PDFCONCAT_SCALE=1 PDFCONCAT_REQUIRE_QA_TOOLS=1
go run ./tools/qualitygate test -run ^TestScaleAcceptance$ -require TestScaleAcceptance -timeout 30m ./test/scale

Without PDFCONCAT_SCALE=1 the acceptance test skips, saying so. With it set, a missing prerequisite (the executable does not build, qpdf or Poppler is missing) fails the test, so a dedicated CI job cannot pass by skipping. PDFCONCAT_SCALE_RESULTS names a file that receives one JSON object per run.

Cases: 5,000 distinct one-page PDFs interleaved with 5,000 generated pages as a plan file and on standard input, with one repeated and with all-distinct blank styles; a 15,000-page job with repeated source occurrences, grouped paths, compact blank counts and linked sources; and a resource-heavy corpus of image-rich and multi-page PDFs; and 3,000 distinct generated pages with 10,000-character texts via file and stdin. Long-text cases verify complete extracted text and report their envelope, without claiming that their workload has the light-case budgets. The light cases are gated at 1 GiB peak resident memory, 64 open descriptors at --jobs 4 and 60 seconds; the other cases are measured and reported.

Measurement covers the executable from launch to exit. Fixture generation and the independent verification (qpdf, pdftotext, pdftoppm) are timed separately and excluded. Peak memory comes from the kernel's accounting of the child (rusage on Unix, the peak working set on Windows); descriptors are sampled while the process runs. Capped Unix cases additionally verify a 64/64 kernel limit on the same owned PID through a private native launcher. It records unprivileged identity, an actual refused hard-limit raise, executable identity and configured inheritance hygiene; the launched Go-runtime controls independently verify the limit and inherited-object closure. A native C compiler is required for capped Unix cases; source, compiler/SDK and executable identities are recorded, and helper compilation is excluded from measured wall time. The frozen executable/input directories must have no concurrent writer or privileged external limit mutation. The ceiling applies to the product process after successful exec, not aggregate descriptors in arbitrary descendants or an unconstrained production peak. Windows peak RSS is a sampled lower bound, while Unix RSS uses launch-through-exit kernel accounting. Each result records valid/unavailable/error states, successful/attempted descriptor samples and the sampled temporal span as a fraction of wall time; that fraction does not prove every transient maximum was observed. Enabled acceptance rejects missing or failed required readings in uncapped cases. Verified Unix capped cases keep a separate resource-bound result and observation quality: partial/error readings remain visible, and 64 is never inserted into the sampled maximum. At least one actual descriptor reading is still required to record descriptor cost; no successful readings means unavailable observation. Missing/contradictory cap evidence, failed product execution, sampler cleanup, RSS, scratch and independent-oracle failures still fail acceptance. Windows retains sampled native handle checks.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DirectorySize

func DirectorySize(dir string) (int64, error)

DirectorySize totals the regular files under dir, for input and output byte accounting.

func FileSize

func FileSize(path string) (int64, error)

FileSize returns the size in bytes of the file at path.

func WriteFile

func WriteFile(path string, data []byte) error

WriteFile writes data to a new or existing private file at path.

Types

type Appearance

type Appearance struct {
	Page  int
	X, Y  int
	Color [3]uint8
}

Appearance is a rendered check of one generated page: the pixel at (X, Y) must be Color, within a small tolerance, on output page Page (1-based).

type BlankStyles

type BlankStyles int

BlankStyles says how the generated pages of a light workload are styled.

const (

	// SharedBlankStyle gives every generated page of a light workload the same text and style.
	SharedBlankStyle BlankStyles = 0
	// DistinctBlankStyles gives every generated page of a light workload its own text.
	DistinctBlankStyles BlankStyles = 1

	// MixedPages is the output size of MixedWorkload.
	MixedPages = 15000
)

type DescriptorCeiling added in v0.2.0

type DescriptorCeiling struct {
	NativeCompilerIdentity

	SourceSHA256       string `json:"source_sha256"`
	LauncherSHA256     string `json:"launcher_sha256"`
	BinarySHA256       string `json:"binary_sha256"`
	InvocationSHA256   string `json:"invocation_sha256"`
	Token              string `json:"token"`
	Hygiene            string `json:"hygiene"`
	PID                int    `json:"pid"`
	UID                int    `json:"uid"`
	EUID               int    `json:"euid"`
	GID                int    `json:"gid"`
	EGID               int    `json:"egid"`
	Soft               uint64 `json:"soft"`
	Hard               uint64 `json:"hard"`
	Device             uint64 `json:"device"`
	Inode              uint64 `json:"inode"`
	Bytes              int64  `json:"bytes"`
	Mode               uint64 `json:"mode"`
	RaiseErrno         int    `json:"raise_errno"`
	ControlCloseOnExec bool   `json:"control_cloexec"`
	HygieneConfigured  bool   `json:"hygiene_configured"`
}

DescriptorCeiling records native cap preparation; execution and sample quality are separate facts.

type DescriptorCollectorIdentity added in v0.2.0

type DescriptorCollectorIdentity struct {
	NativeCompilerIdentity

	ReadinessStarted  time.Time `json:"readiness_started"`
	ReadinessFinished time.Time `json:"readiness_finished"`
	ReadinessFrame    string    `json:"readiness_frame"`

	SourceSHA256 string `json:"source_sha256"`
	BinarySHA256 string `json:"binary_sha256"`
	ReadinessPID int    `json:"readiness_pid"`
}

DescriptorCollectorIdentity identifies a compiled test-only descriptor query. Its observed counts are sampled lower bounds, independent of kernel ceilings.

type Measurement

type Measurement struct {
	DescriptorCollector *DescriptorCollectorIdentity `json:"descriptor_collector,omitempty"`
	DescriptorCeiling   *DescriptorCeiling           `json:"descriptor_ceiling,omitempty"`
	ObserverRetries     ObserverRetryEvidence
	Stdout              string
	Stderr              string
	// RSSState is valid, unavailable, or error; an error includes any failed intermediate RSS sample.
	RSSState string
	// DescriptorState is valid only when every attempted live-process sample succeeds.
	DescriptorState string
	ReadingFailures []ReadingFailure
	Wall            time.Duration
	PeakRSSBytes    int64
	MaxDescriptors  int64
	// DescriptorSamples counts successful readings. SampleAttempts also includes failures.
	TerminalSamples           int64
	DescriptorTerminalSamples int64
	DescriptorSamples         int64
	SampleAttempts            int64
	// DescriptorCoverage is the observed temporal span divided by launch-to-exit wall time, not exhaustive coverage.
	DescriptorCoverage float64
	PeakScratchBytes   int64
	ExitCode           int
}

Measurement is what one execution cost.

func Measure

func Measure(ctx context.Context, spec RunSpec) (Measurement, error)

Measure runs the command and measures it. A nonzero exit status is reported in the Measurement, not as an error. Returned errors identify process, scratch-inspection or collector-cleanup failures.

func (*Measurement) DescriptorBoundVerified added in v0.2.0

func (m *Measurement) DescriptorBoundVerified() bool

DescriptorBoundVerified distinguishes the completed process's checked ceiling from sample quality. Its facts are produced by the owned native launch boundary, not by a requested RunSpec limit.

type NativeCompilerIdentity added in v0.2.0

type NativeCompilerIdentity struct {
	Compiler       string `json:"compiler"`
	CompilerPath   string `json:"compiler_path"`
	CompilerSHA256 string `json:"compiler_sha256"`
	SDK            string `json:"sdk,omitempty"`
}

NativeCompilerIdentity identifies the compiler and selected SDK for a test-only native tool.

type ObserverRetryEvidence

type ObserverRetryEvidence struct {
	First time.Time `json:"first,omitzero"`
	Last  time.Time `json:"last,omitzero"`
	Cause string    `json:"cause,omitempty"`
	Count int64     `json:"count"`
}

ObserverRetryEvidence records bounded evidence of interrupted native exit-observer calls.

type ReadingFailure

type ReadingFailure struct {
	ProofWaitStarted  time.Time `json:"proof_wait_started,omitzero"`
	ProofWaitFinished time.Time `json:"proof_wait_finished,omitzero"`
	ReadStarted       time.Time `json:"read_started"`
	ReadFinished      time.Time `json:"read_finished"`
	Metric            string    `json:"metric"`
	Phase             string    `json:"phase"`
	Cause             string    `json:"cause"`
	Stderr            string    `json:"stderr,omitempty"`
	Stdout            string    `json:"stdout,omitempty"`
	Probe             string    `json:"probe,omitempty"`
	ExitCode          int       `json:"exit_code"`
	NativeCode        uint64    `json:"native_code,omitempty"`
}

ReadingFailure preserves the cause and phase of an unsuccessful process observation.

type RunSpec

type RunSpec struct {
	// Binary is the executable to run.
	Binary string
	// Dir is the working directory.
	Dir string
	// ScratchDir is a directory whose total file size is sampled while the process runs; the executable
	// puts its private workspace beside the output, so this is the output directory.
	ScratchDir string
	// Stdin, when not nil, is the process's standard input.
	Stdin io.Reader
	// Env is the process environment; nil inherits this process's.
	Env []string
	// OnSample, when not nil, is called from the sampling goroutine each time a reading of the running
	// process, and of ScratchDir, is complete. A caller that keeps the process alive until it has been
	// read counts the calls instead of guessing how long a reading takes.
	OnSample func()
	// Args are the command-line arguments after the executable's name.
	Args []string
	// DescriptorLimit, when not zero, caps the process's open descriptors on Unix, where exceeding it
	// makes its opens fail; Windows only samples handles.
	DescriptorLimit uint64
}

RunSpec describes one measured process execution.

type Verification

type Verification struct {
	// Findings are the failed oracle checks and appearance mismatches; empty means the output is right.
	Findings []string
	// Elapsed is how long qpdf, pdftotext and pdftoppm took; it is excluded from the run's measurement.
	Elapsed time.Duration
	// Pages and Objects are the output's page and object counts as qpdf sees them.
	Pages, Objects int
}

Verification is the independent judgement of one output file.

func Verify

func Verify(tools pdforacle.Tools, workload *Workload, path string) (Verification, error)

Verify checks the output at path against the workload with qpdf, pdftotext and pdftoppm: page count and text of every page, source identity and occurrence of every source page, link and destination membership, geometry, version, and the rendered background of each recorded appearance.

type VisualSource

type VisualSource struct {
	Path                   string
	SourcePage, OutputPage int
}

VisualSource binds an original source raster to its output occurrence.

type Workload

type Workload struct {
	// Name identifies the case in results.
	Name string
	// Dir is the directory holding the plan's sources; the executable runs with it as working directory.
	Dir string
	// Plan is the plan JSON.
	Plan []byte
	// Expectation is what the oracle must find in the output.
	Expectation pdforacle.Expectation
	// Appearances lists generated-page appearances to verify by rendering a sample page of each.
	Appearances []Appearance
	// VisualSources samples original image-bearing source pages in the assembled output.
	VisualSources []VisualSource
	// FullTexts verifies long text after whitespace normalization of independent extraction.
	FullTexts map[int]string

	// Pages is the expected number of output pages.
	Pages int
	// SourceFiles and InputBytes describe the input corpus, filled in by Write.
	SourceFiles int
	InputBytes  int64
	// contains filtered or unexported fields
}

Workload is one scale case: the plan the executable reads, the files it refers to, and everything an independent checker needs to judge the output without trusting the executable.

func HeavyWorkload

func HeavyWorkload(dir string) (*Workload, error)

HeavyWorkload is a resource-heavy corpus at lower counts: image-rich pages of incompressible data and multi-page documents, interleaved with generated pages.

func LightWorkload

func LightWorkload(dir string, count int, styles BlankStyles) (*Workload, error)

LightWorkload is count distinct one-page sources interleaved with count generated pages. With DistinctBlankStyles every generated page has its own text; otherwise all share one text and style.

func LongTextWorkload

func LongTextWorkload(dir string) (*Workload, error)

LongTextWorkload is 3,000 distinct 10,000-character pages, a shaped-text lifetime stress case.

func MixedWorkload

func MixedWorkload(dir string) (*Workload, error)

MixedWorkload is the 15,000-page case: repeated source occurrences (every source is used once per round, rounds visit the groups in opposite directions), leading and trailing blanks, grouped directories, compact blank counts with distinct text and backgrounds, and linked sources whose links must stay inside their own occurrence.

func (*Workload) FixtureSignature

func (w *Workload) FixtureSignature() []string

FixtureSignature is a digest-free fingerprint of the fixture set for determinism tests: the sorted relative paths with byte sizes.

func (*Workload) Stage

func (w *Workload) Stage() error

Stage writes the fixtures, the plan as the working directory's job.json and an empty output directory, so the executable can run with w.Dir as its working directory.

func (*Workload) Write

func (w *Workload) Write() error

Write creates the fixture files under w.Dir and fills in SourceFiles and InputBytes.

Jump to

Keyboard shortcuts

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