blob: 1316fe90141153e96643fdb8e1201993ab933b22 [file] [log] [blame]
/*
* 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 android.platform.test.rule;
import static java.util.stream.Collectors.joining;
import android.os.SystemClock;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import org.junit.runner.Description;
import org.junit.runners.model.InitializationError;
import java.util.HashSet;
import java.util.Set;
/** This rule compiles the applications with the specified filter, or skips if unspecified. */
public class CompilationFilterRule extends TestWatcher {
//
private static final String LOG_TAG = CompilationFilterRule.class.getSimpleName();
// Compilation constants
@VisibleForTesting static final String COMPILE_CMD_FORMAT = "cmd package compile -f -m %s %s";
@VisibleForTesting static final String DUMP_PROFILE_CMD = "killall -s SIGUSR1 %s";
private static final ImmutableList<String> COMPILE_FILTER_LIST =
ImmutableList.of("speed", "speed-profile", "quicken", "verify");
@VisibleForTesting static final String SPEED_PROFILE_FILTER = "speed-profile";
private static final String PROFILE_SAVE_TIMEOUT = "profile-save-timeout";
@VisibleForTesting static final String COMPILE_FILTER_OPTION = "compilation-filter";
@VisibleForTesting static final String COMPILE_SUCCESS = "Success";
private static Set<String> mCompiledTests = new HashSet<>();
private final String[] mApplications;
public CompilationFilterRule() throws InitializationError {
throw new InitializationError("Must supply an application to compile.");
}
public CompilationFilterRule(String... applications) {
mApplications = applications;
}
@Override
protected void finished(Description description) {
// Identify the filter option to use.
String filter = getArguments().getString(COMPILE_FILTER_OPTION);
// Default speed profile save timeout set to 5 secs.
long profileSaveTimeout = Integer
.parseInt(getArguments().getString(PROFILE_SAVE_TIMEOUT, "5000"));
if (filter == null) {
// No option provided, default to a no-op.
Log.d(LOG_TAG, "Skipping complation because filter option is unset.");
return;
} else if (!COMPILE_FILTER_LIST.contains(filter)) {
String filterOptions = COMPILE_FILTER_LIST.stream().collect(joining(", "));
throw new IllegalArgumentException(
String.format(
"Unknown compiler filter: %s, not part of %s", filter, filterOptions));
}
// Profile varies based on the test even for the same app. Tracking the test id to make
// sure the test compiled once after the first iteration of the test.
String testId = description.getDisplayName();
if (!mCompiledTests.contains(testId)) {
for (String app : mApplications) {
// For speed profile compilation, ART team recommended to wait for 5 secs when app
// is in the foreground, dump the profile, wait for another 5 secs before
// speed-profile compilation.
if (filter.equalsIgnoreCase(SPEED_PROFILE_FILTER)) {
SystemClock.sleep(profileSaveTimeout);
// Send SIGUSR1 to force dumping a profile.
String response = executeShellCommand(String.format(DUMP_PROFILE_CMD, app));
if (!response.isEmpty()) {
Log.d(LOG_TAG,
String.format("Received dump profile cmd response: %s", response));
throw new RuntimeException(
String.format("Failed to dump profile %s.", app));
}
// killall is async, wait few seconds to let the app save the profile.
SystemClock.sleep(profileSaveTimeout);
}
String response = executeShellCommand(
String.format(COMPILE_CMD_FORMAT, filter, app));
if (!response.contains(COMPILE_SUCCESS)) {
Log.d(LOG_TAG, String.format("Received compile cmd response: %s", response));
throw new RuntimeException(String.format("Failed to compile %s.", app));
} else {
mCompiledTests.add(testId);
}
}
} else {
Log.d(LOG_TAG, String.format("Test %s already compiled", testId));
}
}
}