In the regression suite's own fenced/unfenced A/B (t405_2_NetworkModel_PBL_zonderFence vs
t405_3_NetworkModel_PBL_metFence, NetworkModel_PBL, 12 provinces, one PhaseContainer per
province), the fenced run emits no PhaseContainer(<n>): ... message at all, although that
message is the last statement of a successful PhaseContainerOperator::CalcResult.
This is an observation plus a hypothesis, not a confirmed diagnosis — there is no minimal repro
yet. Filing it because if it holds, a PhaseContainer can be silently inert, which would matter to
users independently of the scheduling work that turned it up.
What was measured
Installed GeoDms 20.10.0.m, GeoDmsRun /S1 /S2 /S3, Windows x64.
- The message is absent. Zero matches for
PhaseContainer in the fenced run's log.
- It is not a log-level artefact.
ST_MajorTrace is otherwise present in that same log:
105 [!][progress], 93 [!][storage read], 36 [!][storage write].
- The message argument is not empty, so the
if (msgData.size() != 1 || !msgData[0].empty())
guard in CalcResult is not what suppresses it. The config builds it as
quote(PhaseString) + quote(regio_name), which parses to Generated output for 'Groningen
(the doubled quote is an escape, so it is one non-empty literal).
- The fenced branch really did run. Its outputs are named from
'_FENCE-' + string(/UseFence)
and all carry FENCE-True.
- Results are correct — the paired indicator test
t405_3_2 passes.
- The fence has no observable effect on execution. Extracting the region segment of every item
path from both logs, the 12 provinces run strictly sequentially in both variants (~43 s each,
no overlap; "regions with an open window per 10 s bucket" is max 2 / mean 0.90 in each). Peak
memory is not lower with the fence: 31 665 MB vs 33 620 MB Highest CommitCharge, and
Reserved in blocks / Highest freed are byte-identical across the two runs.
Point 6 alone does not prove the fence is inert — that model turns out to be serial for its own
reasons (the demand is driven by an AsList(..., ' + ') reduction over the per-province export
drivers), so there was no concurrency for a fence to remove. It is point 1 combined with 2-4 that
suggests CalcResult never completed.
Hypothesis
CreateResultCaller builds a mirror tree whose sub-items get a SupplCache pointing at the
corresponding source item. The consumer here demands a sub-item of that mirror tree by direct
path reference (<regio>/PublicTransport/Generate_Output_metFence/OUTPUT_Generate_fullOD_long_CSVFiles),
not the container. If that sub-item's update resolves through its SupplCache straight to the
source, the source is calculated and the phase is bypassed — while the hook that actually joins the
phase's OperationContext (TreeItem::DoUpdate, rtc/dll/src/tic/TreeItem.cpp) only fires for an
item whose own GetOrgDC() is the PhaseContainer FuncDC, i.e. for the container itself.
That would explain a fence that costs its bookkeeping, produces correct results, and enforces no
ordering — consistent with everything above.
Suggested next step
A minimal repro rather than more inference: a config with two independent expensive branches behind
one PhaseContainer, a consumer that demands a sub-item of the phase, and a second variant whose
consumer demands the container. Compare whether the PhaseContainer(<n>) message appears and
whether getUniqueLicenseToRun's phase gate (m_PhaseNumber > s_CurrActivePhaseNumber) ever
requeues anything. If the sub-item variant is the inert one, the fix is to make a sub-item demand
join the phase the same way the container demand does.
Possibly related: #1128 (PhaseContainer progress deferred until final consumer joins).
In the regression suite's own fenced/unfenced A/B (
t405_2_NetworkModel_PBL_zonderFencevst405_3_NetworkModel_PBL_metFence, NetworkModel_PBL, 12 provinces, onePhaseContainerperprovince), the fenced run emits no
PhaseContainer(<n>): ...message at all, although thatmessage is the last statement of a successful
PhaseContainerOperator::CalcResult.This is an observation plus a hypothesis, not a confirmed diagnosis — there is no minimal repro
yet. Filing it because if it holds, a
PhaseContainercan be silently inert, which would matter tousers independently of the scheduling work that turned it up.
What was measured
Installed GeoDms 20.10.0.m,
GeoDmsRun /S1 /S2 /S3, Windows x64.PhaseContainerin the fenced run's log.ST_MajorTraceis otherwise present in that same log:105
[!][progress], 93[!][storage read], 36[!][storage write].if (msgData.size() != 1 || !msgData[0].empty())guard in
CalcResultis not what suppresses it. The config builds it asquote(PhaseString) + quote(regio_name), which parses toGenerated output for 'Groningen(the doubled quote is an escape, so it is one non-empty literal).
'_FENCE-' + string(/UseFence)and all carry
FENCE-True.t405_3_2passes.path from both logs, the 12 provinces run strictly sequentially in both variants (~43 s each,
no overlap; "regions with an open window per 10 s bucket" is max 2 / mean 0.90 in each). Peak
memory is not lower with the fence: 31 665 MB vs 33 620 MB Highest CommitCharge, and
Reserved in blocks/Highest freedare byte-identical across the two runs.Point 6 alone does not prove the fence is inert — that model turns out to be serial for its own
reasons (the demand is driven by an
AsList(..., ' + ')reduction over the per-province exportdrivers), so there was no concurrency for a fence to remove. It is point 1 combined with 2-4 that
suggests
CalcResultnever completed.Hypothesis
CreateResultCallerbuilds a mirror tree whose sub-items get aSupplCachepointing at thecorresponding source item. The consumer here demands a sub-item of that mirror tree by direct
path reference (
<regio>/PublicTransport/Generate_Output_metFence/OUTPUT_Generate_fullOD_long_CSVFiles),not the container. If that sub-item's update resolves through its
SupplCachestraight to thesource, the source is calculated and the phase is bypassed — while the hook that actually joins the
phase's
OperationContext(TreeItem::DoUpdate,rtc/dll/src/tic/TreeItem.cpp) only fires for anitem whose own
GetOrgDC()is thePhaseContainerFuncDC, i.e. for the container itself.That would explain a fence that costs its bookkeeping, produces correct results, and enforces no
ordering — consistent with everything above.
Suggested next step
A minimal repro rather than more inference: a config with two independent expensive branches behind
one
PhaseContainer, a consumer that demands a sub-item of the phase, and a second variant whoseconsumer demands the container. Compare whether the
PhaseContainer(<n>)message appears andwhether
getUniqueLicenseToRun's phase gate (m_PhaseNumber > s_CurrActivePhaseNumber) everrequeues anything. If the sub-item variant is the inert one, the fix is to make a sub-item demand
join the phase the same way the container demand does.
Possibly related: #1128 (PhaseContainer progress deferred until final consumer joins).