From 135c418cadef7180d285fec74d85edcf1809ccb1 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Thu, 26 May 2016 12:25:40 +0300 Subject: [PATCH] performance in case of thousands events in the queue should be linear, not quadratic --- .../src/com/intellij/ide/IdeEventQueue.java | 98 +++++++++++-------- .../com/intellij/ide/IdeEventQueueTest.java | 40 ++++++++ 2 files changed, 95 insertions(+), 43 deletions(-) create mode 100644 platform/platform-tests/testSrc/com/intellij/ide/IdeEventQueueTest.java diff --git a/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java b/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java index 1fce159d8d2b..049a2dbda779 100644 --- a/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java +++ b/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java @@ -123,6 +123,7 @@ public class IdeEventQueue extends EventQueue { * Swing event. */ private int myEventCount; + private int myKeyboardEventsInTheQueue; // accessed in EDT only private boolean myIsInInputEvent; @@ -356,50 +357,57 @@ public class IdeEventQueue extends EventQueue { @Override public void dispatchEvent(@NotNull AWTEvent e) { - if (!appIsLoaded()) { - try { - super.dispatchEvent(e); + try { + if (!appIsLoaded()) { + try { + super.dispatchEvent(e); + } + catch (Throwable t) { + processException(t); + } + return; + } + + e = InertialMouseRouter.changeSourceIfNeeded(e); + + e = fixNonEnglishKeyboardLayouts(e); + + e = mapEvent(e); + if (Registry.is("keymap.windows.as.meta")) { + e = mapMetaState(e); + } + + boolean wasInputEvent = myIsInInputEvent; + myIsInInputEvent = e instanceof InputEvent || e instanceof InputMethodEvent || e instanceof WindowEvent || e instanceof ActionEvent; + if (myIsInInputEvent) { + HeavyProcessLatch.INSTANCE.prioritizeUiActivity(); + } + AWTEvent oldEvent = myCurrentEvent; + myCurrentEvent = e; + + boolean userActivity = myIsInInputEvent || e instanceof ItemEvent; + try (AccessToken ignored = startActivity(userActivity)) { + _dispatchEvent(e, false); } catch (Throwable t) { processException(t); } - return; - } + finally { + myIsInInputEvent = wasInputEvent; + myCurrentEvent = oldEvent; - e = InertialMouseRouter.changeSourceIfNeeded(e); + for (EventDispatcher each : myPostProcessors) { + each.dispatch(e); + } - e = fixNonEnglishKeyboardLayouts(e); - - e = mapEvent(e); - if (Registry.is("keymap.windows.as.meta")) { - e = mapMetaState(e); - } - - boolean wasInputEvent = myIsInInputEvent; - myIsInInputEvent = e instanceof InputEvent || e instanceof InputMethodEvent || e instanceof WindowEvent || e instanceof ActionEvent; - if (myIsInInputEvent) { - HeavyProcessLatch.INSTANCE.prioritizeUiActivity(); - } - AWTEvent oldEvent = myCurrentEvent; - myCurrentEvent = e; - - boolean userActivity = myIsInInputEvent || e instanceof ItemEvent; - try (AccessToken ignored = startActivity(userActivity)) { - _dispatchEvent(e, false); - } - catch (Throwable t) { - processException(t); + if (e instanceof KeyEvent) { + maybeReady(); + } + } } finally { - myIsInInputEvent = wasInputEvent; - myCurrentEvent = oldEvent; - - for (EventDispatcher each : myPostProcessors) { - each.dispatch(e); - } - - if (e instanceof KeyEvent) { - maybeReady(); + if (isKeyboardEvent(e)) { + myKeyboardEventsInTheQueue--; } } } @@ -586,10 +594,7 @@ public class IdeEventQueue extends EventQueue { enterSuspendModeIfNeeded(e); } - myKeyboardBusy = e instanceof KeyEvent || - peekEvent(KeyEvent.KEY_PRESSED) != null || - peekEvent(KeyEvent.KEY_RELEASED) != null || - peekEvent(KeyEvent.KEY_TYPED) != null; + myKeyboardBusy = myKeyboardEventsInTheQueue != 0; if (e instanceof KeyEvent) { if (e.getID() == KeyEvent.KEY_RELEASED && ((KeyEvent)e).getKeyCode() == KeyEvent.VK_SHIFT) { @@ -1150,9 +1155,16 @@ public class IdeEventQueue extends EventQueue { private final FrequentEventDetector myFrequentEventDetector = new FrequentEventDetector(1009, 100); @Override - public void postEvent(@NotNull AWTEvent theEvent) { - myFrequentEventDetector.eventHappened(theEvent); - super.postEvent(theEvent); + public void postEvent(@NotNull AWTEvent event) { + myFrequentEventDetector.eventHappened(event); + if (isKeyboardEvent(event)) { + myKeyboardEventsInTheQueue++; + } + super.postEvent(event); + } + + private static boolean isKeyboardEvent(@NotNull AWTEvent event) { + return event instanceof KeyEvent && (event.getID() == KeyEvent.KEY_PRESSED || event.getID() == KeyEvent.KEY_RELEASED || event.getID() == KeyEvent.KEY_TYPED); } @Override diff --git a/platform/platform-tests/testSrc/com/intellij/ide/IdeEventQueueTest.java b/platform/platform-tests/testSrc/com/intellij/ide/IdeEventQueueTest.java new file mode 100644 index 000000000000..39ba20e0703c --- /dev/null +++ b/platform/platform-tests/testSrc/com/intellij/ide/IdeEventQueueTest.java @@ -0,0 +1,40 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.ide; + +import com.intellij.testFramework.PlatformTestCase; +import com.intellij.testFramework.PlatformTestUtil; +import com.intellij.util.ui.UIUtil; + +import javax.swing.*; +import java.util.concurrent.atomic.AtomicInteger; + +public class IdeEventQueueTest extends PlatformTestCase { + public void testManyEvents() { + int N = 100000; + PlatformTestUtil.startPerformanceTest("Event queue dispatch", 10000, () -> { + AtomicInteger count = new AtomicInteger(); + UIUtil.dispatchAllInvocationEvents(); + for (int i=0;i { + count.incrementAndGet(); + }); + } + UIUtil.dispatchAllInvocationEvents(); + assertEquals(N, count.get()); + }).assertTiming(); + } +}