zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

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 }