Home | History | Annotate | Download | only in profman
      1 /*
      2  * Copyright (C) 2016 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 #include <gtest/gtest.h>
     18 
     19 #include "base/unix_file/fd_file.h"
     20 #include "common_runtime_test.h"
     21 #include "profile_assistant.h"
     22 #include "jit/offline_profiling_info.h"
     23 #include "utils.h"
     24 
     25 namespace art {
     26 
     27 class ProfileAssistantTest : public CommonRuntimeTest {
     28  protected:
     29   void SetupProfile(const std::string& id,
     30                     uint32_t checksum,
     31                     uint16_t number_of_methods,
     32                     uint16_t number_of_classes,
     33                     const ScratchFile& profile,
     34                     ProfileCompilationInfo* info,
     35                     uint16_t start_method_index = 0) {
     36     std::string dex_location1 = "location1" + id;
     37     uint32_t dex_location_checksum1 = checksum;
     38     std::string dex_location2 = "location2" + id;
     39     uint32_t dex_location_checksum2 = 10 * checksum;
     40     for (uint16_t i = start_method_index; i < start_method_index + number_of_methods; i++) {
     41       ASSERT_TRUE(info->AddMethodIndex(dex_location1, dex_location_checksum1, i));
     42       ASSERT_TRUE(info->AddMethodIndex(dex_location2, dex_location_checksum2, i));
     43     }
     44     for (uint16_t i = 0; i < number_of_classes; i++) {
     45       ASSERT_TRUE(info->AddClassIndex(dex_location1, dex_location_checksum1, i));
     46     }
     47 
     48     ASSERT_TRUE(info->Save(GetFd(profile)));
     49     ASSERT_EQ(0, profile.GetFile()->Flush());
     50     ASSERT_TRUE(profile.GetFile()->ResetOffset());
     51   }
     52 
     53   int GetFd(const ScratchFile& file) const {
     54     return static_cast<int>(file.GetFd());
     55   }
     56 
     57   void CheckProfileInfo(ScratchFile& file, const ProfileCompilationInfo& info) {
     58     ProfileCompilationInfo file_info;
     59     ASSERT_TRUE(file.GetFile()->ResetOffset());
     60     ASSERT_TRUE(file_info.Load(GetFd(file)));
     61     ASSERT_TRUE(file_info.Equals(info));
     62   }
     63 
     64     // Runs test with given arguments.
     65   int ProcessProfiles(const std::vector<int>& profiles_fd, int reference_profile_fd) {
     66     std::string file_path = GetTestAndroidRoot();
     67     file_path += "/bin/profman";
     68     if (kIsDebugBuild) {
     69       file_path += "d";
     70     }
     71 
     72     EXPECT_TRUE(OS::FileExists(file_path.c_str())) << file_path << " should be a valid file path";
     73     std::vector<std::string> argv_str;
     74     argv_str.push_back(file_path);
     75     for (size_t k = 0; k < profiles_fd.size(); k++) {
     76       argv_str.push_back("--profile-file-fd=" + std::to_string(profiles_fd[k]));
     77     }
     78     argv_str.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile_fd));
     79 
     80     std::string error;
     81     return ExecAndReturnCode(argv_str, &error);
     82   }
     83 };
     84 
     85 TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferences) {
     86   ScratchFile profile1;
     87   ScratchFile profile2;
     88   ScratchFile reference_profile;
     89 
     90   std::vector<int> profile_fds({
     91       GetFd(profile1),
     92       GetFd(profile2)});
     93   int reference_profile_fd = GetFd(reference_profile);
     94 
     95   const uint16_t kNumberOfMethodsToEnableCompilation = 100;
     96   ProfileCompilationInfo info1;
     97   SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
     98   ProfileCompilationInfo info2;
     99   SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
    100 
    101   // We should advise compilation.
    102   ASSERT_EQ(ProfileAssistant::kCompile,
    103             ProcessProfiles(profile_fds, reference_profile_fd));
    104   // The resulting compilation info must be equal to the merge of the inputs.
    105   ProfileCompilationInfo result;
    106   ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
    107   ASSERT_TRUE(result.Load(reference_profile_fd));
    108 
    109   ProfileCompilationInfo expected;
    110   ASSERT_TRUE(expected.MergeWith(info1));
    111   ASSERT_TRUE(expected.MergeWith(info2));
    112   ASSERT_TRUE(expected.Equals(result));
    113 
    114   // The information from profiles must remain the same.
    115   CheckProfileInfo(profile1, info1);
    116   CheckProfileInfo(profile2, info2);
    117 }
    118 
    119 // TODO(calin): Add more tests for classes.
    120 TEST_F(ProfileAssistantTest, AdviseCompilationEmptyReferencesBecauseOfClasses) {
    121   ScratchFile profile1;
    122   ScratchFile reference_profile;
    123 
    124   std::vector<int> profile_fds({
    125       GetFd(profile1)});
    126   int reference_profile_fd = GetFd(reference_profile);
    127 
    128   const uint16_t kNumberOfClassesToEnableCompilation = 100;
    129   ProfileCompilationInfo info1;
    130   SetupProfile("p1", 1, 0, kNumberOfClassesToEnableCompilation, profile1, &info1);
    131 
    132   // We should advise compilation.
    133   ASSERT_EQ(ProfileAssistant::kCompile,
    134             ProcessProfiles(profile_fds, reference_profile_fd));
    135   // The resulting compilation info must be equal to the merge of the inputs.
    136   ProfileCompilationInfo result;
    137   ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
    138   ASSERT_TRUE(result.Load(reference_profile_fd));
    139 
    140   ProfileCompilationInfo expected;
    141   ASSERT_TRUE(expected.MergeWith(info1));
    142   ASSERT_TRUE(expected.Equals(result));
    143 
    144   // The information from profiles must remain the same.
    145   CheckProfileInfo(profile1, info1);
    146 }
    147 
    148 TEST_F(ProfileAssistantTest, AdviseCompilationNonEmptyReferences) {
    149   ScratchFile profile1;
    150   ScratchFile profile2;
    151   ScratchFile reference_profile;
    152 
    153   std::vector<int> profile_fds({
    154       GetFd(profile1),
    155       GetFd(profile2)});
    156   int reference_profile_fd = GetFd(reference_profile);
    157 
    158   // The new profile info will contain the methods with indices 0-100.
    159   const uint16_t kNumberOfMethodsToEnableCompilation = 100;
    160   ProfileCompilationInfo info1;
    161   SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
    162   ProfileCompilationInfo info2;
    163   SetupProfile("p2", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
    164 
    165 
    166   // The reference profile info will contain the methods with indices 50-150.
    167   const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
    168   ProfileCompilationInfo reference_info;
    169   SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
    170       &reference_info, kNumberOfMethodsToEnableCompilation / 2);
    171 
    172   // We should advise compilation.
    173   ASSERT_EQ(ProfileAssistant::kCompile,
    174             ProcessProfiles(profile_fds, reference_profile_fd));
    175 
    176   // The resulting compilation info must be equal to the merge of the inputs
    177   ProfileCompilationInfo result;
    178   ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
    179   ASSERT_TRUE(result.Load(reference_profile_fd));
    180 
    181   ProfileCompilationInfo expected;
    182   ASSERT_TRUE(expected.MergeWith(info1));
    183   ASSERT_TRUE(expected.MergeWith(info2));
    184   ASSERT_TRUE(expected.MergeWith(reference_info));
    185   ASSERT_TRUE(expected.Equals(result));
    186 
    187   // The information from profiles must remain the same.
    188   CheckProfileInfo(profile1, info1);
    189   CheckProfileInfo(profile2, info2);
    190 }
    191 
    192 TEST_F(ProfileAssistantTest, DoNotAdviseCompilation) {
    193   ScratchFile profile1;
    194   ScratchFile profile2;
    195   ScratchFile reference_profile;
    196 
    197   std::vector<int> profile_fds({
    198       GetFd(profile1),
    199       GetFd(profile2)});
    200   int reference_profile_fd = GetFd(reference_profile);
    201 
    202   const uint16_t kNumberOfMethodsToSkipCompilation = 1;
    203   ProfileCompilationInfo info1;
    204   SetupProfile("p1", 1, kNumberOfMethodsToSkipCompilation, 0, profile1, &info1);
    205   ProfileCompilationInfo info2;
    206   SetupProfile("p2", 2, kNumberOfMethodsToSkipCompilation, 0, profile2, &info2);
    207 
    208   // We should not advise compilation.
    209   ASSERT_EQ(ProfileAssistant::kSkipCompilation,
    210             ProcessProfiles(profile_fds, reference_profile_fd));
    211 
    212   // The information from profiles must remain the same.
    213   ProfileCompilationInfo file_info1;
    214   ASSERT_TRUE(profile1.GetFile()->ResetOffset());
    215   ASSERT_TRUE(file_info1.Load(GetFd(profile1)));
    216   ASSERT_TRUE(file_info1.Equals(info1));
    217 
    218   ProfileCompilationInfo file_info2;
    219   ASSERT_TRUE(profile2.GetFile()->ResetOffset());
    220   ASSERT_TRUE(file_info2.Load(GetFd(profile2)));
    221   ASSERT_TRUE(file_info2.Equals(info2));
    222 
    223   // Reference profile files must remain empty.
    224   ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
    225 
    226   // The information from profiles must remain the same.
    227   CheckProfileInfo(profile1, info1);
    228   CheckProfileInfo(profile2, info2);
    229 }
    230 
    231 TEST_F(ProfileAssistantTest, FailProcessingBecauseOfProfiles) {
    232   ScratchFile profile1;
    233   ScratchFile profile2;
    234   ScratchFile reference_profile;
    235 
    236   std::vector<int> profile_fds({
    237       GetFd(profile1),
    238       GetFd(profile2)});
    239   int reference_profile_fd = GetFd(reference_profile);
    240 
    241   const uint16_t kNumberOfMethodsToEnableCompilation = 100;
    242   // Assign different hashes for the same dex file. This will make merging of information to fail.
    243   ProfileCompilationInfo info1;
    244   SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
    245   ProfileCompilationInfo info2;
    246   SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, profile2, &info2);
    247 
    248   // We should fail processing.
    249   ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
    250             ProcessProfiles(profile_fds, reference_profile_fd));
    251 
    252   // The information from profiles must remain the same.
    253   CheckProfileInfo(profile1, info1);
    254   CheckProfileInfo(profile2, info2);
    255 
    256   // Reference profile files must still remain empty.
    257   ASSERT_EQ(0, reference_profile.GetFile()->GetLength());
    258 }
    259 
    260 TEST_F(ProfileAssistantTest, FailProcessingBecauseOfReferenceProfiles) {
    261   ScratchFile profile1;
    262   ScratchFile reference_profile;
    263 
    264   std::vector<int> profile_fds({
    265       GetFd(profile1)});
    266   int reference_profile_fd = GetFd(reference_profile);
    267 
    268   const uint16_t kNumberOfMethodsToEnableCompilation = 100;
    269   // Assign different hashes for the same dex file. This will make merging of information to fail.
    270   ProfileCompilationInfo info1;
    271   SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1);
    272   ProfileCompilationInfo reference_info;
    273   SetupProfile("p1", 2, kNumberOfMethodsToEnableCompilation, 0, reference_profile, &reference_info);
    274 
    275   // We should not advise compilation.
    276   ASSERT_TRUE(profile1.GetFile()->ResetOffset());
    277   ASSERT_TRUE(reference_profile.GetFile()->ResetOffset());
    278   ASSERT_EQ(ProfileAssistant::kErrorBadProfiles,
    279             ProcessProfiles(profile_fds, reference_profile_fd));
    280 
    281   // The information from profiles must remain the same.
    282   CheckProfileInfo(profile1, info1);
    283 }
    284 
    285 }  // namespace art
    286