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();
  }
This commit is contained in:
Maxim.Mossienko
2018-01-11 18:33:02 +01:00
parent b07dd7aab2
commit d4217688fa
@@ -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<ProgressIndicator, Set<Thread>> threadsUnderIndicator = new THashMap<>();
// THashMap is avoided here because of tombstones overhead
static final Map<ProgressIndicator, Set<Thread>> threadsUnderIndicator = new HashMap<>();
// the active indicator for the thread id
private static final ConcurrentLongObjectMap<ProgressIndicator> currentIndicators = ContainerUtil.createConcurrentLongObjectMap();
// top-level indicators for the thread id
private static final ConcurrentLongObjectMap<ProgressIndicator> threadTopLevelIndicators = ContainerUtil.createConcurrentLongObjectMap();
// threads which are running under canceled indicator
static final Set<Thread> threadsUnderCanceledIndicator = new THashSet<>(); // guarded by threadsUnderIndicator
// THashSet is avoided here because of possible tombstones overhead
static final Set<Thread> threadsUnderCanceledIndicator = new HashSet<>(); // guarded by threadsUnderIndicator
private static volatile boolean shouldCheckCanceled;
/** active (i.e. which have {@link #executeProcessUnderProgress(Runnable, ProgressIndicator)} method running) indicators