Skip to content

Commit ea38537

Browse files
Add heap size support for salsa structs (#943)
* Improve unstable size analysis support 1. Include an option `panic_if_missing` that will panic if there is an ingredient with no `heap_size()` defined, to ensure coverage. 2. Add `heap_size()` to tracked structs, interneds an inputs. * Make heap size a separate field, remove panic argument * Remove stale comment --------- Co-authored-by: Chayim Refael Friedman <chayimfr@gmail.com>
1 parent 5b2a97b commit ea38537

21 files changed

+136
-60
lines changed

components/salsa-macro-rules/src/setup_input_struct.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ macro_rules! setup_input_struct {
5050
// If true, generate a debug impl.
5151
generate_debug_impl: $generate_debug_impl:tt,
5252

53+
// The function used to implement `C::heap_size`.
54+
heap_size_fn: $($heap_size_fn:path)?,
55+
5356
// Annoyingly macro-rules hygiene does not extend to items defined in the macro.
5457
// We have the procedural macro generate names for those items that are
5558
// not used elsewhere in the user's code.
@@ -98,6 +101,12 @@ macro_rules! setup_input_struct {
98101

99102
type Revisions = [$zalsa::Revision; $N];
100103
type Durabilities = [$zalsa::Durability; $N];
104+
105+
$(
106+
fn heap_size(value: &Self::Fields) -> Option<usize> {
107+
Some($heap_size_fn(value))
108+
}
109+
)?
101110
}
102111

103112
impl $Configuration {

components/salsa-macro-rules/src/setup_interned_struct.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ macro_rules! setup_interned_struct {
6666
// If true, generate a debug impl.
6767
generate_debug_impl: $generate_debug_impl:tt,
6868

69+
// The function used to implement `C::heap_size`.
70+
heap_size_fn: $($heap_size_fn:path)?,
71+
6972
// Annoyingly macro-rules hygiene does not extend to items defined in the macro.
7073
// We have the procedural macro generate names for those items that are
7174
// not used elsewhere in the user's code.
@@ -146,6 +149,12 @@ macro_rules! setup_interned_struct {
146149
)?
147150
type Fields<'a> = $StructDataIdent<'a>;
148151
type Struct<'db> = $Struct< $($db_lt_arg)? >;
152+
153+
$(
154+
fn heap_size(value: &Self::Fields<'_>) -> Option<usize> {
155+
Some($heap_size_fn(value))
156+
}
157+
)?
149158
}
150159

151160
impl $Configuration {

components/salsa-macro-rules/src/setup_tracked_fn.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,8 +240,8 @@ macro_rules! setup_tracked_fn {
240240
$($values_equal)+
241241

242242
$(
243-
fn heap_size(value: &Self::Output<'_>) -> usize {
244-
$heap_size_fn(value)
243+
fn heap_size(value: &Self::Output<'_>) -> Option<usize> {
244+
Some($heap_size_fn(value))
245245
}
246246
)?
247247

components/salsa-macro-rules/src/setup_tracked_struct.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ macro_rules! setup_tracked_struct {
8888
// If true, generate a debug impl.
8989
generate_debug_impl: $generate_debug_impl:tt,
9090

91+
// The function used to implement `C::heap_size`.
92+
heap_size_fn: $($heap_size_fn:path)?,
93+
9194
// Annoyingly macro-rules hygiene does not extend to items defined in the macro.
9295
// We have the procedural macro generate names for those items that are
9396
// not used elsewhere in the user's code.
@@ -185,6 +188,12 @@ macro_rules! setup_tracked_struct {
185188
)* false
186189
}
187190
}
191+
192+
$(
193+
fn heap_size(value: &Self::Fields<'_>) -> Option<usize> {
194+
Some($heap_size_fn(value))
195+
}
196+
)?
188197
}
189198

190199
impl $Configuration {

components/salsa-macros/src/input.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ impl crate::options::AllowedOptions for InputStruct {
6565

6666
const REVISIONS: bool = false;
6767

68-
const HEAP_SIZE: bool = false;
68+
const HEAP_SIZE: bool = true;
6969

7070
const SELF_TY: bool = false;
7171
}
@@ -112,6 +112,7 @@ impl Macro {
112112
let field_attrs = salsa_struct.field_attrs();
113113
let is_singleton = self.args.singleton.is_some();
114114
let generate_debug_impl = salsa_struct.generate_debug_impl();
115+
let heap_size_fn = self.args.heap_size_fn.iter();
115116

116117
let zalsa = self.hygiene.ident("zalsa");
117118
let zalsa_struct = self.hygiene.ident("zalsa_struct");
@@ -140,6 +141,7 @@ impl Macro {
140141
num_fields: #num_fields,
141142
is_singleton: #is_singleton,
142143
generate_debug_impl: #generate_debug_impl,
144+
heap_size_fn: #(#heap_size_fn)*,
143145
unused_names: [
144146
#zalsa,
145147
#zalsa_struct,

components/salsa-macros/src/interned.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ impl crate::options::AllowedOptions for InternedStruct {
6565

6666
const REVISIONS: bool = true;
6767

68-
const HEAP_SIZE: bool = false;
68+
const HEAP_SIZE: bool = true;
6969

7070
const SELF_TY: bool = false;
7171
}
@@ -131,6 +131,8 @@ impl Macro {
131131
(None, quote!(#struct_ident), static_lifetime)
132132
};
133133

134+
let heap_size_fn = self.args.heap_size_fn.iter();
135+
134136
let zalsa = self.hygiene.ident("zalsa");
135137
let zalsa_struct = self.hygiene.ident("zalsa_struct");
136138
let Configuration = self.hygiene.ident("Configuration");
@@ -161,6 +163,7 @@ impl Macro {
161163
field_attrs: [#([#(#field_unused_attrs),*]),*],
162164
num_fields: #num_fields,
163165
generate_debug_impl: #generate_debug_impl,
166+
heap_size_fn: #(#heap_size_fn)*,
164167
unused_names: [
165168
#zalsa,
166169
#zalsa_struct,

components/salsa-macros/src/tracked_struct.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ impl crate::options::AllowedOptions for TrackedStruct {
6161

6262
const REVISIONS: bool = false;
6363

64-
const HEAP_SIZE: bool = false;
64+
const HEAP_SIZE: bool = true;
6565

6666
const SELF_TY: bool = false;
6767
}
@@ -141,6 +141,8 @@ impl Macro {
141141
}
142142
});
143143

144+
let heap_size_fn = self.args.heap_size_fn.iter();
145+
144146
let num_tracked_fields = salsa_struct.num_tracked_fields();
145147
let generate_debug_impl = salsa_struct.generate_debug_impl();
146148

@@ -188,6 +190,9 @@ impl Macro {
188190

189191
num_tracked_fields: #num_tracked_fields,
190192
generate_debug_impl: #generate_debug_impl,
193+
194+
heap_size_fn: #(#heap_size_fn)*,
195+
191196
unused_names: [
192197
#zalsa,
193198
#zalsa_struct,

src/database.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,17 +172,24 @@ mod memory_usage {
172172
let mut size_of_fields = 0;
173173
let mut size_of_metadata = 0;
174174
let mut instances = 0;
175+
let mut heap_size_of_fields = None;
175176

176177
for slot in ingredient.memory_usage(self)? {
177178
instances += 1;
178179
size_of_fields += slot.size_of_fields;
179180
size_of_metadata += slot.size_of_metadata;
181+
182+
if let Some(slot_heap_size) = slot.heap_size_of_fields {
183+
heap_size_of_fields =
184+
Some(heap_size_of_fields.unwrap_or_default() + slot_heap_size);
185+
}
180186
}
181187

182188
Some(IngredientInfo {
183189
count: instances,
184190
size_of_fields,
185191
size_of_metadata,
192+
heap_size_of_fields,
186193
debug_name: ingredient.debug_name(),
187194
})
188195
})
@@ -211,6 +218,11 @@ mod memory_usage {
211218
info.count += 1;
212219
info.size_of_fields += memo.output.size_of_fields;
213220
info.size_of_metadata += memo.output.size_of_metadata;
221+
222+
if let Some(memo_heap_size) = memo.output.heap_size_of_fields {
223+
info.heap_size_of_fields =
224+
Some(info.heap_size_of_fields.unwrap_or_default() + memo_heap_size);
225+
}
214226
}
215227
}
216228
}
@@ -226,6 +238,7 @@ mod memory_usage {
226238
count: usize,
227239
size_of_metadata: usize,
228240
size_of_fields: usize,
241+
heap_size_of_fields: Option<usize>,
229242
}
230243

231244
impl IngredientInfo {
@@ -234,11 +247,18 @@ mod memory_usage {
234247
self.debug_name
235248
}
236249

237-
/// Returns the total size of the fields of any instances of this ingredient, in bytes.
250+
/// Returns the total stack size of the fields of any instances of this ingredient, in bytes.
238251
pub fn size_of_fields(&self) -> usize {
239252
self.size_of_fields
240253
}
241254

255+
/// Returns the total heap size of the fields of any instances of this ingredient, in bytes.
256+
///
257+
/// Returns `None` if the ingredient doesn't specify a `heap_size` function.
258+
pub fn heap_size_of_fields(&self) -> Option<usize> {
259+
self.heap_size_of_fields
260+
}
261+
242262
/// Returns the total size of Salsa metadata of any instances of this ingredient, in bytes.
243263
pub fn size_of_metadata(&self) -> usize {
244264
self.size_of_metadata
@@ -255,6 +275,7 @@ mod memory_usage {
255275
pub(crate) debug_name: &'static str,
256276
pub(crate) size_of_metadata: usize,
257277
pub(crate) size_of_fields: usize,
278+
pub(crate) heap_size_of_fields: Option<usize>,
258279
pub(crate) memos: Vec<MemoInfo>,
259280
}
260281

src/function.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ pub trait Configuration: Any {
7575
fn id_to_input(zalsa: &Zalsa, key: Id) -> Self::Input<'_>;
7676

7777
/// Returns the size of any heap allocations in the output value, in bytes.
78-
fn heap_size(_value: &Self::Output<'_>) -> usize {
79-
0
78+
fn heap_size(_value: &Self::Output<'_>) -> Option<usize> {
79+
None
8080
}
8181

8282
/// Invoked when we need to compute the value for the given key, either because we've never

src/function/memo.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -321,14 +321,19 @@ where
321321
#[cfg(feature = "salsa_unstable")]
322322
fn memory_usage(&self) -> crate::database::MemoInfo {
323323
let size_of = std::mem::size_of::<Memo<C>>() + self.revisions.allocation_size();
324-
let heap_size = self.value.as_ref().map(C::heap_size).unwrap_or(0);
324+
let heap_size = if let Some(value) = self.value.as_ref() {
325+
C::heap_size(value)
326+
} else {
327+
Some(0)
328+
};
325329

326330
crate::database::MemoInfo {
327331
debug_name: C::DEBUG_NAME,
328332
output: crate::database::SlotInfo {
329333
size_of_metadata: size_of - std::mem::size_of::<C::Output<'static>>(),
330334
debug_name: std::any::type_name::<C::Output<'static>>(),
331-
size_of_fields: std::mem::size_of::<C::Output<'static>>() + heap_size,
335+
size_of_fields: std::mem::size_of::<C::Output<'static>>(),
336+
heap_size_of_fields: heap_size,
332337
memos: Vec::new(),
333338
},
334339
}

0 commit comments

Comments
 (0)