Skip to content

Commit

Permalink
InsetsStateController: Replace ArrayMap with HashMap for performance
Browse files Browse the repository at this point in the history
When opening and closing activities in Settings, a significant amount of
CPU time is spent looking up ArrayMap entries, as reported by simpleperf:

0.12%     /system/framework/arm64/boot-framework.oat
                             android.util.ArrayMap.binarySearchHashes

InsetsStateController is responsible for a significant portion of the time
spent in ArrayMap lookups:

0.08%     0.08%  /system/framework/arm64/boot-framework.oat
                  android.util.ArrayMap.binarySearchHashes
       |
       -- android.util.ArrayMap.binarySearchHashes
          |
           --50.00%-- android.util.ArrayMap.indexOf
               |
               |--36.71%-- android.util.ArrayMap.get
               |    |--0.87%-- [hit in function]
               |    |
               |    |--6.67%-- com.android.server.wm.InsetsStateController.peekSourceProvider
               |    |    |
               |    |    |--68.77%-- com.android.server.wm.DisplayPolicy.beginLayoutLw
               |    |    |           com.android.server.wm.DisplayContent.performLayoutNoTrace
               |    |    |           com.android.server.wm.DisplayContent.performLayout
               |    |    |           com.android.server.wm.DisplayContent.applySurfaceChangesTransaction
               |    |    |           com.android.server.wm.RootWindowContainer.applySurfaceChangesTransaction
               |    |    |           com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace
               |    |    |           com.android.server.wm.RootWindowContainer.performSurfacePlacement
               |    |    |           com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop
               |    |    |           com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement
               |    |    |           com.android.server.wm.WindowManagerService.relayoutWindow
               |    |    |           com.android.server.wm.Session.relayout
               |    |    |           android.view.IWindowSession$Stub.onTransact
               |    |    |           com.android.server.wm.Session.onTransact
               |    |    |           android.os.Binder.execTransactInternal
               |    |    |           android.os.Binder.execTransact
               |    |    |           art_quick_invoke_stub
               |    |    |           art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)
               |    |    |           art::JValue art::InvokeVirtualOrInterfaceWithVarArgs<art::ArtMethod*>(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, art::ArtMethod*, std::__va_list)
               |    |    |           art::JValue art::InvokeVirtualOrInterfaceWithVarArgs<_jmethodID*>(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jmethodID*, std::__va_list)
               |    |    |           art::JNI<false>::CallBooleanMethodV(_JNIEnv*, _jobject*, _jmethodID*, std::__va_list)
               |    |    |           _JNIEnv::CallBooleanMethod(_jobject*, _jmethodID*, ...)
               |    |    |           JavaBBinder::onTransact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)
               |    |    |           android::BBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)
               |    |    |           android::IPCThreadState::executeCommand(int)
               |    |    |           android::IPCThreadState::getAndExecuteCommand()
               |    |    |           android::IPCThreadState::joinThreadPool(bool)
               |    |    |           android::PoolThread::threadLoop()
               |    |    |           android::Thread::_threadLoop(void*)
               |    |    |           android::AndroidRuntime::javaThreadShell(void*)
               |    |    |           thread_data_t::trampoline(thread_data_t const*)
               |    |    |           __pthread_start(void*)
               |    |    |           __start_thread
               |    |    |
               |    |     --31.23%-- com.android.server.wm.DisplayPolicy.updateHideNavInputEventReceiver
               |    |                com.android.server.wm.InsetsPolicy.updateBarControlTarget
               |    |                com.android.server.wm.DisplayPolicy.updateSystemUiVisibilityLw
               |    |                com.android.server.wm.DisplayPolicy.finishPostLayoutPolicyLw
               |    |                com.android.server.wm.DisplayContent.applySurfaceChangesTransaction
               |    |                com.android.server.wm.RootWindowContainer.applySurfaceChangesTransaction
               |    |                com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace
               |    |                com.android.server.wm.RootWindowContainer.performSurfacePlacement
               |    |                com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop
               |    |                com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement
               |    |                com.android.server.wm.WindowManagerService.postWindowRemoveCleanupLocked
               |    |                com.android.server.wm.WindowState.removeImmediately
               |    |                com.android.server.wm.WindowState.removeIfPossible
               |    |                com.android.server.wm.WindowState.removeIfPossible
               |    |                com.android.server.wm.WindowManagerService.removeWindow
               |    |                com.android.server.wm.Session.remove
               |    |                android.view.IWindowSession$Stub.onTransact
               |    |                com.android.server.wm.Session.onTransact
               |    |                android.os.Binder.execTransactInternal
               |    |                android.os.Binder.execTransact
               |    |                art_quick_invoke_stub
               |    |                art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)
               |    |                art::JValue art::InvokeVirtualOrInterfaceWithVarArgs<art::ArtMethod*>(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, art::ArtMethod*, std::__va_list)
               |    |                art::JValue art::InvokeVirtualOrInterfaceWithVarArgs<_jmethodID*>(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jmethodID*, std::__va_list)
               |    |                art::JNI<false>::CallBooleanMethodV(_JNIEnv*, _jobject*, _jmethodID*, std::__va_list)
               |    |                _JNIEnv::CallBooleanMethod(_jobject*, _jmethodID*, ...)
               |    |                JavaBBinder::onTransact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)
               |    |                android::BBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)
               |    |                android::IPCThreadState::executeCommand(int)
               |    |                android::IPCThreadState::getAndExecuteCommand()
               |    |                android::IPCThreadState::joinThreadPool(bool)
               |    |                android::PoolThread::threadLoop()
               |    |                android::Thread::_threadLoop(void*)
               |    |                android::AndroidRuntime::javaThreadShell(void*)
               |    |                thread_data_t::trampoline(thread_data_t const*)
               |    |                __pthread_start(void*)
               |    |                __start_thread
               |    |

