From d4217688fa24a30e3d5eb6c027a3c86769fedf37 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Thu, 11 Jan 2018 18:23:03 +0100 Subject: [PATCH] attempt to fix test blinking tests avoid using THashMap / THashSet when Map / Set is intensively updated: with multiple tombstones the cost of accessing map maybe linear. For the record here is small example: public void testProgressPerformance() { // Int values + code to produce nontrivial empty THashMap nearly completely filled with deleted tombstones // THash.compactIfNecessary limits compaction on deletion to hashes larger than MAGIC_VALUE = 42 int max = 29; // THash's initialCapacity that will produce Object[37], 37 < MAGIC_VALUE class IdBackedEmptyProgressIndicator extends EmptyProgressIndicator { final int myId; IdBackedEmptyProgressIndicator(int id) { myId = id; } @Override public int hashCode() { return myId; } @Override public boolean equals(Object obj) { if (!(obj instanceof IdBackedEmptyProgressIndicator)) return false; return myId == ((IdBackedEmptyProgressIndicator)obj).myId; } } for(int i = 0; i < max; ++i) { CoreProgressManager.threadsUnderIndicator.put(new IdBackedEmptyProgressIndicator(i), Collections.emptySet()); } for(int i = 0; i < max ; ++i) { CoreProgressManager.threadsUnderIndicator.remove(new IdBackedEmptyProgressIndicator(i)); } // THashMap in CoreProgressManager.threadsUnderIndicator has 29 tombstones Random random = new Random(2); for(int i = 0; i < 2 * max; ++i) { IdBackedEmptyProgressIndicator key = new IdBackedEmptyProgressIndicator(random.nextInt()); CoreProgressManager.threadsUnderIndicator.put(key, Collections.emptySet()); CoreProgressManager.threadsUnderIndicator.remove(key); } // THashMap in CoreProgressManager.threadsUnderIndicator has 36 tombstones, // 33th slot is free, more removals will cause rehash / clear of tombstones PlatformTestUtil.startPerformanceTest("executeProcessUnderProgress", 100, () -> { EmptyProgressIndicator indicator = new IdBackedEmptyProgressIndicator(16); // hash 16 will hit missing element 33 at 37th iteration for (int i=0;i<100000;i++) { ProgressManager.getInstance().executeProcessUnderProgress(EmptyRunnable.getInstance(), indicator); } }).assertTiming(); } --- .../openapi/progress/impl/CoreProgressManager.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/platform/core-impl/src/com/intellij/openapi/progress/impl/CoreProgressManager.java b/platform/core-impl/src/com/intellij/openapi/progress/impl/CoreProgressManager.java index 3b6517183b63..4566d5b30221 100644 --- a/platform/core-impl/src/com/intellij/openapi/progress/impl/CoreProgressManager.java +++ b/platform/core-impl/src/com/intellij/openapi/progress/impl/CoreProgressManager.java @@ -19,8 +19,6 @@ import com.intellij.util.ExceptionUtil; import com.intellij.util.containers.ConcurrentLongObjectMap; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.SmartHashSet; -import gnu.trove.THashMap; -import gnu.trove.THashSet; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -46,13 +44,15 @@ public class CoreProgressManager extends ProgressManager implements Disposable { private ScheduledFuture myCheckCancelledFuture; // guarded by threadsUnderIndicator // indicator -> threads which are running under this indicator. guarded by threadsUnderIndicator. - private static final Map> threadsUnderIndicator = new THashMap<>(); + // THashMap is avoided here because of tombstones overhead + static final Map> threadsUnderIndicator = new HashMap<>(); // the active indicator for the thread id private static final ConcurrentLongObjectMap currentIndicators = ContainerUtil.createConcurrentLongObjectMap(); // top-level indicators for the thread id private static final ConcurrentLongObjectMap threadTopLevelIndicators = ContainerUtil.createConcurrentLongObjectMap(); // threads which are running under canceled indicator - static final Set threadsUnderCanceledIndicator = new THashSet<>(); // guarded by threadsUnderIndicator + // THashSet is avoided here because of possible tombstones overhead + static final Set threadsUnderCanceledIndicator = new HashSet<>(); // guarded by threadsUnderIndicator private static volatile boolean shouldCheckCanceled; /** active (i.e. which have {@link #executeProcessUnderProgress(Runnable, ProgressIndicator)} method running) indicators