• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 <memory>
18 #include <set>
19 
20 #include "boot_image_profile.h"
21 #include "dex/class_accessor-inl.h"
22 #include "dex/dex_file-inl.h"
23 #include "dex/method_reference.h"
24 #include "dex/type_reference.h"
25 #include "profile/profile_compilation_info.h"
26 
27 namespace art {
28 
29 using Hotness = ProfileCompilationInfo::MethodHotness;
30 
GenerateBootImageProfile(const std::vector<std::unique_ptr<const DexFile>> & dex_files,const std::vector<std::unique_ptr<const ProfileCompilationInfo>> & profiles,const BootImageOptions & options,bool verbose,ProfileCompilationInfo * out_profile)31 void GenerateBootImageProfile(
32     const std::vector<std::unique_ptr<const DexFile>>& dex_files,
33     const std::vector<std::unique_ptr<const ProfileCompilationInfo>>& profiles,
34     const BootImageOptions& options,
35     bool verbose,
36     ProfileCompilationInfo* out_profile) {
37   for (const std::unique_ptr<const ProfileCompilationInfo>& profile : profiles) {
38     // Avoid merging classes since we may want to only add classes that fit a certain criteria.
39     // If we merged the classes, every single class in each profile would be in the out_profile,
40     // but we want to only included classes that are in at least a few profiles.
41     out_profile->MergeWith(*profile, /*merge_classes=*/ false);
42   }
43 
44   // Image classes that were added because they are commonly used.
45   size_t class_count = 0;
46   // Image classes that were only added because they were clean.
47   size_t clean_class_count = 0;
48   // Total clean classes.
49   size_t clean_count = 0;
50   // Total dirty classes.
51   size_t dirty_count = 0;
52 
53   for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
54     // Inferred classes are classes inferred from method samples.
55     std::set<std::pair<const ProfileCompilationInfo*, dex::TypeIndex>> inferred_classes;
56     for (size_t i = 0; i < dex_file->NumMethodIds(); ++i) {
57       MethodReference ref(dex_file.get(), i);
58       // This counter is how many profiles contain the method as sampled or hot.
59       size_t counter = 0;
60       for (const std::unique_ptr<const ProfileCompilationInfo>& profile : profiles) {
61         Hotness hotness = profile->GetMethodHotness(ref);
62         if (hotness.IsInProfile()) {
63           ++counter;
64           out_profile->AddMethodHotness(ref, hotness);
65           inferred_classes.emplace(profile.get(), ref.GetMethodId().class_idx_);
66         }
67       }
68       // If the counter is greater or equal to the compile threshold, mark the method as hot.
69       // Note that all hot methods are also marked as hot in the out profile during the merging
70       // process.
71       if (counter >= options.compiled_method_threshold) {
72         Hotness hotness;
73         hotness.AddFlag(Hotness::kFlagHot);
74         out_profile->AddMethodHotness(ref, hotness);
75       }
76     }
77     // Walk all of the classes and add them to the profile if they meet the requirements.
78     for (ClassAccessor accessor : dex_file->GetClasses()) {
79       TypeReference ref(dex_file.get(), accessor.GetClassIdx());
80       bool is_clean = true;
81       auto method_visitor = [&](const ClassAccessor::Method& method) {
82         const uint32_t flags = method.GetAccessFlags();
83         if ((flags & kAccNative) != 0) {
84           // Native method will get dirtied.
85           is_clean = false;
86         }
87         if ((flags & kAccConstructor) != 0 && (flags & kAccStatic) != 0) {
88           // Class initializer, may get dirtied (not sure).
89           is_clean = false;
90         }
91       };
92       accessor.VisitFieldsAndMethods(
93           [&](const ClassAccessor::Field& field) {
94             if (!field.IsFinal()) {
95               // Not final static field will probably dirty the class.
96               is_clean = false;
97             }
98           },
99           /*instance_field_visitor=*/ VoidFunctor(),
100           method_visitor,
101           method_visitor);
102 
103       ++(is_clean ? clean_count : dirty_count);
104       // This counter is how many profiles contain the class.
105       size_t counter = 0;
106       for (const std::unique_ptr<const ProfileCompilationInfo>& profile : profiles) {
107         auto it = inferred_classes.find(std::make_pair(profile.get(), ref.TypeIndex()));
108         if (it != inferred_classes.end() ||
109             profile->ContainsClass(*ref.dex_file, ref.TypeIndex())) {
110           ++counter;
111         }
112       }
113       if (counter == 0) {
114         continue;
115       }
116       if (counter >= options.image_class_theshold) {
117         ++class_count;
118         out_profile->AddClassForDex(ref);
119       } else if (is_clean && counter >= options.image_class_clean_theshold) {
120         ++clean_class_count;
121         out_profile->AddClassForDex(ref);
122       }
123     }
124   }
125   if (verbose) {
126     LOG(INFO) << "Image classes " << class_count + clean_class_count
127               << " added because clean " << clean_class_count
128               << " total clean " << clean_count << " total dirty " << dirty_count;
129   }
130 }
131 
132 }  // namespace art
133