Empirical testing reveals that mProviders usually contains 9 entries,
at which HashMap is 34% faster than ArrayMap for lookups and 57% faster
[1] for insertions. The increased memory usage should be negligible at
this size, so we can safely convert the map to a HashMap in order to
improve performance in this hotpath.

[1] https://docs.google.com/spreadsheets/d/136UJS2yVlZyPx30KDNgj4AWldkp9xbzIcWkLFj9RGgk/edit

Test: simpleperf record -a; verify that InsetsStateController no longer
      appears under ArrayMap.binarySearchHashes
Change-Id: Ic08d4c3e56cf10b322eabc115de441c6c5f4a898
  • Loading branch information
kdrag0n committed Oct 16, 2021
1 parent 5474e80 commit 0d61dca
Showing 1 changed file with 13 additions and 15 deletions.
28 changes: 13 additions & 15 deletions services/core/java/com/android/server/wm/InsetsStateController.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.function.Consumer;
import java.util.HashMap;
import java.util.Map;

/**
* Manages global window inset state in the system represented by {@link InsetsState}.
Expand All @@ -67,7 +69,7 @@ class InsetsStateController {
private final InsetsState mState = new InsetsState();
private final DisplayContent mDisplayContent;

private final ArrayMap<Integer, InsetsSourceProvider> mProviders = new ArrayMap<>();
private final HashMap<Integer, InsetsSourceProvider> mProviders = new HashMap<>();
private final ArrayMap<InsetsControlTarget, ArrayList<Integer>> mControlTargetTypeMap =
new ArrayMap<>();
private final SparseArray<InsetsControlTarget> mTypeControlTargetMap = new SparseArray<>();
Expand Down Expand Up @@ -201,8 +203,7 @@ private InsetsState getInsetsForTarget(@InternalInsetsType int type,

// IME needs different frames for certain cases (e.g. navigation bar in gesture nav).
if (type == ITYPE_IME) {
for (int i = mProviders.size() - 1; i >= 0; i--) {
InsetsSourceProvider otherProvider = mProviders.valueAt(i);
for (InsetsSourceProvider otherProvider : mProviders.values()) {
if (otherProvider.overridesImeFrame()) {
InsetsSource override =
new InsetsSource(
Expand Down Expand Up @@ -249,8 +250,7 @@ InsetsState getRawInsetsState() {
}

public void addProvidersToTransition() {
for (int i = mProviders.size() - 1; i >= 0; --i) {
final InsetsSourceProvider p = mProviders.valueAt(i);
for (final InsetsSourceProvider p : mProviders.values()) {
if (p == null) continue;
final WindowContainer wc = p.mWin;
if (wc == null) continue;
Expand Down Expand Up @@ -288,8 +288,8 @@ ImeInsetsSourceProvider getImeSourceProvider() {
*/
void onPostLayout() {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "ISC.onPostLayout");
for (int i = mProviders.size() - 1; i >= 0; i--) {
mProviders.valueAt(i).onPostLayout();
for (InsetsSourceProvider provider : mProviders.values()) {
provider.onPostLayout();
}
final ArrayList<WindowState> winInsetsChanged = mDisplayContent.mWinInsetsChanged;
if (!mLastState.equals(mState)) {
Expand Down Expand Up @@ -379,8 +379,8 @@ void onDisplayInfoUpdated(boolean notifyInsetsChange) {

void onInsetsModified(InsetsControlTarget caller) {
boolean changed = false;
for (int i = mProviders.size() - 1; i >= 0; i--) {
changed |= mProviders.valueAt(i).updateClientVisibility(caller);
for (InsetsSourceProvider provider : mProviders.values()) {
changed |= provider.updateClientVisibility(caller);
}
if (changed) {
notifyInsetsChanged();
Expand All @@ -399,8 +399,7 @@ void onInsetsModified(InsetsControlTarget caller) {
void computeSimulatedState(WindowState win, DisplayFrames displayFrames,
WindowFrames windowFrames) {
final InsetsState state = displayFrames.mInsetsState;
for (int i = mProviders.size() - 1; i >= 0; i--) {
final InsetsSourceProvider provider = mProviders.valueAt(i);
for (final InsetsSourceProvider provider : mProviders.values()) {
if (provider.mWin == win) {
state.addSource(provider.createSimulatedSource(displayFrames, windowFrames));
}
Expand Down Expand Up @@ -542,8 +541,7 @@ private void notifyPendingInsetsControlChanged() {
return;
}
mDisplayContent.mWmService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
for (int i = mProviders.size() - 1; i >= 0; i--) {
final InsetsSourceProvider provider = mProviders.valueAt(i);
for (final InsetsSourceProvider provider : mProviders.values()) {
provider.onSurfaceTransactionApplied();
}
final ArraySet<InsetsControlTarget> newControlTargets = new ArraySet<>();
Expand Down Expand Up @@ -582,8 +580,8 @@ void dump(String prefix, PrintWriter pw) {
+ mTypeControlTargetMap.valueAt(i));
}
pw.println(prefix + "InsetsSourceProviders:");
for (int i = mProviders.size() - 1; i >= 0; i--) {
mProviders.valueAt(i).dump(pw, prefix + " ");
for (InsetsSourceProvider provider : mProviders.values()) {
provider.dump(pw, prefix + " ");
}
}
}

0 comments on commit 0d61dca

Please sign in to comment.