@@ -1181,6 +1181,10 @@ void TPlan::LoadStage(std::shared_ptr<TStage> stage, const NJson::TJsonValue& no
11811181 if (auto * wotNode = stage->StatsNode ->GetValueByPath (" WaitOutputTimeUs" )) {
11821182 stage->WaitOutputTime = std::make_shared<TSingleMetric>(WaitOutputTime, *wotNode, stage->MinTime , stage->MaxTime );
11831183 }
1184+
1185+ if (auto * updateTimeNode = stage->StatsNode ->GetValueByPath (" UpdateTimeMs" )) {
1186+ stage->UpdateTime = updateTimeNode->GetIntegerSafe ();
1187+ }
11841188 }
11851189
11861190 if (stage->IngressBytes ) {
@@ -1214,6 +1218,7 @@ void TPlan::LoadStage(std::shared_ptr<TStage> stage, const NJson::TJsonValue& no
12141218 }
12151219
12161220 Max0 (MaxTime, stage->MaxTime );
1221+ Max0 (UpdateTime, stage->UpdateTime );
12171222}
12181223
12191224void TPlan::LoadSource (const NJson::TJsonValue& node, std::vector<TOperatorInfo>& stageOperators, const NJson::TJsonValue* ingressRowsNode) {
@@ -1534,7 +1539,7 @@ void TPlan::PrintStageSummary(TStringBuilder& background, TStringBuilder&, ui32
15341539 }
15351540}
15361541
1537- void TPlan::PrintSvg (ui64 maxTime, ui32& offsetY, TStringBuilder& background, TStringBuilder& canvas) {
1542+ void TPlan::PrintSvg (ui64 maxTime, ui32 timelineDelta, ui32 & offsetY, TStringBuilder& background, TStringBuilder& canvas) {
15381543 OffsetY = offsetY;
15391544 ui32 planHeight = 0 ;
15401545
@@ -1637,8 +1642,8 @@ void TPlan::PrintSvg(ui64 maxTime, ui32& offsetY, TStringBuilder& background, TS
16371642 ui32 y0 = s->OffsetY + offsetY + INTERNAL_GAP_Y;
16381643
16391644 auto tx0 = Config.TimelineLeft ;
1640- auto px = tx0 + TimeOffset * Config.TimelineWidth / maxTime;
1641- auto pw = MaxTime * Config.TimelineWidth / maxTime;
1645+ auto px = tx0 + TimeOffset * ( Config.TimelineWidth - timelineDelta) / maxTime;
1646+ auto pw = MaxTime * ( Config.TimelineWidth - timelineDelta) / maxTime;
16421647
16431648 if (s->External ) {
16441649 canvas
@@ -2191,6 +2196,7 @@ void TPlanVisualizer::PostProcessPlans() {
21912196 for (auto & p : Plans) {
21922197 p.TimeOffset = p.BaseTime - BaseTime;
21932198 MaxTime = std::max (MaxTime, p.TimeOffset + p.MaxTime );
2199+ UpdateTime = std::max (UpdateTime, p.TimeOffset + p.UpdateTime );
21942200 }
21952201}
21962202
@@ -2208,6 +2214,7 @@ TString TPlanVisualizer::PrintSvg() {
22082214 TStringBuilder svg;
22092215
22102216 ui32 offsetY = 0 ;
2217+ ui32 timelineDelta = (UpdateTime > MaxTime) ? std::min<ui32>(Config.TimelineWidth * (UpdateTime - MaxTime) / UpdateTime, Config.TimelineWidth / 10 ) : 0 ;
22112218
22122219 ui32 summary3 = (Config.SummaryWidth - INTERNAL_GAP_X * 2 ) / 3 ;
22132220 for (auto & p : Plans) {
@@ -2278,7 +2285,7 @@ TString TPlanVisualizer::PrintSvg() {
22782285 << " ' y='" << offsetY + INTERNAL_TEXT_HEIGHT * 2 + GAP_Y<< " '>" << FormatBytes (p.MaxMemoryUsage ->Value ) << " </text>" << Endl
22792286 << " </g>" << Endl;
22802287
2281- auto x = Config.TimelineLeft + Config.TimelineWidth * (p.MaxTime + p.TimeOffset ) / MaxTime;
2288+ auto x = Config.TimelineLeft + ( Config.TimelineWidth - timelineDelta) * (p.MaxTime + p.TimeOffset ) / MaxTime;
22822289 canvas
22832290 << " <g><title>" << " Duration: " << FormatTimeMs (p.MaxTime ) << " , Total " << FormatTimeMs (p.MaxTime + p.TimeOffset ) << " </title>" << Endl
22842291 << " <rect x='" << x - summary3 << " ' y='" << offsetY
@@ -2297,7 +2304,7 @@ TString TPlanVisualizer::PrintSvg() {
22972304 p.PrintDeriv (canvas, p.TotalCpuTime , tx0, offsetY, tw, INTERNAL_HEIGHT, " Max CPU " + FormatMCpu (maxCpu), Config.Palette .CpuMedium , Config.Palette .CpuLight );
22982305 }
22992306 offsetY += INTERNAL_HEIGHT;
2300- p.PrintSvg (MaxTime, offsetY, background, canvas);
2307+ p.PrintSvg (MaxTime, timelineDelta, offsetY, background, canvas);
23012308 }
23022309
23032310 svg << " <svg width='" << Config.Width << " ' height='" << offsetY << " ' xmlns='http://www.w3.org/2000/svg'>" << Endl;
@@ -2354,7 +2361,7 @@ TString TPlanVisualizer::PrintSvg() {
23542361 }
23552362
23562363 auto x = Config.TimelineLeft + INTERNAL_GAP_X;
2357- auto w = Config.TimelineWidth - INTERNAL_GAP_X * 2 ;
2364+ auto w = Config.TimelineWidth - timelineDelta - INTERNAL_GAP_X * 2 ;
23582365
23592366 for (ui64 t = 0 ; t < maxSec; t += deltaSec) {
23602367 ui64 x1 = t * w / maxSec;
@@ -2371,6 +2378,22 @@ TString TPlanVisualizer::PrintSvg() {
23712378 }
23722379 }
23732380
2381+ if (timelineDelta) {
2382+ auto opacity = MaxTime ? std::min (0.5 , static_cast <double >(UpdateTime - MaxTime) / (2 * MaxTime)) : 0.5 ;
2383+ svg
2384+ << " <rect x='" << Config.TimelineLeft + Config.TimelineWidth - timelineDelta << " ' y='" << 0
2385+ << " ' width='" << timelineDelta << " ' height='" << offsetY
2386+ << " ' stroke-width='0' opacity='" << opacity << " ' fill='" << Config.Palette .StageTextHighlight << " '/>" << Endl;
2387+ svg
2388+ << " <g><title>" << " Last Update: " << FormatTimeMs (UpdateTime) << " </title>" << Endl
2389+ << " <rect x='" << Config.TimelineLeft + Config.TimelineWidth - summary3 << " ' y='" << GAP_Y
2390+ << " ' width='" << summary3 << " ' height='" << TIME_HEIGHT
2391+ << " ' stroke-width='0' fill='" << Config.Palette .StageTextHighlight << " '/>" << Endl
2392+ << " <text text-anchor='end' font-family='Verdana' font-size='" << INTERNAL_TEXT_HEIGHT << " px' fill='" << Config.Palette .TextInverted << " ' x='" << Config.TimelineLeft + Config.TimelineWidth - 2
2393+ << " ' y='" << GAP_Y + INTERNAL_TEXT_HEIGHT << " '>" << FormatTimeMs (UpdateTime) << " </text>" << Endl
2394+ << " </g>" << Endl;
2395+ }
2396+
23742397 svg << TString (canvas) << Endl;
23752398 svg << " </svg>" << Endl;
23762399
0 commit comments