time_report.zig (9478B) - Raw
1 const std = @import("std"); 2 const gpa = std.heap.wasm_allocator; 3 const abi = std.Build.abi.time_report; 4 const fmtEscapeHtml = @import("root").fmtEscapeHtml; 5 const step_list = &@import("root").step_list; 6 7 const js = struct { 8 extern "time_report" fn updateGeneric( 9 /// The index of the step. 10 step_idx: u32, 11 // The HTML which will be used to populate the template slots. 12 inner_html_ptr: [*]const u8, 13 inner_html_len: usize, 14 ) void; 15 extern "time_report" fn updateCompile( 16 /// The index of the step. 17 step_idx: u32, 18 // The HTML which will be used to populate the template slots. 19 inner_html_ptr: [*]const u8, 20 inner_html_len: usize, 21 // The HTML which will populate the <tbody> of the file table. 22 file_table_html_ptr: [*]const u8, 23 file_table_html_len: usize, 24 // The HTML which will populate the <tbody> of the decl table. 25 decl_table_html_ptr: [*]const u8, 26 decl_table_html_len: usize, 27 /// Whether the LLVM backend was used. If not, LLVM-specific statistics are hidden. 28 use_llvm: bool, 29 ) void; 30 }; 31 32 pub fn genericResultMessage(msg_bytes: []u8) error{OutOfMemory}!void { 33 if (msg_bytes.len != @sizeOf(abi.GenericResult)) @panic("malformed GenericResult message"); 34 const msg: *const abi.GenericResult = @ptrCast(msg_bytes); 35 if (msg.step_idx >= step_list.*.len) @panic("malformed GenericResult message"); 36 const inner_html = try std.fmt.allocPrint(gpa, 37 \\<code slot="step-name">{[step_name]f}</code> 38 \\<span slot="stat-total-time">{[stat_total_time]D}</span> 39 , .{ 40 .step_name = fmtEscapeHtml(step_list.*[msg.step_idx].name), 41 .stat_total_time = msg.ns_total, 42 }); 43 defer gpa.free(inner_html); 44 js.updateGeneric(msg.step_idx, inner_html.ptr, inner_html.len); 45 } 46 47 pub fn compileResultMessage(msg_bytes: []u8) error{ OutOfMemory, WriteFailed }!void { 48 const max_table_rows = 500; 49 50 if (msg_bytes.len < @sizeOf(abi.CompileResult)) @panic("malformed CompileResult message"); 51 const hdr: *const abi.CompileResult = @ptrCast(msg_bytes[0..@sizeOf(abi.CompileResult)]); 52 if (hdr.step_idx >= step_list.*.len) @panic("malformed CompileResult message"); 53 var trailing = msg_bytes[@sizeOf(abi.CompileResult)..]; 54 55 const llvm_pass_timings = trailing[0..hdr.llvm_pass_timings_len]; 56 trailing = trailing[hdr.llvm_pass_timings_len..]; 57 58 const FileTimeReport = struct { 59 name: []const u8, 60 ns_sema: u64, 61 ns_codegen: u64, 62 ns_link: u64, 63 }; 64 const DeclTimeReport = struct { 65 file_name: []const u8, 66 name: []const u8, 67 sema_count: u32, 68 ns_sema: u64, 69 ns_codegen: u64, 70 ns_link: u64, 71 }; 72 73 const slowest_files = try gpa.alloc(FileTimeReport, hdr.files_len); 74 defer gpa.free(slowest_files); 75 76 const slowest_decls = try gpa.alloc(DeclTimeReport, hdr.decls_len); 77 defer gpa.free(slowest_decls); 78 79 for (slowest_files) |*file_out| { 80 const i = std.mem.indexOfScalar(u8, trailing, 0) orelse @panic("malformed CompileResult message"); 81 file_out.* = .{ 82 .name = trailing[0..i], 83 .ns_sema = 0, 84 .ns_codegen = 0, 85 .ns_link = 0, 86 }; 87 trailing = trailing[i + 1 ..]; 88 } 89 90 for (slowest_decls) |*decl_out| { 91 const i = std.mem.indexOfScalar(u8, trailing, 0) orelse @panic("malformed CompileResult message"); 92 const file_idx = std.mem.readInt(u32, trailing[i..][1..5], .little); 93 const sema_count = std.mem.readInt(u32, trailing[i..][5..9], .little); 94 const sema_ns = std.mem.readInt(u64, trailing[i..][9..17], .little); 95 const codegen_ns = std.mem.readInt(u64, trailing[i..][17..25], .little); 96 const link_ns = std.mem.readInt(u64, trailing[i..][25..33], .little); 97 const file = &slowest_files[file_idx]; 98 decl_out.* = .{ 99 .file_name = file.name, 100 .name = trailing[0..i], 101 .sema_count = sema_count, 102 .ns_sema = sema_ns, 103 .ns_codegen = codegen_ns, 104 .ns_link = link_ns, 105 }; 106 trailing = trailing[i + 33 ..]; 107 file.ns_sema += sema_ns; 108 file.ns_codegen += codegen_ns; 109 file.ns_link += link_ns; 110 } 111 112 const S = struct { 113 fn fileLessThan(_: void, lhs: FileTimeReport, rhs: FileTimeReport) bool { 114 const lhs_ns = lhs.ns_sema + lhs.ns_codegen + lhs.ns_link; 115 const rhs_ns = rhs.ns_sema + rhs.ns_codegen + rhs.ns_link; 116 return lhs_ns > rhs_ns; // flipped to sort in reverse order 117 } 118 fn declLessThan(_: void, lhs: DeclTimeReport, rhs: DeclTimeReport) bool { 119 //if (true) return lhs.sema_count > rhs.sema_count; 120 const lhs_ns = lhs.ns_sema + lhs.ns_codegen + lhs.ns_link; 121 const rhs_ns = rhs.ns_sema + rhs.ns_codegen + rhs.ns_link; 122 return lhs_ns > rhs_ns; // flipped to sort in reverse order 123 } 124 }; 125 std.mem.sort(FileTimeReport, slowest_files, {}, S.fileLessThan); 126 std.mem.sort(DeclTimeReport, slowest_decls, {}, S.declLessThan); 127 128 const stats = hdr.stats; 129 const inner_html = try std.fmt.allocPrint(gpa, 130 \\<code slot="step-name">{[step_name]f}</code> 131 \\<span slot="stat-reachable-files">{[stat_reachable_files]d}</span> 132 \\<span slot="stat-imported-files">{[stat_imported_files]d}</span> 133 \\<span slot="stat-generic-instances">{[stat_generic_instances]d}</span> 134 \\<span slot="stat-inline-calls">{[stat_inline_calls]d}</span> 135 \\<span slot="stat-compilation-time">{[stat_compilation_time]D}</span> 136 \\<span slot="cpu-time-parse">{[cpu_time_parse]D}</span> 137 \\<span slot="cpu-time-astgen">{[cpu_time_astgen]D}</span> 138 \\<span slot="cpu-time-sema">{[cpu_time_sema]D}</span> 139 \\<span slot="cpu-time-codegen">{[cpu_time_codegen]D}</span> 140 \\<span slot="cpu-time-link">{[cpu_time_link]D}</span> 141 \\<span slot="real-time-files">{[real_time_files]D}</span> 142 \\<span slot="real-time-decls">{[real_time_decls]D}</span> 143 \\<span slot="real-time-llvm-emit">{[real_time_llvm_emit]D}</span> 144 \\<span slot="real-time-link-flush">{[real_time_link_flush]D}</span> 145 \\<pre slot="llvm-pass-timings"><code>{[llvm_pass_timings]f}</code></pre> 146 \\ 147 , .{ 148 .step_name = fmtEscapeHtml(step_list.*[hdr.step_idx].name), 149 .stat_reachable_files = stats.n_reachable_files, 150 .stat_imported_files = stats.n_imported_files, 151 .stat_generic_instances = stats.n_generic_instances, 152 .stat_inline_calls = stats.n_inline_calls, 153 .stat_compilation_time = hdr.ns_total, 154 155 .cpu_time_parse = stats.cpu_ns_parse, 156 .cpu_time_astgen = stats.cpu_ns_astgen, 157 .cpu_time_sema = stats.cpu_ns_sema, 158 .cpu_time_codegen = stats.cpu_ns_codegen, 159 .cpu_time_link = stats.cpu_ns_link, 160 .real_time_files = stats.real_ns_files, 161 .real_time_decls = stats.real_ns_decls, 162 .real_time_llvm_emit = stats.real_ns_llvm_emit, 163 .real_time_link_flush = stats.real_ns_link_flush, 164 165 .llvm_pass_timings = fmtEscapeHtml(llvm_pass_timings), 166 }); 167 defer gpa.free(inner_html); 168 169 var file_table_html: std.Io.Writer.Allocating = .init(gpa); 170 defer file_table_html.deinit(); 171 172 for (slowest_files[0..@min(max_table_rows, slowest_files.len)]) |file| { 173 try file_table_html.writer.print( 174 \\<tr> 175 \\ <th scope="row"><code>{f}</code></th> 176 \\ <td>{D}</td> 177 \\ <td>{D}</td> 178 \\ <td>{D}</td> 179 \\ <td>{D}</td> 180 \\</tr> 181 \\ 182 , .{ 183 fmtEscapeHtml(file.name), 184 file.ns_sema, 185 file.ns_codegen, 186 file.ns_link, 187 file.ns_sema + file.ns_codegen + file.ns_link, 188 }); 189 } 190 if (slowest_files.len > max_table_rows) { 191 try file_table_html.writer.print( 192 \\<tr><td colspan="4">{d} more rows omitted</td></tr> 193 \\ 194 , .{slowest_files.len - max_table_rows}); 195 } 196 197 var decl_table_html: std.Io.Writer.Allocating = .init(gpa); 198 defer decl_table_html.deinit(); 199 200 for (slowest_decls[0..@min(max_table_rows, slowest_decls.len)]) |decl| { 201 try decl_table_html.writer.print( 202 \\<tr> 203 \\ <th scope="row"><code>{f}</code></th> 204 \\ <th scope="row"><code>{f}</code></th> 205 \\ <td>{d}</td> 206 \\ <td>{D}</td> 207 \\ <td>{D}</td> 208 \\ <td>{D}</td> 209 \\ <td>{D}</td> 210 \\</tr> 211 \\ 212 , .{ 213 fmtEscapeHtml(decl.file_name), 214 fmtEscapeHtml(decl.name), 215 decl.sema_count, 216 decl.ns_sema, 217 decl.ns_codegen, 218 decl.ns_link, 219 decl.ns_sema + decl.ns_codegen + decl.ns_link, 220 }); 221 } 222 if (slowest_decls.len > max_table_rows) { 223 try decl_table_html.writer.print( 224 \\<tr><td colspan="6">{d} more rows omitted</td></tr> 225 \\ 226 , .{slowest_decls.len - max_table_rows}); 227 } 228 229 js.updateCompile( 230 hdr.step_idx, 231 inner_html.ptr, 232 inner_html.len, 233 file_table_html.written().ptr, 234 file_table_html.written().len, 235 decl_table_html.written().ptr, 236 decl_table_html.written().len, 237 hdr.flags.use_llvm, 238 ); 239 }