authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-05-23 18:45:04-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-05-27 20:56:48-07:00
log3a768bd6ce9e891ad258b32fb2dd0ed912ef9e9b
tree522b5e592a3a6fa35f5dade357c578334f0b02e4
parentdf46f5af690889508ebcb07b46c8579acaad06a2

std.Progress: save a copy of IPC data

so that the previous message can be used when the pipe is empty. prevents flickering

1 files changed, 80 insertions(+), 10 deletions(-)

lib/std/Progress.zig+80-10
...@@ -472,6 +472,7 @@ const Serialized = struct {...@@ -472,6 +472,7 @@ const Serialized = struct {
472472
473fn serialize() Serialized {473fn serialize() Serialized {
474 var serialized_len: usize = 0;474 var serialized_len: usize = 0;
475 var any_ipc = false;
475476
476 // Iterate all of the nodes and construct a serializable copy of the state that can be examined477 // Iterate all of the nodes and construct a serializable copy of the state that can be examined
477 // without atomics.478 // without atomics.
...@@ -486,6 +487,8 @@ fn serialize() Serialized {...@@ -486,6 +487,8 @@ fn serialize() Serialized {
486 dest_storage.completed_count = @atomicLoad(u32, &storage_ptr.completed_count, .monotonic);487 dest_storage.completed_count = @atomicLoad(u32, &storage_ptr.completed_count, .monotonic);
487 dest_storage.estimated_total_count = @atomicLoad(u32, &storage_ptr.estimated_total_count, .monotonic);488 dest_storage.estimated_total_count = @atomicLoad(u32, &storage_ptr.estimated_total_count, .monotonic);
488489
490 any_ipc = any_ipc or dest_storage.getIpcFd() != null;
491
489 const end_parent = @atomicLoad(Node.Parent, parent_ptr, .seq_cst);492 const end_parent = @atomicLoad(Node.Parent, parent_ptr, .seq_cst);
490 if (begin_parent == end_parent) {493 if (begin_parent == end_parent) {
491 serialized_node_parents_buffer[serialized_len] = begin_parent;494 serialized_node_parents_buffer[serialized_len] = begin_parent;
...@@ -508,6 +511,32 @@ fn serialize() Serialized {...@@ -508,6 +511,32 @@ fn serialize() Serialized {
508 }511 }
509512
510 // Find nodes which correspond to child processes.513 // Find nodes which correspond to child processes.
514 if (any_ipc)
515 serialized_len = serializeIpc(serialized_len);
516
517 return .{
518 .parents = serialized_node_parents_buffer[0..serialized_len],
519 .storage = serialized_node_storage_buffer[0..serialized_len],
520 };
521}
522
523var parents_copy: [default_node_storage_buffer_len]Node.Parent = undefined;
524var storage_copy: [default_node_storage_buffer_len]Node.Storage = undefined;
525
526const SavedMetadata = extern struct {
527 start_index: u16,
528 nodes_len: u16,
529 main_index: u16,
530 flags: Flags,
531
532 const Flags = enum(u16) {
533 saved = std.math.maxInt(u16),
534 _,
535 };
536};
537
538fn serializeIpc(start_serialized_len: usize) usize {
539 var serialized_len = start_serialized_len;
511 var pipe_buf: [4096]u8 align(4) = undefined;540 var pipe_buf: [4096]u8 align(4) = undefined;
512541
513 for (542 for (
...@@ -532,24 +561,23 @@ fn serialize() Serialized {...@@ -532,24 +561,23 @@ fn serialize() Serialized {
532 // Ignore all but the last message on the pipe.561 // Ignore all but the last message on the pipe.
533 var input: []align(2) u8 = pipe_buf[0..bytes_read];562 var input: []align(2) u8 = pipe_buf[0..bytes_read];
534 if (input.len == 0) {563 if (input.len == 0) {
535 main_storage.completed_count = 0;564 serialized_len = useSavedIpcData(serialized_len, main_storage, main_index);
536 main_storage.estimated_total_count = 0;
537 continue;565 continue;
538 }566 }
539567
540 const storage, const parents = while (true) {568 const storage, const parents = while (true) {
541 if (input.len < 4) {569 if (input.len < 4) {
542 std.log.warn("short read: {d} out of 4 header bytes", .{input.len});570 std.log.warn("short read: {d} out of 4 header bytes", .{input.len});
543 main_storage.completed_count = 0;571 // TODO keep track of the short read to trash odd bytes with the next read
544 main_storage.estimated_total_count = 0;572 serialized_len = useSavedIpcData(serialized_len, main_storage, main_index);
545 continue;573 continue;
546 }574 }
547 const subtree_len = std.mem.readInt(u32, input[0..4], .little);575 const subtree_len = std.mem.readInt(u32, input[0..4], .little);
548 const expected_bytes = 4 + subtree_len * (@sizeOf(Node.Storage) + @sizeOf(Node.Parent));576 const expected_bytes = 4 + subtree_len * (@sizeOf(Node.Storage) + @sizeOf(Node.Parent));
549 if (input.len < expected_bytes) {577 if (input.len < expected_bytes) {
550 std.log.warn("short read: {d} out of {d} ({d} nodes)", .{ input.len, expected_bytes, subtree_len });578 std.log.warn("short read: {d} out of {d} ({d} nodes)", .{ input.len, expected_bytes, subtree_len });
551 main_storage.completed_count = 0;579 // TODO keep track of the short read to trash odd bytes with the next read
552 main_storage.estimated_total_count = 0;580 serialized_len = useSavedIpcData(serialized_len, main_storage, main_index);
553 continue;581 continue;
554 }582 }
555 if (input.len > expected_bytes) {583 if (input.len > expected_bytes) {
...@@ -564,6 +592,14 @@ fn serialize() Serialized {...@@ -564,6 +592,14 @@ fn serialize() Serialized {
564 };592 };
565 };593 };
566594
595 // Remember in case the pipe is empty on next update.
596 @as(*SavedMetadata, @ptrCast(&main_storage.name)).* = .{
597 .start_index = @intCast(serialized_len),
598 .nodes_len = @intCast(parents.len),
599 .main_index = @intCast(main_index),
600 .flags = .saved,
601 };
602
567 // Mount the root here.603 // Mount the root here.
568 main_storage.* = storage[0];604 main_storage.* = storage[0];
569605
...@@ -580,6 +616,7 @@ fn serialize() Serialized {...@@ -580,6 +616,7 @@ fn serialize() Serialized {
580 // Root node is being mounted here.616 // Root node is being mounted here.
581 @as(Node.Parent, @enumFromInt(0)) => @enumFromInt(main_index),617 @as(Node.Parent, @enumFromInt(0)) => @enumFromInt(main_index),
582 // Other nodes mounted at the end.618 // Other nodes mounted at the end.
619 // TODO check for bad data pointing outside the expected range
583 _ => |off| @enumFromInt(serialized_len + @intFromEnum(off) - 1),620 _ => |off| @enumFromInt(serialized_len + @intFromEnum(off) - 1),
584 };621 };
585 }622 }
...@@ -587,10 +624,43 @@ fn serialize() Serialized {...@@ -587,10 +624,43 @@ fn serialize() Serialized {
587 serialized_len += storage.len - 1;624 serialized_len += storage.len - 1;
588 }625 }
589626
590 return .{627 // Save a copy in case any pipes are empty on the next update.
591 .parents = serialized_node_parents_buffer[0..serialized_len],628 @memcpy(parents_copy[0..serialized_len], serialized_node_parents_buffer[0..serialized_len]);
592 .storage = serialized_node_storage_buffer[0..serialized_len],629 @memcpy(storage_copy[0..serialized_len], serialized_node_storage_buffer[0..serialized_len]);
593 };630
631 return serialized_len;
632}
633
634fn useSavedIpcData(start_serialized_len: usize, main_storage: *Node.Storage, main_index: usize) usize {
635 const saved_metadata: *SavedMetadata = @ptrCast(&main_storage.name);
636 if (saved_metadata.flags != .saved) {
637 main_storage.completed_count = 0;
638 main_storage.estimated_total_count = 0;
639 return start_serialized_len;
640 }
641
642 const start_index = saved_metadata.start_index;
643 const nodes_len = saved_metadata.nodes_len;
644 const old_main_index = saved_metadata.main_index;
645
646 const parents = parents_copy[start_index..][0 .. nodes_len - 1];
647 const storage = storage_copy[start_index..][0 .. nodes_len - 1];
648
649 main_storage.* = storage_copy[old_main_index];
650
651 @memcpy(serialized_node_storage_buffer[start_serialized_len..][0..storage.len], storage);
652
653 for (serialized_node_parents_buffer[start_serialized_len..][0..parents.len], parents) |*dest, p| {
654 dest.* = switch (p) {
655 .none, .unused => .none,
656 _ => |prev| @enumFromInt(if (@intFromEnum(prev) == old_main_index)
657 main_index
658 else
659 @intFromEnum(prev) - start_index + start_serialized_len),
660 };
661 }
662
663 return start_serialized_len + storage.len;
594}664}
595665
596fn computeRedraw() []u8 {666fn computeRedraw() []u8 {