19 "base": "bdce49a66c74c9a8f993578e31a7c9aa0fac52bb",
20 "head": "bdce49a66c74c9a8f993578e31a7c9aa0fac52bb",
21 "cob": "d41501595d48ce727e31b0da9069675cee207a0d"
22+ },
23+ {
24+ "base": "bdce49a66c74c9a8f993578e31a7c9aa0fac52bb",
25+ "head": "5637ecc41deeda7a6c37a28a721fcb49a6b11010",
26+ "cob": "3c20aff5d9ebe67bb3376c8fb0b433b281436f07"
27 }
28 ]
29 }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.
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."}}
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)
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
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
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