Add tracy

This commit is contained in:
Auguste Rame 2022-06-05 23:50:17 -04:00 committed by Auguste Rame
parent 2fc5047cbd
commit 29d2dd6802
4 changed files with 567 additions and 5 deletions

View File

@ -22,8 +22,48 @@ pub fn build(b: *std.build.Builder) !void {
b.option(std.log.Level, "log_level", "The Log Level to be used.") orelse .info, b.option(std.log.Level, "log_level", "The Log Level to be used.") orelse .info,
); );
const enable_tracy = b.option(bool, "enable_tracy", "Whether of not tracy should be enabled.") orelse false;
exe_options.addOption(
bool,
"enable_tracy",
enable_tracy,
);
exe_options.addOption(
bool,
"enable_tracy_allocation",
b.option(bool, "enable_tracy_allocation", "Enable using TracyAllocator to monitor allocations.") orelse false,
);
exe_options.addOption(
bool,
"enable_tracy_callstack",
b.option(bool, "enable_tracy_callstack", "Enable callstack graphs.") orelse false,
);
exe.addPackage(.{ .name = "known-folders", .source = .{ .path = "src/known-folders/known-folders.zig" } }); exe.addPackage(.{ .name = "known-folders", .source = .{ .path = "src/known-folders/known-folders.zig" } });
if (enable_tracy) {
const client_cpp = "src/tracy/TracyClient.cpp";
// On mingw, we need to opt into windows 7+ to get some features required by tracy.
const tracy_c_flags: []const []const u8 = if (target.isWindows() and target.getAbi() == .gnu)
&[_][]const u8{ "-DTRACY_ENABLE=1", "-fno-sanitize=undefined", "-D_WIN32_WINNT=0x601" }
else
&[_][]const u8{ "-DTRACY_ENABLE=1", "-fno-sanitize=undefined" };
exe.addIncludePath("src/tracy");
exe.addCSourceFile(client_cpp, tracy_c_flags);
exe.linkSystemLibraryName("c++");
exe.linkLibC();
if (target.isWindows()) {
exe.linkSystemLibrary("dbghelp");
exe.linkSystemLibrary("ws2_32");
}
}
exe.setTarget(target); exe.setTarget(target);
exe.setBuildMode(mode); exe.setBuildMode(mode);
exe.install(); exe.install();

View File

