Skip to content

Commit 28cecee

Browse files
authored
Improve performance for large pipeline graphs (#503)
1 parent 434d2ab commit 28cecee

File tree

7 files changed

+252
-189
lines changed

7 files changed

+252
-189
lines changed

src/main/java/io/jenkins/plugins/pipelinegraphview/treescanner/NodeRelationship.java

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,6 @@ public NodeRelationship(@NonNull FlowNode start, @NonNull FlowNode end, @CheckFo
3737
this.end = end;
3838
}
3939

40-
// Print debug message if 'isDebugEnabled' is true.
41-
protected void dump(String message, Object... args) {
42-
if (isDebugEnabled) {
43-
logger.debug(String.format(message, args));
44-
}
45-
}
46-
4740
/*
4841
* Returns the recorded node that was run before this node
4942
* Returns null if unset (e.g.)
@@ -92,9 +85,13 @@ public FlowNode getEnd() {
9285
*/
9386
public @NonNull TimingInfo getTimingInfo(@NonNull WorkflowRun run) {
9487
long pause = PauseAction.getPauseDuration(this.start);
95-
dump(
96-
"Calculating Chunk Timing info start: %s, end: %s after: %s",
97-
this.start.getId(), this.end.getId(), (this.after != null) ? this.after.getId() : "null");
88+
if (isDebugEnabled) {
89+
logger.debug(
90+
"Calculating Chunk Timing info start: {}, end: {} after: {}",
91+
this.start.getId(),
92+
this.end.getId(),
93+
(this.after != null) ? this.after.getId() : "null");
94+
}
9895
TimingInfo timing = StatusAndTiming.computeChunkTiming(run, pause, this.start, this.end, this.after);
9996
if (timing != null) {
10097
return timing;
@@ -112,9 +109,13 @@ public FlowNode getEnd() {
112109
} else if (PipelineNodeUtil.isPaused(this.end)) {
113110
return new NodeRunStatus(BlueRun.BlueRunResult.UNKNOWN, BlueRun.BlueRunState.PAUSED);
114111
}
115-
dump(
116-
"Calculating Chunk Status start: %s, end: %s after: %s",
117-
this.start.getId(), this.end.getId(), (this.after != null) ? this.after.getId() : "null");
112+
if (isDebugEnabled) {
113+
logger.debug(
114+
"Calculating Chunk Status start: {}, end: {} after: {}",
115+
this.start.getId(),
116+
this.end.getId(),
117+
(this.after != null) ? this.after.getId() : "null");
118+
}
118119

119120
// If start and end are equal this is a StepNode
120121
if (this.start.getId().equals(this.end.getId())) {

src/main/java/io/jenkins/plugins/pipelinegraphview/treescanner/NodeRelationshipFinder.java

Lines changed: 54 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,6 @@ public class NodeRelationshipFinder {
4242

4343
private LinkedHashMap<String, NodeRelationship> relationships = new LinkedHashMap<>();
4444

45-
// Print debug message if 'isDebugEnabled' is true.
46-
private void dump(String message, Object... args) {
47-
if (isDebugEnabled) {
48-
logger.debug(String.format(message, args));
49-
}
50-
}
51-
5245
public NodeRelationshipFinder() {}
5346

5447
/**
@@ -57,14 +50,18 @@ public NodeRelationshipFinder() {}
5750
@NonNull
5851
public LinkedHashMap<String, NodeRelationship> getNodeRelationships(
5952
@NonNull LinkedHashMap<String, FlowNode> nodeMap) {
60-
dump("Original Ids: %s", String.join(", ", nodeMap.keySet()));
53+
if (isDebugEnabled) {
54+
logger.debug("Original Ids: {}", String.join(", ", nodeMap.keySet()));
55+
}
6156
// This is important, determining the the relationships depends on the order of
6257
// iteration.
6358
// If there was a method to tell if a node was a parallel block this might be
6459
// less of an issue.
6560
List<String> sortedIds = new ArrayList<>(nodeMap.keySet());
6661
Collections.sort(sortedIds, new FlowNodeWrapper.NodeIdComparator().reversed());
67-
dump("Sorted Ids: %s", String.join(", ", sortedIds));
62+
if (isDebugEnabled) {
63+
logger.debug("Sorted Ids: {}", String.join(", ", sortedIds));
64+
}
6865
for (String id : sortedIds) {
6966
getRelationshipForNode(nodeMap.get(id));
7067
// Add this node to the parents's stack as the last of it's child nodes that
@@ -90,15 +87,17 @@ private void handleBlockStart(@NonNull FlowNode node) {
9087
if (FlowNodeWrapper.isStart(node)) {
9188
addBlockRelationship(node);
9289
} else {
93-
dump("Why are we here?? %s - %s", node.getId(), node.getClass());
90+
logger.debug("Why are we here?? {} - {}", node.getId(), node.getClass());
9491
}
9592
}
9693

9794
private void addSeenNodes(FlowNode node) {
9895
if (!seenChildNodes.keySet().contains(node.getEnclosingId())) {
9996
seenChildNodes.put(node.getEnclosingId(), new ArrayDeque<FlowNode>());
10097
}
101-
dump("Adding %s to seenChildNodes %s", node.getId(), node.getEnclosingId());
98+
if (isDebugEnabled) {
99+
logger.debug("Adding {} to seenChildNodes {}", node.getId(), node.getEnclosingId());
100+
}
102101
seenChildNodes.get(node.getEnclosingId()).push(node);
103102
}
104103

@@ -113,9 +112,13 @@ private FlowNode getAfterNode(FlowNode node) {
113112
// If there are no later siblings, get the parents later sibling.
114113
ArrayDeque<FlowNode> parentsLaterSiblings = getProcessedChildren(getFirstEnclosingNode(parentStartNode));
115114
after = parentsLaterSiblings.isEmpty() ? null : parentsLaterSiblings.peek();
116-
dump(parentsLaterSiblings.toString());
115+
if (isDebugEnabled) {
116+
logger.debug(parentsLaterSiblings.toString());
117+
}
117118
} else {
118-
dump(laterSiblings.toString());
119+
if (isDebugEnabled) {
120+
logger.debug(laterSiblings.toString());
121+
}
119122
after = laterSiblings.peek();
120123
}
121124
return after;
@@ -136,15 +139,19 @@ private ArrayDeque<FlowNode> getProcessedChildren(@CheckForNull FlowNode node) {
136139
}
137140

138141
private void addStepRelationship(@NonNull StepAtomNode step) {
139-
dump("Generating relationship for step %s", step.getId());
142+
if (isDebugEnabled) {
143+
logger.debug("Generating relationship for step {}", step.getId());
144+
}
140145
// FlowNode after = subsequentNode;
141146
FlowNode after = getAfterNode(step);
142-
dump(
143-
"Adding step for %s(%s),%s(%s)",
144-
step.getId(),
145-
step.getClass().getName(),
146-
after == null ? "null" : after.getId(),
147-
after == null ? "null" : after.getClass().getName());
147+
if (isDebugEnabled) {
148+
logger.debug(
149+
"Adding step for {}({}),{}({})",
150+
step.getId(),
151+
step.getClass().getName(),
152+
after == null ? "null" : after.getId(),
153+
after == null ? "null" : after.getClass().getName());
154+
}
148155
NodeRelationship nodeRelationship = new NodeRelationship(step, step, after);
149156
relationships.put(step.getId(), nodeRelationship);
150157
}
@@ -166,7 +173,9 @@ private void addBlockRelationship(@NonNull FlowNode node) {
166173
if (PipelineNodeUtil.isParallelBranch(node)) {
167174
addParallelBranchRelationship(node, endNode);
168175
} else {
169-
dump("Adding relationship for %s", node.getId());
176+
if (isDebugEnabled) {
177+
logger.debug("Adding relationship for {}", node.getId());
178+
}
170179
if (!pendingBranchRelationships.isEmpty()) {
171180
blockRelationship = addParallelRelationship(node, endNode);
172181
} else {
@@ -186,12 +195,14 @@ private void addParallelBranchRelationship(@NonNull FlowNode node, @NonNull Flow
186195
// Store a parallel branch relationship - these will be used to build up the
187196
// parent parallel block relationship.
188197
// Once generated, that relationship will be superseded this one.
189-
dump(
190-
"Adding parallel branch relationship for %s(%s)->%s(%s)",
191-
node.getId(),
192-
node.getClass().getName(),
193-
endNode.getId(),
194-
endNode.getClass().getName());
198+
if (isDebugEnabled) {
199+
logger.debug(
200+
"Adding parallel branch relationship for {}({})->{}({})",
201+
node.getId(),
202+
node.getClass().getName(),
203+
endNode.getId(),
204+
endNode.getClass().getName());
205+
}
195206
// After doesn't matter as this relationship object is temporary (only start and
196207
// end node are used).
197208
NodeRelationship blockRelationship = new NodeRelationship(node, endNode, after);
@@ -200,9 +211,12 @@ private void addParallelBranchRelationship(@NonNull FlowNode node, @NonNull Flow
200211

201212
private NodeRelationship addParallelRelationship(@NonNull FlowNode node, @NonNull FlowNode endNode) {
202213
FlowNode after = getAfterNode(node);
203-
dump(
204-
"Generating relationship for parallel Block %s (with after %s)",
205-
node.getId(), (after != null) ? after.getId() : "null");
214+
if (isDebugEnabled) {
215+
logger.debug(
216+
"Generating relationship for parallel Block {} (with after {})",
217+
node.getId(),
218+
(after != null) ? after.getId() : "null");
219+
}
206220
// handle parallel block case.
207221
NodeRelationship parallelRelationship =
208222
new ParallelBlockRelationship(node, endNode, after, pendingBranchRelationships);
@@ -221,14 +235,16 @@ private NodeRelationship addParallelRelationship(@NonNull FlowNode node, @NonNul
221235

222236
private NodeRelationship addStageRelationship(@NonNull FlowNode node, @NonNull FlowNode endNode) {
223237
FlowNode after = getAfterNode(node);
224-
dump(
225-
"Generating relationship for Block %s{%s}->%s{%s} (with after %s{%s})",
226-
node.getId(),
227-
node.getClass(),
228-
endNode.getId(),
229-
endNode.getClass(),
230-
(after != null) ? after.getId() : "null",
231-
(after != null) ? after.getClass() : "null");
238+
if (isDebugEnabled) {
239+
logger.debug(
240+
"Generating relationship for Block {}{{}}->{}{{}} (with after {}{{}})",
241+
node.getId(),
242+
node.getClass(),
243+
endNode.getId(),
244+
endNode.getClass(),
245+
(after != null) ? after.getId() : "null",
246+
(after != null) ? after.getClass() : "null");
247+
}
232248
return new NodeRelationship(node, endNode, after);
233249
}
234250
}

src/main/java/io/jenkins/plugins/pipelinegraphview/treescanner/ParallelBlockRelationship.java

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,6 @@ public ParallelBlockRelationship(
4545
this.branchEnds = branchEnds;
4646
}
4747

48-
// Print debug message if 'isDebugEnabled' is true.
49-
@Override
50-
protected void dump(String message, Object... args) {
51-
if (isDebugEnabled) {
52-
logger.debug(String.format(message, args));
53-
}
54-
}
55-
5648
public ParallelBlockRelationship(
5749
@NonNull FlowNode start,
5850
@NonNull FlowNode end,
@@ -125,13 +117,18 @@ private void calculateTimings(WorkflowRun run) {
125117
for (int i = 0; i < this.branchStarts.size(); i++) {
126118
FlowNode branchStart = this.branchStarts.get(i);
127119
FlowNode branchEnd = this.branchEnds.get(i);
128-
dump(
129-
"Calculating parallel branch timings %s, %s",
130-
branchStart.getId(), (branchEnd != null) ? branchEnd.getId() : "null");
120+
if (isDebugEnabled) {
121+
logger.debug(
122+
"Calculating parallel branch timings {}, {}",
123+
branchStart.getId(),
124+
(branchEnd != null) ? branchEnd.getId() : "null");
125+
}
131126
}
132127
this.branchTimings = StatusAndTiming.computeParallelBranchTimings(
133128
run, this.start, this.branchStarts, this.branchEnds, parallelEndNode, pauseDurations);
134-
dump("Calculating parallel timings %s, %s (with above branches)", start.getId(), end.getId());
129+
if (isDebugEnabled) {
130+
logger.debug("Calculating parallel timings {}, {} (with above branches)", start.getId(), end.getId());
131+
}
135132
this.overallTiming =
136133
StatusAndTiming.computeOverallParallelTiming(run, this.branchTimings, this.start, parallelEndNode);
137134
}
@@ -144,7 +141,9 @@ private void calculateTimings(WorkflowRun run) {
144141
if (this.overallStatus == null) {
145142
calculateStatuses(run);
146143
}
147-
dump("Overall status for '%s': '%s'", this.start, this.overallStatus);
144+
if (isDebugEnabled) {
145+
logger.debug("Overall status for '{}': '{}'", this.start, this.overallStatus);
146+
}
148147
return new NodeRunStatus(this.overallStatus);
149148
}
150149

@@ -155,11 +154,13 @@ private void calculateTimings(WorkflowRun run) {
155154
if (this.branchStatuses == null) {
156155
calculateStatuses(run);
157156
}
158-
dump(
159-
"Branch status for %s (%s): '%s'",
160-
branchStartNode.getId(),
161-
getBranchName(branchStartNode),
162-
this.branchStatuses.get(getBranchName(branchStartNode)));
157+
if (isDebugEnabled) {
158+
logger.debug(
159+
"Branch status for {} ({}): '{}'",
160+
branchStartNode.getId(),
161+
getBranchName(branchStartNode),
162+
this.branchStatuses.get(getBranchName(branchStartNode)));
163+
}
163164
boolean skippedStage = PipelineNodeUtil.isSkippedStage(branchStartNode);
164165
return new NodeRunStatus(this.branchStatuses.get(getBranchName(branchStartNode)), skippedStage);
165166
}
@@ -176,14 +177,19 @@ private void calculateStatuses(WorkflowRun run) {
176177
for (int i = 0; i < this.branchStarts.size(); i++) {
177178
BlockStartNode branchStart = this.branchStarts.get(i);
178179
FlowNode branchEnd = this.branchEnds.get(i);
179-
dump(
180-
"Calculating parallel branch status %s, %s: %s",
181-
branchStart.getId(),
182-
(branchEnd != null) ? branchEnd.getId() : "null",
183-
getBranchStatus(run, branchStart));
180+
if (isDebugEnabled) {
181+
logger.debug(
182+
"Calculating parallel branch status {}, {}: {}",
183+
branchStart.getId(),
184+
(branchEnd != null) ? branchEnd.getId() : "null",
185+
getBranchStatus(run, branchStart));
186+
}
184187
}
185188

186-
dump("Calculating parallel status %s, %s (with above branches)", this.start.getId(), this.end.getId());
189+
if (isDebugEnabled) {
190+
logger.debug(
191+
"Calculating parallel status {}, {} (with above branches)", this.start.getId(), this.end.getId());
192+
}
187193
this.overallStatus = StatusAndTiming.condenseStatus(this.branchStatuses.values());
188194
}
189195
}

0 commit comments

Comments
 (0)