1use std::mem;
2
3use super::{
4 GroupRecord, SlotDebugAnchor, SlotDebugEntry, SlotDebugEntryKind, SlotDebugGroup,
5 SlotDebugScope, SlotDebugSnapshot, SlotTable, SlotTableLocalDebugStats,
6};
7use crate::{Key, ScopeId};
8
9impl SlotTable {
10 fn group_heap_bytes(&self) -> usize {
11 self.groups.capacity() * mem::size_of::<GroupRecord>()
12 }
13
14 pub fn heap_bytes(&self) -> usize {
15 self.group_heap_bytes()
16 + self.payload_heap_bytes()
17 + self.node_heap_bytes()
18 + self.anchors.heap_bytes()
19 + self.payload_anchors.heap_bytes()
20 + self.scope_index.heap_bytes()
21 }
22
23 pub fn debug_stats(&self) -> SlotTableLocalDebugStats {
24 SlotTableLocalDebugStats {
25 group_count: self.groups.len(),
26 group_capacity: self.groups.capacity(),
27 group_record_size: mem::size_of::<GroupRecord>(),
28 group_heap_bytes: self.group_heap_bytes(),
29 payload_count: self.total_payload_count(),
30 payload_capacity: self.payload_debug_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 scope_index_count: self.scope_index.len(),
49 scope_index_capacity: self.scope_index.capacity(),
50 mutation: self.diagnostics.mutation(),
51 }
52 }
53
54 pub fn debug_dump_groups(&self) -> Vec<(usize, Key, Option<ScopeId>, usize)> {
55 self.groups
56 .iter()
57 .enumerate()
58 .map(|(index, group)| {
59 (
60 index,
61 group.key.static_key,
62 group.scope_id,
63 group.subtree_len as usize,
64 )
65 })
66 .collect()
67 }
68
69 pub fn debug_snapshot(&self) -> SlotDebugSnapshot {
70 let active_groups = self
71 .groups
72 .iter()
73 .enumerate()
74 .map(|(index, group)| SlotDebugGroup {
75 index,
76 anchor: group.anchor,
77 parent_anchor: group.parent_anchor,
78 static_key: group.key.static_key,
79 explicit_key: group.key.explicit_key,
80 ordinal: group.key.ordinal,
81 scope_id: group.scope_id,
82 depth: group.depth,
83 subtree_len: group.subtree_len,
84 payload_len: self.group_payload_len_at(index),
85 node_len: self.group_node_len_at(index),
86 subtree_node_count: group.subtree_node_count,
87 })
88 .collect::<Vec<_>>();
89 let mut anchors = self
90 .anchors
91 .active_entries()
92 .map(|(anchor, group_index)| SlotDebugAnchor {
93 anchor,
94 group_index,
95 })
96 .collect::<Vec<_>>();
97 anchors.sort_by_key(|entry| entry.group_index);
98
99 let mut scopes = self
100 .scope_index
101 .entries()
102 .filter_map(|(scope_id, anchor)| {
103 self.anchors
104 .active_index(anchor)
105 .map(|group_index| SlotDebugScope {
106 scope_id,
107 anchor,
108 group_index,
109 })
110 })
111 .collect::<Vec<_>>();
112 scopes.sort_by_key(|entry| entry.scope_id);
113
114 SlotDebugSnapshot {
115 active_payload_count: self.total_payload_count(),
116 active_node_count: self.total_node_count(),
117 active_scope_count: scopes.len(),
118 scope_index_count: self.scope_index.len(),
119 runtime_scope_registry_count: None,
120 active_groups,
121 anchors,
122 scopes,
123 retained_subtree_count: 0,
124 retained_group_count: 0,
125 retained_payload_count: 0,
126 retained_node_count: 0,
127 retained_scope_count: 0,
128 }
129 }
130
131 pub fn debug_dump_slot_entries(&self) -> Vec<SlotDebugEntry> {
132 let mut rows = Vec::new();
133 for (index, group) in self.groups.iter().enumerate() {
134 rows.push(SlotDebugEntry {
135 kind: SlotDebugEntryKind::Group,
136 path: format!("group[{index}]"),
137 line: format!(
138 "Group(key={:?}, scope={:?}, subtree_len={}, payload_len={}, node_len={})",
139 group.key,
140 group.scope_id,
141 group.subtree_len,
142 self.group_payload_len_at(index),
143 self.group_node_len_at(index)
144 ),
145 });
146 }
147 for (group_index, _) in self.groups.iter().enumerate() {
148 for (payload_index, payload) in self
149 .group_payload_records_at(group_index)
150 .iter()
151 .enumerate()
152 {
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 payload.owner,
159 payload.kind.label(),
160 payload.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}