← back

generic_nesting

One generic struct instantiated with itself n levels deep: a chain of `typealias T_i = Pair<Leaf, T_{i-1}>` where `Pair` is constrained to an interface that extends another. Every other generic workload in the suite scales BREADTH (many shallow instantiations); this one scales DEPTH, the axis on which the front-end's substitution / inheritance-witness work is known to multiply per level. The shape arises in real code that composes generic "model"/"module" types recursively (e.g. chained ML evaluator stacks), where each wrapper layer adds one level of nesting. Scaling null: each level adds O(1) declarations, so ideal front-end cost is O(n). Measured behavior when this was added (2026-07): substitution work grows ~3-4x PER LEVEL (exponential), with the wall-clock knee near depth 18 — v2025.14 through tip-of-tree all take ~17-20 s at depth 24. The sweep ladder deliberately stays at or below the knee; the finding to watch is the top rung's multiple of the linear expectation moving.

bucket: sema  ·  compile mode: module  ·  flags: (none)  ·  default N: 16

Phase composition across releases

Full sub-counter decomposition of compileInner — named leaf timers plus (self) residuals (a parent's time not covered by a named child, e.g. the autodiff transform in linkAndOptimizeIR (self)). Topmost band traces compileInner; hover a band for its phase.

Across releases

generic_nesting — Across releases (median ms) generic_nesting 0.03× 0.0 57 114 25.12 25.13 25.14 25.15 25.16 25.17 25.18 25.19 25.20 25.21 25.22 25.23 25.24 26.1 26.2 26.3 26.4 26.5 26.7 26.8 26.9 26.10 26.11 26.12 26.13 26.13.1 26.14 26.14.1 26.16 26.16.1 generic_nesting — parseTranslationUnit generic_nesting — SemanticChecking generic_nesting — generateIR generic_nesting — frontEndExecute (self) generic_nesting — generateOutput (self) generic_nesting — compileInner (self) phase buckets parseTranslationUnit SemanticChecking generateIR frontEndExecute (self) specializeModule simplifyIR linkIR unrollLoopsInModule legalizeResourceTypes legalizeExistentialTypeLayout performMandatoryEarlyInlining performForceInlining linkAndOptimizeIR (self) emitEntryPointsSourceFromIR generateOutput (self) compileInner (self)

Daily tip-of-tree (last 30 days)

generic_nesting — Daily tip-of-tree (last 30 days) (median ms) generic_nesting 0.98× 0.0 1.6 3.3 07-30 07-31 08-01 08-02 08-03 08-04 08-05 08-06 08-07 08-08 08-09 08-10 08-11 08-12 08-13 08-14 08-15 08-15 08-18 08-19 08-20 08-21 08-22 08-23 08-24 08-25 08-26 08-27 08-28 08-29 generic_nesting — parseTranslationUnit generic_nesting — SemanticChecking generic_nesting — generateIR generic_nesting — frontEndExecute (self) generic_nesting — generateOutput (self) generic_nesting — compileInner (self) phase buckets parseTranslationUnit SemanticChecking generateIR frontEndExecute (self) specializeModule simplifyIR linkIR unrollLoopsInModule legalizeResourceTypes legalizeExistentialTypeLayout performMandatoryEarlyInlining performForceInlining linkAndOptimizeIR (self) emitEntryPointsSourceFromIR generateOutput (self) compileInner (self)

Daily window progress

Overall compileInner: 3.0 → 3.0 ms  -2.0%  (2026-07-30 7c58a326b → 2026-08-29 28c755b09)

Contributors — the mutually-exclusive phase buckets (named leaves + (self) residuals) that tile compileInner; the pp column sums to the overall %. Buckets moving the total by ≥0.2% are listed, the rest fold into the remainder row. Below them, every other reported counter (nested/overlapping, e.g. serialized-module reads — own change only):

counterΔown %of total
frontEndExecute (self)-0.0 ms-32.1%-1.5pp
SemanticChecking+0.0 ms+6.0%+1.3pp
generateOutput (self)-0.0 ms-3.8%-1.2pp
generateIR-0.0 ms-0.9%-0.3pp
compileInner (self)-0.0 ms-0.3pp
(remaining 1 buckets)+0.0 ms+0.0pp
loadBuiltinModule-5.0 ms-4.6%
readSerializedModuleIR-2.7 ms-5.0%

Largest day steps (≥5% of the previous day, both directions; bisect with git log <c0>..<c1> -- source/):

boundary% vs prev daycommitstop buckets (own %)
none

Reproduce

Run from the slang repo root. This regenerates the sources below and re-runs this workload's measurement; --gen-dir keeps the generated files (they go to a tempdir and are deleted otherwise).

python3 tools/compile-perf/bench.py --slangc /path/to/slangc --only generic_nesting --label repro --gen-dir repro-generic_nesting

Compiled Slang source

the complete compiled source (N = 16), shown in full

generic_nesting.slang (34 lines)

// AUTO-GENERATED by perf-suite/workloads.py - do not edit by hand.
interface IBase {}
interface IModel : IBase {}
struct Leaf : IModel {}

struct Pair<First : IModel, Second : IModel> : IModel
{
    First first;
    Second second;
}

typealias T0 = Leaf;
typealias T1 = Pair<Leaf, T0>;
typealias T2 = Pair<Leaf, T1>;
typealias T3 = Pair<Leaf, T2>;
typealias T4 = Pair<Leaf, T3>;
typealias T5 = Pair<Leaf, T4>;
typealias T6 = Pair<Leaf, T5>;
typealias T7 = Pair<Leaf, T6>;
typealias T8 = Pair<Leaf, T7>;
typealias T9 = Pair<Leaf, T8>;
typealias T10 = Pair<Leaf, T9>;
typealias T11 = Pair<Leaf, T10>;
typealias T12 = Pair<Leaf, T11>;
typealias T13 = Pair<Leaf, T12>;
typealias T14 = Pair<Leaf, T13>;
typealias T15 = Pair<Leaf, T14>;
typealias T16 = Pair<Leaf, T15>;

T16 value;

[shader("compute")]
[numthreads(1, 1, 1)]
void computeMain() {}