Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,11 @@ jobs:
# Every SIMD kernel has a scalar fallback, and the fallback is only real if it is
# exercised: the classes tests/scalar-pass.txt names, which reach every fallback the
# whole suite does, and the conformance corpus run again with intrinsics disabled.
# Vorticity.Zstd's suite does not: its only vector paths are Arm's, which an x64 runner
# never takes, so the run above already took every one of its fallbacks.
- name: Vorticity's fallbacks and the conformance corpus, intrinsics disabled
projects: tests/Vorticity.Tests tests/Vorticity.Conformance
# Vorticity.Zstd's suite runs whole: an x64 runner takes its x64 paths, and with
# intrinsics disabled the portable ones, Arm64's shape without its vectors.
- name: Vorticity's fallbacks, Vorticity.Zstd and the conformance corpus, intrinsics disabled
projects: tests/Vorticity.Tests tests/Vorticity.Zstd.Tests tests/Vorticity.Conformance
zstd-data: true
scalar-pass: true
steps:
# Nothing here pushes to git: the token is not left on disk.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ at the same version as the core.
|---|---|
| [docs/guide/](docs/guide/README.md) | **Using the library**: pages named by what you are trying to do, each one a program the samples project compiles and runs |
| [docs/guide/benchmarks.md](docs/guide/benchmarks.md) | Every figure the bench publishes: what this costs against the Rust implementation, and each kernel against its baseline |
| [docs/guide/benchmarks-x64.md](docs/guide/benchmarks-x64.md) | The sections that compare Vorticity with itself, from an x64 machine, a Zen 4 processor under Windows |
| [docs/guide/benchmarks-x64.md](docs/guide/benchmarks-x64.md) | The same page from an x64 machine, a Zen 4 processor under Windows, against a Rust built there |
| [docs/guide/benchmarks-duckdb.md](docs/guide/benchmarks-duckdb.md) | Our group bys against DuckDB's on the same files, through its Vortex reader and from its own table: where we lead and where we trail |
| [docs/design/](docs/design/README.md) | **Why it is shaped this way**: the design documents, from the scope to the byte layout to the public API |

