Skip to content

Commit 0d61dca

Browse files
committed
InsetsStateController: Replace ArrayMap with HashMap for performance
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
1 parent 5474e80 commit 0d61dca

1 file changed

Lines changed: 13 additions & 15 deletions

File tree

services/core/java/com/android/server/wm/InsetsStateController.java

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@
5757
import java.io.PrintWriter;
5858
import java.util.ArrayList;
5959
import java.util.function.Consumer;
60+
import java.util.HashMap;
61+
import java.util.Map;
6062

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

70-
private final ArrayMap<Integer, InsetsSourceProvider> mProviders = new ArrayMap<>();
72+
private final HashMap<Integer, InsetsSourceProvider> mProviders = new HashMap<>();
7173
private final ArrayMap<InsetsControlTarget, ArrayList<Integer>> mControlTargetTypeMap =
7274
new ArrayMap<>();
7375
private final SparseArray<InsetsControlTarget> mTypeControlTargetMap = new SparseArray<>();
@@ -201,8 +203,7 @@ private InsetsState getInsetsForTarget(@InternalInsetsType int type,
201203

202204
// IME needs different frames for certain cases (e.g. navigation bar in gesture nav).
203205
if (type == ITYPE_IME) {
204-
for (int i = mProviders.size() - 1; i >= 0; i--) {
205-
InsetsSourceProvider otherProvider = mProviders.valueAt(i);
206+
for (InsetsSourceProvider otherProvider : mProviders.values()) {
206207
if (otherProvider.overridesImeFrame()) {
207208
InsetsSource override =
208209
new InsetsSource(
@@ -249,8 +250,7 @@ InsetsState getRawInsetsState() {
249250
}
250251

251252
public void addProvidersToTransition() {
252-
for (int i = mProviders.size() - 1; i >= 0; --i) {
253-
final InsetsSourceProvider p = mProviders.valueAt(i);
253+
for (final InsetsSourceProvider p : mProviders.values()) {
254254
if (p == null) continue;
255255
final WindowContainer wc = p.mWin;
256256
if (wc == null) continue;
@@ -288,8 +288,8 @@ ImeInsetsSourceProvider getImeSourceProvider() {
288288
*/
289289
void onPostLayout() {
290290
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "ISC.onPostLayout");
291-
for (int i = mProviders.size() - 1; i >= 0; i--) {
292-
mProviders.valueAt(i).onPostLayout();
291+
for (InsetsSourceProvider provider : mProviders.values()) {
292+
provider.onPostLayout();
293293
}
294294
final ArrayList<WindowState> winInsetsChanged = mDisplayContent.mWinInsetsChanged;
295295
if (!mLastState.equals(mState)) {
@@ -379,8 +379,8 @@ void onDisplayInfoUpdated(boolean notifyInsetsChange) {
379379

380380
void onInsetsModified(InsetsControlTarget caller) {
381381
boolean changed = false;
382-
for (int i = mProviders.size() - 1; i >= 0; i--) {
383-
changed |= mProviders.valueAt(i).updateClientVisibility(caller);
382+
for (InsetsSourceProvider provider : mProviders.values()) {
383+
changed |= provider.updateClientVisibility(caller);
384384
}
385385
if (changed) {
386386
notifyInsetsChanged();
@@ -399,8 +399,7 @@ void onInsetsModified(InsetsControlTarget caller) {
399399
void computeSimulatedState(WindowState win, DisplayFrames displayFrames,
400400
WindowFrames windowFrames) {
401401
final InsetsState state = displayFrames.mInsetsState;
402-
for (int i = mProviders.size() - 1; i >= 0; i--) {
403-
final InsetsSourceProvider provider = mProviders.valueAt(i);
402+
for (final InsetsSourceProvider provider : mProviders.values()) {
404403
if (provider.mWin == win) {
405404
state.addSource(provider.createSimulatedSource(displayFrames, windowFrames));
406405
}
@@ -542,8 +541,7 @@ private void notifyPendingInsetsControlChanged() {
542541
return;
543542
}
544543
mDisplayContent.mWmService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
545-
for (int i = mProviders.size() - 1; i >= 0; i--) {
546-
final InsetsSourceProvider provider = mProviders.valueAt(i);
544+
for (final InsetsSourceProvider provider : mProviders.values()) {
547545
provider.onSurfaceTransactionApplied();
548546
}
549547
final ArraySet<InsetsControlTarget> newControlTargets = new ArraySet<>();
@@ -582,8 +580,8 @@ void dump(String prefix, PrintWriter pw) {
582580
+ mTypeControlTargetMap.valueAt(i));
583581
}
584582
pw.println(prefix + "InsetsSourceProviders:");
585-
for (int i = mProviders.size() - 1; i >= 0; i--) {
586-
mProviders.valueAt(i).dump(pw, prefix + " ");
583+
for (InsetsSourceProvider provider : mProviders.values()) {
584+
provider.dump(pw, prefix + " ");
587585
}
588586
}
589587
}

0 commit comments

Comments
 (0)