authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-06-20 20:14:33-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-06-20 20:14:33-04:00
log64dfd1883eb2b9ab175af9b07c84bd4b53b7e904
tree468d8404da72474318a8abb166238b0b0b572436
parent0a9672fb86b84658f8780f57e769be45e41f3034

zig fmt: avoid unnecessary file system access

zig fmt previously would write a temp file, and then either rename it into place if necessary, or unlink it if nothing was changed. Now zig fmt renders into a memory buffer, and only writes the temp file and renames it into place if anything changed. Based on the performance testing I did this actually did not have much of an impact, however it's likely that on other operating systems and other hard drives this could make a big difference.

1 files changed, 17 insertions(+), 8 deletions(-)

src-self-hosted/main.zig+17-8
......@@ -546,6 +546,7 @@ const Fmt = struct {
546546 any_error: bool,
547547 color: Color,
548548 gpa: *Allocator,
549 out_buffer: std.ArrayList(u8),
549550
550551 const SeenMap = std.AutoHashMap(fs.File.INode, void);
551552};
......@@ -641,7 +642,10 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {
641642 .seen = Fmt.SeenMap.init(gpa),
642643 .any_error = false,
643644 .color = color,
645 .out_buffer = std.ArrayList(u8).init(gpa),
644646 };
647 defer fmt.seen.deinit();
648 defer fmt.out_buffer.deinit();
645649
646650 for (input_files.span()) |file_path| {
647651 // Get the real path here to avoid Windows failing on relative file paths with . or .. in them.
......@@ -767,14 +771,19 @@ fn fmtPathFile(
767771 fmt.any_error = true;
768772 }
769773 } else {
770 const baf = try io.BufferedAtomicFile.create(fmt.gpa, dir, sub_path, .{ .mode = stat.mode });
771 defer baf.destroy();
772
773 const anything_changed = try std.zig.render(fmt.gpa, baf.stream(), tree);
774 if (anything_changed) {
775 std.debug.warn("{}\n", .{file_path});
776 try baf.finish();
777 }
774 // As a heuristic, we make enough capacity for the same as the input source.
775 try fmt.out_buffer.ensureCapacity(source_code.len);
776 fmt.out_buffer.items.len = 0;
777 const anything_changed = try std.zig.render(fmt.gpa, fmt.out_buffer.writer(), tree);
778 if (!anything_changed)
779 return; // Good thing we didn't waste any file system access on this.
780
781 var af = try dir.atomicFile(sub_path, .{ .mode = stat.mode });
782 defer af.deinit();
783
784 try af.file.writeAll(fmt.out_buffer.items);
785 try af.finish();
786 std.debug.warn("{}\n", .{file_path});
778787 }
779788}
780789