1 /*
2  * Copyright 2014 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_JIT_JIT_H_
18 #define ART_RUNTIME_JIT_JIT_H_
19 
20 #include "base/histogram-inl.h"
21 #include "base/macros.h"
22 #include "base/mutex.h"
23 #include "base/timing_logger.h"
24 #include "jit/profile_saver_options.h"
25 #include "obj_ptr.h"
26 #include "thread_pool.h"
27 
28 namespace art {
29 
30 class ArtMethod;
31 class ClassLinker;
32 struct RuntimeArgumentMap;
33 union JValue;
34 
35 namespace mirror {
36 class Object;
37 class Class;
38 }   // namespace mirror
39 
40 namespace jit {
41 
42 class JitCodeCache;
43 class JitOptions;
44 
45 static constexpr int16_t kJitCheckForOSR = -1;
46 static constexpr int16_t kJitHotnessDisabled = -2;
47 
48 class Jit {
49  public:
50   static constexpr size_t kDefaultPriorityThreadWeightRatio = 1000;
51   static constexpr size_t kDefaultInvokeTransitionWeightRatio = 500;
52   // How frequently should the interpreter check to see if OSR compilation is ready.
53   static constexpr int16_t kJitRecheckOSRThreshold = 100;
54 
55   virtual ~Jit();
56   static Jit* Create(JitOptions* options, std::string* error_msg);
57   bool CompileMethod(ArtMethod* method, Thread* self, bool osr)
58       REQUIRES_SHARED(Locks::mutator_lock_);
59   void CreateThreadPool();
60 
GetCodeCache()61   const JitCodeCache* GetCodeCache() const {
62     return code_cache_.get();
63   }
64 
GetCodeCache()65   JitCodeCache* GetCodeCache() {
66     return code_cache_.get();
67   }
68 
69   void DeleteThreadPool();
70   // Dump interesting info: #methods compiled, code vs data size, compile / verify cumulative
71   // loggers.
72   void DumpInfo(std::ostream& os) REQUIRES(!lock_);
73   // Add a timing logger to cumulative_timings_.
74   void AddTimingLogger(const TimingLogger& logger);
75 
76   void AddMemoryUsage(ArtMethod* method, size_t bytes)
77       REQUIRES(!lock_)
78       REQUIRES_SHARED(Locks::mutator_lock_);
79 
OSRMethodThreshold()80   size_t OSRMethodThreshold() const {
81     return osr_method_threshold_;
82   }
83 
HotMethodThreshold()84   size_t HotMethodThreshold() const {
85     return hot_method_threshold_;
86   }
87 
WarmMethodThreshold()88   size_t WarmMethodThreshold() const {
89     return warm_method_threshold_;
90   }
91 
PriorityThreadWeight()92   uint16_t PriorityThreadWeight() const {
93     return priority_thread_weight_;
94   }
95 
96   // Returns false if we only need to save profile information and not compile methods.
UseJitCompilation()97   bool UseJitCompilation() const {
98     return use_jit_compilation_;
99   }
100 
GetSaveProfilingInfo()101   bool GetSaveProfilingInfo() const {
102     return profile_saver_options_.IsEnabled();
103   }
104 
105   // Wait until there is no more pending compilation tasks.
106   void WaitForCompilationToFinish(Thread* self);
107 
108   // Profiling methods.
109   void MethodEntered(Thread* thread, ArtMethod* method)
110       REQUIRES_SHARED(Locks::mutator_lock_);
111 
112   void AddSamples(Thread* self, ArtMethod* method, uint16_t samples, bool with_backedges)
113       REQUIRES_SHARED(Locks::mutator_lock_);
114 
115   void InvokeVirtualOrInterface(ObjPtr<mirror::Object> this_object,
116                                 ArtMethod* caller,
117                                 uint32_t dex_pc,
118                                 ArtMethod* callee)
119       REQUIRES_SHARED(Locks::mutator_lock_);
120 
NotifyInterpreterToCompiledCodeTransition(Thread * self,ArtMethod * caller)121   void NotifyInterpreterToCompiledCodeTransition(Thread* self, ArtMethod* caller)
122       REQUIRES_SHARED(Locks::mutator_lock_) {
123     AddSamples(self, caller, invoke_transition_weight_, false);
124   }
125 
NotifyCompiledCodeToInterpreterTransition(Thread * self,ArtMethod * callee)126   void NotifyCompiledCodeToInterpreterTransition(Thread* self, ArtMethod* callee)
127       REQUIRES_SHARED(Locks::mutator_lock_) {
128     AddSamples(self, callee, invoke_transition_weight_, false);
129   }
130 
131   // Starts the profile saver if the config options allow profile recording.
132   // The profile will be stored in the specified `filename` and will contain
133   // information collected from the given `code_paths` (a set of dex locations).
134   void StartProfileSaver(const std::string& filename,
135                          const std::vector<std::string>& code_paths);
136   void StopProfileSaver();
137 
138   void DumpForSigQuit(std::ostream& os) REQUIRES(!lock_);
139 
140   static void NewTypeLoadedIfUsingJit(mirror::Class* type)
141       REQUIRES_SHARED(Locks::mutator_lock_);
142 
143   // If debug info generation is turned on then write the type information for types already loaded
144   // into the specified class linker to the jit debug interface,
145   void DumpTypeInfoForLoadedTypes(ClassLinker* linker);
146 
147   // Return whether we should try to JIT compiled code as soon as an ArtMethod is invoked.
148   bool JitAtFirstUse();
149 
150   // Return whether we can invoke JIT code for `method`.
151   bool CanInvokeCompiledCode(ArtMethod* method);
152 
153   // Return whether the runtime should use a priority thread weight when sampling.
154   static bool ShouldUsePriorityThreadWeight(Thread* self);
155 
156   // If an OSR compiled version is available for `method`,
157   // and `dex_pc + dex_pc_offset` is an entry point of that compiled
158   // version, this method will jump to the compiled code, let it run,
159   // and return true afterwards. Return false otherwise.
160   static bool MaybeDoOnStackReplacement(Thread* thread,
161                                         ArtMethod* method,
162                                         uint32_t dex_pc,
163                                         int32_t dex_pc_offset,
164                                         JValue* result)
165       REQUIRES_SHARED(Locks::mutator_lock_);
166 
167   static bool LoadCompilerLibrary(std::string* error_msg);
168 
GetThreadPool()169   ThreadPool* GetThreadPool() const {
170     return thread_pool_.get();
171   }
172 
173   // Stop the JIT by waiting for all current compilations and enqueued compilations to finish.
174   void Stop();
175 
176   // Start JIT threads.
177   void Start();
178 
179  private:
180   Jit();
181 
182   static bool LoadCompiler(std::string* error_msg);
183 
184   // JIT compiler
185   static void* jit_library_handle_;
186   static void* jit_compiler_handle_;
187   static void* (*jit_load_)(bool*);
188   static void (*jit_unload_)(void*);
189   static bool (*jit_compile_method_)(void*, ArtMethod*, Thread*, bool);
190   static void (*jit_types_loaded_)(void*, mirror::Class**, size_t count);
191 
192   // Performance monitoring.
193   bool dump_info_on_shutdown_;
194   CumulativeLogger cumulative_timings_;
195   Histogram<uint64_t> memory_use_ GUARDED_BY(lock_);
196   Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
197 
198   std::unique_ptr<jit::JitCodeCache> code_cache_;
199 
200   bool use_jit_compilation_;
201   ProfileSaverOptions profile_saver_options_;
202   static bool generate_debug_info_;
203   uint16_t hot_method_threshold_;
204   uint16_t warm_method_threshold_;
205   uint16_t osr_method_threshold_;
206   uint16_t priority_thread_weight_;
207   uint16_t invoke_transition_weight_;
208   std::unique_ptr<ThreadPool> thread_pool_;
209 
210   DISALLOW_COPY_AND_ASSIGN(Jit);
211 };
212 
213 class JitOptions {
214  public:
215   static JitOptions* CreateFromRuntimeArguments(const RuntimeArgumentMap& options);
GetCompileThreshold()216   size_t GetCompileThreshold() const {
217     return compile_threshold_;
218   }
GetWarmupThreshold()219   size_t GetWarmupThreshold() const {
220     return warmup_threshold_;
221   }
GetOsrThreshold()222   size_t GetOsrThreshold() const {
223     return osr_threshold_;
224   }
GetPriorityThreadWeight()225   uint16_t GetPriorityThreadWeight() const {
226     return priority_thread_weight_;
227   }
GetInvokeTransitionWeight()228   size_t GetInvokeTransitionWeight() const {
229     return invoke_transition_weight_;
230   }
GetCodeCacheInitialCapacity()231   size_t GetCodeCacheInitialCapacity() const {
232     return code_cache_initial_capacity_;
233   }
GetCodeCacheMaxCapacity()234   size_t GetCodeCacheMaxCapacity() const {
235     return code_cache_max_capacity_;
236   }
DumpJitInfoOnShutdown()237   bool DumpJitInfoOnShutdown() const {
238     return dump_info_on_shutdown_;
239   }
GetProfileSaverOptions()240   const ProfileSaverOptions& GetProfileSaverOptions() const {
241     return profile_saver_options_;
242   }
GetSaveProfilingInfo()243   bool GetSaveProfilingInfo() const {
244     return profile_saver_options_.IsEnabled();
245   }
UseJitCompilation()246   bool UseJitCompilation() const {
247     return use_jit_compilation_;
248   }
SetUseJitCompilation(bool b)249   void SetUseJitCompilation(bool b) {
250     use_jit_compilation_ = b;
251   }
SetSaveProfilingInfo(bool save_profiling_info)252   void SetSaveProfilingInfo(bool save_profiling_info) {
253     profile_saver_options_.SetEnabled(save_profiling_info);
254   }
SetWaitForJitNotificationsToSaveProfile(bool value)255   void SetWaitForJitNotificationsToSaveProfile(bool value) {
256     profile_saver_options_.SetWaitForJitNotificationsToSave(value);
257   }
SetProfileAOTCode(bool value)258   void SetProfileAOTCode(bool value) {
259     profile_saver_options_.SetProfileAOTCode(value);
260   }
261 
SetJitAtFirstUse()262   void SetJitAtFirstUse() {
263     use_jit_compilation_ = true;
264     compile_threshold_ = 0;
265   }
266 
267  private:
268   bool use_jit_compilation_;
269   size_t code_cache_initial_capacity_;
270   size_t code_cache_max_capacity_;
271   size_t compile_threshold_;
272   size_t warmup_threshold_;
273   size_t osr_threshold_;
274   uint16_t priority_thread_weight_;
275   size_t invoke_transition_weight_;
276   bool dump_info_on_shutdown_;
277   ProfileSaverOptions profile_saver_options_;
278 
JitOptions()279   JitOptions()
280       : use_jit_compilation_(false),
281         code_cache_initial_capacity_(0),
282         code_cache_max_capacity_(0),
283         compile_threshold_(0),
284         warmup_threshold_(0),
285         osr_threshold_(0),
286         priority_thread_weight_(0),
287         invoke_transition_weight_(0),
288         dump_info_on_shutdown_(false) {}
289 
290   DISALLOW_COPY_AND_ASSIGN(JitOptions);
291 };
292 
293 // Helper class to stop the JIT for a given scope. This will wait for the JIT to quiesce.
294 class ScopedJitSuspend {
295  public:
296   ScopedJitSuspend();
297   ~ScopedJitSuspend();
298 
299  private:
300   bool was_on_;
301 };
302 
303 }  // namespace jit
304 }  // namespace art
305 
306 #endif  // ART_RUNTIME_JIT_JIT_H_
307