authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-05-05 18:07:25-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-06-10 20:42:28-07:00
log0471638734257d479d21abcb490ed9459df42b9b
treee952a9b22f4d7f02cb42c616b5594d99f6c2156e
parent9ec0017f460854300004ab263bf585c2d376d1fb

InternPool: add a dump function

So we can see stats

2 files changed, 148 insertions(+), 12 deletions(-)

src/Compilation.zig+5
...@@ -2026,6 +2026,11 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void...@@ -2026,6 +2026,11 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void
2026 try comp.performAllTheWork(main_progress_node);2026 try comp.performAllTheWork(main_progress_node);
20272027
2028 if (comp.bin_file.options.module) |module| {2028 if (comp.bin_file.options.module) |module| {
2029 std.debug.print("intern pool stats for '{s}':\n", .{
2030 comp.bin_file.options.root_name,
2031 });
2032 module.intern_pool.dump();
2033
2029 if (comp.bin_file.options.is_test and comp.totalErrorCount() == 0) {2034 if (comp.bin_file.options.is_test and comp.totalErrorCount() == 0) {
2030 // The `test_functions` decl has been intentionally postponed until now,2035 // The `test_functions` decl has been intentionally postponed until now,
2031 // at which point we must populate it with the list of test functions that2036 // at which point we must populate it with the list of test functions that
src/InternPool.zig+143-12
...@@ -722,10 +722,10 @@ pub const Tag = enum(u8) {...@@ -722,10 +722,10 @@ pub const Tag = enum(u8) {
722 /// data is float value bitcasted to u32.722 /// data is float value bitcasted to u32.
723 float_f32,723 float_f32,
724 /// An f64 value.724 /// An f64 value.
725 /// data is payload index to Float64.725 /// data is extra index to Float64.
726 float_f64,726 float_f64,
727 /// An f128 value.727 /// An f128 value.
728 /// data is payload index to Float128.728 /// data is extra index to Float128.
729 float_f128,729 float_f128,
730 /// An extern function.730 /// An extern function.
731 extern_func,731 extern_func,
...@@ -877,6 +877,33 @@ pub const Int = struct {...@@ -877,6 +877,33 @@ pub const Int = struct {
877 limbs_len: u32,877 limbs_len: u32,
878};878};
879879
880/// A f64 value, broken up into 2 u32 parts.
881pub const Float64 = struct {
882 piece0: u32,
883 piece1: u32,
884
885 pub fn get(self: Float64) f64 {
886 const int_bits = @as(u64, self.piece0) | (@as(u64, self.piece1) << 32);
887 return @bitCast(u64, int_bits);
888 }
889};
890
891/// A f128 value, broken up into 4 u32 parts.
892pub const Float128 = struct {
893 piece0: u32,
894 piece1: u32,
895 piece2: u32,
896 piece3: u32,
897
898 pub fn get(self: Float128) f128 {
899 const int_bits = @as(u128, self.piece0) |
900 (@as(u128, self.piece1) << 32) |
901 (@as(u128, self.piece2) << 64) |
902 (@as(u128, self.piece3) << 96);
903 return @bitCast(f128, int_bits);
904 }
905};
906
880pub fn init(ip: *InternPool, gpa: Allocator) !void {907pub fn init(ip: *InternPool, gpa: Allocator) !void {
881 assert(ip.items.len == 0);908 assert(ip.items.len == 0);
882909
...@@ -1293,20 +1320,42 @@ fn addLimbsAssumeCapacity(ip: *InternPool, limbs: []const usize) void {...@@ -1293,20 +1320,42 @@ fn addLimbsAssumeCapacity(ip: *InternPool, limbs: []const usize) void {
1293}1320}
12941321
1295fn extraData(ip: InternPool, comptime T: type, index: usize) T {1322fn extraData(ip: InternPool, comptime T: type, index: usize) T {
1296 const fields = std.meta.fields(T);
1297 var i: usize = index;
1298 var result: T = undefined;1323 var result: T = undefined;
1299 inline for (fields) |field| {1324 inline for (@typeInfo(T).Struct.fields, 0..) |field, i| {
1325 const int32 = ip.extra.items[i + index];
1300 @field(result, field.name) = switch (field.type) {1326 @field(result, field.name) = switch (field.type) {
1301 u32 => ip.extra.items[i],1327 u32 => int32,
1302 Index => @intToEnum(Index, ip.extra.items[i]),1328 Index => @intToEnum(Index, int32),
1303 i32 => @bitCast(i32, ip.extra.items[i]),1329 i32 => @bitCast(i32, int32),
1304 Pointer.Flags => @bitCast(Pointer.Flags, ip.extra.items[i]),1330 Pointer.Flags => @bitCast(Pointer.Flags, int32),
1305 Pointer.PackedOffset => @bitCast(Pointer.PackedOffset, ip.extra.items[i]),1331 Pointer.PackedOffset => @bitCast(Pointer.PackedOffset, int32),
1306 Pointer.VectorIndex => @intToEnum(Pointer.VectorIndex, ip.extra.items[i]),1332 Pointer.VectorIndex => @intToEnum(Pointer.VectorIndex, int32),
1333 else => @compileError("bad field type: " ++ @typeName(field.type)),
1334 };
1335 }
1336 return result;
1337}
1338
1339/// Asserts the struct has 32-bit fields and the number of fields is evenly divisible by 2.
1340fn limbData(ip: InternPool, comptime T: type, index: usize) T {
1341 switch (@sizeOf(usize)) {
1342 @sizeOf(u32) => return extraData(ip, T, index),
1343 @sizeOf(u64) => {},
1344 else => @compileError("unsupported host"),
1345 }
1346 var result: T = undefined;
1347 inline for (@typeInfo(T).Struct.fields, 0..) |field, i| {
1348 const host_int = ip.limbs.items[index + i / 2];
1349 const int32 = if (i % 2 == 0)
1350 @truncate(u32, host_int)
1351 else
1352 @truncate(u32, host_int >> 32);
1353
1354 @field(result, field.name) = switch (field.type) {
1355 u32 => int32,
1356 Index => @intToEnum(Index, int32),
1307 else => @compileError("bad field type: " ++ @typeName(field.type)),1357 else => @compileError("bad field type: " ++ @typeName(field.type)),
1308 };1358 };
1309 i += 1;
1310 }1359 }
1311 return result;1360 return result;
1312}1361}
...@@ -1350,3 +1399,85 @@ pub fn childType(ip: InternPool, i: Index) Index {...@@ -1350,3 +1399,85 @@ pub fn childType(ip: InternPool, i: Index) Index {
1350 else => unreachable,1399 else => unreachable,
1351 };1400 };
1352}1401}
1402
1403pub fn dump(ip: InternPool) void {
1404 dumpFallible(ip, std.heap.page_allocator) catch return;
1405}
1406
1407fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {
1408 const items_size = (1 + 4) * ip.items.len;
1409 const extra_size = 4 * ip.extra.items.len;
1410 const limbs_size = 8 * ip.limbs.items.len;
1411
1412 // TODO: map overhead size is not taken into account
1413 const total_size = @sizeOf(InternPool) + items_size + extra_size + limbs_size;
1414
1415 std.debug.print(
1416 \\InternPool size: {d} bytes
1417 \\ items: {d} bytes
1418 \\ extra: {d} bytes
1419 \\ limbs: {d} bytes
1420 \\
1421 , .{ total_size, items_size, extra_size, limbs_size });
1422
1423 const tags = ip.items.items(.tag);
1424 const datas = ip.items.items(.data);
1425 const TagStats = struct {
1426 count: usize = 0,
1427 bytes: usize = 0,
1428 };
1429 var counts = std.AutoArrayHashMap(Tag, TagStats).init(arena);
1430 for (tags, datas) |tag, data| {
1431 const gop = try counts.getOrPut(tag);
1432 if (!gop.found_existing) gop.value_ptr.* = .{};
1433 gop.value_ptr.count += 1;
1434 gop.value_ptr.bytes += 1 + 4 + @as(usize, switch (tag) {
1435 .type_int_signed => 0,
1436 .type_int_unsigned => 0,
1437 .type_array => @sizeOf(Vector),
1438 .type_vector => @sizeOf(Vector),
1439 .type_pointer => @sizeOf(Pointer),
1440 .type_optional => 0,
1441 .type_error_union => @sizeOf(ErrorUnion),
1442 .type_enum_simple => @sizeOf(EnumSimple),
1443 .simple_type => 0,
1444 .simple_value => 0,
1445 .simple_internal => 0,
1446 .int_u32 => 0,
1447 .int_i32 => 0,
1448 .int_usize => 0,
1449 .int_comptime_int_u32 => 0,
1450 .int_comptime_int_i32 => 0,
1451
1452 .int_positive,
1453 .int_negative,
1454 .enum_tag_positive,
1455 .enum_tag_negative,
1456 => b: {
1457 const int = ip.limbData(Int, data);
1458 break :b @sizeOf(Int) + int.limbs_len * 8;
1459 },
1460
1461 .float_f32 => 0,
1462 .float_f64 => @sizeOf(Float64),
1463 .float_f128 => @sizeOf(Float128),
1464 .extern_func => @panic("TODO"),
1465 .func => @panic("TODO"),
1466 });
1467 }
1468 const SortContext = struct {
1469 map: *std.AutoArrayHashMap(Tag, TagStats),
1470 pub fn lessThan(ctx: @This(), a_index: usize, b_index: usize) bool {
1471 const values = ctx.map.values();
1472 return values[a_index].bytes > values[b_index].bytes;
1473 }
1474 };
1475 counts.sort(SortContext{ .map = &counts });
1476 const len = @min(50, tags.len);
1477 std.debug.print("top 50 tags:\n", .{});
1478 for (counts.keys()[0..len], counts.values()[0..len]) |tag, stats| {
1479 std.debug.print(" {s}: {d} occurrences, {d} total bytes\n", .{
1480 @tagName(tag), stats.count, stats.bytes,
1481 });
1482 }
1483}