authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-07-05 13:34:14-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-07-07 22:59:52-04:00
log383cffbfae2d6be5862cbadaf138618c5b37b345
tree91f26367041a8bbea33989325026bb2d80a71d03
parent92ddb959a7c8877c98363b27c71cd5ae4b9603f4

InternPool: temporarily disable multi-threaded behavior

This reduces the cost of the new data structure until the multi-threaded behavior is actually used.

3 files changed, 67 insertions(+), 41 deletions(-)

lib/std/Thread/Pool.zig+8-3
...@@ -8,8 +8,13 @@ cond: std.Thread.Condition = .{},...@@ -8,8 +8,13 @@ cond: std.Thread.Condition = .{},
8run_queue: RunQueue = .{},8run_queue: RunQueue = .{},
9is_running: bool = true,9is_running: bool = true,
10allocator: std.mem.Allocator,10allocator: std.mem.Allocator,
11threads: []std.Thread,11threads: if (builtin.single_threaded) [0]std.Thread else []std.Thread,
12ids: std.AutoArrayHashMapUnmanaged(std.Thread.Id, void),12ids: if (builtin.single_threaded) struct {
13 inline fn deinit(_: @This(), _: std.mem.Allocator) void {}
14 fn getIndex(_: @This(), _: std.Thread.Id) usize {
15 return 0;
16 }
17} else std.AutoArrayHashMapUnmanaged(std.Thread.Id, void),
1318
14const RunQueue = std.SinglyLinkedList(Runnable);19const RunQueue = std.SinglyLinkedList(Runnable);
15const Runnable = struct {20const Runnable = struct {
...@@ -29,7 +34,7 @@ pub fn init(pool: *Pool, options: Options) !void {...@@ -29,7 +34,7 @@ pub fn init(pool: *Pool, options: Options) !void {
2934
30 pool.* = .{35 pool.* = .{
31 .allocator = allocator,36 .allocator = allocator,
32 .threads = &[_]std.Thread{},37 .threads = if (builtin.single_threaded) .{} else &.{},
33 .ids = .{},38 .ids = .{},
34 };39 };
3540
src/InternPool.zig+58-37
...@@ -4,11 +4,10 @@...@@ -4,11 +4,10 @@
44
5locals: []Local = &.{},5locals: []Local = &.{},
6shards: []Shard = &.{},6shards: []Shard = &.{},
7tid_width: std.math.Log2Int(u32) = 0,7tid_width: if (single_threaded) u0 else std.math.Log2Int(u32) = 0,
8tid_shift_31: std.math.Log2Int(u32) = 31,8tid_shift_31: if (single_threaded) u0 else std.math.Log2Int(u32) = if (single_threaded) 0 else 31,
9tid_shift_32: std.math.Log2Int(u32) = 31,9tid_shift_32: if (single_threaded) u0 else std.math.Log2Int(u32) = if (single_threaded) 0 else 31,
1010
11//items: std.MultiArrayList(Item) = .{},
12extra: std.ArrayListUnmanaged(u32) = .{},11extra: std.ArrayListUnmanaged(u32) = .{},
13/// On 32-bit systems, this array is ignored and extra is used for everything.12/// On 32-bit systems, this array is ignored and extra is used for everything.
14/// On 64-bit systems, this array is used for big integers and associated metadata.13/// On 64-bit systems, this array is used for big integers and associated metadata.
...@@ -92,6 +91,14 @@ free_dep_entries: std.ArrayListUnmanaged(DepEntry.Index) = .{},...@@ -92,6 +91,14 @@ free_dep_entries: std.ArrayListUnmanaged(DepEntry.Index) = .{},
92/// Value is the `Decl` of the struct that represents this `File`.91/// Value is the `Decl` of the struct that represents this `File`.
93files: std.AutoArrayHashMapUnmanaged(Cache.BinDigest, OptionalDeclIndex) = .{},92files: std.AutoArrayHashMapUnmanaged(Cache.BinDigest, OptionalDeclIndex) = .{},
9493
94/// Whether a multi-threaded intern pool is useful.
95/// Currently `false` until the intern pool is actually accessed
96/// from multiple threads to reduce the cost of this data structure.
97const want_multi_threaded = false;
98
99/// Whether a single-threaded intern pool impl is in use.
100pub const single_threaded = builtin.single_threaded or !want_multi_threaded;
101
95pub const FileIndex = enum(u32) {102pub const FileIndex = enum(u32) {
96 _,103 _,
97};104};
...@@ -497,19 +504,23 @@ const Local = struct {...@@ -497,19 +504,23 @@ const Local = struct {
497 var new_list: ListSelf = .{ .bytes = @ptrCast(buf[bytes_offset..].ptr) };504 var new_list: ListSelf = .{ .bytes = @ptrCast(buf[bytes_offset..].ptr) };
498 new_list.header().* = .{ .capacity = capacity };505 new_list.header().* = .{ .capacity = capacity };
499 const len = mutable.lenPtr().*;506 const len = mutable.lenPtr().*;
500 const old_slice = mutable.list.view().slice();507 // this cold, quickly predictable, condition enables
501 const new_slice = new_list.view().slice();508 // the `MultiArrayList` optimization in `view`
502 inline for (fields) |field| {509 if (len > 0) {
503 @memcpy(new_slice.items(field)[0..len], old_slice.items(field)[0..len]);510 const old_slice = mutable.list.view().slice();
511 const new_slice = new_list.view().slice();
512 inline for (fields) |field| @memcpy(new_slice.items(field)[0..len], old_slice.items(field)[0..len]);
504 }513 }
505 mutable.list.release(new_list);514 mutable.list.release(new_list);
506 }515 }
507516
508 fn view(mutable: Mutable) View {517 fn view(mutable: Mutable) View {
518 const capacity = mutable.capacityPtr().*;
519 assert(capacity > 0); // optimizes `MultiArrayList.Slice.items`
509 return .{520 return .{
510 .bytes = mutable.list.bytes,521 .bytes = mutable.list.bytes,
511 .len = mutable.lenPtr().*,522 .len = mutable.lenPtr().*,
512 .capacity = mutable.capacityPtr().*,523 .capacity = capacity,
513 };524 };
514 }525 }
515526
...@@ -550,6 +561,7 @@ const Local = struct {...@@ -550,6 +561,7 @@ const Local = struct {
550561
551 fn view(list: ListSelf) View {562 fn view(list: ListSelf) View {
552 const capacity = list.header().capacity;563 const capacity = list.header().capacity;
564 assert(capacity > 0); // optimizes `MultiArrayList.Slice.items`
553 return .{565 return .{
554 .bytes = list.bytes,566 .bytes = list.bytes,
555 .len = capacity,567 .len = capacity,
...@@ -665,13 +677,8 @@ const Shard = struct {...@@ -665,13 +677,8 @@ const Shard = struct {
665 }677 }
666};678};
667679
668fn getShard(ip: *InternPool, tid: Zcu.PerThread.Id) *Shard {
669 return &ip.shards[@intFromEnum(tid)];
670}
671
672fn getTidMask(ip: *const InternPool) u32 {680fn getTidMask(ip: *const InternPool) u32 {
673 assert(std.math.isPowerOfTwo(ip.shards.len));681 return (@as(u32, 1) << ip.tid_width) - 1;
674 return @intCast(ip.shards.len - 1);
675}682}
676683
677fn getIndexMask(ip: *const InternPool, comptime BackingInt: type) u32 {684fn getIndexMask(ip: *const InternPool, comptime BackingInt: type) u32 {
...@@ -809,7 +816,7 @@ pub const String = enum(u32) {...@@ -809,7 +816,7 @@ pub const String = enum(u32) {
809 };816 };
810 }817 }
811818
812 fn toOverlongSlice(string: String, ip: *const InternPool) []const u8 {819 noinline fn toOverlongSlice(string: String, ip: *const InternPool) []const u8 {
813 const unwrapped = string.unwrap(ip);820 const unwrapped = string.unwrap(ip);
814 return ip.getLocalShared(unwrapped.tid).strings.acquire().view().items(.@"0")[unwrapped.index..];821 return ip.getLocalShared(unwrapped.tid).strings.acquire().view().items(.@"0")[unwrapped.index..];
815 }822 }
...@@ -3230,19 +3237,35 @@ pub const Index = enum(u32) {...@@ -3230,19 +3237,35 @@ pub const Index = enum(u32) {
3230 }3237 }
3231 };3238 };
32323239
3233 pub fn getItem(index: Index, ip: *const InternPool) Item {3240 pub inline fn getItem(index: Index, ip: *const InternPool) Item {
3234 const unwrapped = index.unwrap(ip);3241 const item_ptr = index.itemPtr(ip);
3235 return ip.getLocalShared(unwrapped.tid).items.acquire().view().get(unwrapped.index);3242 const tag = @atomicLoad(Tag, item_ptr.tag_ptr, .acquire);
3243 return .{ .tag = tag, .data = item_ptr.data_ptr.* };
3236 }3244 }
32373245
3238 pub fn getTag(index: Index, ip: *const InternPool) Tag {3246 pub inline fn getTag(index: Index, ip: *const InternPool) Tag {
3239 const unwrapped = index.unwrap(ip);3247 const item_ptr = index.itemPtr(ip);
3240 return ip.getLocalShared(unwrapped.tid).items.acquire().view().items(.tag)[unwrapped.index];3248 return @atomicLoad(Tag, item_ptr.tag_ptr, .acquire);
3241 }3249 }
32423250
3243 pub fn getData(index: Index, ip: *const InternPool) u32 {3251 pub inline fn getData(index: Index, ip: *const InternPool) u32 {
3244 const unwrapped = index.unwrap(ip);3252 return index.getItem(ip).data;
3245 return ip.getLocalShared(unwrapped.tid).items.acquire().view().items(.data)[unwrapped.index];3253 }
3254
3255 const ItemPtr = struct {
3256 tag_ptr: *Tag,
3257 data_ptr: *u32,
3258 };
3259 fn itemPtr(index: Index, ip: *const InternPool) ItemPtr {
3260 const unwrapped: Unwrapped = if (single_threaded) .{
3261 .tid = .main,
3262 .index = @intFromEnum(index),
3263 } else index.unwrap(ip);
3264 const slice = ip.getLocalShared(unwrapped.tid).items.acquire().view().slice();
3265 return .{
3266 .tag_ptr = &slice.items(.tag)[unwrapped.index],
3267 .data_ptr = &slice.items(.data)[unwrapped.index],
3268 };
3246 }3269 }
32473270
3248 const Unwrapped = struct {3271 const Unwrapped = struct {
...@@ -4905,11 +4928,12 @@ pub const MemoizedCall = struct {...@@ -4905,11 +4928,12 @@ pub const MemoizedCall = struct {
4905 result: Index,4928 result: Index,
4906};4929};
49074930
4908pub fn init(ip: *InternPool, gpa: Allocator, total_threads: usize) !void {4931pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {
4909 errdefer ip.deinit(gpa);4932 errdefer ip.deinit(gpa);
4910 assert(ip.locals.len == 0 and ip.shards.len == 0);4933 assert(ip.locals.len == 0 and ip.shards.len == 0);
49114934
4912 ip.locals = try gpa.alloc(Local, total_threads);4935 const used_threads = if (single_threaded) 1 else available_threads;
4936 ip.locals = try gpa.alloc(Local, used_threads);
4913 @memset(ip.locals, .{4937 @memset(ip.locals, .{
4914 .shared = .{4938 .shared = .{
4915 .items = Local.List(Item).empty,4939 .items = Local.List(Item).empty,
...@@ -4922,9 +4946,9 @@ pub fn init(ip: *InternPool, gpa: Allocator, total_threads: usize) !void {...@@ -4922,9 +4946,9 @@ pub fn init(ip: *InternPool, gpa: Allocator, total_threads: usize) !void {
4922 },4946 },
4923 });4947 });
49244948
4925 ip.tid_width = @intCast(std.math.log2_int_ceil(usize, total_threads));4949 ip.tid_width = @intCast(std.math.log2_int_ceil(usize, used_threads));
4926 ip.tid_shift_31 = 31 - ip.tid_width;4950 ip.tid_shift_31 = if (single_threaded) 0 else 31 - ip.tid_width;
4927 ip.tid_shift_32 = ip.tid_shift_31 +| 1;4951 ip.tid_shift_32 = if (single_threaded) 0 else ip.tid_shift_31 +| 1;
4928 ip.shards = try gpa.alloc(Shard, @as(usize, 1) << ip.tid_width);4952 ip.shards = try gpa.alloc(Shard, @as(usize, 1) << ip.tid_width);
4929 @memset(ip.shards, .{4953 @memset(ip.shards, .{
4930 .shared = .{4954 .shared = .{
...@@ -7063,7 +7087,7 @@ pub fn getExternFunc(...@@ -7063,7 +7087,7 @@ pub fn getExternFunc(
7063 .tag = .extern_func,7087 .tag = .extern_func,
7064 .data = extra_index,7088 .data = extra_index,
7065 });7089 });
7066 errdefer ip.items.lenPtr().* -= 1;7090 errdefer items.lenPtr().* -= 1;
7067 return gop.put();7091 return gop.put();
7068}7092}
70697093
...@@ -10146,12 +10170,9 @@ pub fn iesFuncIndex(ip: *const InternPool, ies_index: Index) Index {...@@ -10146,12 +10170,9 @@ pub fn iesFuncIndex(ip: *const InternPool, ies_index: Index) Index {
10146/// error set function. The returned pointer is invalidated when anything is10170/// error set function. The returned pointer is invalidated when anything is
10147/// added to `ip`.10171/// added to `ip`.
10148pub fn iesResolved(ip: *const InternPool, ies_index: Index) *Index {10172pub fn iesResolved(ip: *const InternPool, ies_index: Index) *Index {
10149 assert(ies_index != .none);10173 const ies_item = ies_index.getItem(ip);
10150 const tags = ip.items.items(.tag);10174 assert(ies_item.tag == .type_inferred_error_set);
10151 const datas = ip.items.items(.data);10175 return funcIesResolved(ip, ies_item.data);
10152 assert(tags[@intFromEnum(ies_index)] == .type_inferred_error_set);
10153 const func_index = datas[@intFromEnum(ies_index)];
10154 return funcIesResolved(ip, func_index);
10155}10176}
1015610177
10157/// Returns a mutable pointer to the resolved error set type of an inferred10178/// Returns a mutable pointer to the resolved error set type of an inferred
src/Zcu/PerThread.zig+1-1
...@@ -3,7 +3,7 @@ zcu: *Zcu,...@@ -3,7 +3,7 @@ zcu: *Zcu,
3/// Dense, per-thread unique index.3/// Dense, per-thread unique index.
4tid: Id,4tid: Id,
55
6pub const Id = if (builtin.single_threaded) enum { main } else enum(usize) { main, _ };6pub const Id = if (InternPool.single_threaded) enum { main } else enum(usize) { main, _ };
77
8pub fn astGenFile(8pub fn astGenFile(
9 pt: Zcu.PerThread,9 pt: Zcu.PerThread,