mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-23 20:26:09 +03:00
synthetic cli (ghostty-gen)
This commit is contained in:
@ -3,12 +3,13 @@ const Allocator = std.mem.Allocator;
|
||||
const cli = @import("../cli.zig");
|
||||
|
||||
/// The available actions for the CLI. This is the list of available
|
||||
/// benchmarks.
|
||||
/// benchmarks. View docs for each individual one in the predictably
|
||||
/// named files.
|
||||
pub const Action = enum {
|
||||
@"terminal-stream",
|
||||
@"codepoint-width",
|
||||
@"grapheme-break",
|
||||
@"terminal-parser",
|
||||
@"terminal-stream",
|
||||
|
||||
/// Returns the struct associated with the action. The struct
|
||||
/// should have a few decls:
|
||||
|
@ -7,5 +7,5 @@ pub const GraphemeBreak = @import("GraphemeBreak.zig");
|
||||
pub const TerminalParser = @import("TerminalParser.zig");
|
||||
|
||||
test {
|
||||
_ = @import("std").testing.refAllDecls(@This());
|
||||
@import("std").testing.refAllDecls(@This());
|
||||
}
|
||||
|
@ -14,7 +14,24 @@ pub fn init(
|
||||
var steps = std.ArrayList(*std.Build.Step.Compile).init(b.allocator);
|
||||
errdefer steps.deinit();
|
||||
|
||||
// Our new benchmarking application.
|
||||
// Our synthetic data generator
|
||||
{
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "ghostty-gen",
|
||||
.root_module = b.createModule(.{
|
||||
.root_source_file = b.path("src/main_gen.zig"),
|
||||
.target = deps.config.target,
|
||||
// We always want our datagen to be fast because it
|
||||
// takes awhile to run.
|
||||
.optimize = .ReleaseFast,
|
||||
}),
|
||||
});
|
||||
exe.linkLibC();
|
||||
_ = try deps.add(exe);
|
||||
try steps.append(exe);
|
||||
}
|
||||
|
||||
// Our benchmarking application.
|
||||
{
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "ghostty-bench",
|
||||
|
5
src/main_gen.zig
Normal file
5
src/main_gen.zig
Normal file
@ -0,0 +1,5 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const synthetic = @import("synthetic/main.zig");
|
||||
|
||||
pub const main = synthetic.cli.main;
|
95
src/synthetic/cli.zig
Normal file
95
src/synthetic/cli.zig
Normal file
@ -0,0 +1,95 @@
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const cli = @import("../cli.zig");
|
||||
|
||||
/// The available actions for the CLI. This is the list of available
|
||||
/// synthetic generators. View docs for each individual one in the
|
||||
/// predictably named files under `cli/`.
|
||||
pub const Action = enum {
|
||||
ascii,
|
||||
|
||||
/// Returns the struct associated with the action. The struct
|
||||
/// should have a few decls:
|
||||
///
|
||||
/// - `const Options`: The CLI options for the action.
|
||||
/// - `fn create`: Create a new instance of the action from options.
|
||||
/// - `fn destroy`: Destroy the instance of the action.
|
||||
///
|
||||
/// See TerminalStream for an example.
|
||||
pub fn Struct(comptime action: Action) type {
|
||||
return switch (action) {
|
||||
.ascii => @import("cli/Ascii.zig"),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/// An entrypoint for the synthetic generator CLI.
|
||||
pub fn main() !void {
|
||||
const alloc = std.heap.c_allocator;
|
||||
const action_ = try cli.action.detectArgs(Action, alloc);
|
||||
const action = action_ orelse return error.NoAction;
|
||||
try mainAction(alloc, action, .cli);
|
||||
}
|
||||
|
||||
pub const Args = union(enum) {
|
||||
/// The arguments passed to the CLI via argc/argv.
|
||||
cli,
|
||||
|
||||
/// Simple string arguments, parsed via std.process.ArgIteratorGeneral.
|
||||
string: []const u8,
|
||||
};
|
||||
|
||||
pub fn mainAction(
|
||||
alloc: Allocator,
|
||||
action: Action,
|
||||
args: Args,
|
||||
) !void {
|
||||
switch (action) {
|
||||
inline else => |comptime_action| {
|
||||
const Impl = Action.Struct(comptime_action);
|
||||
try mainActionImpl(Impl, alloc, args);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn mainActionImpl(
|
||||
comptime Impl: type,
|
||||
alloc: Allocator,
|
||||
args: Args,
|
||||
) !void {
|
||||
// First, parse our CLI options.
|
||||
const Options = Impl.Options;
|
||||
var opts: Options = .{};
|
||||
defer if (@hasDecl(Options, "deinit")) opts.deinit();
|
||||
switch (args) {
|
||||
.cli => {
|
||||
var iter = try cli.args.argsIterator(alloc);
|
||||
defer iter.deinit();
|
||||
try cli.args.parse(Options, alloc, &opts, &iter);
|
||||
},
|
||||
.string => |str| {
|
||||
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
||||
alloc,
|
||||
str,
|
||||
);
|
||||
defer iter.deinit();
|
||||
try cli.args.parse(Options, alloc, &opts, &iter);
|
||||
},
|
||||
}
|
||||
|
||||
// TODO: Make this a command line option.
|
||||
const seed: u64 = @truncate(@as(
|
||||
u128,
|
||||
@bitCast(std.time.nanoTimestamp()),
|
||||
));
|
||||
var prng = std.Random.DefaultPrng.init(seed);
|
||||
const rand = prng.random();
|
||||
|
||||
// Our output always goes to stdout.
|
||||
const writer = std.io.getStdOut().writer();
|
||||
|
||||
// Create our implementation
|
||||
const impl = try Impl.create(alloc, opts);
|
||||
defer impl.destroy(alloc);
|
||||
try impl.run(writer, rand);
|
||||
}
|
53
src/synthetic/cli/Ascii.zig
Normal file
53
src/synthetic/cli/Ascii.zig
Normal file
@ -0,0 +1,53 @@
|
||||
//! This benchmark tests the throughput of grapheme break calculation.
|
||||
//! This is a common operation in terminal character printing for terminals
|
||||
//! that support grapheme clustering.
|
||||
const Ascii = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const synthetic = @import("../main.zig");
|
||||
|
||||
const log = std.log.scoped(.@"terminal-stream-bench");
|
||||
|
||||
pub const Options = struct {};
|
||||
|
||||
/// Create a new terminal stream handler for the given arguments.
|
||||
pub fn create(
|
||||
alloc: Allocator,
|
||||
_: Options,
|
||||
) !*Ascii {
|
||||
const ptr = try alloc.create(Ascii);
|
||||
errdefer alloc.destroy(ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
pub fn destroy(self: *Ascii, alloc: Allocator) void {
|
||||
alloc.destroy(self);
|
||||
}
|
||||
|
||||
pub fn run(self: *Ascii, writer: anytype, rand: std.Random) !void {
|
||||
_ = self;
|
||||
|
||||
var gen: synthetic.Bytes = .{
|
||||
.rand = rand,
|
||||
.alphabet = synthetic.Bytes.Alphabet.ascii,
|
||||
};
|
||||
|
||||
var buf: [1024]u8 = undefined;
|
||||
while (true) {
|
||||
const data = try gen.next(&buf);
|
||||
writer.writeAll(data) catch |err| switch (err) {
|
||||
error.BrokenPipe => return, // stdout closed
|
||||
else => return err,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
test Ascii {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
const impl: *Ascii = try .create(alloc, .{});
|
||||
defer impl.destroy(alloc);
|
||||
}
|
@ -13,6 +13,8 @@
|
||||
//! is not limited to that and we may want to extract this to a
|
||||
//! standalone package one day.
|
||||
|
||||
pub const cli = @import("cli.zig");
|
||||
|
||||
pub const Generator = @import("Generator.zig");
|
||||
pub const Bytes = @import("Bytes.zig");
|
||||
pub const Utf8 = @import("Utf8.zig");
|
||||
|
Reference in New Issue
Block a user