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
@ -50,6 +50,18 @@ pub fn build(b: *std.build.Builder) !void {
|
|||||||
b.option(bool, "enable_tracy_callstack", "Enable callstack graphs.") orelse false,
|
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 = v: {
|
||||||
const version_string = b.fmt("{d}.{d}.{d}", .{ zls_version.major, zls_version.minor, zls_version.patch });
|
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,
|
error_completions: CompletionSet,
|
||||||
enum_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 {
|
pub fn deinit(self: *DocumentScope, allocator: std.mem.Allocator) void {
|
||||||
for (self.scopes.items) |*scope| {
|
for (self.scopes.items) |*scope| {
|
||||||
scope.deinit(allocator);
|
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 Server = @import("Server.zig");
|
||||||
const setup = @import("setup.zig");
|
const setup = @import("setup.zig");
|
||||||
const Header = @import("Header.zig");
|
const Header = @import("Header.zig");
|
||||||
|
const debug = @import("debug.zig");
|
||||||
|
|
||||||
const logger = std.log.scoped(.main);
|
const logger = std.log.scoped(.main);
|
||||||
|
|
||||||
@ -263,9 +264,12 @@ const stack_frames = switch (zig_builtin.mode) {
|
|||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
var gpa_state = std.heap.GeneralPurposeAllocator(.{ .stack_trace_frames = stack_frames }){};
|
var gpa_state = std.heap.GeneralPurposeAllocator(.{ .stack_trace_frames = stack_frames }){};
|
||||||
defer _ = gpa_state.deinit();
|
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{
|
var config = ConfigWithPath{
|
||||||
.config = undefined,
|
.config = undefined,
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
pub const analysis = @import("analysis.zig");
|
pub const analysis = @import("analysis.zig");
|
||||||
pub const Header = @import("Header.zig");
|
pub const Header = @import("Header.zig");
|
||||||
|
pub const debug = @import("debug.zig");
|
||||||
pub const offsets = @import("offsets.zig");
|
pub const offsets = @import("offsets.zig");
|
||||||
pub const Config = @import("Config.zig");
|
pub const Config = @import("Config.zig");
|
||||||
pub const Server = @import("Server.zig");
|
pub const Server = @import("Server.zig");
|
||||||
|
Loading…
Reference in New Issue
Block a user