Debugging utilities (#860)
* add debug printing for Ast and DocumentScope * add optional failing allocator
This commit is contained in:
parent
f473088b64
commit
94ec3a0a86
12
build.zig
12
build.zig
@ -49,6 +49,18 @@ pub fn build(b: *std.build.Builder) !void {
|
||||
"enable_tracy_callstack",
|
||||
b.option(bool, "enable_tracy_callstack", "Enable callstack graphs.") orelse false,
|
||||
);
|
||||
|
||||
exe_options.addOption(
|
||||
bool,
|
||||
"enable_failing_allocator",
|
||||
b.option(bool, "enable_failing_allocator", "Whether to use a randomly failing allocator.") orelse false,
|
||||
);
|
||||
|
||||
exe_options.addOption(
|
||||
u32,
|
||||
"enable_failing_allocator_likelihood",
|
||||
b.option(u32, "enable_failing_allocator_likelihood", "The chance that an allocation will fail is `1/likelihood`") orelse 256,
|
||||
);
|
||||
|
||||
const version = v: {
|
||||
const version_string = b.fmt("{d}.{d}.{d}", .{ zls_version.major, zls_version.minor, zls_version.patch });
|
||||
|
@ -2389,30 +2389,6 @@ pub const DocumentScope = struct {
|
||||
error_completions: CompletionSet,
|
||||
enum_completions: CompletionSet,
|
||||
|
||||
pub fn debugPrint(self: DocumentScope) void {
|
||||
for (self.scopes.items) |scope| {
|
||||
log.debug(
|
||||
\\--------------------------
|
||||
\\Scope {}, loc: [{d}, {d})
|
||||
\\ {d} usingnamespaces
|
||||
\\Decls:
|
||||
, .{
|
||||
scope.data,
|
||||
scope.loc.start,
|
||||
scope.loc.end,
|
||||
scope.uses.len,
|
||||
});
|
||||
|
||||
var decl_it = scope.decls.iterator();
|
||||
var idx: usize = 0;
|
||||
while (decl_it.next()) |_| : (idx += 1) {
|
||||
if (idx != 0) log.debug(", ", .{});
|
||||
}
|
||||
// log.debug("{s}", .{name_decl.key});
|
||||
log.debug("\n--------------------------\n", .{});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deinit(self: *DocumentScope, allocator: std.mem.Allocator) void {
|
||||
for (self.scopes.items) |*scope| {
|
||||
scope.deinit(allocator);
|
||||
|
136
src/debug.zig
Normal file
136
src/debug.zig
Normal file
@ -0,0 +1,136 @@
|
||||
const std = @import("std");
|
||||
|
||||
const analysis = @import("analysis.zig");
|
||||
const offsets = @import("offsets.zig");
|
||||
|
||||
pub fn printTree(tree: std.zig.Ast) void {
|
||||
if (!std.debug.runtime_safety) @compileError("this function should only be used in debug mode!");
|
||||
|
||||
std.debug.print(
|
||||
\\
|
||||
\\nodes tag lhs rhs token
|
||||
\\-----------------------------------------------
|
||||
\\
|
||||
, .{});
|
||||
var i: usize = 0;
|
||||
while (i < tree.nodes.len) : (i += 1) {
|
||||
std.debug.print(" {d:<3} {s:<20} {d:<3} {d:<3} {d:<3} {s}\n", .{
|
||||
i,
|
||||
@tagName(tree.nodes.items(.tag)[i]),
|
||||
tree.nodes.items(.data)[i].lhs,
|
||||
tree.nodes.items(.data)[i].rhs,
|
||||
tree.nodes.items(.main_token)[i],
|
||||
offsets.tokenToSlice(tree, tree.nodes.items(.main_token)[i]),
|
||||
});
|
||||
}
|
||||
|
||||
std.debug.print(
|
||||
\\
|
||||
\\tokens tag start
|
||||
\\----------------------------------
|
||||
\\
|
||||
, .{});
|
||||
i = 0;
|
||||
while (i < tree.tokens.len) : (i += 1) {
|
||||
std.debug.print(" {d:<3} {s:<20} {d:<}\n", .{
|
||||
i,
|
||||
@tagName(tree.tokens.items(.tag)[i]),
|
||||
tree.tokens.items(.start)[i],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn printDocumentScope(doc_scope: analysis.DocumentScope) void {
|
||||
if (!std.debug.runtime_safety) @compileError("this function should only be used in debug mode!");
|
||||
|
||||
for (doc_scope.scopes.items) |scope, i| {
|
||||
if (i != 0) std.debug.print("\n\n", .{});
|
||||
std.debug.print(
|
||||
\\[{d}, {d}] {}
|
||||
\\usingnamespaces: {d}
|
||||
\\Decls:
|
||||
\\
|
||||
, .{
|
||||
scope.loc.start,
|
||||
scope.loc.end,
|
||||
scope.data,
|
||||
scope.uses.items.len,
|
||||
});
|
||||
|
||||
var decl_it = scope.decls.iterator();
|
||||
var idx: usize = 0;
|
||||
while (decl_it.next()) |entry| : (idx += 1) {
|
||||
std.debug.print(" {s:<8} {}\n", .{ entry.key_ptr.*, entry.value_ptr.* });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const FailingAllocator = struct {
|
||||
internal_allocator: std.mem.Allocator,
|
||||
random: std.rand.DefaultPrng,
|
||||
likelihood: u32,
|
||||
|
||||
/// the chance that an allocation will fail is `1/likelihood`
|
||||
/// `likelihood == 0` means that every allocation will fail
|
||||
/// `likelihood == std.math.intMax(u32)` means that no allocation will be forced to fail
|
||||
pub fn init(internal_allocator: std.mem.Allocator, likelihood: u32) FailingAllocator {
|
||||
var seed = std.mem.zeroes([8]u8);
|
||||
std.os.getrandom(&seed) catch {};
|
||||
|
||||
return FailingAllocator{
|
||||
.internal_allocator = internal_allocator,
|
||||
.random = std.rand.DefaultPrng.init(@bitCast(u64, seed)),
|
||||
.likelihood = likelihood,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn allocator(self: *FailingAllocator) std.mem.Allocator {
|
||||
return .{
|
||||
.ptr = self,
|
||||
.vtable = &.{
|
||||
.alloc = alloc,
|
||||
.resize = resize,
|
||||
.free = free,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn alloc(
|
||||
ctx: *anyopaque,
|
||||
len: usize,
|
||||
log2_ptr_align: u8,
|
||||
return_address: usize,
|
||||
) ?[*]u8 {
|
||||
const self = @ptrCast(*FailingAllocator, @alignCast(@alignOf(FailingAllocator), ctx));
|
||||
if (shouldFail(self)) return null;
|
||||
return self.internal_allocator.rawAlloc(len, log2_ptr_align, return_address);
|
||||
}
|
||||
|
||||
fn resize(
|
||||
ctx: *anyopaque,
|
||||
old_mem: []u8,
|
||||
log2_old_align: u8,
|
||||
new_len: usize,
|
||||
ra: usize,
|
||||
) bool {
|
||||
const self = @ptrCast(*FailingAllocator, @alignCast(@alignOf(FailingAllocator), ctx));
|
||||
if (!self.internal_allocator.rawResize(old_mem, log2_old_align, new_len, ra))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
fn free(
|
||||
ctx: *anyopaque,
|
||||
old_mem: []u8,
|
||||
log2_old_align: u8,
|
||||
ra: usize,
|
||||
) void {
|
||||
const self = @ptrCast(*FailingAllocator, @alignCast(@alignOf(FailingAllocator), ctx));
|
||||
self.internal_allocator.rawFree(old_mem, log2_old_align, ra);
|
||||
}
|
||||
|
||||
fn shouldFail(self: *FailingAllocator) bool {
|
||||
if (self.likelihood == std.math.maxInt(u32)) return false;
|
||||
return 0 == self.random.random().intRangeAtMostBiased(u32, 0, self.likelihood);
|
||||
}
|
||||
};
|
@ -8,6 +8,7 @@ const configuration = @import("configuration.zig");
|
||||
const Server = @import("Server.zig");
|
||||
const setup = @import("setup.zig");
|
||||
const Header = @import("Header.zig");
|
||||
const debug = @import("debug.zig");
|
||||
|
||||
const logger = std.log.scoped(.main);
|
||||
|
||||
@ -263,9 +264,12 @@ const stack_frames = switch (zig_builtin.mode) {
|
||||
pub fn main() !void {
|
||||
var gpa_state = std.heap.GeneralPurposeAllocator(.{ .stack_trace_frames = stack_frames }){};
|
||||
defer _ = gpa_state.deinit();
|
||||
var tracy_state = if (tracy.enable_allocation) tracy.tracyAllocator(gpa_state.allocator()) else void{};
|
||||
|
||||
const allocator: std.mem.Allocator = if (tracy.enable_allocation) tracy_state.allocator() else gpa_state.allocator();
|
||||
var tracy_state = if (tracy.enable_allocation) tracy.tracyAllocator(gpa_state.allocator()) else void{};
|
||||
const inner_allocator: std.mem.Allocator = if (tracy.enable_allocation) tracy_state.allocator() else gpa_state.allocator();
|
||||
|
||||
var failing_allocator_state = if(build_options.enable_failing_allocator) debug.FailingAllocator.init(inner_allocator, build_options.enable_failing_allocator_likelihood) else void{};
|
||||
const allocator: std.mem.Allocator = if(build_options.enable_failing_allocator) failing_allocator_state.allocator() else inner_allocator;
|
||||
|
||||
var config = ConfigWithPath{
|
||||
.config = undefined,
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
pub const analysis = @import("analysis.zig");
|
||||
pub const Header = @import("Header.zig");
|
||||
pub const debug = @import("debug.zig");
|
||||
pub const offsets = @import("offsets.zig");
|
||||
pub const Config = @import("Config.zig");
|
||||
pub const Server = @import("Server.zig");
|
||||
|
Loading…
Reference in New Issue
Block a user