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