Skip to content

Commit a3d776c

Browse files
author
Jörg Kubitz
committed
[performance] Avoid O(n^2) in DeadlockDetector.lockAcquired()
With n conflicting rules. "conflicting.contains(possible)" has been observed as severe hotspot in a workspace with n= ~1000 projects Also avoid second pass if nothing changed. Functionality is tested with IJobManagerTest.testTransferToJobWaitingOnChildRule() OrderedLockTest.testComplex() DeadlockDetectionTest.testImplicitRules()
1 parent d3dd4bf commit a3d776c

File tree

1 file changed

+24
-13
lines changed

1 file changed

+24
-13
lines changed

runtime/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/DeadlockDetector.java

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
import java.io.PrintWriter;
1717
import java.io.StringWriter;
1818
import java.util.ArrayList;
19+
import java.util.Collection;
20+
import java.util.HashSet;
21+
import java.util.Set;
1922
import org.eclipse.core.internal.runtime.RuntimeLog;
2023
import org.eclipse.core.runtime.Assert;
2124
import org.eclipse.core.runtime.IStatus;
@@ -304,23 +307,31 @@ void lockAcquired(Thread owner, ISchedulingRule lock) {
304307
* or conflict with a lock the given lock will acquire implicitly
305308
* (locks are acquired implicitly when a conflicting lock is acquired)
306309
*/
307-
ArrayList<ISchedulingRule> conflicting = new ArrayList<>(1);
308-
//only need two passes through all the locks to pick up all conflicting rules
309-
int NUM_PASSES = 2;
310-
conflicting.add(lock);
311310
graph[threadIndex][lockIndex]++;
312-
for (int i = 0; i < NUM_PASSES; i++) {
313-
for (int k = 0; k < conflicting.size(); k++) {
314-
ISchedulingRule current = conflicting.get(k);
315-
for (int j = 0; j < locks.size(); j++) {
316-
ISchedulingRule possible = locks.get(j);
317-
if (!conflicting.contains(possible) && current.isConflicting(possible)) {
318-
conflicting.add(possible);
319-
graph[threadIndex][j]++;
320-
}
311+
312+
// first pass tests against lock:
313+
Collection<ISchedulingRule> conflicting = Set.of(lock);
314+
conflicting = computeConflicting(threadIndex, conflicting);
315+
316+
// second pass tests also transitive:
317+
if (!conflicting.isEmpty()) {
318+
conflicting.add(lock);
319+
conflicting = computeConflicting(threadIndex, conflicting);
320+
}
321+
}
322+
323+
private Collection<ISchedulingRule> computeConflicting(int threadIndex, Collection<ISchedulingRule> candidates) {
324+
Collection<ISchedulingRule> added = new HashSet<>();
325+
for (ISchedulingRule current : candidates) {
326+
for (int j = 0; j < locks.size(); j++) {
327+
ISchedulingRule possible = locks.get(j);
328+
if (!added.contains(possible) && !candidates.contains(possible) && current.isConflicting(possible)) {
329+
added.add(possible);
330+
graph[threadIndex][j]++;
321331
}
322332
}
323333
}
334+
return added;
324335
}
325336

326337
/**

0 commit comments

Comments
 (0)