Merge "Reduce system calls of ThreadPriorityBooster" into qt-dev

am: 00e76b8c13

Change-Id: I1cd901b20b5bd08519fde5c105de87c2e8664e94
This commit is contained in:
Riddle Hsu
2019-04-15 01:15:10 -07:00
committed by android-build-merger
2 changed files with 109 additions and 14 deletions

View File

@@ -26,6 +26,7 @@ import static android.os.Process.setThreadPriority;
public class ThreadPriorityBooster { public class ThreadPriorityBooster {
private static final boolean ENABLE_LOCK_GUARD = false; private static final boolean ENABLE_LOCK_GUARD = false;
private static final int PRIORITY_NOT_ADJUSTED = Integer.MAX_VALUE;
private volatile int mBoostToPriority; private volatile int mBoostToPriority;
private final int mLockGuardIndex; private final int mLockGuardIndex;
@@ -42,13 +43,12 @@ public class ThreadPriorityBooster {
} }
public void boost() { public void boost() {
final int tid = myTid();
final PriorityState state = mThreadState.get(); final PriorityState state = mThreadState.get();
if (state.regionCounter == 0) { if (state.regionCounter == 0) {
final int prevPriority = getThreadPriority(tid); final int prevPriority = getThreadPriority(state.tid);
state.prevPriority = prevPriority;
if (prevPriority > mBoostToPriority) { if (prevPriority > mBoostToPriority) {
setThreadPriority(tid, mBoostToPriority); setThreadPriority(state.tid, mBoostToPriority);
state.prevPriority = prevPriority;
} }
} }
state.regionCounter++; state.regionCounter++;
@@ -60,11 +60,9 @@ public class ThreadPriorityBooster {
public void reset() { public void reset() {
final PriorityState state = mThreadState.get(); final PriorityState state = mThreadState.get();
state.regionCounter--; state.regionCounter--;
if (state.regionCounter == 0) { if (state.regionCounter == 0 && state.prevPriority != PRIORITY_NOT_ADJUSTED) {
final int currentPriority = getThreadPriority(myTid()); setThreadPriority(state.tid, state.prevPriority);
if (state.prevPriority != currentPriority) { state.prevPriority = PRIORITY_NOT_ADJUSTED;
setThreadPriority(myTid(), state.prevPriority);
}
} }
} }
@@ -78,16 +76,16 @@ public class ThreadPriorityBooster {
// variable immediately. // variable immediately.
mBoostToPriority = priority; mBoostToPriority = priority;
final PriorityState state = mThreadState.get(); final PriorityState state = mThreadState.get();
final int tid = myTid();
if (state.regionCounter != 0) { if (state.regionCounter != 0) {
final int prevPriority = getThreadPriority(tid); final int prevPriority = getThreadPriority(state.tid);
if (prevPriority != priority) { if (prevPriority != priority) {
setThreadPriority(tid, priority); setThreadPriority(state.tid, priority);
} }
} }
} }
private static class PriorityState { private static class PriorityState {
final int tid = myTid();
/** /**
* Acts as counter for number of synchronized region that needs to acquire 'this' as a lock * Acts as counter for number of synchronized region that needs to acquire 'this' as a lock
@@ -99,6 +97,6 @@ public class ThreadPriorityBooster {
/** /**
* The thread's previous priority before boosting. * The thread's previous priority before boosting.
*/ */
int prevPriority; int prevPriority = PRIORITY_NOT_ADJUSTED;
} }
} }

View File

@@ -0,0 +1,97 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* 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.android.server;
import static android.os.Process.getThreadPriority;
import static android.os.Process.myTid;
import static android.os.Process.setThreadPriority;
import static org.junit.Assert.assertEquals;
import android.os.Process;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
import org.junit.Test;
/**
* Tests for {@link ThreadPriorityBooster}.
* Build/Install/Run:
* atest FrameworksServicesTests:ThreadPriorityBoosterTest
*/
@SmallTest
@Presubmit
public class ThreadPriorityBoosterTest {
private static final int PRIORITY_BOOST = Process.THREAD_PRIORITY_FOREGROUND;
private static final int PRIORITY_BOOST_MORE = Process.THREAD_PRIORITY_DISPLAY;
private final ThreadPriorityBooster mBooster = new ThreadPriorityBooster(PRIORITY_BOOST,
0 /* lockGuardIndex */);
@Test
public void testThreadPriorityBooster() {
joinNewThread(() -> {
final int origPriority = Process.THREAD_PRIORITY_DEFAULT;
setThreadPriority(origPriority);
boost(() -> {
assertThreadPriority(PRIORITY_BOOST);
boost(() -> {
// Inside the boost region, the priority should also apply to current thread.
mBooster.setBoostToPriority(PRIORITY_BOOST_MORE);
assertThreadPriority(PRIORITY_BOOST_MORE);
});
// It is still in the boost region so the set priority should be kept.
assertThreadPriority(PRIORITY_BOOST_MORE);
joinNewThread(() -> boost(() -> assertThreadPriority(PRIORITY_BOOST_MORE)));
});
// The priority should be restored after leaving the boost region.
assertThreadPriority(origPriority);
// It doesn't apply to current thread because outside of the boost region, but the boost
// in other threads will use the set priority.
mBooster.setBoostToPriority(PRIORITY_BOOST);
joinNewThread(() -> boost(() -> assertThreadPriority(PRIORITY_BOOST)));
assertThreadPriority(origPriority);
});
}
private static void assertThreadPriority(int expectedPriority) {
assertEquals(expectedPriority, getThreadPriority(myTid()));
}
private static void joinNewThread(Runnable action) {
final Thread thread = new Thread(action);
thread.start();
try {
thread.join();
} catch (InterruptedException ignored) {
}
}
private void boost(Runnable action) {
try {
mBooster.boost();
action.run();
} finally {
mBooster.reset();
}
}
}