Expand All @@ -176,6 +176,6 @@ prefix filter on FSST strings (0.93x) and a band over bit-packed integers (0.98x

Every figure is on [the benchmark page](docs/guide/benchmarks.md), each section with the machine
and the commit it was measured on, and [its x64 twin](docs/guide/benchmarks-x64.md) holds the
sections measured on x64. [docs/design/05-benchmarks.md](docs/design/05-benchmarks.md) says what is
same sections measured on x64. [docs/design/05-benchmarks.md](docs/design/05-benchmarks.md) says what is
compared and how, and [bench/README.md](bench/README.md) how to run each instrument: `bench/gate.sh`
runs everything that gates a commit.
8 changes: 5 additions & 3 deletions bench/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -279,9 +279,11 @@ and say which change in the commit message.

**A new reference binary is carried, not recalibrated.** Both gates record the fingerprint of the
`vxbench` build their tables were set under (`CalibratedShim`) and refuse to gate under another: a
ratio through a different denominator is a number about the rebuild. After rebuilding
`tools/vxbench-rs` — a new `vortex` pin, a new toolchain, a changed entry point — keep the previous
build and carry the tables over:
ratio through a different denominator is a number about the rebuild. Another machine builds another
binary, and its ratios are its own: there `--ratio-check --out` and `--throughput --take --out` (or
`--write`) measure every axis or file for that machine's page and hold none to a reference. After
rebuilding `tools/vxbench-rs` — a new `vortex` pin, a new toolchain, a changed entry point — keep
the previous build and carry the tables over:

```
dotnet run -c Release PROJ -- --ratio-check --recalibrate 3 --rebase-from <previous libvxbench.dylib>
Expand Down
4 changes: 3 additions & 1 deletion bench/Vorticity.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,9 @@ reports no change in our own time
by what the binary moved the ratio
--lanes N adds `full scan, N lanes`, threads pinned
--out <page> the axes as the page's section, after a
check of every axis
check of every axis; under a reference
binary the references do not name, every
axis measured and none held
--throughput [family…] 57 encodings at a million rows, ~55 s
--check hold each ratio to its ceiling. Refused
with a family filter: a short run is +32%
Expand Down
26 changes: 20 additions & 6 deletions bench/Vorticity.Benchmarks/RatioCheck.cs
Original file line number Diff line number Diff line change
Expand Up @@ -681,7 +681,15 @@ private static async Task<int> CheckAsync(string path, Axis[] axes)
: string.Equals(running, CalibratedShim, StringComparison.Ordinal)
? $" reference binary: {running}, the one the references were calibrated against"
: $" reference binary: {running}, but the references were calibrated against {CalibratedShim}");
if (CalibratedShim is not null && !string.Equals(running, CalibratedShim, StringComparison.Ordinal))

// The references are the calibrating machine's: another machine builds another binary, and
// its ratios are its own. Its page is still measured, every axis of it, and held to nothing.
bool held = CalibratedShim is null || string.Equals(running, CalibratedShim, StringComparison.Ordinal);
if (!held && Page is not null)
{
Console.Out.WriteLine(" for the page only: no axis is held to references set under another binary");
}
else if (!held)
{
Console.Error.WriteLine(
$"REFUSED: the references were calibrated against reference binary {CalibratedShim} and " +
Expand Down Expand Up @@ -711,7 +719,11 @@ private static async Task<int> CheckAsync(string path, Axis[] axes)
Interval ratio = m.Ratio;
string columns;
string verdict = string.Empty;
if (!References.TryGetValue(axis.Name, out Reference entry))
if (!held)
{
columns = " -- --";
}
else if (!References.TryGetValue(axis.Name, out Reference entry))
{
unreferenced.Add(string.Create(
CultureInfo.InvariantCulture,
Expand Down Expand Up @@ -798,10 +810,12 @@ private static async Task<int> CheckAsync(string path, Axis[] axes)
}

Console.Out.WriteLine(
over == 0
? "Every axis is inside its ceiling."
: $"{over} axis/axes above ceiling. A ratio only moves when the code moves: " +
"find the change, do not raise the ceiling.");
!held
? "No axis was held to a ceiling: this run writes the page and gates nothing."
: over == 0
? "Every axis is inside its ceiling."
: $"{over} axis/axes above ceiling. A ratio only moves when the code moves: " +
"find the change, do not raise the ceiling.");
if (Page is not null)
{
await ResultsPage.WriteAsync(Page, [("in-process", Section(measured, running))]).ConfigureAwait(false);
Expand Down
38 changes: 33 additions & 5 deletions bench/Vorticity.Zstd.Perf/Corpus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ namespace Vorticity.Zstd.Perf;
/// frames byte for byte, and give the content back from them.
/// </summary>
/// <remarks>
/// Usage: <c>Vorticity.Zstd.Perf --corpus silesia,github,github-dict [--levels 1,3,19] [--seconds S] [--only zstd]
/// Usage: <c>Vorticity.Zstd.Perf --corpus silesia,github,github-dict [--levels 1,3,19] [--seconds S] [--only zstd] [--directions decompression]
/// [--results file.tsv] [--markdown file.md]</c>, or <c>Vorticity.Zstd.Perf --corpus-report file.tsv [--markdown file.md]</c>
/// to render results already measured. <c>silesia</c> is silesia.tar, the twelve files in one frame,
/// as lzbench reads it; <c>github</c> the 500 records, a frame each, on one context;
Expand Down Expand Up @@ -63,8 +63,9 @@ public static Row FromTsv(string line)
}
}

public static int Run(string[] sets, string? levels, string? seconds, string? only, string? results, string? markdown)
public static int Run(string[] sets, string? levels, string? seconds, string? only, string? results, string? markdown, string? directions = null)
{
Compresses = directions is null || directions.Split(',').Contains("compression");
int[] levelList = levels?.Split(',').Select(l => int.Parse(l, CultureInfo.InvariantCulture)).ToArray() ?? DefaultLevels;
double budget = seconds is null ? 5 : double.Parse(seconds, CultureInfo.InvariantCulture);
NativeReference? native = NativeReference.TryLoad();
Expand Down Expand Up @@ -179,6 +180,9 @@ private static (List<Candidate> Candidates, IDisposable[] Owned) Candidates(Nati
/// every other candidate must write too; then the decoding of those frames, whose first round
/// checks that every candidate gives the content back.
/// </summary>
/// <summary>Whether compression is timed: <c>--directions decompression</c> leaves it out, the frames written once.</summary>
private static bool Compresses { get; set; } = true;

private static List<Row> Measure(DataSet set, int level, List<Candidate> candidates, double budget)
{
int records = set.Offsets.Length - 1;
Expand All @@ -200,7 +204,13 @@ private static List<Row> Measure(DataSet set, int level, List<Candidate> candida
int count = candidates.Count;

bool[] compressionDiffers = new bool[count];
double[] compression = Time(candidates, budget, (c, round) =>
if (!Compresses)
{
// Decompression alone: libzstd's frames, written once, untimed.
Pass(candidates[0].Compress, set.Content, set.Offsets, reference, bounds, sizes);
}

double[] compression = !Compresses ? new double[count] : Time(candidates, budget, (c, round) =>
{
if (round > 0)
{
Expand Down Expand Up @@ -255,7 +265,7 @@ private static List<Row> Measure(DataSet set, int level, List<Candidate> candida

double ratio = (double)set.Content.Length / frames.Length;
var rows = new List<Row>();
for (int c = 0; c < count; c++)
for (int c = 0; c < count && Compresses; c++)
{
rows.Add(new Row(set.Name, set.Label, set.Title, level, ratio, "compression", candidates[c].Name, candidates[c].Label,
set.Content.Length / compression[c] / 1e6, compressionDiffers[c]));
Expand Down Expand Up @@ -459,6 +469,24 @@ private static DataSet Load(string name)
return new DataSet(name, "silesia.tar", $"the Silesia corpus as one tar, {tar.Length:N0} bytes, one frame", tar, [0, tar.Length], null);
}

case "silesia-sample":
{
// 1 MiB every 16 MiB of silesia.tar, as one frame: its kinds of data, text, binaries,
// images and databases, in a frame that compresses in a fraction of the time, for the
// micro-benchmarks and the profiler.
byte[] tar = SilesiaTar(Path.Combine(directory, "silesia.zip"));
const int Slice = 1 << 20;
const int Stride = 16 << 20;
using var sample = new MemoryStream();
for (int at = 0; at + Slice <= tar.Length; at += Stride)
{
sample.Write(tar, at, Slice);
}

byte[] content = sample.ToArray();
return new DataSet(name, "silesia sample", $"1 MiB every 16 MiB of silesia.tar, {content.Length:N0} bytes, one frame", content, [0, content.Length], null);
}

case "github":
case "github-dict":
{
Expand All @@ -481,7 +509,7 @@ private static DataSet Load(string name)
}

default:
throw new ArgumentException("unknown corpus " + name + " (silesia, github, github-dict, github.tar, github.tar-dict)", nameof(name));
throw new ArgumentException("unknown corpus " + name + " (silesia, silesia-sample, github, github-dict, github.tar, github.tar-dict)", nameof(name));
}
}

Expand Down
Loading
Loading