Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

experiment: parallelize chmod and \r\n normalization in bun install #15777

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 69 additions & 3 deletions src/install/bin.zig
Original file line number Diff line number Diff line change
Expand Up @@ -598,8 +598,62 @@ pub const Bin = extern struct {
}

if (comptime !Environment.isWindows) {
const pm = Install.PackageManager.get();
const task = CRLFNormalizerTask.init(abs_target, pm);
_ = pm.incrementPendingTasks(1);
_ = pm.pending_linking_tasks.fetchAdd(1, .monotonic);
pm.thread_pool.schedule(bun.ThreadPool.Batch.from(&task.task));
}
}

const ChmodTask = struct {
abs_target: [:0]const u8,
package_manager: *bun.install.PackageManager,
task: bun.ThreadPool.Task = .{ .callback = run },

pub usingnamespace bun.New(@This());

pub fn init(abs_target: [:0]const u8, package_manager: *bun.install.PackageManager) *ChmodTask {
return ChmodTask.new(.{
.abs_target = bun.default_allocator.dupeZ(u8, abs_target) catch bun.outOfMemory(),
.package_manager = package_manager,
});
}

pub fn run(task: *bun.ThreadPool.Task) void {
const this: *ChmodTask = @fieldParentPtr("task", task);
defer this.deinit();
_ = bun.sys.chmod(this.abs_target, umask | 0o777);
}

pub fn deinit(this: *ChmodTask) void {
_ = this.package_manager.decrementPendingTasks();
_ = this.package_manager.pending_linking_tasks.fetchSub(1, .monotonic);
this.package_manager.wake();
bun.default_allocator.free(this.abs_target);
this.destroy();
}
};

const CRLFNormalizerTask = struct {
abs_target: [:0]const u8,
package_manager: *bun.install.PackageManager,
task: bun.ThreadPool.Task = .{ .callback = run },

pub usingnamespace bun.New(@This());

pub fn init(abs_target: [:0]const u8, package_manager: *bun.install.PackageManager) *CRLFNormalizerTask {
return CRLFNormalizerTask.new(.{
.abs_target = bun.default_allocator.dupeZ(u8, abs_target) catch bun.outOfMemory(),
.package_manager = package_manager,
});
}

pub fn run(task: *bun.ThreadPool.Task) void {
const this: *CRLFNormalizerTask = @fieldParentPtr("task", task);
defer this.deinit();
// any error here is ignored
const bin = bun.sys.File.openat(bun.invalid_fd, abs_target, bun.O.RDWR, 0o664).unwrap() catch return;
const bin = bun.sys.File.openat(bun.invalid_fd, this.abs_target, bun.O.RDWR, 0o664).unwrap() catch return;
defer bin.close();

var shebang_buf: [1024]u8 = undefined;
Expand All @@ -617,7 +671,16 @@ pub const Bin = extern struct {
}
}
}
}

pub fn deinit(this: *CRLFNormalizerTask) void {
_ = this.package_manager.decrementPendingTasks();
_ = this.package_manager.pending_linking_tasks.fetchSub(1, .monotonic);
this.package_manager.wake();

bun.default_allocator.free(this.abs_target);
this.destroy();
}
};

fn createWindowsShim(this: *Linker, target: bun.FileDescriptor, abs_target: [:0]const u8, abs_dest: [:0]const u8, global: bool) void {
const WinBinLinkingShim = @import("./windows-shim/BinLinkingShim.zig");
Expand Down Expand Up @@ -708,7 +771,10 @@ pub const Bin = extern struct {
fn createSymlink(this: *Linker, abs_target: [:0]const u8, abs_dest: [:0]const u8, global: bool) void {
defer {
if (this.err == null) {
_ = bun.sys.chmod(abs_target, umask | 0o777);
const task = ChmodTask.init(abs_target, Install.PackageManager.get());
_ = task.package_manager.pending_linking_tasks.fetchAdd(1, .monotonic);
_ = task.package_manager.incrementPendingTasks(1);
task.package_manager.thread_pool.schedule(bun.ThreadPool.Batch.from(&task.task));
}
}

Expand Down
12 changes: 12 additions & 0 deletions src/install/install.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2692,6 +2692,7 @@ pub const PackageManager = struct {
/// every single time, because someone could edit the patchfile at anytime
pending_pre_calc_hashes: std.atomic.Value(u32) = std.atomic.Value(u32).init(0),
pending_tasks: std.atomic.Value(u32) = std.atomic.Value(u32).init(0),
pending_linking_tasks: std.atomic.Value(u32) = std.atomic.Value(u32).init(0),
total_tasks: u32 = 0,
preallocated_network_tasks: PreallocatedNetworkTasks = PreallocatedNetworkTasks.init(bun.default_allocator),
preallocated_resolve_tasks: PreallocatedTaskStore = PreallocatedTaskStore.init(bun.default_allocator),
Expand Down Expand Up @@ -14010,7 +14011,9 @@ pub const PackageManager = struct {

// need to make sure bins are linked before completing any remaining scripts.
// this can happen if a package fails to download

installer.linkRemainingBins(log_level);
this.sleepUntilLinkingFinishes();
installer.completeRemainingScripts(log_level);

while (this.pending_lifecycle_script_tasks.load(.monotonic) > 0) {
Expand All @@ -14033,6 +14036,15 @@ pub const PackageManager = struct {
return manager.pending_tasks.load(.monotonic);
}

pub fn sleepUntilLinkingFinishes(manager: *PackageManager) void {
const Closure = struct {
pub fn isDone(pm: *PackageManager) bool {
return pm.pending_linking_tasks.load(.monotonic) == 0;
}
};
manager.sleepUntil(manager, &Closure.isDone);
}

pub inline fn incrementPendingTasks(manager: *PackageManager, count: u32) u32 {
manager.total_tasks += count;
return manager.pending_tasks.fetchAdd(count, .monotonic);
Expand Down
Loading