Skip to content

Commit

Permalink
perf: rework decoder interface
Browse files Browse the repository at this point in the history
The updated interface decodes codepoints directly from a reader rather
than being implemented as a state machine. This turns out to be
considerably more efficient than the previous implementation, with
around 25% improvement on the `token_reader` and `reader` benchmarks:

```
Benchmark 1 (27 runs): zig-out/bin-old/token_reader Gtk-4.0.gir
  measurement          mean ± σ            min … max           outliers         delta
  wall_time           188ms ± 14.5ms     168ms …  205ms          0 ( 0%)        0%
  peak_rss           7.31MB ± 58.5KB    7.21MB … 7.34MB          0 ( 0%)        0%
  cpu_cycles          688M  ± 4.20M      684M  …  706M           1 ( 4%)        0%
  instructions       1.19G  ± 29.4      1.19G  … 1.19G           0 ( 0%)        0%
  cache_references    412K  ±  763K      239K  … 4.21M           2 ( 7%)        0%
  cache_misses       10.0K  ± 7.40K     7.90K  … 46.8K           2 ( 7%)        0%
  branch_misses       814K  ± 1.37K      813K  …  821K           1 ( 4%)        0%
Benchmark 2 (37 runs): zig-out/bin/token_reader Gtk-4.0.gir
  measurement          mean ± σ            min … max           outliers         delta
  wall_time           136ms ± 13.8ms     115ms …  147ms          0 ( 0%)        ⚡- 27.7% ±  3.8%
  peak_rss           7.31MB ± 54.7KB    7.21MB … 7.34MB          8 (22%)          +  0.1% ±  0.4%
  cpu_cycles          462M  ± 1.87M      459M  …  466M           0 ( 0%)        ⚡- 32.8% ±  0.2%
  instructions       1.14G  ± 26.6      1.14G  … 1.14G           0 ( 0%)        ⚡-  4.1% ±  0.0%
  cache_references    236K  ± 4.86K      227K  …  244K           0 ( 0%)          - 42.7% ± 60.7%
  cache_misses       9.40K  ± 1.25K     7.88K  … 11.5K           0 ( 0%)          -  6.5% ± 24.6%
  branch_misses       815K  ± 1.01K      813K  …  817K           0 ( 0%)          +  0.1% ±  0.1%
```

```
Benchmark 1 (23 runs): zig-out/bin-old/reader Gtk-4.0.gir
  measurement          mean ± σ            min … max           outliers         delta
  wall_time           225ms ± 14.2ms     199ms …  249ms          0 ( 0%)        0%
  peak_rss           7.25MB ±  100KB    7.08MB … 7.34MB          0 ( 0%)        0%
  cpu_cycles          823M  ± 12.2M      813M  …  847M           0 ( 0%)        0%
  instructions       1.43G  ± 23.0      1.43G  … 1.43G           0 ( 0%)        0%
  cache_references    757K  ±  129K      635K  … 1.07M           1 ( 4%)        0%
  cache_misses       13.7K  ± 1.18K     12.5K  … 17.2K           2 ( 9%)        0%
  branch_misses      1.43M  ± 3.35K     1.42M  … 1.43M           0 ( 0%)        0%
Benchmark 2 (31 runs): zig-out/bin/reader Gtk-4.0.gir
  measurement          mean ± σ            min … max           outliers         delta
  wall_time           166ms ± 13.9ms     144ms …  175ms          0 ( 0%)        ⚡- 26.5% ±  3.4%
  peak_rss           7.27MB ± 81.8KB    7.08MB … 7.34MB          0 ( 0%)          +  0.3% ±  0.7%
  cpu_cycles          581M  ± 1.54M      579M  …  584M           0 ( 0%)        ⚡- 29.4% ±  0.5%
  instructions       1.38G  ± 16.0      1.38G  … 1.38G           9 (29%)        ⚡-  3.8% ±  0.0%
  cache_references    715K  ±  219K      563K  … 1.71M           3 (10%)          -  5.5% ± 13.6%
  cache_misses       13.5K  ± 1.31K     11.4K  … 16.5K           2 ( 6%)          -  1.2% ±  5.1%
  branch_misses      1.07M  ± 20.3K     1.05M  … 1.11M           5 (16%)        ⚡- 25.3% ±  0.6%
```
  • Loading branch information
ianprime0509 committed Oct 15, 2023
1 parent ea0fcb1 commit 47f384f
Show file tree
Hide file tree
Showing 4 changed files with 240 additions and 298 deletions.
11 changes: 7 additions & 4 deletions bench/src/scanner.zig
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
const std = @import("std");
const xml = @import("xml");

pub const main = @import("common.zig").main;

pub fn runBench(data: []const u8) !void {
var scanner = xml.Scanner{};
var data_stream = std.io.fixedBufferStream(data);
var decoder = xml.encoding.Utf8Decoder{};
for (data) |b| {
if (try decoder.next(b)) |c| {
_ = try scanner.next(c, 1);
}
var buf: [4]u8 = undefined;
while (true) {
const c = try decoder.readCodepoint(data_stream.reader(), &buf);
if (!c.present) break;
_ = try scanner.next(c.codepoint, c.byte_length);
}
}
20 changes: 6 additions & 14 deletions examples/scan.zig
Original file line number Diff line number Diff line change
Expand Up @@ -27,27 +27,19 @@ pub fn main() !void {

var line: usize = 1;
var column: usize = 1;
read: while (true) {
var codepoint_bytes: usize = 0;
const c = while (true) {
const b = input_reader.readByte() catch |e| switch (e) {
error.EndOfStream => break :read,
else => |other| return other,
};
codepoint_bytes += 1;
if (try decoder.next(b)) |codepoint| {
break codepoint;
}
};
const token = scanner.next(c, codepoint_bytes) catch |e| {
while (true) {
var buf: [4]u8 = undefined;
const c = try decoder.readCodepoint(input_reader, &buf);
if (!c.present) break;
const token = scanner.next(c.codepoint, c.byte_length) catch |e| {
try stdout_buffered_writer.flush();
try stderr.print("error: {} ({}:{}): {}\n", .{ scanner.pos, line, column, e });
return;
};
if (token != .ok) {
try stdout.print("{} ({}:{}): {}\n", .{ scanner.pos, line, column, token });
}
if (c == '\n') {
if (c.codepoint == '\n') {
line += 1;
column = 1;
} else {
Expand Down
Loading

0 comments on commit 47f384f

Please sign in to comment.