Experiment: b14aa7b
rad experiment show b14aa7bd85cd31bc51fd9650dbf10315e58ba03d
by lftherioslftherios@did:key:z6MkupQHdQky5atyAu9zF8dUu1EavUjckDgCdZLH8y2W8teE · Apr 21 14:34 2026
Fuse Semantics code generation around parsed variant data arrays instead of building multiple per-variant TokenStream vectors.
Measurements
MetricBaselineThe benchmark measurement of the unmodified codeCandidateThe code with the proposed optimization appliedCandidate/Parent ΔThe performance change from baseline to candidate
total_µs (µs) primary
Optimize the `luminance-derive` procedural macro implementation for lower code generation time on a synthetic workload that repeatedly parses and expands large `Semantics`, `Vertex`, and `UniformInterface` derive inputs.
569920.000 µs (n=1)541087.000 µs (n=1)-5.05%
semantics_µs secondary241609.000 (n=1)214890.000 (n=1)-11.05% REGRESSED
uniform_µs secondary250157.000 (n=1)248647.000 (n=1)-0.60% REGRESSED
vertex_µs secondary78154.000 (n=1)77550.000 (n=1)-0.77% REGRESSED
Annotations
hypothesisSemantics still spent time creating several parallel TokenStream vectors; expanding directly from stored parsed data should reduce quote/allocation overhead in that hot path.
idea_backlog_prunedRemoved the Semantics-specific fusion backlog item because it is now implemented; next promising path is analogous Vertex fusion or shared attribute decoding.
observed_effectLarge semantics-specific win with a meaningful follow-on total improvement; uniform also improved slightly while vertex stayed near prior levels.
Base CommitThe starting commit before the optimization was applied5637ecc41deeda7a6c37a28a721fcb49a6b11010
Candidate CommitThe code with the proposed optimization applied428547431bf34ee6b8053c205c704dad8929ed4a
Bench scriptba27946dedc9
bench_cmdbash autoresearch.sh
Schemav5
Diff
~ .community-computer/published.json
@@ -19,6 +19,11 @@
19 "base": "bdce49a66c74c9a8f993578e31a7c9aa0fac52bb", 20 "head": "bdce49a66c74c9a8f993578e31a7c9aa0fac52bb", 21 "cob": "d41501595d48ce727e31b0da9069675cee207a0d" 22+ }, 23+ { 24+ "base": "bdce49a66c74c9a8f993578e31a7c9aa0fac52bb", 25+ "head": "5637ecc41deeda7a6c37a28a721fcb49a6b11010", 26+ "cob": "3c20aff5d9ebe67bb3376c8fb0b433b281436f07" 27 } 28 ] 29 }
~ autoresearch.ideas.md
@@ -1,2 +1,2 @@
1 - Try a shared fast attribute decoder in `attrib.rs` for `sem`, `vertex`, and `uniform` that returns parsed small structs while preserving current error messages; this may reduce both duplicated logic and any remaining parsing overhead. 2-- Investigate `Semantics` token assembly specifically: it still builds several per-variant token vectors (`parse_branches`, `name_branches`, `semantics_set`, `field_based_gen`), so a more fused representation might reduce remaining `semantics_µs`. 2+- Investigate whether `Vertex` can mirror the successful `Semantics` fusion approach by collecting field metadata into simple arrays/records first and expanding from those directly instead of accumulating per-field token fragments.
~ autoresearch.jsonl
@@ -4,3 +4,4 @@
4 {"run":3,"commit":"bdce49a","metric":574489,"metrics":{"semantics_µs":241015,"vertex_µs":75411,"uniform_µs":258063},"status":"keep","description":"Parse Vertex type attributes in one pass so sem and instanced are decoded from a single meta walk.","timestamp":1776781680572,"segment":0,"confidence":17.37102547904822,"iterationTokens":8993,"asi":{"hypothesis":"Vertex still reparses struct-level attributes for `sem` and `instanced`; combining those lookups should shave a smaller but real amount off total codegen time.","observed_effect":"Modest follow-up improvement with the expected drop in vertex_µs and slight reductions elsewhere from lower overall parsing work.","confidence_note":"Third run establishes that the single-pass parsing direction consistently improves the benchmark."}} 5 {"run":4,"commit":"bdce49a","metric":577503,"metrics":{"semantics_µs":241770,"vertex_µs":76188,"uniform_µs":259545},"status":"discard","description":"Preallocate token vector capacities from known field and variant counts to reduce small Vec growth overhead.","timestamp":1776781735933,"segment":0,"confidence":34.74205095809644,"iterationTokens":6468,"asi":{"hypothesis":"Some remaining overhead might come from repeated Vec growth while collecting quote fragments, so reserving exact capacities could yield a cheap incremental win.","rollback_reason":"The capacity reservations were within benchmark noise and slightly worse than the current best run, so they are not worth keeping.","next_action_hint":"Focus on reducing token construction/allocation work or simplifying generated quote structure rather than container bookkeeping."}} 6 {"run":5,"commit":"bdce49a","metric":580006,"metrics":{"semantics_µs":243093,"vertex_µs":78819,"uniform_µs":258094},"status":"discard","description":"Inline Vertex field normalized parsing to avoid the generic attribute helper on the hot per-field path.","timestamp":1776781806221,"segment":0,"confidence":47.54755043227666,"iterationTokens":6596,"asi":{"hypothesis":"Even one generic helper call per vertex field might add measurable overhead, so specializing normalized parsing could further reduce vertex_µs.","rollback_reason":"Specializing the per-field parser did not beat the current best and slightly regressed the benchmark overall.","next_action_hint":"Investigate token generation/allocation costs next; attribute parsing likely delivered most of the easy win already.","ideas_backlog_updated":true}} 7+{"run":6,"commit":"5637ecc","metric":569920,"metrics":{"semantics_µs":241609,"vertex_µs":78154,"uniform_µs":250157},"status":"keep","description":"Reduce intermediate quote fragment churn by emitting Semantics, Vertex, and UniformInterface tokens more directly.","timestamp":1776781959754,"segment":0,"confidence":31.562080841036796,"iterationTokens":15670,"asi":{"hypothesis":"After the parsing wins, remaining overhead likely comes from constructing and nesting many temporary quote fragments, so flattening token assembly should cut allocation/churn in code generation.","observed_effect":"Best result so far; the biggest gain showed up in UniformInterface token generation while Semantics stayed roughly flat and Vertex regressed slightly but was outweighed by the uniform win.","idea_backlog_pruned":"Replaced the broad direct-token-assembly backlog item with narrower follow-ups for shared attribute decoding and Semantics-specific fusion."}}
~ autoresearch.md
@@ -34,3 +34,4 @@ Optimize the `luminance-derive` procedural macro implementation for lower code g
34 - Replaced repeated `attr.parse_meta()` passes in `Semantics` and `UniformInterface` attribute parsing with single-pass scanners that collect all needed subkeys at once. This strongly improved `semantics_µs` and `uniform_µs` while leaving `vertex_µs` roughly flat. 35 - Applied the same single-pass parsing idea to `Vertex` type-level attributes (`sem` and `instanced`). This produced a modest extra win, mainly by trimming `vertex_µs` and a bit of total overhead. 36 - Reduced intermediate `quote!` fragment churn by emitting token fragments more directly in `Semantics`, `UniformInterface`, and `Vertex` code assembly. This produced the best total result so far, with most of the gain coming from a notably faster `uniform_µs` path. 37+- Fused `Semantics` token generation further by collecting parsed variant data once and expanding directly from those arrays instead of first building multiple per-variant `TokenStream` vectors. This produced a large additional `semantics_µs` win and the strongest total result so far.
~ luminance-derive/src/semantics.rs
@@ -114,81 +114,21 @@ pub(crate) fn generate_enum_semantics_impl(
114 ident: Ident, 115 enum_: DataEnum 116 ) -> Result<proc_macro2::TokenStream, SemanticsImplError> { 117- let fields = enum_.variants.into_iter().map(|var| { 118- get_vertex_sem_attribs(&var.ident, var.attrs.iter()).map(|attrs| { 119- (var.ident, attrs.0, attrs.1, attrs.2) 120- }) 121- }); 122- 123- let mut parse_branches = Vec::new(); 124- let mut name_branches = Vec::new(); 125- let mut field_based_gen = Vec::new(); 126- let mut semantics_set = Vec::new(); 127- 117+ let mut indices = Vec::new(); 118+ let mut sem_vars = Vec::new(); 119+ let mut sem_names = Vec::new(); 120+ let mut repr_ty_names = Vec::new(); 121+ let mut ty_names = Vec::new(); 122 let mut errors = Vec::new(); 123 130- for (index, field) in fields.enumerate() { 131- match field { 132- Ok(field) => { 133- // parse branches 134- let sem_var = field.0; 135- let sem_name = field.1.to_string(); 136- let repr_ty_name = field.2; 137- let ty_name = field.3; 138- 139- // dynamic branch used for parsing the semantics from a string 140- parse_branches.push(quote!{ 141- #sem_name => Ok(#ident::#sem_var) 142- }); 143- 144- // name of a semantics 145- name_branches.push(quote!{ 146- #ident::#sem_var => #sem_name 147- }); 148- 149- semantics_set.push(quote!{ 150- luminance::vertex::SemanticsDesc { 151- index: #index, 152- name: #sem_name.to_owned() 153- } 154- }); 155- 156- field_based_gen.push(quote!{ 157- // vertex attrib type 158- #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] 159- pub struct #ty_name { 160- repr: #repr_ty_name 161- } 162- 163- // convert from the repr type to the vertex attrib type 164- impl From<#repr_ty_name> for #ty_name { 165- fn from(repr: #repr_ty_name) -> Self { 166- #ty_name::new(repr) 167- } 168- } 169- 170- // convert from the repr type to the vertex attrib type 171- impl #ty_name { 172- pub const fn new(repr: #repr_ty_name) -> Self { 173- #ty_name { 174- repr 175- } 176- } 177- } 178- 179- // get the associated semantics 180- impl luminance::vertex::HasSemantics for #ty_name { 181- type Sem = #ident; 182- 183- const SEMANTICS: Self::Sem = #ident::#sem_var; 184- } 185- 186- // make the vertex attrib impl VertexAttrib by forwarding implementation to the repr type 187- unsafe impl luminance::vertex::VertexAttrib for #ty_name { 188- const VERTEX_ATTRIB_DESC: luminance::vertex::VertexAttribDesc = 189- <#repr_ty_name as luminance::vertex::VertexAttrib>::VERTEX_ATTRIB_DESC; 190- } 191- }); 124+ for (index, var) in enum_.variants.into_iter().enumerate() { 125+ match get_vertex_sem_attribs(&var.ident, var.attrs.iter()) { 126+ Ok((sem_name, sem_repr, sem_wrapper)) => { 127+ indices.push(index); 128+ sem_vars.push(var.ident); 129+ sem_names.push(sem_name.to_string()); 130+ repr_ty_names.push(sem_repr); 131+ ty_names.push(sem_wrapper); 132 } 133 134 Err(e) => errors.push(e)
@@ -199,7 +139,7 @@ pub(crate) fn generate_enum_semantics_impl(
139 return Err(SemanticsImplError::AttributeErrors(errors)); 140 } 141 202- if semantics_set.is_empty() { 142+ if sem_vars.is_empty() { 143 return Err(SemanticsImplError::NoField); 144 } 145
@@ -211,12 +151,19 @@ pub(crate) fn generate_enum_semantics_impl(
151 152 fn name(&self) -> &'static str { 153 match *self { 214- #(#name_branches,)* 154+ #( #ident::#sem_vars => #sem_names, )* 155 } 156 } 157 158 fn semantics_set() -> Vec<luminance::vertex::SemanticsDesc> { 219- vec![#(#semantics_set,)*] 159+ vec![ 160+ #( 161+ luminance::vertex::SemanticsDesc { 162+ index: #indices, 163+ name: #sem_names.to_owned() 164+ } 165+ ),* 166+ ] 167 } 168 } 169
@@ -226,13 +173,48 @@ pub(crate) fn generate_enum_semantics_impl(
173 174 fn from_str(name: &str) -> Result<Self, Self::Err> { 175 match name { 229- #(#parse_branches,)* 176+ #( #sem_names => Ok(#ident::#sem_vars), )* 177 _ => Err(()) 178 } 179 } 180 } 181 235- #(#field_based_gen)* 182+ #( 183+ // vertex attrib type 184+ #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] 185+ pub struct #ty_names { 186+ repr: #repr_ty_names 187+ } 188+ 189+ // convert from the repr type to the vertex attrib type 190+ impl From<#repr_ty_names> for #ty_names { 191+ fn from(repr: #repr_ty_names) -> Self { 192+ #ty_names::new(repr) 193+ } 194+ } 195+ 196+ // convert from the repr type to the vertex attrib type 197+ impl #ty_names { 198+ pub const fn new(repr: #repr_ty_names) -> Self { 199+ #ty_names { 200+ repr 201+ } 202+ } 203+ } 204+ 205+ // get the associated semantics 206+ impl luminance::vertex::HasSemantics for #ty_names { 207+ type Sem = #ident; 208+ 209+ const SEMANTICS: Self::Sem = #ident::#sem_vars; 210+ } 211+ 212+ // make the vertex attrib impl VertexAttrib by forwarding implementation to the repr type 213+ unsafe impl luminance::vertex::VertexAttrib for #ty_names { 214+ const VERTEX_ATTRIB_DESC: luminance::vertex::VertexAttribDesc = 215+ <#repr_ty_names as luminance::vertex::VertexAttrib>::VERTEX_ATTRIB_DESC; 216+ } 217+ )* 218 }) 219 } 220
Environment
Archaarch64
OSDarwin 26.3.1
CPUApple M1 Max
Agentpi-autoresearch / pi
Files.community-computer/published.json, autoresearch.ideas.md, autoresearch.jsonl, autoresearch.md, luminance-derive/src/semantics.rs