Skip to content

Commit 7c37e05

Browse files
authored
Merge pull request #519 from Vlatombe/timings-concurrency
Use a concurrent map to manage timings
2 parents d0a8f6a + fc580de commit 7c37e05

File tree

1 file changed

+16
-30
lines changed

1 file changed

+16
-30
lines changed

src/main/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java

Lines changed: 16 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
import java.util.NavigableMap;
9393
import java.util.Stack;
9494
import java.util.TreeMap;
95+
import java.util.concurrent.ConcurrentHashMap;
9596
import java.util.concurrent.CopyOnWriteArrayList;
9697
import java.util.concurrent.ExecutionException;
9798
import java.util.concurrent.Future;
@@ -384,8 +385,7 @@ enum TimingKind {
384385
}
385386

386387
/** accumulated time in ns of a given {@link TimingKind#name}; {@link String} key for pretty XStream form */
387-
@GuardedBy("this")
388-
@CheckForNull Map<String, Long> timings;
388+
@NonNull Map<String, Long> timings = new ConcurrentHashMap<>();
389389

390390
@Deprecated
391391
public CpsFlowExecution(String script, FlowExecutionOwner owner) throws IOException {
@@ -410,9 +410,14 @@ public CpsFlowExecution(String script, boolean sandbox, FlowExecutionOwner owner
410410
/**
411411
* Perform post-deserialization state resurrection that handles version evolution
412412
*/
413+
@SuppressFBWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE", justification = "Could be null if deserialized from old version")
413414
private Object readResolve() {
414415
if (loadedScripts==null)
415416
loadedScripts = new HashMap<>(); // field added later
417+
// Convert timings to concurrent hash map
418+
if (!(timings instanceof ConcurrentHashMap)) {
419+
timings = timings == null ? new ConcurrentHashMap<>() : new ConcurrentHashMap<>(timings);
420+
}
416421
return this;
417422
}
418423

@@ -424,16 +429,7 @@ private Timing(TimingKind kind) {
424429
start = System.nanoTime();
425430
}
426431
@Override public void close() {
427-
synchronized (CpsFlowExecution.this) {
428-
if (timings == null) {
429-
timings = new HashMap<>();
430-
}
431-
Long orig = timings.get(kind.name());
432-
if (orig == null) {
433-
orig = 0L;
434-
}
435-
timings.put(kind.name(), orig + System.nanoTime() - start);
436-
}
432+
timings.merge(kind.name(), System.nanoTime() - start, Long::sum);
437433
}
438434
}
439435

@@ -448,12 +444,10 @@ Timing time(TimingKind kind) {
448444

449445
static final Logger TIMING_LOGGER = Logger.getLogger(CpsFlowExecution.class.getName() + ".timing");
450446

451-
synchronized void logTimings() {
452-
if (timings != null && TIMING_LOGGER.isLoggable(Level.FINE)) {
447+
void logTimings() {
448+
if (TIMING_LOGGER.isLoggable(Level.FINE)) {
453449
Map<String, String> formatted = new TreeMap<>();
454-
for (Map.Entry<String, Long> entry : timings.entrySet()) {
455-
formatted.put(entry.getKey(), entry.getValue() / 1000 / 1000 + "ms");
456-
}
450+
timings.forEach((k, v) -> formatted.put(k, v / 1000 / 1000 + "ms"));
457451
TIMING_LOGGER.log(Level.FINE, "timings for {0}: {1}", new Object[] {owner, formatted});
458452
}
459453
}
@@ -1643,11 +1637,7 @@ public void marshal(Object source, HierarchicalStreamWriter w, MarshallingContex
16431637
if (e.durabilityHint != null) {
16441638
writeChild(w, context, "durabilityHint", e.durabilityHint, FlowDurabilityHint.class);
16451639
}
1646-
synchronized (e) {
1647-
if (e.timings != null) {
1648-
writeChild(w, context, "timings", e.timings, Map.class);
1649-
}
1650-
}
1640+
writeChild(w, context, "timings", e.timings, Map.class);
16511641
writeChild(w, context, "sandbox", e.sandbox, Boolean.class);
16521642
if (e.user != null) {
16531643
writeChild(w, context, "user", e.user, String.class);
@@ -1931,14 +1921,10 @@ public void autopersist(@NonNull FlowNode n) throws IOException {
19311921
continue;
19321922
}
19331923
if (exec instanceof CpsFlowExecution) {
1934-
Map<String, Long> timings = ((CpsFlowExecution) exec).timings;
1935-
if (timings != null) {
1936-
pw.println("Timings for " + run + ":");
1937-
for (Map.Entry<String, Long> entry : new TreeMap<>(timings).entrySet()) {
1938-
pw.println(" " + entry.getKey() + "\t" + entry.getValue() / 1000 / 1000 + "ms");
1939-
}
1940-
pw.println();
1941-
}
1924+
Map<String, Long> sortedTimings = new TreeMap<>(((CpsFlowExecution) exec).timings);
1925+
pw.println("Timings for " + run + ":");
1926+
sortedTimings.forEach((k, v) -> pw.println(" " + k + "\t" + v / 1000 / 1000 + "ms"));
1927+
pw.println();
19421928
}
19431929
}
19441930
}

0 commit comments

Comments
 (0)