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