Skip to content

Commit a0eb54e

Browse files
authored
feat: add more shader group diagnostics to compile_report (#2085)
When compile_report >= 1, report several new post-optimization stats for the shader group: * Number of active (non-unused) layers * Maximum connection depth of the shader network (node count along the longest layer-to-layer chain, so a single unconnected node = 1 and a chain A->B->C = 3) * Number of texture ops (texture, environment, gettextureinfo, texture3d) * Number of noise ops Note that these stats (number of layers, texture ops, noise ops) are the total number in the post-optimized shader, but not the number that will be run on any particular execution of the shader. Trivial example: the noise calls may all be inside an "if" statement with a condition that is never true in practice, but that can't be known ahead of time. In the other direction, a loop with noise calls in the body will underestimate how many calls are made in each shader run. So take with a grain of salt -- these stats are related overall shader code complexity, but not necessarily to execution cost. Coded via pair programming with Claude Code, using the Claude Sonnet 4.6 model. --------- Signed-off-by: Larry Gritz <lg@larrygritz.com>
1 parent 344fded commit a0eb54e

File tree

1 file changed

+38
-4
lines changed

1 file changed

+38
-4
lines changed

src/liboslexec/runtimeoptimize.cpp

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3278,11 +3278,15 @@ RuntimeOptimizer::run()
32783278
m_userdata_needed.clear();
32793279
m_attributes_needed.clear();
32803280
bool does_nothing = true;
3281+
int active_layers = 0;
3282+
int n_texture_ops = 0;
3283+
int n_noise_ops = 0;
32813284
std::vector<uint8_t> interactive_data;
32823285
for (int layer = 0; layer < nlayers; ++layer) {
32833286
set_inst(layer);
32843287
if (inst()->unused())
32853288
continue; // no need to print or gather stats for unused layers
3289+
++active_layers;
32863290
FOREACH_SYM(Symbol & s, inst())
32873291
{
32883292
// set the layer numbers
@@ -3355,6 +3359,7 @@ RuntimeOptimizer::run()
33553359
}
33563360
}
33573361
if (opd->flags & OpDescriptor::Tex) {
3362+
++n_texture_ops;
33583363
// for all the texture ops, arg 1 is the texture name
33593364
Symbol* sym = opargsym(op, 1);
33603365
OSL_DASSERT(sym && sym->typespec().is_string());
@@ -3364,6 +3369,13 @@ RuntimeOptimizer::run()
33643369
m_unknown_textures_needed = true;
33653370
}
33663371
}
3372+
if (op.opname() == Strings::noise || op.opname() == Strings::snoise
3373+
|| op.opname() == Strings::pnoise
3374+
|| op.opname() == Strings::psnoise
3375+
|| op.opname() == Strings::cellnoise
3376+
|| op.opname() == Strings::hashnoise) {
3377+
++n_noise_ops;
3378+
}
33673379
if (op.opname() == u_closure) {
33683380
// It's either 'closure result weight name' or 'closure result name'
33693381
Symbol* sym = opargsym(op, 1); // arg 1 is the closure name
@@ -3445,6 +3457,23 @@ RuntimeOptimizer::run()
34453457
group().does_nothing(does_nothing);
34463458
group().setup_interactive_arena(interactive_data);
34473459

3460+
// Compute the maximum depth of the shader network: the length of the
3461+
// longest chain of layer-to-layer connections. Layers are already in
3462+
// topological order, so a single forward pass suffices.
3463+
std::vector<int> layer_depth(nlayers, 0);
3464+
int max_network_depth = 0;
3465+
for (int layer = 0; layer < nlayers; ++layer) {
3466+
if (group()[layer]->unused())
3467+
continue;
3468+
layer_depth[layer] = 1;
3469+
for (auto&& c : group()[layer]->connections()) {
3470+
if (!group()[c.srclayer]->unused())
3471+
layer_depth[layer] = std::max(layer_depth[layer],
3472+
layer_depth[c.srclayer] + 1);
3473+
}
3474+
max_network_depth = std::max(max_network_depth, layer_depth[layer]);
3475+
}
3476+
34483477
m_stat_specialization_time = rop_timer();
34493478
{
34503479
// adjust memory stats
@@ -3468,26 +3497,31 @@ RuntimeOptimizer::run()
34683497
new_nops, old_nops,
34693498
100.0 * double((long long)new_nops - (long long)old_nops)
34703499
/ double(old_nops));
3500+
shadingcontext()->infofmt(" Group active layers: {}", active_layers);
3501+
shadingcontext()->infofmt(" Group network connection depth: {}",
3502+
max_network_depth);
3503+
shadingcontext()->infofmt(" Group texture ops: {}", n_texture_ops);
3504+
shadingcontext()->infofmt(" Group noise ops: {}", n_noise_ops);
34713505
}
34723506
if (shadingsys().m_compile_report > 1) {
34733507
if (does_nothing)
3474-
shadingcontext()->infofmt("Group does nothing");
3508+
shadingcontext()->infofmt(" Group does nothing");
34753509
if (m_textures_needed.size()) {
3476-
shadingcontext()->infofmt("Group needs textures:");
3510+
shadingcontext()->infofmt(" Group needs textures:");
34773511
for (auto&& f : m_textures_needed)
34783512
shadingcontext()->infofmt(" {}", f);
34793513
if (m_unknown_textures_needed)
34803514
shadingcontext()->infofmt(
34813515
" Also may construct texture names on the fly.");
34823516
}
34833517
if (m_userdata_needed.size()) {
3484-
shadingcontext()->infofmt("Group potentially needs userdata:");
3518+
shadingcontext()->infofmt(" Group potentially needs userdata:");
34853519
for (auto&& f : m_userdata_needed)
34863520
shadingcontext()->infofmt(" {} {} {}", f.name, f.type,
34873521
f.derivs ? "(derivs)" : "");
34883522
}
34893523
if (m_attributes_needed.size()) {
3490-
shadingcontext()->infofmt("Group needs attributes:");
3524+
shadingcontext()->infofmt(" Group needs attributes:");
34913525
for (auto&& f : m_attributes_needed)
34923526
shadingcontext()->infofmt(" {} {} {}", f.name, f.scope,
34933527
f.type);

0 commit comments

Comments
 (0)