1use super::{
2 GroupRecord, SlotDebugAnchor, SlotDebugEntry, SlotDebugEntryKind, SlotDebugGroup,
3 SlotDebugScope, SlotDebugSnapshot, SlotTable, SlotTableLocalDebugStats,
4 SlotTableMutationDebugStats,
5};
6use crate::{Key, RecomposeScope, ScopeId};
7
8impl SlotTable {
9 fn group_heap_bytes(&self) -> usize {
10 self.groups.capacity() * size_of::<GroupRecord>()
11 }
12
13 pub fn heap_bytes(&self) -> usize {
15 self.group_heap_bytes()
16 + self.payloads.heap_bytes()
17 + self.node_heap_bytes()
18 + self.anchors.heap_bytes()
19 + self.payload_anchors.heap_bytes()
20 }
21
22 pub fn debug_stats(&self) -> SlotTableLocalDebugStats {
24 SlotTableLocalDebugStats {
25 group_count: self.groups.len(),
26 group_capacity: self.groups.capacity(),
27 group_record_size: size_of::<GroupRecord>(),
28 group_heap_bytes: self.group_heap_bytes(),
29 payload_count: self.total_payload_count(),
30 payload_capacity: self.payloads.capacity(),
31 active_payload_anchor_count: self.payload_anchors.active_len(),
32 payload_anchor_slot_count: self.payload_anchors.slot_len(),
33 detached_payload_anchor_count: self.payload_anchors.detached_len(),
34 invalidated_payload_anchor_count: self.payload_anchors.invalidated_len(),
35 free_payload_anchor_count: self.payload_anchors.free_len(),
36 payload_anchor_capacity: self.payload_anchors.capacity(),
37 payload_anchor_heap_bytes: self.payload_anchors.heap_bytes(),
38 node_count: self.total_node_count(),
39 node_capacity: self.node_debug_capacity(),
40 active_anchor_count: self.anchors.active_len(),
41 anchor_slot_count: self.anchors.slot_len(),
42 anchor_sparse_count: self.anchors.sparse_slot_len(),
43 detached_anchor_count: self.anchors.detached_len(),
44 invalidated_anchor_count: self.anchors.invalidated_len(),
45 free_anchor_count: self.anchors.free_len(),
46 anchor_capacity: self.anchors.capacity(),
47 anchor_heap_bytes: self.anchors.heap_bytes(),
48 mutation: SlotTableMutationDebugStats {
49 payload_shift_bytes: self.payloads.shift_bytes(),
50 ..self.diagnostics.mutation()
51 },
52 }
53 }
54
55 pub fn debug_dump_groups(&self) -> Vec<(usize, Key, Option<ScopeId>, usize)> {
57 self.groups
58 .iter()
59 .enumerate()
60 .map(|(index, group)| {
61 (
62 index,
63 group.key.static_key,
64 group.scope.as_ref().map(RecomposeScope::id),
65 group.subtree_len as usize,
66 )
67 })
68 .collect()
69 }
70
71 pub fn debug_snapshot(&self) -> SlotDebugSnapshot {
74 let active_groups = self
75 .groups
76 .iter()
77 .enumerate()
78 .map(|(index, group)| SlotDebugGroup {
79 index,
80 anchor: group.anchor,
81 parent_anchor: group.parent_anchor,
82 static_key: group.key.static_key,
83 explicit_key: group.key.explicit_key,
84 ordinal: group.key.ordinal,
85 scope_id: group.scope.as_ref().map(RecomposeScope::id),
86 depth: group.depth,
87 subtree_len: group.subtree_len,
88 payload_len: self.group_payload_len_at(index),
89 node_len: self.group_node_len_at(index),
90 subtree_node_count: group.subtree_node_count,
91 })
92 .collect::<Vec<_>>();
93 let mut anchors = self
94 .anchors
95 .active_entries()
96 .map(|(anchor, stored)| SlotDebugAnchor {
97 anchor,
98 group_index: self.resolve_group_index(stored, anchor).unwrap_or(stored),
99 })
100 .collect::<Vec<_>>();
101 anchors.sort_by_key(|entry| entry.group_index);
102
103 let mut scopes = self
104 .groups
105 .iter()
106 .enumerate()
107 .filter_map(|(group_index, group)| {
108 group.scope.as_ref().map(|scope| SlotDebugScope {
109 scope_id: scope.id(),
110 anchor: group.anchor,
111 group_index,
112 })
113 })
114 .collect::<Vec<_>>();
115 scopes.sort_by_key(|entry| entry.scope_id);
116
117 SlotDebugSnapshot {
118 active_payload_count: self.total_payload_count(),
119 active_node_count: self.total_node_count(),
120 active_scope_count: scopes.len(),
121 active_groups,
122 anchors,
123 scopes,
124 retained_subtree_count: 0,
125 retained_group_count: 0,
126 retained_payload_count: 0,
127 retained_node_count: 0,
128 retained_scope_count: 0,
129 }
130 }
131
132 pub fn debug_dump_slot_entries(&self) -> Vec<SlotDebugEntry> {
134 let mut rows = Vec::new();
135 for (index, group) in self.groups.iter().enumerate() {
136 rows.push(SlotDebugEntry {
137 kind: SlotDebugEntryKind::Group,
138 path: format!("group[{index}]"),
139 line: format!(
140 "Group(key={:?}, scope={:?}, subtree_len={}, payload_len={}, node_len={})",
141 group.key,
142 group.scope.as_ref().map(RecomposeScope::id),
143 group.subtree_len,
144 self.group_payload_len_at(index),
145 self.group_node_len_at(index)
146 ),
147 });
148 }
149 for (group_index, group) in self.groups.iter().enumerate() {
150 for (payload_index, payload) in self.group_payload_records_at(group_index).enumerate() {
151 rows.push(SlotDebugEntry {
152 kind: SlotDebugEntryKind::Payload,
153 path: format!("group[{group_index}].payload[{payload_index}]"),
154 line: format!(
155 "Payload(owner={:?}, kind={}, type={})",
156 group.anchor,
157 payload.kind.label(),
158 (payload.payload_type.type_name)()
159 ),
160 });
161 }
162 }
163 for (group_index, _) in self.groups.iter().enumerate() {
164 for (node_index, node) in self.group_node_records_at(group_index).iter().enumerate() {
165 rows.push(SlotDebugEntry {
166 kind: SlotDebugEntryKind::Node,
167 path: format!("group[{group_index}].node[{node_index}]"),
168 line: format!(
169 "Node(owner={:?}, parent={:?}, id={}, gen={}, lifecycle={:?})",
170 node.owner, node.parent_id, node.id, node.generation, node.lifecycle
171 ),
172 });
173 }
174 }
175 rows
176 }
177}