mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-24 20:56:08 +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");
|
const cli = @import("../cli.zig");
|
||||||
|
|
||||||
/// The available actions for the CLI. This is the list of available
|
/// 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 {
|
pub const Action = enum {
|
||||||
@"terminal-stream",
|
|
||||||
@"codepoint-width",
|
@"codepoint-width",
|
||||||
@"grapheme-break",
|
@"grapheme-break",
|
||||||
@"terminal-parser",
|
@"terminal-parser",
|
||||||
|
@"terminal-stream",
|
||||||
|
|
||||||
/// Returns the struct associated with the action. The struct
|
/// Returns the struct associated with the action. The struct
|
||||||
/// should have a few decls:
|
/// should have a few decls:
|
||||||
|
@ -7,5 +7,5 @@ pub const GraphemeBreak = @import("GraphemeBreak.zig");
|
|||||||
pub const TerminalParser = @import("TerminalParser.zig");
|
pub const TerminalParser = @import("TerminalParser.zig");
|
||||||
|
|
||||||
test {
|
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);
|
var steps = std.ArrayList(*std.Build.Step.Compile).init(b.allocator);
|
||||||
errdefer steps.deinit();
|
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(.{
|
const exe = b.addExecutable(.{
|
||||||
.name = "ghostty-bench",
|
.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
|
//! is not limited to that and we may want to extract this to a
|
||||||
//! standalone package one day.
|
//! standalone package one day.
|
||||||
|
|
||||||
|
pub const cli = @import("cli.zig");
|
||||||
|
|
||||||
pub const Generator = @import("Generator.zig");
|
pub const Generator = @import("Generator.zig");
|
||||||
pub const Bytes = @import("Bytes.zig");
|
pub const Bytes = @import("Bytes.zig");
|
||||||
pub const Utf8 = @import("Utf8.zig");
|
pub const Utf8 = @import("Utf8.zig");
|
||||||
|
Reference in New Issue
Block a user