@ -6,6 +6,7 @@ const offsets = @import("./offsets.zig");
const log = std.log.scoped(.doc_store); const log = std.log.scoped(.doc_store);
const Ast = std.zig.Ast; const Ast = std.zig.Ast;
const BuildAssociatedConfig = @import("./BuildAssociatedConfig.zig"); const BuildAssociatedConfig = @import("./BuildAssociatedConfig.zig");
const tracy = @import("./tracy.zig");
const DocumentStore = @This(); const DocumentStore = @This();
@ -119,6 +120,9 @@ const LoadPackagesContext = struct {
}; };
fn loadPackages(context: LoadPackagesContext) !void { fn loadPackages(context: LoadPackagesContext) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
const allocator = context.allocator; const allocator = context.allocator;
const build_file = context.build_file; const build_file = context.build_file;
const build_runner_path = context.build_runner_path; const build_runner_path = context.build_runner_path;
@ -195,6 +199,9 @@ fn loadPackages(context: LoadPackagesContext) !void {
/// This function asserts the document is not open yet and takes ownership /// This function asserts the document is not open yet and takes ownership
/// of the uri and text passed in. /// of the uri and text passed in.
fn newDocument(self: *DocumentStore, uri: []const u8, text: [:0]u8) anyerror!*Handle { fn newDocument(self: *DocumentStore, uri: []const u8, text: [:0]u8) anyerror!*Handle {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
log.debug("Opened document: {s}", .{uri}); log.debug("Opened document: {s}", .{uri});
var handle = try self.allocator.create(Handle); var handle = try self.allocator.create(Handle);

View File

@ -16,6 +16,7 @@ const semantic_tokens = @import("./semantic_tokens.zig");
const shared = @import("./shared.zig"); const shared = @import("./shared.zig");
const Ast = std.zig.Ast; const Ast = std.zig.Ast;
const known_folders = @import("known-folders"); const known_folders = @import("known-folders");
const tracy = @import("./tracy.zig");
const data = switch (build_options.data_version) { const data = switch (build_options.data_version) {
.master => @import("data/master.zig"), .master => @import("data/master.zig"),
@ -38,6 +39,9 @@ var actual_log_level: std.log.Level = switch (zig_builtin.mode) {
}; };
pub fn log(comptime message_level: std.log.Level, comptime scope: @Type(.EnumLiteral), comptime format: []const u8, args: anytype) void { pub fn log(comptime message_level: std.log.Level, comptime scope: @Type(.EnumLiteral), comptime format: []const u8, args: anytype) void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
if (@enumToInt(message_level) > @enumToInt(actual_log_level)) { if (@enumToInt(message_level) > @enumToInt(actual_log_level)) {
return; return;
} }
@ -118,6 +122,9 @@ const no_semantic_tokens_response =
/// Sends a request or response /// Sends a request or response
fn send(arena: *std.heap.ArenaAllocator, reqOrRes: anytype) !void { fn send(arena: *std.heap.ArenaAllocator, reqOrRes: anytype) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
var arr = std.ArrayList(u8).init(arena.allocator()); var arr = std.ArrayList(u8).init(arena.allocator());
try std.json.stringify(reqOrRes, .{}, arr.writer()); try std.json.stringify(reqOrRes, .{}, arr.writer());
@ -138,6 +145,9 @@ fn truncateCompletions(list: []types.CompletionItem, max_detail_length: usize) v
} }
fn respondGeneric(id: types.RequestId, response: []const u8) !void { fn respondGeneric(id: types.RequestId, response: []const u8) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
const id_len = switch (id) { const id_len = switch (id) {
.Integer => |id_val| blk: { .Integer => |id_val| blk: {
if (id_val == 0) break :blk 1; if (id_val == 0) break :blk 1;
@ -194,6 +204,9 @@ fn astLocationToRange(loc: Ast.Location) types.Range {
} }
fn publishDiagnostics(arena: *std.heap.ArenaAllocator, handle: DocumentStore.Handle, config: *const Config) !void { fn publishDiagnostics(arena: *std.heap.ArenaAllocator, handle: DocumentStore.Handle, config: *const Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
const tree = handle.tree; const tree = handle.tree;
var diagnostics = std.ArrayList(types.Diagnostic).init(arena.allocator()); var diagnostics = std.ArrayList(types.Diagnostic).init(arena.allocator());
@ -273,7 +286,16 @@ fn publishDiagnostics(arena: *std.heap.ArenaAllocator, handle: DocumentStore.Han
}); });
} }
fn typeToCompletion(arena: *std.heap.ArenaAllocator, list: *std.ArrayList(types.CompletionItem), field_access: analysis.FieldAccessReturn, orig_handle: *DocumentStore.Handle, config: *const Config) error{OutOfMemory}!void { fn typeToCompletion(
arena: *std.heap.ArenaAllocator,
list: *std.ArrayList(types.CompletionItem),
field_access: analysis.FieldAccessReturn,
orig_handle: *DocumentStore.Handle,
config: *const Config,
) error{OutOfMemory}!void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
const type_handle = field_access.original; const type_handle = field_access.original;
switch (type_handle.type.data) { switch (type_handle.type.data) {
.slice => { .slice => {
@ -327,7 +349,19 @@ fn typeToCompletion(arena: *std.heap.ArenaAllocator, list: *std.ArrayList(types.
} }
} }
fn nodeToCompletion(arena: *std.heap.ArenaAllocator, list: *std.ArrayList(types.CompletionItem), node_handle: analysis.NodeWithHandle, unwrapped: ?analysis.TypeWithHandle, orig_handle: *DocumentStore.Handle, is_type_val: bool, parent_is_type_val: ?bool, config: *const Config) error{OutOfMemory}!void { fn nodeToCompletion(
arena: *std.heap.ArenaAllocator,
list: *std.ArrayList(types.CompletionItem),
node_handle: analysis.NodeWithHandle,
unwrapped: ?analysis.TypeWithHandle,
orig_handle: *DocumentStore.Handle,
is_type_val: bool,
parent_is_type_val: ?bool,
config: *const Config,
) error{OutOfMemory}!void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
const node = node_handle.node; const node = node_handle.node;
const handle = node_handle.handle; const handle = node_handle.handle;
const tree = handle.tree; const tree = handle.tree;
@ -547,6 +581,9 @@ fn isSymbolChar(char: u8) bool {
} }
fn gotoDefinitionSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, decl_handle: analysis.DeclWithHandle, resolve_alias: bool) !void { fn gotoDefinitionSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, decl_handle: analysis.DeclWithHandle, resolve_alias: bool) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
var handle = decl_handle.handle; var handle = decl_handle.handle;
const location = switch (decl_handle.decl.*) { const location = switch (decl_handle.decl.*) {
@ -586,6 +623,9 @@ fn gotoDefinitionSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, de
} }
fn hoverSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, decl_handle: analysis.DeclWithHandle) (std.os.WriteError || error{OutOfMemory})!void { fn hoverSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, decl_handle: analysis.DeclWithHandle) (std.os.WriteError || error{OutOfMemory})!void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
const handle = decl_handle.handle; const handle = decl_handle.handle;
const tree = handle.tree; const tree = handle.tree;
@ -660,6 +700,9 @@ fn hoverSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, decl_handle
} }
fn getLabelGlobal(pos_index: usize, handle: *DocumentStore.Handle) !?analysis.DeclWithHandle { fn getLabelGlobal(pos_index: usize, handle: *DocumentStore.Handle) !?analysis.DeclWithHandle {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
const name = identifierFromPosition(pos_index, handle.*); const name = identifierFromPosition(pos_index, handle.*);
if (name.len == 0) return null; if (name.len == 0) return null;
@ -667,6 +710,9 @@ fn getLabelGlobal(pos_index: usize, handle: *DocumentStore.Handle) !?analysis.De
} }
fn getSymbolGlobal(arena: *std.heap.ArenaAllocator, pos_index: usize, handle: *DocumentStore.Handle) !?analysis.DeclWithHandle { fn getSymbolGlobal(arena: *std.heap.ArenaAllocator, pos_index: usize, handle: *DocumentStore.Handle) !?analysis.DeclWithHandle {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
const name = identifierFromPosition(pos_index, handle.*); const name = identifierFromPosition(pos_index, handle.*);
if (name.len == 0) return null; if (name.len == 0) return null;
@ -674,6 +720,9 @@ fn getSymbolGlobal(arena: *std.heap.ArenaAllocator, pos_index: usize, handle: *D
} }
fn gotoDefinitionLabel(arena: *std.heap.ArenaAllocator, id: types.RequestId, pos_index: usize, handle: *DocumentStore.Handle, config: *const Config) !void { fn gotoDefinitionLabel(arena: *std.heap.ArenaAllocator, id: types.RequestId, pos_index: usize, handle: *DocumentStore.Handle, config: *const Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
_ = config; _ = config;
const decl = (try getLabelGlobal(pos_index, handle)) orelse return try respondGeneric(id, null_result_response); const decl = (try getLabelGlobal(pos_index, handle)) orelse return try respondGeneric(id, null_result_response);
@ -681,6 +730,9 @@ fn gotoDefinitionLabel(arena: *std.heap.ArenaAllocator, id: types.RequestId, pos
} }
fn gotoDefinitionGlobal(arena: *std.heap.ArenaAllocator, id: types.RequestId, pos_index: usize, handle: *DocumentStore.Handle, config: *const Config, resolve_alias: bool) !void { fn gotoDefinitionGlobal(arena: *std.heap.ArenaAllocator, id: types.RequestId, pos_index: usize, handle: *DocumentStore.Handle, config: *const Config, resolve_alias: bool) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
_ = config; _ = config;
const decl = (try getSymbolGlobal(arena, pos_index, handle)) orelse return try respondGeneric(id, null_result_response); const decl = (try getSymbolGlobal(arena, pos_index, handle)) orelse return try respondGeneric(id, null_result_response);
@ -688,6 +740,9 @@ fn gotoDefinitionGlobal(arena: *std.heap.ArenaAllocator, id: types.RequestId, po
} }
fn hoverDefinitionLabel(arena: *std.heap.ArenaAllocator, id: types.RequestId, pos_index: usize, handle: *DocumentStore.Handle, config: *const Config) !void { fn hoverDefinitionLabel(arena: *std.heap.ArenaAllocator, id: types.RequestId, pos_index: usize, handle: *DocumentStore.Handle, config: *const Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
_ = config; _ = config;
const decl = (try getLabelGlobal(pos_index, handle)) orelse return try respondGeneric(id, null_result_response); const decl = (try getLabelGlobal(pos_index, handle)) orelse return try respondGeneric(id, null_result_response);
@ -695,6 +750,9 @@ fn hoverDefinitionLabel(arena: *std.heap.ArenaAllocator, id: types.RequestId, po
} }
fn hoverDefinitionBuiltin(arena: *std.heap.ArenaAllocator, id: types.RequestId, pos_index: usize, handle: *DocumentStore.Handle) !void { fn hoverDefinitionBuiltin(arena: *std.heap.ArenaAllocator, id: types.RequestId, pos_index: usize, handle: *DocumentStore.Handle) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
const name = identifierFromPosition(pos_index, handle.*); const name = identifierFromPosition(pos_index, handle.*);
if (name.len == 0) return try respondGeneric(id, null_result_response); if (name.len == 0) return try respondGeneric(id, null_result_response);
@ -719,6 +777,9 @@ fn hoverDefinitionBuiltin(arena: *std.heap.ArenaAllocator, id: types.RequestId,
} }
fn hoverDefinitionGlobal(arena: *std.heap.ArenaAllocator, id: types.RequestId, pos_index: usize, handle: *DocumentStore.Handle, config: *const Config) !void { fn hoverDefinitionGlobal(arena: *std.heap.ArenaAllocator, id: types.RequestId, pos_index: usize, handle: *DocumentStore.Handle, config: *const Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
_ = config; _ = config;
const decl = (try getSymbolGlobal(arena, pos_index, handle)) orelse return try respondGeneric(id, null_result_response); const decl = (try getSymbolGlobal(arena, pos_index, handle)) orelse return try respondGeneric(id, null_result_response);
@ -726,6 +787,9 @@ fn hoverDefinitionGlobal(arena: *std.heap.ArenaAllocator, id: types.RequestId, p
} }
fn getSymbolFieldAccess(handle: *DocumentStore.Handle, arena: *std.heap.ArenaAllocator, position: offsets.DocumentPosition, range: analysis.SourceRange, config: *const Config) !?analysis.DeclWithHandle { fn getSymbolFieldAccess(handle: *DocumentStore.Handle, arena: *std.heap.ArenaAllocator, position: offsets.DocumentPosition, range: analysis.SourceRange, config: *const Config) !?analysis.DeclWithHandle {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
_ = config; _ = config;
const name = identifierFromPosition(position.absolute_index, handle.*); const name = identifierFromPosition(position.absolute_index, handle.*);
@ -755,16 +819,25 @@ fn getSymbolFieldAccess(handle: *DocumentStore.Handle, arena: *std.heap.ArenaAll
} }
fn gotoDefinitionFieldAccess(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, position: offsets.DocumentPosition, range: analysis.SourceRange, config: *const Config, resolve_alias: bool) !void { fn gotoDefinitionFieldAccess(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, position: offsets.DocumentPosition, range: analysis.SourceRange, config: *const Config, resolve_alias: bool) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
const decl = (try getSymbolFieldAccess(handle, arena, position, range, config)) orelse return try respondGeneric(id, null_result_response); const decl = (try getSymbolFieldAccess(handle, arena, position, range, config)) orelse return try respondGeneric(id, null_result_response);
return try gotoDefinitionSymbol(id, arena, decl, resolve_alias); return try gotoDefinitionSymbol(id, arena, decl, resolve_alias);
} }
fn hoverDefinitionFieldAccess(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, position: offsets.DocumentPosition, range: analysis.SourceRange, config: *const Config) !void { fn hoverDefinitionFieldAccess(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, position: offsets.DocumentPosition, range: analysis.SourceRange, config: *const Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
const decl = (try getSymbolFieldAccess(handle, arena, position, range, config)) orelse return try respondGeneric(id, null_result_response); const decl = (try getSymbolFieldAccess(handle, arena, position, range, config)) orelse return try respondGeneric(id, null_result_response);
return try hoverSymbol(id, arena, decl); return try hoverSymbol(id, arena, decl);
} }
fn gotoDefinitionString(arena: *std.heap.ArenaAllocator, id: types.RequestId, pos_index: usize, handle: *DocumentStore.Handle, config: *const Config) !void { fn gotoDefinitionString(arena: *std.heap.ArenaAllocator, id: types.RequestId, pos_index: usize, handle: *DocumentStore.Handle, config: *const Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
_ = config; _ = config;
const tree = handle.tree; const tree = handle.tree;
@ -791,6 +864,9 @@ fn gotoDefinitionString(arena: *std.heap.ArenaAllocator, id: types.RequestId, po
} }
fn renameDefinitionGlobal(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, pos_index: usize, new_name: []const u8) !void { fn renameDefinitionGlobal(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, pos_index: usize, new_name: []const u8) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
const decl = (try getSymbolGlobal(arena, pos_index, handle)) orelse return try respondGeneric(id, null_result_response); const decl = (try getSymbolGlobal(arena, pos_index, handle)) orelse return try respondGeneric(id, null_result_response);
var workspace_edit = types.WorkspaceEdit{ var workspace_edit = types.WorkspaceEdit{
@ -804,6 +880,9 @@ fn renameDefinitionGlobal(arena: *std.heap.ArenaAllocator, id: types.RequestId,
} }
fn renameDefinitionFieldAccess(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, position: offsets.DocumentPosition, range: analysis.SourceRange, new_name: []const u8, config: *const Config) !void { fn renameDefinitionFieldAccess(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, position: offsets.DocumentPosition, range: analysis.SourceRange, new_name: []const u8, config: *const Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
const decl = (try getSymbolFieldAccess(handle, arena, position, range, config)) orelse return try respondGeneric(id, null_result_response); const decl = (try getSymbolFieldAccess(handle, arena, position, range, config)) orelse return try respondGeneric(id, null_result_response);
var workspace_edit = types.WorkspaceEdit{ var workspace_edit = types.WorkspaceEdit{
@ -817,6 +896,9 @@ fn renameDefinitionFieldAccess(arena: *std.heap.ArenaAllocator, id: types.Reques
} }
fn renameDefinitionLabel(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, pos_index: usize, new_name: []const u8) !void { fn renameDefinitionLabel(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, pos_index: usize, new_name: []const u8) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
const decl = (try getLabelGlobal(pos_index, handle)) orelse return try respondGeneric(id, null_result_response); const decl = (try getLabelGlobal(pos_index, handle)) orelse return try respondGeneric(id, null_result_response);
var workspace_edit = types.WorkspaceEdit{ var workspace_edit = types.WorkspaceEdit{
@ -830,6 +912,9 @@ fn renameDefinitionLabel(arena: *std.heap.ArenaAllocator, id: types.RequestId, h
} }
fn referencesDefinitionGlobal(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, pos_index: usize, include_decl: bool, skip_std_references: bool) !void { fn referencesDefinitionGlobal(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, pos_index: usize, include_decl: bool, skip_std_references: bool) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
const decl = (try getSymbolGlobal(arena, pos_index, handle)) orelse return try respondGeneric(id, null_result_response); const decl = (try getSymbolGlobal(arena, pos_index, handle)) orelse return try respondGeneric(id, null_result_response);
var locs = std.ArrayList(types.Location).init(arena.allocator()); var locs = std.ArrayList(types.Location).init(arena.allocator());
try references.symbolReferences( try references.symbolReferences(
@ -849,6 +934,9 @@ fn referencesDefinitionGlobal(arena: *std.heap.ArenaAllocator, id: types.Request
} }
fn referencesDefinitionFieldAccess(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, position: offsets.DocumentPosition, range: analysis.SourceRange, include_decl: bool, config: *const Config) !void { fn referencesDefinitionFieldAccess(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, position: offsets.DocumentPosition, range: analysis.SourceRange, include_decl: bool, config: *const Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
const decl = (try getSymbolFieldAccess(handle, arena, position, range, config)) orelse return try respondGeneric(id, null_result_response); const decl = (try getSymbolFieldAccess(handle, arena, position, range, config)) orelse return try respondGeneric(id, null_result_response);
var locs = std.ArrayList(types.Location).init(arena.allocator()); var locs = std.ArrayList(types.Location).init(arena.allocator());
try references.symbolReferences(arena, &document_store, decl, offset_encoding, include_decl, &locs, std.ArrayList(types.Location).append, config.skip_std_references); try references.symbolReferences(arena, &document_store, decl, offset_encoding, include_decl, &locs, std.ArrayList(types.Location).append, config.skip_std_references);
@ -859,6 +947,9 @@ fn referencesDefinitionFieldAccess(arena: *std.heap.ArenaAllocator, id: types.Re
} }
fn referencesDefinitionLabel(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, pos_index: usize, include_decl: bool) !void { fn referencesDefinitionLabel(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, pos_index: usize, include_decl: bool) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
const decl = (try getLabelGlobal(pos_index, handle)) orelse return try respondGeneric(id, null_result_response); const decl = (try getLabelGlobal(pos_index, handle)) orelse return try respondGeneric(id, null_result_response);
var locs = std.ArrayList(types.Location).init(arena.allocator()); var locs = std.ArrayList(types.Location).init(arena.allocator());
try references.labelReferences(arena, decl, offset_encoding, include_decl, &locs, std.ArrayList(types.Location).append); try references.labelReferences(arena, decl, offset_encoding, include_decl, &locs, std.ArrayList(types.Location).append);
@ -869,6 +960,9 @@ fn referencesDefinitionLabel(arena: *std.heap.ArenaAllocator, id: types.RequestI
} }
fn hasComment(tree: Ast.Tree, start_token: Ast.TokenIndex, end_token: Ast.TokenIndex) bool { fn hasComment(tree: Ast.Tree, start_token: Ast.TokenIndex, end_token: Ast.TokenIndex) bool {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
const token_starts = tree.tokens.items(.start); const token_starts = tree.tokens.items(.start);
const start = token_starts[start_token]; const start = token_starts[start_token];
@ -886,6 +980,9 @@ const DeclToCompletionContext = struct {
}; };
fn declToCompletion(context: DeclToCompletionContext, decl_handle: analysis.DeclWithHandle) !void { fn declToCompletion(context: DeclToCompletionContext, decl_handle: analysis.DeclWithHandle) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
const tree = decl_handle.handle.tree; const tree = decl_handle.handle.tree;
switch (decl_handle.decl.*) { switch (decl_handle.decl.*) {
.ast_node => |node| try nodeToCompletion( .ast_node => |node| try nodeToCompletion(
@ -967,6 +1064,9 @@ fn declToCompletion(context: DeclToCompletionContext, decl_handle: analysis.Decl
} }
fn completeLabel(arena: *std.heap.ArenaAllocator, id: types.RequestId, pos_index: usize, handle: *DocumentStore.Handle, config: *const Config) !void { fn completeLabel(arena: *std.heap.ArenaAllocator, id: types.RequestId, pos_index: usize, handle: *DocumentStore.Handle, config: *const Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
var completions = std.ArrayList(types.CompletionItem).init(arena.allocator()); var completions = std.ArrayList(types.CompletionItem).init(arena.allocator());
const context = DeclToCompletionContext{ const context = DeclToCompletionContext{
@ -991,6 +1091,9 @@ fn completeLabel(arena: *std.heap.ArenaAllocator, id: types.RequestId, pos_index
var builtin_completions: ?[]types.CompletionItem = null; var builtin_completions: ?[]types.CompletionItem = null;
fn completeBuiltin(arena: *std.heap.ArenaAllocator, id: types.RequestId, config: *const Config) !void { fn completeBuiltin(arena: *std.heap.ArenaAllocator, id: types.RequestId, config: *const Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
if (builtin_completions == null) { if (builtin_completions == null) {
builtin_completions = try allocator.alloc(types.CompletionItem, data.builtins.len); builtin_completions = try allocator.alloc(types.CompletionItem, data.builtins.len);
for (data.builtins) |builtin, idx| { for (data.builtins) |builtin, idx| {
@ -1033,6 +1136,9 @@ fn completeBuiltin(arena: *std.heap.ArenaAllocator, id: types.RequestId, config:
} }
fn completeGlobal(arena: *std.heap.ArenaAllocator, id: types.RequestId, pos_index: usize, handle: *DocumentStore.Handle, config: *const Config) !void { fn completeGlobal(arena: *std.heap.ArenaAllocator, id: types.RequestId, pos_index: usize, handle: *DocumentStore.Handle, config: *const Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
var completions = std.ArrayList(types.CompletionItem).init(arena.allocator()); var completions = std.ArrayList(types.CompletionItem).init(arena.allocator());
const context = DeclToCompletionContext{ const context = DeclToCompletionContext{
@ -1056,6 +1162,9 @@ fn completeGlobal(arena: *std.heap.ArenaAllocator, id: types.RequestId, pos_inde
} }
fn completeFieldAccess(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, position: offsets.DocumentPosition, range: analysis.SourceRange, config: *const Config) !void { fn completeFieldAccess(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, position: offsets.DocumentPosition, range: analysis.SourceRange, config: *const Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
var completions = std.ArrayList(types.CompletionItem).init(arena.allocator()); var completions = std.ArrayList(types.CompletionItem).init(arena.allocator());
const line_mem_start = @ptrToInt(position.line.ptr) - @ptrToInt(handle.document.mem.ptr); const line_mem_start = @ptrToInt(position.line.ptr) - @ptrToInt(handle.document.mem.ptr);
@ -1081,6 +1190,9 @@ fn completeFieldAccess(arena: *std.heap.ArenaAllocator, id: types.RequestId, han
} }
fn completeError(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, config: *const Config) !void { fn completeError(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, config: *const Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
const completions = try document_store.errorCompletionItems(arena, handle); const completions = try document_store.errorCompletionItems(arena, handle);
truncateCompletions(completions, config.max_detail_length); truncateCompletions(completions, config.max_detail_length);
logger.debug("Completing error:", .{}); logger.debug("Completing error:", .{});
@ -1097,6 +1209,9 @@ fn completeError(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *
} }
fn completeDot(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, config: *const Config) !void { fn completeDot(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, config: *const Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
var completions = try document_store.enumCompletionItems(arena, handle); var completions = try document_store.enumCompletionItems(arena, handle);
truncateCompletions(completions, config.max_detail_length); truncateCompletions(completions, config.max_detail_length);
@ -1112,6 +1227,9 @@ fn completeDot(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *Do
} }
fn documentSymbol(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle) !void { fn documentSymbol(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
try send(arena, types.Response{ try send(arena, types.Response{
.id = id, .id = id,
.result = .{ .DocumentSymbols = try analysis.getDocumentSymbols(arena.allocator(), handle.tree, offset_encoding) }, .result = .{ .DocumentSymbols = try analysis.getDocumentSymbols(arena.allocator(), handle.tree, offset_encoding) },
@ -1119,6 +1237,9 @@ fn documentSymbol(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle:
} }
fn loadConfigFile(file_path: []const u8) ?Config { fn loadConfigFile(file_path: []const u8) ?Config {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
var file = std.fs.cwd().openFile(file_path, .{}) catch |err| { var file = std.fs.cwd().openFile(file_path, .{}) catch |err| {
if (err != error.FileNotFound) if (err != error.FileNotFound)
logger.warn("Error while reading configuration file: {}", .{err}); logger.warn("Error while reading configuration file: {}", .{err});
@ -1148,12 +1269,18 @@ fn loadConfigFile(file_path: []const u8) ?Config {
} }
fn loadConfigInFolder(folder_path: []const u8) ?Config { fn loadConfigInFolder(folder_path: []const u8) ?Config {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
const full_path = std.fs.path.resolve(allocator, &.{ folder_path, "zls.json" }) catch return null; const full_path = std.fs.path.resolve(allocator, &.{ folder_path, "zls.json" }) catch return null;
defer allocator.free(full_path); defer allocator.free(full_path);
return loadConfigFile(full_path); return loadConfigFile(full_path);
} }
fn initializeHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.Initialize, config: *const Config) !void { fn initializeHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.Initialize, config: *const Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
_ = config; _ = config;
for (req.params.capabilities.offsetEncoding.value) |encoding| { for (req.params.capabilities.offsetEncoding.value) |encoding| {
@ -1287,6 +1414,9 @@ fn shutdownHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, config:
} }
fn openDocumentHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.OpenDocument, config: *const Config) !void { fn openDocumentHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.OpenDocument, config: *const Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
const handle = try document_store.openDocument(req.params.textDocument.uri, req.params.textDocument.text); const handle = try document_store.openDocument(req.params.textDocument.uri, req.params.textDocument.text);
try publishDiagnostics(arena, handle.*, config); try publishDiagnostics(arena, handle.*, config);
@ -1295,6 +1425,9 @@ fn openDocumentHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req
} }
fn changeDocumentHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.ChangeDocument, config: *const Config) !void { fn changeDocumentHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.ChangeDocument, config: *const Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
_ = id; _ = id;
const handle = document_store.getHandle(req.params.textDocument.uri) orelse { const handle = document_store.getHandle(req.params.textDocument.uri) orelse {
@ -1307,6 +1440,9 @@ fn changeDocumentHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, r
} }
fn saveDocumentHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.SaveDocument, config: *const Config) error{OutOfMemory}!void { fn saveDocumentHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.SaveDocument, config: *const Config) error{OutOfMemory}!void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
_ = config; _ = config;
_ = id; _ = id;
_ = arena; _ = arena;
@ -1318,6 +1454,9 @@ fn saveDocumentHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req
} }
fn closeDocumentHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.CloseDocument, config: *const Config) error{}!void { fn closeDocumentHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.CloseDocument, config: *const Config) error{}!void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
_ = config; _ = config;
_ = id; _ = id;
_ = arena; _ = arena;
@ -1325,6 +1464,9 @@ fn closeDocumentHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, re
} }
fn semanticTokensFullHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.SemanticTokensFull, config: *const Config) !void { fn semanticTokensFullHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.SemanticTokensFull, config: *const Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
if (config.enable_semantic_tokens) blk: { if (config.enable_semantic_tokens) blk: {
const handle = document_store.getHandle(req.params.textDocument.uri) orelse { const handle = document_store.getHandle(req.params.textDocument.uri) orelse {
logger.warn("Trying to get semantic tokens of non existent document {s}", .{req.params.textDocument.uri}); logger.warn("Trying to get semantic tokens of non existent document {s}", .{req.params.textDocument.uri});
@ -1343,6 +1485,9 @@ fn semanticTokensFullHandler(arena: *std.heap.ArenaAllocator, id: types.RequestI
} }
fn completionHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.Completion, config: *const Config) !void { fn completionHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.Completion, config: *const Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
const handle = document_store.getHandle(req.params.textDocument.uri) orelse { const handle = document_store.getHandle(req.params.textDocument.uri) orelse {
logger.warn("Trying to complete in non existent document {s}", .{req.params.textDocument.uri}); logger.warn("Trying to complete in non existent document {s}", .{req.params.textDocument.uri});
return try respondGeneric(id, no_completions_response); return try respondGeneric(id, no_completions_response);
@ -1366,6 +1511,9 @@ fn completionHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req:
} }
fn signatureHelpHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.SignatureHelp, config: *const Config) !void { fn signatureHelpHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.SignatureHelp, config: *const Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
_ = config; _ = config;
const getSignatureInfo = @import("signature_help.zig").getSignatureInfo; const getSignatureInfo = @import("signature_help.zig").getSignatureInfo;
@ -1400,6 +1548,9 @@ fn signatureHelpHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, re
} }
fn gotoHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.GotoDefinition, config: *const Config, resolve_alias: bool) !void { fn gotoHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.GotoDefinition, config: *const Config, resolve_alias: bool) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
const handle = document_store.getHandle(req.params.textDocument.uri) orelse { const handle = document_store.getHandle(req.params.textDocument.uri) orelse {
logger.warn("Trying to go to definition in non existent document {s}", .{req.params.textDocument.uri}); logger.warn("Trying to go to definition in non existent document {s}", .{req.params.textDocument.uri});
return try respondGeneric(id, null_result_response); return try respondGeneric(id, null_result_response);
@ -1422,14 +1573,23 @@ fn gotoHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: reques
} }
fn gotoDefinitionHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.GotoDefinition, config: *const Config) !void { fn gotoDefinitionHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.GotoDefinition, config: *const Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
try gotoHandler(arena, id, req, config, true); try gotoHandler(arena, id, req, config, true);
} }
fn gotoDeclarationHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.GotoDeclaration, config: *const Config) !void { fn gotoDeclarationHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.GotoDeclaration, config: *const Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
try gotoHandler(arena, id, req, config, false); try gotoHandler(arena, id, req, config, false);
} }
fn hoverHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.Hover, config: *const Config) !void { fn hoverHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.Hover, config: *const Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
const handle = document_store.getHandle(req.params.textDocument.uri) orelse { const handle = document_store.getHandle(req.params.textDocument.uri) orelse {
logger.warn("Trying to get hover in non existent document {s}", .{req.params.textDocument.uri}); logger.warn("Trying to get hover in non existent document {s}", .{req.params.textDocument.uri});
return try respondGeneric(id, null_result_response); return try respondGeneric(id, null_result_response);
@ -1451,6 +1611,9 @@ fn hoverHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: reque
} }
fn documentSymbolsHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.DocumentSymbols, config: *const Config) !void { fn documentSymbolsHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.DocumentSymbols, config: *const Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
_ = config; _ = config;
const handle = document_store.getHandle(req.params.textDocument.uri) orelse { const handle = document_store.getHandle(req.params.textDocument.uri) orelse {
@ -1461,6 +1624,9 @@ fn documentSymbolsHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId,
} }
fn formattingHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.Formatting, config: *const Config) !void { fn formattingHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.Formatting, config: *const Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
if (config.zig_exe_path) |zig_exe_path| { if (config.zig_exe_path) |zig_exe_path| {
const handle = document_store.getHandle(req.params.textDocument.uri) orelse { const handle = document_store.getHandle(req.params.textDocument.uri) orelse {
logger.warn("Trying to got to definition in non existent document {s}", .{req.params.textDocument.uri}); logger.warn("Trying to got to definition in non existent document {s}", .{req.params.textDocument.uri});
@ -1503,6 +1669,9 @@ fn formattingHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req:
} }
fn renameHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.Rename, config: *const Config) !void { fn renameHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.Rename, config: *const Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
const handle = document_store.getHandle(req.params.textDocument.uri) orelse { const handle = document_store.getHandle(req.params.textDocument.uri) orelse {
logger.warn("Trying to rename in non existent document {s}", .{req.params.textDocument.uri}); logger.warn("Trying to rename in non existent document {s}", .{req.params.textDocument.uri});
return try respondGeneric(id, null_result_response); return try respondGeneric(id, null_result_response);
@ -1524,6 +1693,9 @@ fn renameHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requ
} }
fn didChangeConfigurationHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.Configuration, config: *Config) !void { fn didChangeConfigurationHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.Configuration, config: *Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
_ = arena; _ = arena;
_ = id; _ = id;
inline for (std.meta.fields(Config)) |field| { inline for (std.meta.fields(Config)) |field| {
@ -1535,6 +1707,9 @@ fn didChangeConfigurationHandler(arena: *std.heap.ArenaAllocator, id: types.Requ
} }
fn referencesHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.References, config: *const Config) !void { fn referencesHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req: requests.References, config: *const Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
const handle = document_store.getHandle(req.params.textDocument.uri) orelse { const handle = document_store.getHandle(req.params.textDocument.uri) orelse {
logger.warn("Trying to get references in non existent document {s}", .{req.params.textDocument.uri}); logger.warn("Trying to get references in non existent document {s}", .{req.params.textDocument.uri});
return try respondGeneric(id, null_result_response); return try respondGeneric(id, null_result_response);
@ -1563,6 +1738,9 @@ fn extractErr(val: anytype) anyerror {
} }
fn processJsonRpc(arena: *std.heap.ArenaAllocator, parser: *std.json.Parser, json: []const u8, config: *Config) !void { fn processJsonRpc(arena: *std.heap.ArenaAllocator, parser: *std.json.Parser, json: []const u8, config: *Config) !void {
const tracy_zone = tracy.trace(@src());
defer tracy_zone.end();
var tree = try parser.parse(json); var tree = try parser.parse(json);
defer tree.deinit(); defer tree.deinit();
@ -1673,14 +1851,18 @@ const stack_frames = switch (zig_builtin.mode) {
.Debug => 10, .Debug => 10,
else => 0, else => 0,
}; };
var gpa_state = std.heap.GeneralPurposeAllocator(.{ .stack_trace_frames = stack_frames }){}; var gpa_state = std.heap.GeneralPurposeAllocator(.{ .stack_trace_frames = stack_frames }){ .backing_allocator = std.heap.page_allocator };
pub fn main() anyerror!void { pub fn main() anyerror!void {
defer _ = gpa_state.deinit(); defer _ = gpa_state.deinit();
defer keep_running = false; defer keep_running = false;
// allocator = &gpa_state.allocator; allocator = gpa_state.allocator();
if (tracy.enable_allocation) {
allocator = tracy.tracyAllocator(allocator).allocator();
}
defer _ = gpa_state.deinit();
// @TODO Using the GPA here, realloc calls hang currently for some reason // @TODO Using the GPA here, realloc calls hang currently for some reason
allocator = std.heap.page_allocator; // allocator = std.heap.page_allocator;
analysis.init(allocator); analysis.init(allocator);
defer analysis.deinit(); defer analysis.deinit();

333
src/tracy.zig Normal file
View File

@ -0,0 +1,333 @@
//! Tracy bindings from Zig compiler
//
// The MIT License (Expat)
//
// Copyright (c) 2015-2022, Zig contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
const std = @import("std");
const builtin = @import("builtin");
const build_options = @import("build_options");
pub const enable = if (builtin.is_test) false else build_options.enable_tracy;
pub const enable_allocation = enable and build_options.enable_tracy_allocation;
pub const enable_callstack = enable and build_options.enable_tracy_callstack;
// TODO: make this configurable
const callstack_depth = 10;
const ___tracy_c_zone_context = extern struct {
id: u32,
active: c_int,
pub inline fn end(self: @This()) void {
___tracy_emit_zone_end(self);
}
pub inline fn addText(self: @This(), text: []const u8) void {
___tracy_emit_zone_text(self, text.ptr, text.len);
}
pub inline fn setName(self: @This(), name: []const u8) void {
___tracy_emit_zone_name(self, name.ptr, name.len);
}
pub inline fn setColor(self: @This(), color: u32) void {
___tracy_emit_zone_color(self, color);
}
pub inline fn setValue(self: @This(), value: u64) void {
___tracy_emit_zone_value(self, value);
}
};
pub const Ctx = if (enable) ___tracy_c_zone_context else struct {
pub inline fn end(self: @This()) void {
_ = self;
}
pub inline fn addText(self: @This(), text: []const u8) void {
_ = self;
_ = text;
}
pub inline fn setName(self: @This(), name: []const u8) void {
_ = self;
_ = name;
}
pub inline fn setColor(self: @This(), color: u32) void {
_ = self;
_ = color;
}
pub inline fn setValue(self: @This(), value: u64) void {
_ = self;
_ = value;
}
};
pub inline fn trace(comptime src: std.builtin.SourceLocation) Ctx {
if (!enable) return .{};
if (enable_callstack) {
return ___tracy_emit_zone_begin_callstack(&.{
.name = null,
.function = src.fn_name.ptr,
.file = src.file.ptr,
.line = src.line,
.color = 0,
}, callstack_depth, 1);
} else {
return ___tracy_emit_zone_begin(&.{
.name = null,
.function = src.fn_name.ptr,
.file = src.file.ptr,
.line = src.line,
.color = 0,
}, 1);
}
}
pub inline fn traceNamed(comptime src: std.builtin.SourceLocation, comptime name: [:0]const u8) Ctx {
if (!enable) return .{};
if (enable_callstack) {
return ___tracy_emit_zone_begin_callstack(&.{
.name = name.ptr,
.function = src.fn_name.ptr,
.file = src.file.ptr,
.line = src.line,
.color = 0,
}, callstack_depth, 1);
} else {
return ___tracy_emit_zone_begin(&.{
.name = name.ptr,
.function = src.fn_name.ptr,
.file = src.file.ptr,
.line = src.line,
.color = 0,
}, 1);
}
}
pub fn tracyAllocator(allocator: std.mem.Allocator) TracyAllocator(null) {
return TracyAllocator(null).init(allocator);
}
pub fn TracyAllocator(comptime name: ?[:0]const u8) type {
return struct {
parent_allocator: std.mem.Allocator,
const Self = @This();
pub fn init(parent_allocator: std.mem.Allocator) Self {
return .{
.parent_allocator = parent_allocator,
};
}
pub fn allocator(self: *Self) std.mem.Allocator {
return std.mem.Allocator.init(self, allocFn, resizeFn, freeFn);
}
fn allocFn(self: *Self, len: usize, ptr_align: u29, len_align: u29, ret_addr: usize) std.mem.Allocator.Error![]u8 {
const result = self.parent_allocator.rawAlloc(len, ptr_align, len_align, ret_addr);
if (result) |data| {
if (data.len != 0) {
if (name) |n| {
allocNamed(data.ptr, data.len, n);
} else {
alloc(data.ptr, data.len);
}
}
} else |_| {
messageColor("allocation failed", 0xFF0000);
}
return result;
}
fn resizeFn(self: *Self, buf: []u8, buf_align: u29, new_len: usize, len_align: u29, ret_addr: usize) ?usize {
if (self.parent_allocator.rawResize(buf, buf_align, new_len, len_align, ret_addr)) |resized_len| {
if (name) |n| {
freeNamed(buf.ptr, n);
allocNamed(buf.ptr, resized_len, n);
} else {
free(buf.ptr);
alloc(buf.ptr, resized_len);
}
return resized_len;
}
// during normal operation the compiler hits this case thousands of times due to this
// emitting messages for it is both slow and causes clutter
return null;
}
fn freeFn(self: *Self, buf: []u8, buf_align: u29, ret_addr: usize) void {
self.parent_allocator.rawFree(buf, buf_align, ret_addr);
// this condition is to handle free being called on an empty slice that was never even allocated
// example case: `std.process.getSelfExeSharedLibPaths` can return `&[_][:0]u8{}`
if (buf.len != 0) {
if (name) |n| {
freeNamed(buf.ptr, n);
} else {
free(buf.ptr);
}
}
}
};
}
// This function only accepts comptime known strings, see `messageCopy` for runtime strings
pub inline fn message(comptime msg: [:0]const u8) void {
if (!enable) return;
___tracy_emit_messageL(msg.ptr, if (enable_callstack) callstack_depth else 0);
}
// This function only accepts comptime known strings, see `messageColorCopy` for runtime strings
pub inline fn messageColor(comptime msg: [:0]const u8, color: u32) void {
if (!enable) return;
___tracy_emit_messageLC(msg.ptr, color, if (enable_callstack) callstack_depth else 0);
}
pub inline fn messageCopy(msg: []const u8) void {
if (!enable) return;
___tracy_emit_message(msg.ptr, msg.len, if (enable_callstack) callstack_depth else 0);
}
pub inline fn messageColorCopy(msg: [:0]const u8, color: u32) void {
if (!enable) return;
___tracy_emit_messageC(msg.ptr, msg.len, color, if (enable_callstack) callstack_depth else 0);
}
pub inline fn frameMark() void {
if (!enable) return;
___tracy_emit_frame_mark(null);
}
pub inline fn frameMarkNamed(comptime name: [:0]const u8) void {
if (!enable) return;
___tracy_emit_frame_mark(name.ptr);
}
pub inline fn namedFrame(comptime name: [:0]const u8) Frame(name) {
frameMarkStart(name);
return .{};
}
pub fn Frame(comptime name: [:0]const u8) type {
return struct {
pub fn end(_: @This()) void {
frameMarkEnd(name);
}
};
}
inline fn frameMarkStart(comptime name: [:0]const u8) void {
if (!enable) return;
___tracy_emit_frame_mark_start(name.ptr);
}
inline fn frameMarkEnd(comptime name: [:0]const u8) void {
if (!enable) return;
___tracy_emit_frame_mark_end(name.ptr);
}
extern fn ___tracy_emit_frame_mark_start(name: [*:0]const u8) void;
extern fn ___tracy_emit_frame_mark_end(name: [*:0]const u8) void;
inline fn alloc(ptr: [*]u8, len: usize) void {
if (!enable) return;
if (enable_callstack) {
___tracy_emit_memory_alloc_callstack(ptr, len, callstack_depth, 0);
} else {
___tracy_emit_memory_alloc(ptr, len, 0);
}
}
inline fn allocNamed(ptr: [*]u8, len: usize, comptime name: [:0]const u8) void {
if (!enable) return;
if (enable_callstack) {
___tracy_emit_memory_alloc_callstack_named(ptr, len, callstack_depth, 0, name.ptr);
} else {
___tracy_emit_memory_alloc_named(ptr, len, 0, name.ptr);
}
}
inline fn free(ptr: [*]u8) void {
if (!enable) return;
if (enable_callstack) {
___tracy_emit_memory_free_callstack(ptr, callstack_depth, 0);
} else {
___tracy_emit_memory_free(ptr, 0);
}
}
inline fn freeNamed(ptr: [*]u8, comptime name: [:0]const u8) void {
if (!enable) return;
if (enable_callstack) {
___tracy_emit_memory_free_callstack_named(ptr, callstack_depth, 0, name.ptr);
} else {
___tracy_emit_memory_free_named(ptr, 0, name.ptr);
}
}
extern fn ___tracy_emit_zone_begin(
srcloc: *const ___tracy_source_location_data,
active: c_int,
) ___tracy_c_zone_context;
extern fn ___tracy_emit_zone_begin_callstack(
srcloc: *const ___tracy_source_location_data,
depth: c_int,
active: c_int,
) ___tracy_c_zone_context;
extern fn ___tracy_emit_zone_text(ctx: ___tracy_c_zone_context, txt: [*]const u8, size: usize) void;
extern fn ___tracy_emit_zone_name(ctx: ___tracy_c_zone_context, txt: [*]const u8, size: usize) void;
extern fn ___tracy_emit_zone_color(ctx: ___tracy_c_zone_context, color: u32) void;
extern fn ___tracy_emit_zone_value(ctx: ___tracy_c_zone_context, value: u64) void;
extern fn ___tracy_emit_zone_end(ctx: ___tracy_c_zone_context) void;
extern fn ___tracy_emit_memory_alloc(ptr: *const anyopaque, size: usize, secure: c_int) void;
extern fn ___tracy_emit_memory_alloc_callstack(ptr: *const anyopaque, size: usize, depth: c_int, secure: c_int) void;
extern fn ___tracy_emit_memory_free(ptr: *const anyopaque, secure: c_int) void;
extern fn ___tracy_emit_memory_free_callstack(ptr: *const anyopaque, depth: c_int, secure: c_int) void;
extern fn ___tracy_emit_memory_alloc_named(ptr: *const anyopaque, size: usize, secure: c_int, name: [*:0]const u8) void;
extern fn ___tracy_emit_memory_alloc_callstack_named(ptr: *const anyopaque, size: usize, depth: c_int, secure: c_int, name: [*:0]const u8) void;
extern fn ___tracy_emit_memory_free_named(ptr: *const anyopaque, secure: c_int, name: [*:0]const u8) void;
extern fn ___tracy_emit_memory_free_callstack_named(ptr: *const anyopaque, depth: c_int, secure: c_int, name: [*:0]const u8) void;
extern fn ___tracy_emit_message(txt: [*]const u8, size: usize, callstack: c_int) void;
extern fn ___tracy_emit_messageL(txt: [*:0]const u8, callstack: c_int) void;
extern fn ___tracy_emit_messageC(txt: [*]const u8, size: usize, color: u32, callstack: c_int) void;
extern fn ___tracy_emit_messageLC(txt: [*:0]const u8, color: u32, callstack: c_int) void;
extern fn ___tracy_emit_frame_mark(name: ?[*:0]const u8) void;
const ___tracy_source_location_data = extern struct {
name: ?[*:0]const u8,
function: [*:0]const u8,
file: [*:0]const u8,
line: u32,
color: u32,
};