diff --git a/bench/Makefile b/bench/Makefile index 05f8c7a..a267f1a 100644 --- a/bench/Makefile +++ b/bench/Makefile @@ -1,11 +1,11 @@ -bench-poop: build-picohttpparser build-httparse build-hparse - poop -d 50000 "./picohttpparser/picohttpparser" "./bench-httparse/target/release/bench-httparse" "./hparse/zig-out/bin/hparse" +bench-poop: build-picohttpparser build-httparse build-hparse build-headparser + poop -d 50000 "./picohttpparser/picohttpparser" "./bench-httparse/target/release/bench-httparse" "./hparse/zig-out/bin/hparse" "./headparser/zig-out/bin/headparser" bench-poop-log: - poop -d 10000 "./picohttpparser/picohttpparser" "./bench-httparse/target/release/bench-httparse" "./hparse/zig-out/bin/hparse" > bench.txt + poop -d 10000 "./picohttpparser/picohttpparser" "./bench-httparse/target/release/bench-httparse" "./hparse/zig-out/bin/hparse" "./headparser/zig-out/bin/headparser" > bench.txt -bench-hyperfine: build-picohttpparser build-httparse build-hparse - hyperfine "./hparse/zig-out/bin/hparse" "./picohttpparser/picohttpparser" "./bench-httparse/target/release/bench-httparse" --export-json bench.json +bench-hyperfine: build-picohttpparser build-httparse build-hparse build-headparser + hyperfine "./hparse/zig-out/bin/hparse" "./picohttpparser/picohttpparser" "./bench-httparse/target/release/bench-httparse" "./headparser/zig-out/bin/headparser" --export-json bench.json bench-poop-skylake: build-httparse-skylake build-hparse-skylake poop -d 10000 "./bench-httparse/target/release/bench-httparse" "./hparse/zig-out/bin/hparse" @@ -22,6 +22,9 @@ build-httparse: build-hparse: cd hparse && zig build -Doptimize=ReleaseFast && cd .. +build-headparser: + cd headparser && zig build -Doptimize=ReleaseFast && cd .. + build-httparse-skylake: cd bench-httparse && RUSTFLAGS=-Ctarget-feature=+avx2 cargo build --release && cd .. @@ -29,4 +32,4 @@ build-hparse-skylake: cd hparse && zig build -Dcpu=skylake -Doptimize=ReleaseFast && cd .. clean: - rm picohttpparser/picohttpparser && rm -rf bench-httparse/target && rm -rf hparse/zig-out hparse/.zig-cache + rm picohttpparser/picohttpparser && rm -rf bench-httparse/target && rm -rf hparse/zig-out hparse/.zig-cache && rm -rf headparser/zig-out headpaser/.zig-cache diff --git a/bench/headparser/build.zig b/bench/headparser/build.zig new file mode 100644 index 0000000..7c29be6 --- /dev/null +++ b/bench/headparser/build.zig @@ -0,0 +1,75 @@ +const std = @import("std"); + +// Although this function looks imperative, note that its job is to +// declaratively construct a build graph that will be executed by an external +// runner. +pub fn build(b: *std.Build) void { + // Standard target options allows the person running `zig build` to choose + // what target to build for. Here we do not override the defaults, which + // means any target is allowed, and the default is native. Other options + // for restricting supported target set are available. + const target = b.standardTargetOptions(.{}); + + // Standard optimization options allow the person running `zig build` to select + // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not + // set a preferred release mode, allowing the user to decide how to optimize. + const optimize = b.standardOptimizeOption(.{}); + + // We will also create a module for our other entry point, 'main.zig'. + const exe_mod = b.createModule(.{ + // `root_source_file` is the Zig "entry point" of the module. If a module + // only contains e.g. external object files, you can make this `null`. + // In this case the main source file is merely a path, however, in more + // complicated build scripts, this could be a generated file. + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }); + + // This creates another `std.Build.Step.Compile`, but this one builds an executable + // rather than a static library. + const exe = b.addExecutable(.{ + .name = "headparser", + .root_module = exe_mod, + }); + + // This declares intent for the executable to be installed into the + // standard location when the user invokes the "install" step (the default + // step when running `zig build`). + b.installArtifact(exe); + + // This *creates* a Run step in the build graph, to be executed when another + // step is evaluated that depends on it. The next line below will establish + // such a dependency. + const run_cmd = b.addRunArtifact(exe); + + // By making the run step depend on the install step, it will be run from the + // installation directory rather than directly from within the cache directory. + // This is not necessary, however, if the application depends on other installed + // files, this ensures they will be present and in the expected location. + run_cmd.step.dependOn(b.getInstallStep()); + + // This allows the user to pass arguments to the application in the build + // command itself, like this: `zig build run -- arg1 arg2 etc` + if (b.args) |args| { + run_cmd.addArgs(args); + } + + // This creates a build step. It will be visible in the `zig build --help` menu, + // and can be selected like this: `zig build run` + // This will evaluate the `run` step rather than the default, which is "install". + const run_step = b.step("run", "Run the app"); + run_step.dependOn(&run_cmd.step); + + const exe_unit_tests = b.addTest(.{ + .root_module = exe_mod, + }); + + const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests); + + // Similar to creating the run step earlier, this exposes a `test` step to + // the `zig build --help` menu, providing a way for the user to request + // running the unit tests. + const test_step = b.step("test", "Run unit tests"); + test_step.dependOn(&run_exe_unit_tests.step); +} diff --git a/bench/headparser/build.zig.zon b/bench/headparser/build.zig.zon new file mode 100644 index 0000000..bc41994 --- /dev/null +++ b/bench/headparser/build.zig.zon @@ -0,0 +1,36 @@ +.{ + // This is the default name used by packages depending on this one. For + // example, when a user runs `zig fetch --save `, this field is used + // as the key in the `dependencies` table. Although the user can choose a + // different name, most users will stick with this provided value. + // + // It is redundant to include "zig" in this name because it is already + // within the Zig package namespace. + .name = .headparser_bench, + + .fingerprint = 0x3894df1ca4908eec, + + // This is a [Semantic Version](https://semver.org/). + // In a future version of Zig it will be used for package deduplication. + .version = "0.0.0", + + // This field is optional. + // This is currently advisory only; Zig does not yet do anything + // with this value. + //.minimum_zig_version = "0.11.0", + + // This field is optional. + // Each dependency must either provide a `url` and `hash`, or a `path`. + // `zig build --fetch` can be used to fetch all dependencies of a package, recursively. + // Once all dependencies are fetched, `zig build` no longer requires + // internet connectivity. + .dependencies = .{}, + .paths = .{ + "build.zig", + "build.zig.zon", + "src", + // For example... + //"LICENSE", + //"README.md", + }, +} diff --git a/bench/headparser/src/main.zig b/bench/headparser/src/main.zig new file mode 100644 index 0000000..57bab0c --- /dev/null +++ b/bench/headparser/src/main.zig @@ -0,0 +1,11 @@ +const std = @import("std"); +const Head = std.http.Server.Request.Head; + +pub fn main() !void { + const buffer: []const u8 = "GET /cookies HTTP/1.1\r\nHost: 127.0.0.1:8090\r\nConnection: keep-alive\r\nCache-Control: max-age=0\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.56 Safari/537.17\r\nAccept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\r\nCookie: name=wookie\r\n\r\n"; + + var i: usize = 0; + while (i < 1_000_000_0) : (i += 1) { + _ = try Head.parse(buffer); + } +} diff --git a/bench/hparse/build.zig.zon b/bench/hparse/build.zig.zon index 2b076d9..0dca252 100644 --- a/bench/hparse/build.zig.zon +++ b/bench/hparse/build.zig.zon @@ -26,8 +26,8 @@ // internet connectivity. .dependencies = .{ .hparse = .{ - .url = "https://github.com/nikneym/hparse/archive/0bbc197af29866d230c6f2d73454aef398d4d796.tar.gz", - .hash = "1220fa7c037e154bb8880ffa686a0d26e71d1bad603eed09a3c70f534085557ada1d", + .url = "https://github.com/nikneym/hparse/archive/f8cc9b77b57fe942c3319b597fb0aee4f131c47f.tar.gz", + .hash = "hparse-0.2.0-IukW0s67AADCDZ7ROogFU5EJAVLyI8aiR0LPNvZd88OK", }, }, .paths = .{