1 /* 2 * Copyright (C) 2011 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 #ifndef ART_RUNTIME_PROFILER_H_ 18 #define ART_RUNTIME_PROFILER_H_ 19 20 #include <memory> 21 #include <ostream> 22 #include <set> 23 #include <string> 24 #include <vector> 25 26 #include "barrier.h" 27 #include "base/macros.h" 28 #include "base/mutex.h" 29 #include "globals.h" 30 #include "instrumentation.h" 31 #include "profiler_options.h" 32 #include "os.h" 33 #include "safe_map.h" 34 #include "method_reference.h" 35 36 namespace art { 37 38 namespace mirror { 39 class Class; 40 } // namespace mirror 41 class ArtMethod; 42 class Thread; 43 44 typedef std::pair<ArtMethod*, uint32_t> InstructionLocation; 45 46 // This class stores the sampled bounded stacks in a trie structure. A path of the trie represents 47 // a particular context with the method on top of the stack being a leaf or an internal node of the 48 // trie rather than the root. 49 class StackTrieNode { 50 public: StackTrieNode(MethodReference method,uint32_t dex_pc,uint32_t method_size,StackTrieNode * parent)51 StackTrieNode(MethodReference method, uint32_t dex_pc, uint32_t method_size, 52 StackTrieNode* parent) : 53 parent_(parent), method_(method), dex_pc_(dex_pc), 54 count_(0), method_size_(method_size) { 55 } StackTrieNode()56 StackTrieNode() : parent_(nullptr), method_(nullptr, 0), 57 dex_pc_(0), count_(0), method_size_(0) { 58 } GetParent()59 StackTrieNode* GetParent() { return parent_; } GetMethod()60 MethodReference GetMethod() { return method_; } GetCount()61 uint32_t GetCount() { return count_; } GetDexPC()62 uint32_t GetDexPC() { return dex_pc_; } GetMethodSize()63 uint32_t GetMethodSize() { return method_size_; } AppendChild(StackTrieNode * child)64 void AppendChild(StackTrieNode* child) { children_.insert(child); } 65 StackTrieNode* FindChild(MethodReference method, uint32_t dex_pc); 66 void DeleteChildren(); IncreaseCount()67 void IncreaseCount() { ++count_; } 68 69 private: 70 // Comparator for stack trie node. 71 struct StackTrieNodeComparator { operatorStackTrieNodeComparator72 bool operator()(StackTrieNode* node1, StackTrieNode* node2) const { 73 MethodReference mr1 = node1->GetMethod(); 74 MethodReference mr2 = node2->GetMethod(); 75 if (mr1.dex_file == mr2.dex_file) { 76 if (mr1.dex_method_index == mr2.dex_method_index) { 77 return node1->GetDexPC() < node2->GetDexPC(); 78 } else { 79 return mr1.dex_method_index < mr2.dex_method_index; 80 } 81 } else { 82 return mr1.dex_file < mr2.dex_file; 83 } 84 } 85 }; 86 87 std::set<StackTrieNode*, StackTrieNodeComparator> children_; 88 StackTrieNode* parent_; 89 MethodReference method_; 90 uint32_t dex_pc_; 91 uint32_t count_; 92 uint32_t method_size_; 93 }; 94 95 // 96 // This class holds all the results for all runs of the profiler. It also 97 // counts the number of null methods (where we can't determine the method) and 98 // the number of methods in the boot path (where we have already compiled the method). 99 // 100 // This object is an internal profiler object and uses the same locking as the profiler 101 // itself. 102 class ProfileSampleResults { 103 public: 104 explicit ProfileSampleResults(Mutex& lock); 105 ~ProfileSampleResults(); 106 107 void Put(ArtMethod* method) REQUIRES(!lock_); 108 void PutStack(const std::vector<InstructionLocation>& stack_dump) REQUIRES(!lock_); 109 uint32_t Write(std::ostream &os, ProfileDataType type); 110 void ReadPrevious(int fd, ProfileDataType type); 111 void Clear(); GetNumSamples()112 uint32_t GetNumSamples() { return num_samples_; } NullMethod()113 void NullMethod() { ++num_null_methods_; } BootMethod()114 void BootMethod() { ++num_boot_methods_; } 115 116 private: 117 uint32_t Hash(ArtMethod* method); 118 static constexpr int kHashSize = 17; 119 Mutex& lock_; // Reference to the main profiler lock - we don't need two of them. 120 uint32_t num_samples_; // Total number of samples taken. 121 uint32_t num_null_methods_; // Number of samples where can don't know the method. 122 uint32_t num_boot_methods_; // Number of samples in the boot path. 123 124 typedef std::map<ArtMethod*, uint32_t> Map; // Map of method vs its count. 125 Map *table[kHashSize]; 126 127 typedef std::set<StackTrieNode*> TrieNodeSet; 128 // Map of method hit by profiler vs the set of stack trie nodes for this method. 129 typedef std::map<MethodReference, TrieNodeSet*, MethodReferenceComparator> MethodContextMap; 130 MethodContextMap *method_context_table; 131 StackTrieNode* stack_trie_root_; // Root of the trie that stores sampled stack information. 132 133 // Map from <pc, context> to counts. 134 typedef std::map<std::pair<uint32_t, std::string>, uint32_t> PreviousContextMap; 135 struct PreviousValue { PreviousValuePreviousValue136 PreviousValue() : count_(0), method_size_(0), context_map_(nullptr) {} PreviousValuePreviousValue137 PreviousValue(uint32_t count, uint32_t method_size, PreviousContextMap* context_map) 138 : count_(count), method_size_(method_size), context_map_(context_map) {} 139 uint32_t count_; 140 uint32_t method_size_; 141 PreviousContextMap* context_map_; 142 }; 143 144 typedef std::map<std::string, PreviousValue> PreviousProfile; 145 PreviousProfile previous_; 146 uint32_t previous_num_samples_; 147 uint32_t previous_num_null_methods_; // Number of samples where can don't know the method. 148 uint32_t previous_num_boot_methods_; // Number of samples in the boot path. 149 }; 150 151 // 152 // The BackgroundMethodSamplingProfiler runs in a thread. Most of the time it is sleeping but 153 // occasionally wakes up and counts the number of times a method is called. Each time 154 // it ticks, it looks at the current method and records it in the ProfileSampleResults 155 // table. 156 // 157 // The timing is controlled by a number of variables: 158 // 1. Period: the time between sampling runs. 159 // 2. Interval: the time between each sample in a run. 160 // 3. Duration: the duration of a run. 161 // 162 // So the profiler thread is sleeping for the 'period' time. It wakes up and runs for the 163 // 'duration'. The run consists of a series of samples, each of which is 'interval' microseconds 164 // apart. At the end of a run, it writes the results table to a file and goes back to sleep. 165 166 class BackgroundMethodSamplingProfiler { 167 public: 168 // Start a profile thread with the user-supplied arguments. 169 // Returns true if the profile was started or if it was already running. Returns false otherwise. 170 static bool Start(const std::string& output_filename, const ProfilerOptions& options) 171 REQUIRES(!Locks::mutator_lock_, !Locks::thread_list_lock_, !Locks::thread_suspend_count_lock_, 172 !Locks::profiler_lock_); 173 174 // NO_THREAD_SAFETY_ANALYSIS for static function calling into member function with excludes lock. 175 static void Stop() REQUIRES(!Locks::profiler_lock_, !wait_lock_, !Locks::profiler_lock_) 176 NO_THREAD_SAFETY_ANALYSIS; 177 // NO_THREAD_SAFETY_ANALYSIS for static function calling into member function with excludes lock. 178 static void Shutdown() REQUIRES(!Locks::profiler_lock_) NO_THREAD_SAFETY_ANALYSIS; 179 180 void RecordMethod(ArtMethod *method) SHARED_REQUIRES(Locks::mutator_lock_); 181 void RecordStack(const std::vector<InstructionLocation>& stack) 182 SHARED_REQUIRES(Locks::mutator_lock_); 183 bool ProcessMethod(ArtMethod* method) SHARED_REQUIRES(Locks::mutator_lock_); GetProfilerOptions()184 const ProfilerOptions& GetProfilerOptions() const { return options_; } 185 GetBarrier()186 Barrier& GetBarrier() { 187 return *profiler_barrier_; 188 } 189 190 private: 191 explicit BackgroundMethodSamplingProfiler( 192 const std::string& output_filename, const ProfilerOptions& options); 193 194 // The sampling interval in microseconds is passed as an argument. 195 // NO_THREAD_SAFETY_ANALYSIS for static function calling into member function with excludes lock. 196 static void* RunProfilerThread(void* arg) REQUIRES(!Locks::profiler_lock_) 197 NO_THREAD_SAFETY_ANALYSIS; 198 199 uint32_t WriteProfile() SHARED_REQUIRES(Locks::mutator_lock_); 200 201 void CleanProfile(); 202 uint32_t DumpProfile(std::ostream& os) SHARED_REQUIRES(Locks::mutator_lock_); 203 static bool ShuttingDown(Thread* self) REQUIRES(!Locks::profiler_lock_); 204 205 static BackgroundMethodSamplingProfiler* profiler_ GUARDED_BY(Locks::profiler_lock_); 206 207 // We need to shut the sample thread down at exit. Setting this to true will do that. 208 static volatile bool shutting_down_ GUARDED_BY(Locks::profiler_lock_); 209 210 // Sampling thread, non-zero when sampling. 211 static pthread_t profiler_pthread_; 212 213 // Some measure of the number of samples that are significant. 214 static constexpr uint32_t kSignificantSamples = 10; 215 216 // The name of the file where profile data will be written. 217 std::string output_filename_; 218 // The options used to start the profiler. 219 const ProfilerOptions& options_; 220 221 222 // Profile condition support. 223 Mutex wait_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; 224 ConditionVariable period_condition_ GUARDED_BY(wait_lock_); 225 226 ProfileSampleResults profile_table_; 227 228 std::unique_ptr<Barrier> profiler_barrier_; 229 230 // Set of methods to be filtered out. This will probably be rare because 231 // most of the methods we want to be filtered reside in the boot path and 232 // are automatically filtered. 233 typedef std::set<std::string> FilteredMethods; 234 FilteredMethods filtered_methods_; 235 236 DISALLOW_COPY_AND_ASSIGN(BackgroundMethodSamplingProfiler); 237 }; 238 239 // 240 // Contains profile data generated from previous runs of the program and stored 241 // in a file. It is used to determine whether to compile a particular method or not. 242 class ProfileFile { 243 public: 244 class ProfileData { 245 public: ProfileData()246 ProfileData() : count_(0), method_size_(0), used_percent_(0), top_k_used_percentage_(0) {} ProfileData(const std::string & method_name,uint32_t count,uint32_t method_size,double used_percent,double top_k_used_percentage)247 ProfileData(const std::string& method_name, uint32_t count, uint32_t method_size, 248 double used_percent, double top_k_used_percentage) : 249 method_name_(method_name), count_(count), method_size_(method_size), 250 used_percent_(used_percent), top_k_used_percentage_(top_k_used_percentage) { 251 // TODO: currently method_size_ is unused 252 UNUSED(method_size_); 253 } 254 GetUsedPercent()255 double GetUsedPercent() const { return used_percent_; } GetCount()256 uint32_t GetCount() const { return count_; } GetTopKUsedPercentage()257 double GetTopKUsedPercentage() const { return top_k_used_percentage_; } 258 259 private: 260 std::string method_name_; // Method name. 261 uint32_t count_; // Number of times it has been called. 262 uint32_t method_size_; // Size of the method on dex instructions. 263 double used_percent_; // Percentage of how many times this method was called. 264 double top_k_used_percentage_; // The percentage of the group that comprise K% of the total 265 // used methods this methods belongs to. 266 }; 267 268 public: 269 // Loads profile data from the given file. The new data are merged with any existing data. 270 // Returns true if the file was loaded successfully and false otherwise. 271 bool LoadFile(const std::string& filename); 272 273 // Computes the group that comprise top_k_percentage of the total used methods. 274 bool GetTopKSamples(std::set<std::string>& top_k_methods, double top_k_percentage); 275 276 // If the given method has an entry in the profile table it updates the data 277 // and returns true. Otherwise returns false and leaves the data unchanged. 278 bool GetProfileData(ProfileData* data, const std::string& method_name); 279 280 private: 281 // Profile data is stored in a map, indexed by the full method name. 282 typedef std::map<std::string, ProfileData> ProfileMap; 283 ProfileMap profile_map_; 284 }; 285 286 } // namespace art 287 288 #endif // ART_RUNTIME_PROFILER_H_ 289