lib/sys/src/profiling/font.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

  1 const std = @import("std");
  2 const bench = @import("bench");
  3 const sys = @import("sys");
  4 
  5 const font = sys.font;
  6 
  7 const debug_io = std.Options.debug_io;
  8 const corpus_directories: u16 = 64;
  9 const corpus_files: u16 = 16;
 10 
 11 const limits: font.Catalog.Limits = .{
 12     .entries = 2048,
 13     .directories = 256,
 14     .path_bytes = 512 * 1024,
 15 };
 16 
 17 const Fixture = struct {
 18     tmp: std.testing.TmpDir,
 19     set: font.RootSet,
 20     storage: []align(font.Catalog.storage_alignment) u8,
 21     catalog: font.Catalog,
 22     allocator: std.mem.Allocator,
 23     expected: u32,
 24 
 25     fn init(self: *Fixture, backing_allocator: std.mem.Allocator) !void {
 26         self.allocator = backing_allocator;
 27         self.tmp = std.testing.tmpDir(.{});
 28         errdefer self.tmp.cleanup();
 29         self.expected = try font.fixture.createCorpus(
 30             debug_io,
 31             self.tmp.dir,
 32             corpus_directories,
 33             corpus_files,
 34         );
 35         var path_buffer: [std.Io.Dir.max_path_bytes]u8 = undefined;
 36         const used = try self.tmp.dir.realPath(debug_io, &path_buffer);
 37         self.set = .{};
 38         if (!self.set.append(path_buffer[0..used])) return error.RootRejected;
 39         const capacity = try font.Catalog.Capacity.derive(limits);
 40         self.storage = try backing_allocator.alignedAlloc(
 41             u8,
 42             .fromByteUnits(font.Catalog.storage_alignment),
 43             capacity.storage_bytes,
 44         );
 45         errdefer backing_allocator.free(self.storage);
 46         std.debug.assert(self.expected == @as(u32, corpus_directories) * corpus_files);
 47         std.debug.assert(self.storage.len == capacity.storage_bytes);
 48         self.catalog = try font.Catalog.init(self.storage, limits);
 49         self.catalog.activate();
 50     }
 51 
 52     fn deinit(self: *Fixture) void {
 53         _ = self.catalog.deinit();
 54         self.allocator.free(self.storage);
 55         self.tmp.cleanup();
 56         self.* = undefined;
 57     }
 58 };
 59 
 60 var active_fixture: ?*Fixture = null;
 61 
 62 fn enumerateWorkload(_: std.mem.Allocator) void {
 63     const fixture = active_fixture orelse unreachable;
 64     std.debug.assert(fixture.set.count == 1);
 65     fixture.catalog.reset();
 66     std.debug.assert(fixture.catalog.entryCount() == 0);
 67     var stats: font.Stats = .{};
 68     const phase = bench.phaseAt("sys.font.enumerate_1024", @src());
 69     defer phase.end();
 70     font.enumerate(
 71         debug_io,
 72         &fixture.catalog,
 73         &fixture.set,
 74         .{ .depth_max = 2 },
 75         &stats,
 76     ) catch @panic("sys font enumeration benchmark rejected an admission");
 77     std.debug.assert(stats.directories_visited == corpus_directories + 1);
 78     std.mem.doNotOptimizeAway(stats.directories_visited);
 79     if (fixture.catalog.entryCount() != fixture.expected) {
 80         @panic("sys font enumeration benchmark count failed");
 81     }
 82     bench.coz.progressNamed("sys.font.enumerate.complete");
 83 }
 84 
 85 fn minTimeNs(allocator: std.mem.Allocator) !u64 {
 86     const value = try sys.env.getOwned(allocator, "BENCH_MIN_TIME_NS");
 87     defer if (value) |text| allocator.free(text);
 88     return if (value) |text| try std.fmt.parseUnsigned(u64, text, 10) else 1_000_000;
 89 }
 90 
 91 test "bench: sys font enumeration over a fixture corpus" {
 92     const allocator = sys.allocator.benchmarkAllocator();
 93     var fixture: Fixture = undefined;
 94     try fixture.init(allocator);
 95     defer fixture.deinit();
 96     active_fixture = &fixture;
 97     defer active_fixture = null;
 98 
 99     const filter = try sys.env.getOwned(allocator, "BENCH_FILTER");
100     defer if (filter) |value| allocator.free(value);
101     var suite = bench.Suite.init(allocator, .{
102         .min_time_ns = try minTimeNs(allocator),
103         .min_iterations = 5,
104         .max_iterations = 20,
105         .warmup_iterations = 1,
106         .allocation_attribution = .sample_call,
107     });
108     defer suite.deinit();
109     suite.setFilter(filter);
110     try suite.add("sys font enumerate", enumerateWorkload, .{});
111     try suite.run();
112 }