Skip to content

Commit

Permalink
Start time performance improvements to build tools (#3797)
Browse files Browse the repository at this point in the history
* Make os.cpus() faster on Linux

* Fix crash

See ziglang/zig#16540

* Handle watcher_count == 0

* Add assertion

* Clean up lifetimes of fs watcher a little

* ✂️

* Use `errdefer`

* Make the error better

* Make os.cpus() more lazy

* Please don't translate-c on the entire C standard library

* immediately closing works correctly is still bug

* ops

* fmt+fixeup

* add back verbose

* free instead of destroy

* remove destroy option for watcher tasks

* flush verbose and add debug log

* fixup files

* use log for debug

---------

Co-authored-by: Jarred Sumner <[email protected]>
Co-authored-by: cirospaciari <[email protected]>
  • Loading branch information
3 people authored Jul 27, 2023
1 parent ec2cf38 commit 86633e0
Show file tree
Hide file tree
Showing 13 changed files with 862 additions and 357 deletions.
8 changes: 8 additions & 0 deletions src/bun.js/bindings/c-bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,12 @@ extern "C" void bun_ignore_sigpipe()
{
// ignore SIGPIPE
signal(SIGPIPE, SIG_IGN);
}
extern "C" ssize_t bun_sysconf__SC_CLK_TCK()
{
#ifdef __APPLE__
return sysconf(_SC_CLK_TCK);
#else
return 0;
#endif
}
37 changes: 27 additions & 10 deletions src/bun.js/node/fs_events.zig
Original file line number Diff line number Diff line change
Expand Up @@ -267,10 +267,11 @@ pub const FSEventsLoop = struct {

pub const Queue = UnboundedQueue(ConcurrentTask, .next);

pub fn from(this: *ConcurrentTask, task: Task) *ConcurrentTask {
pub fn from(this: *ConcurrentTask, task: Task, auto_delete: bool) *ConcurrentTask {
this.* = .{
.task = task,
.next = null,
.auto_delete = auto_delete,
};
return this;
}
Expand Down Expand Up @@ -339,8 +340,7 @@ pub const FSEventsLoop = struct {
fn enqueueTaskConcurrent(this: *FSEventsLoop, task: Task) void {
const CF = CoreFoundation.get();
var concurrent = bun.default_allocator.create(ConcurrentTask) catch unreachable;
concurrent.auto_delete = true;
this.tasks.push(concurrent.from(task));
this.tasks.push(concurrent.from(task, true));
CF.RunLoopSourceSignal(this.signal_source);
CF.RunLoopWakeUp(this.loop);
}
Expand Down Expand Up @@ -403,8 +403,9 @@ pub const FSEventsLoop = struct {
}
}

handle.callback(handle.ctx, path, is_file, is_rename);
handle.emit(path, is_file, is_rename);
}
handle.flush();
}
}
}
Expand All @@ -414,6 +415,7 @@ pub const FSEventsLoop = struct {
this.mutex.lock();
defer this.mutex.unlock();
this.has_scheduled_watchers = false;
const watcher_count = this.watcher_count;

var watchers = this.watchers.slice();

Expand All @@ -432,14 +434,18 @@ pub const FSEventsLoop = struct {
// clean old paths
if (this.paths) |p| {
this.paths = null;
bun.default_allocator.destroy(p);
bun.default_allocator.free(p);
}
if (this.cf_paths) |cf| {
this.cf_paths = null;
CF.Release(cf);
}

const paths = bun.default_allocator.alloc(?*anyopaque, this.watcher_count) catch unreachable;
if (watcher_count == 0) {
return;
}

const paths = bun.default_allocator.alloc(?*anyopaque, watcher_count) catch unreachable;
var count: u32 = 0;
for (watchers) |w| {
if (w) |watcher| {
Expand Down Expand Up @@ -567,17 +573,20 @@ pub const FSEventsLoop = struct {
pub const FSEventsWatcher = struct {
path: string,
callback: Callback,
flushCallback: UpdateEndCallback,
loop: ?*FSEventsLoop,
recursive: bool,
ctx: ?*anyopaque,

const Callback = *const fn (ctx: ?*anyopaque, path: string, is_file: bool, is_rename: bool) void;
const UpdateEndCallback = *const fn (ctx: ?*anyopaque) void;

pub fn init(loop: *FSEventsLoop, path: string, recursive: bool, callback: Callback, ctx: ?*anyopaque) *FSEventsWatcher {
pub fn init(loop: *FSEventsLoop, path: string, recursive: bool, callback: Callback, updateEnd: UpdateEndCallback, ctx: ?*anyopaque) *FSEventsWatcher {
var this = bun.default_allocator.create(FSEventsWatcher) catch unreachable;
this.* = FSEventsWatcher{
.path = path,
.callback = callback,
.flushCallback = updateEnd,
.loop = loop,
.recursive = recursive,
.ctx = ctx,
Expand All @@ -587,6 +596,14 @@ pub const FSEventsWatcher = struct {
return this;
}

pub fn emit(this: *FSEventsWatcher, path: string, is_file: bool, is_rename: bool) void {
this.callback(this.ctx, path, is_file, is_rename);
}

pub fn flush(this: *FSEventsWatcher) void {
this.flushCallback(this.ctx);
}

pub fn deinit(this: *FSEventsWatcher) void {
if (this.loop) |loop| {
loop.unregisterWatcher(this);
Expand All @@ -595,15 +612,15 @@ pub const FSEventsWatcher = struct {
}
};

pub fn watch(path: string, recursive: bool, callback: FSEventsWatcher.Callback, ctx: ?*anyopaque) !*FSEventsWatcher {
pub fn watch(path: string, recursive: bool, callback: FSEventsWatcher.Callback, updateEnd: FSEventsWatcher.UpdateEndCallback, ctx: ?*anyopaque) !*FSEventsWatcher {
if (fsevents_default_loop) |loop| {
return FSEventsWatcher.init(loop, path, recursive, callback, ctx);
return FSEventsWatcher.init(loop, path, recursive, callback, updateEnd, ctx);
} else {
fsevents_default_loop_mutex.lock();
defer fsevents_default_loop_mutex.unlock();
if (fsevents_default_loop == null) {
fsevents_default_loop = try FSEventsLoop.init();
}
return FSEventsWatcher.init(fsevents_default_loop.?, path, recursive, callback, ctx);
return FSEventsWatcher.init(fsevents_default_loop.?, path, recursive, callback, updateEnd, ctx);
}
}
9 changes: 7 additions & 2 deletions src/bun.js/node/node_fs.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4488,8 +4488,13 @@ pub const NodeFS = struct {
}
pub fn watch(_: *NodeFS, args: Arguments.Watch, comptime _: Flavor) Maybe(Return.Watch) {
const watcher = args.createFSWatcher() catch |err| {
args.global_this.throwError(err, "Failed to watch filename");
return Maybe(Return.Watch){ .result = JSC.JSValue.jsUndefined() };
var buf = std.fmt.allocPrint(bun.default_allocator, "{s} watching {}", .{ @errorName(err), strings.QuotedFormatter{ .text = args.path.slice() } }) catch unreachable;
defer bun.default_allocator.free(buf);
args.global_this.throwValue((JSC.SystemError{
.message = bun.String.init(buf),
.path = bun.String.init(args.path.slice()),
}).toErrorInstance(args.global_this));
return Maybe(Return.Watch){ .result = JSC.JSValue.undefined };
};
return Maybe(Return.Watch){ .result = watcher };
}
Expand Down
Loading

0 comments on commit 86633e0

Please sign in to comment.