this repo has no description

rework: austin frame storage

altagos.dev 15b8533f 812a65d7

verified
+93 -56
+81 -54
src/austin.zig
··· 18 18 line_number: isize = 0, 19 19 }; 20 20 21 + pub const FrameID = usize; 22 + 21 23 pub const FrameWrapper = union(enum) { 22 - call_stack: Frame, 24 + frame: FrameID, 23 25 invalid: void, 24 26 gc: void, 25 27 }; ··· 47 49 full: Sample, 48 50 partial: PartialSample, 49 51 metric: Metric, 50 - 51 - fn deinit(self: *SampleWrapper, allocator: mem.Allocator) void { 52 - switch (self.*) { 53 - .metric => {}, 54 - inline else => |*sample| { 55 - for (sample.frames) |frame| { 56 - switch (frame) { 57 - .invalid, .gc => {}, 58 - .call_stack => |stack| { 59 - allocator.free(stack.module); 60 - allocator.free(stack.function); 61 - }, 62 - } 63 - } 64 - allocator.free(sample.frames); 65 - }, 66 - } 67 - } 68 52 }; 69 53 70 54 pub const Metadata = struct { ··· 113 97 } 114 98 }; 115 99 116 - const MetadataFields = std.meta.FieldEnum(Metadata); 117 - 118 100 pub const Profile = struct { 119 101 meta: Metadata = .{}, 102 + frames: []Frame = undefined, 120 103 samples: []SampleWrapper = undefined, 121 - _arena: mem.Allocator, 104 + arena: mem.Allocator, 122 105 123 106 pub fn deinit(self: *Profile) void { 124 - for (self.samples) |*sample| { 125 - sample.deinit(self._arena); 107 + for (self.frames) |frame| { 108 + self.arena.free(frame.module); 109 + self.arena.free(frame.function); 126 110 } 127 111 128 - self._arena.free(self.samples); 112 + for (self.samples) |sample| { 113 + switch (sample) { 114 + .metric => {}, 115 + inline else => |s| { 116 + self.arena.free(s.frames); 117 + }, 118 + } 119 + } 120 + 121 + self.arena.free(self.frames); 122 + self.arena.free(self.samples); 123 + } 124 + 125 + pub fn getFrame(self: *const Profile, id: FrameID) ?Frame { 126 + if (id < self.frames.len) { 127 + return self.frames[id]; 128 + } 129 + return null; 129 130 } 130 131 }; 131 132 ··· 149 150 }; 150 151 151 152 arena: mem.Allocator, 153 + profile: Profile, 154 + frames: std.ArrayList(Frame), 155 + samples: std.ArrayList(SampleWrapper), 152 156 153 - pub fn init(arena: mem.Allocator) Parser { 154 - return .{ .arena = arena }; 157 + pub fn init(arena: mem.Allocator) !Parser { 158 + return .{ 159 + .arena = arena, 160 + .profile = .{ .arena = arena }, 161 + .frames = try .initCapacity(arena, 100), 162 + .samples = try .initCapacity(arena, 1_000), 163 + }; 155 164 } 156 165 157 166 pub fn parse(self: *Parser, raw_reader: anytype, progress: *std.Progress.Node) !Profile { 167 + defer self.samples.deinit(); 168 + defer self.frames.deinit(); 169 + 158 170 var buffered_reader = std.io.bufferedReader(raw_reader); 159 171 var reader = buffered_reader.reader(); 160 172 161 - var profile = Profile{ ._arena = self.arena }; 162 - errdefer profile.deinit(); 163 - 164 - var samples: std.ArrayList(SampleWrapper) = try .initCapacity(self.arena, 1_000); 165 - defer samples.deinit(); 166 - 167 173 var reached_end: bool = false; 168 174 169 175 var line: std.ArrayList(u8) = .init(self.arena); ··· 189 195 const key = it.next() orelse return error.MissingKey; 190 196 const value = mem.trimStart(u8, it.next() orelse return error.MissingValue, " "); 191 197 192 - reached_end = profile.meta.parseField(key, value) catch |err| switch (err) { 198 + reached_end = self.profile.meta.parseField(key, value) catch |err| switch (err) { 193 199 error.UnknownMetadataField => { 194 200 log.warn("Unknown metadata field: {s}", .{key}); 195 201 continue; ··· 211 217 std.process.exit(1); 212 218 }; 213 219 214 - try samples.append(sample); 220 + try self.samples.append(sample); 215 221 } 216 222 } 217 223 218 - profile.samples = try samples.toOwnedSlice(); 219 - return profile; 224 + self.profile.frames = try self.frames.toOwnedSlice(); 225 + self.profile.samples = try self.samples.toOwnedSlice(); 226 + return self.profile; 220 227 } 221 228 222 229 const ParseSampleError = ParseError || mem.Allocator.Error || std.fmt.ParseIntError; ··· 367 374 const module = frame.next() orelse return ParseError.NoModule; 368 375 369 376 if (mem.startsWith(u8, frame_raw, "::")) { 370 - return FrameWrapper{ .call_stack = Frame{ 371 - .module = "", 372 - .function = "", 373 - .line_number = std.fmt.parseInt(isize, module, 0) catch 377 + return try self.storeFrame( 378 + "", 379 + "", 380 + std.fmt.parseInt(isize, module, 0) catch 374 381 return ParseError.InvalidLineNumber, 375 - } }; 382 + ); 376 383 } 377 384 378 385 if (mem.eql(u8, module, "GC")) 379 386 return FrameWrapper{ .gc = {} }; 380 387 381 - if (!mem.eql(u8, module, "INVALID")) { 382 - const function = frame.next() orelse return ParseError.NoFunction; 388 + if (mem.eql(u8, module, "INVALID")) 389 + return FrameWrapper{ .invalid = {} }; 383 390 384 - const line_number = std.fmt.parseInt( 385 - isize, 386 - frame.next() orelse return ParseError.NoLineNumber, 387 - 0, 388 - ) catch return ParseError.InvalidLineNumber; 391 + const function = frame.next() orelse return ParseError.NoFunction; 389 392 390 - var f: Frame = .{ .line_number = line_number }; 391 - f.module = try self.arena.dupe(u8, module); 392 - f.function = try self.arena.dupe(u8, function); 393 + const line_number = std.fmt.parseInt( 394 + isize, 395 + frame.next() orelse return ParseError.NoLineNumber, 396 + 0, 397 + ) catch return ParseError.InvalidLineNumber; 393 398 394 - return FrameWrapper{ .call_stack = f }; 399 + return try self.storeFrame(module, function, line_number); 400 + } 401 + 402 + fn storeFrame( 403 + self: *Parser, 404 + module: []const u8, 405 + function: []const u8, 406 + line_number: isize, 407 + ) !FrameWrapper { 408 + var count: usize = 0; 409 + for (self.frames.items, 0..) |*frame, id| { 410 + if (mem.eql(u8, frame.module, module) and 411 + mem.eql(u8, frame.function, function) and 412 + frame.line_number == line_number) 413 + { 414 + return FrameWrapper{ .frame = id }; 415 + } 416 + count += 1; 395 417 } 396 418 397 - return FrameWrapper{ .invalid = {} }; 419 + var f: Frame = .{ .line_number = line_number }; 420 + f.module = try self.arena.dupe(u8, module); 421 + f.function = try self.arena.dupe(u8, function); 422 + 423 + try self.frames.append(f); 424 + return FrameWrapper{ .frame = count + 1 }; 398 425 } 399 426 };
+12 -2
src/main.zig
··· 71 71 var progress = std.Progress.start(.{ .root_name = "Austin Converter" }); 72 72 defer progress.end(); 73 73 74 - var parser: austin.austin.Parser = .init(allocator); 74 + var parser: austin.austin.Parser = try .init(allocator); 75 75 var profile: austin.austin.Profile = undefined; 76 76 defer profile.deinit(); 77 77 ··· 95 95 } 96 96 } 97 97 98 - std.log.info("num samples: {} - meta: {}", .{ profile.samples.len, profile.meta }); 98 + for (profile.frames, 0..) |*frame, id| { 99 + std.log.debug( 100 + "Frame ID: {} => {{\n\tmodule = {s}\n\tfunction = {s}\n\tline number = {}\n}}\n", 101 + .{ id, frame.module, frame.function, frame.line_number }, 102 + ); 103 + } 104 + 105 + std.log.info( 106 + "num samples: {} - num frames: {} - meta: {}", 107 + .{ profile.samples.len, profile.frames.len, profile.meta }, 108 + ); 99 109 }