• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.platform.test.rule;
18 
19 import static java.util.stream.Collectors.joining;
20 
21 import android.os.SystemClock;
22 import android.util.Log;
23 import androidx.annotation.VisibleForTesting;
24 
25 import com.google.common.collect.ImmutableList;
26 
27 import org.junit.runner.Description;
28 import org.junit.runners.model.InitializationError;
29 
30 import java.util.HashSet;
31 import java.util.Set;
32 
33 /** This rule compiles the applications with the specified filter, or skips if unspecified. */
34 public class CompilationFilterRule extends TestWatcher {
35     //
36     private static final String LOG_TAG = CompilationFilterRule.class.getSimpleName();
37     // Compilation constants
38     @VisibleForTesting static final String COMPILE_CMD_FORMAT = "cmd package compile -f -m %s %s";
39     @VisibleForTesting static final String DUMP_PROFILE_CMD = "killall -s SIGUSR1 %s";
40     private static final ImmutableList<String> COMPILE_FILTER_LIST =
41             ImmutableList.of("speed", "speed-profile", "quicken", "verify");
42     @VisibleForTesting static final String SPEED_PROFILE_FILTER = "speed-profile";
43     private static final String PROFILE_SAVE_TIMEOUT = "profile-save-timeout";
44     @VisibleForTesting static final String COMPILE_FILTER_OPTION = "compilation-filter";
45     @VisibleForTesting static final String COMPILE_SUCCESS = "Success";
46     private static Set<String> mCompiledTests = new HashSet<>();
47 
48     private final String[] mApplications;
49 
CompilationFilterRule()50     public CompilationFilterRule() throws InitializationError {
51         throw new InitializationError("Must supply an application to compile.");
52     }
53 
CompilationFilterRule(String... applications)54     public CompilationFilterRule(String... applications) {
55         mApplications = applications;
56     }
57 
58     @Override
finished(Description description)59     protected void finished(Description description) {
60         // Identify the filter option to use.
61         String filter = getArguments().getString(COMPILE_FILTER_OPTION);
62         // Default speed profile save timeout set to 5 secs.
63         long profileSaveTimeout = Integer
64                 .parseInt(getArguments().getString(PROFILE_SAVE_TIMEOUT, "5000"));
65         if (filter == null) {
66             // No option provided, default to a no-op.
67             Log.d(LOG_TAG, "Skipping complation because filter option is unset.");
68             return;
69         } else if (!COMPILE_FILTER_LIST.contains(filter)) {
70             String filterOptions = COMPILE_FILTER_LIST.stream().collect(joining(", "));
71             throw new IllegalArgumentException(
72                     String.format(
73                             "Unknown compiler filter: %s, not part of %s", filter, filterOptions));
74         }
75         // Profile varies based on the test even for the same app. Tracking the test id to make
76         // sure the test compiled once after the first iteration of the test.
77         String testId = description.getDisplayName();
78         if (!mCompiledTests.contains(testId)) {
79             for (String app : mApplications) {
80                 // For speed profile compilation, ART team recommended to wait for 5 secs when app
81                 // is in the foreground, dump the profile, wait for another 5 secs before
82                 // speed-profile compilation.
83                 if (filter.equalsIgnoreCase(SPEED_PROFILE_FILTER)) {
84                     SystemClock.sleep(profileSaveTimeout);
85                     // Send SIGUSR1 to force dumping a profile.
86                     String response = executeShellCommand(String.format(DUMP_PROFILE_CMD, app));
87                     if (!response.isEmpty()) {
88                         Log.d(LOG_TAG,
89                                 String.format("Received dump profile cmd response: %s", response));
90                         throw new RuntimeException(
91                                 String.format("Failed to dump profile %s.", app));
92                     }
93                     // killall is async, wait few seconds to let the app save the profile.
94                     SystemClock.sleep(profileSaveTimeout);
95                 }
96                 String response = executeShellCommand(
97                         String.format(COMPILE_CMD_FORMAT, filter, app));
98                 if (!response.contains(COMPILE_SUCCESS)) {
99                     Log.d(LOG_TAG, String.format("Received compile cmd response: %s", response));
100                     throw new RuntimeException(String.format("Failed to compile %s.", app));
101                 } else {
102                     mCompiledTests.add(testId);
103                 }
104             }
105         } else {
106             Log.d(LOG_TAG, String.format("Test %s already compiled", testId));
107         }
108     }
109 }
110