diff options
author | Mathieu Chartier <mathieuc@google.com> | 2014-12-03 17:38:22 -0800 |
---|---|---|
committer | Mathieu Chartier <mathieuc@google.com> | 2014-12-03 18:27:43 -0800 |
commit | ab972ef472001fa113d54486d7592979e33480b3 (patch) | |
tree | 08a8bf01ddfc0fd3a012faac2b49fafa5853e56f | |
parent | 8b9a97e8b6ed97ff1991596cbd0f7ce78f004766 (diff) | |
download | android_art-ab972ef472001fa113d54486d7592979e33480b3.tar.gz android_art-ab972ef472001fa113d54486d7592979e33480b3.tar.bz2 android_art-ab972ef472001fa113d54486d7592979e33480b3.zip |
Remove method verification results right after compiling a method
This saves memory since it allows the code arrays from methods
compiled in future methods to use the ram we just freed from the
verification results.
GmsCore.apk:
Before: dex2oat took 77.383s (threads: 2) arena alloc=6MB java alloc=30MB native alloc=77MB free=13KB
After: dex2oat took 72.180s (threads: 2) arena alloc=6MB java alloc=30MB native alloc=60MB free=13KB
Bug: 18596910
Change-Id: I5d6df380e4fe58751a2b304202083f4d30b33b7c
(cherry picked from commit 25fda92083d5b93b38cc1f6b12ac6a44d992d6a4)
-rw-r--r-- | compiler/dex/quick/codegen_util.cc | 4 | ||||
-rw-r--r-- | compiler/dex/verification_results.cc | 9 | ||||
-rw-r--r-- | compiler/dex/verification_results.h | 1 | ||||
-rw-r--r-- | compiler/driver/compiler_driver.cc | 42 | ||||
-rw-r--r-- | compiler/driver/compiler_driver.h | 4 | ||||
-rw-r--r-- | compiler/driver/dex_compilation_unit.h | 6 | ||||
-rw-r--r-- | dex2oat/dex2oat.cc | 19 |
7 files changed, 61 insertions, 24 deletions
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index 58bcee2124..00217549b0 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -775,6 +775,10 @@ void Mir2Lir::CreateNativeGcMap() { ": " << PrettyMethod(cu_->method_idx, *cu_->dex_file); native_gc_map_builder.AddEntry(native_offset, references); } + + // Maybe not necessary, but this could help prevent errors where we access the verified method + // after it has been deleted. + mir_graph_->GetCurrentDexCompilationUnit()->ClearVerifiedMethod(); } /* Determine the offset of each literal field */ diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc index 4929b5b2b0..932a532e56 100644 --- a/compiler/dex/verification_results.cc +++ b/compiler/dex/verification_results.cc @@ -84,6 +84,15 @@ const VerifiedMethod* VerificationResults::GetVerifiedMethod(MethodReference ref return (it != verified_methods_.end()) ? it->second : nullptr; } +void VerificationResults::RemoveVerifiedMethod(MethodReference ref) { + WriterMutexLock mu(Thread::Current(), verified_methods_lock_); + auto it = verified_methods_.find(ref); + if (it != verified_methods_.end()) { + delete it->second; + verified_methods_.erase(it); + } +} + void VerificationResults::AddRejectedClass(ClassReference ref) { { WriterMutexLock mu(Thread::Current(), rejected_classes_lock_); diff --git a/compiler/dex/verification_results.h b/compiler/dex/verification_results.h index 0e7923fbc3..7fc2a2363d 100644 --- a/compiler/dex/verification_results.h +++ b/compiler/dex/verification_results.h @@ -48,6 +48,7 @@ class VerificationResults { const VerifiedMethod* GetVerifiedMethod(MethodReference ref) LOCKS_EXCLUDED(verified_methods_lock_); + void RemoveVerifiedMethod(MethodReference ref) LOCKS_EXCLUDED(verified_methods_lock_); void AddRejectedClass(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_); bool IsClassRejected(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_); diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index ab9f41a4b3..e4274712d4 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -23,6 +23,10 @@ #include <vector> #include <unistd.h> +#ifndef __APPLE__ +#include <malloc.h> // For mallinfo +#endif + #include "base/stl_util.h" #include "base/timing_logger.h" #include "class_linker.h" @@ -497,6 +501,7 @@ void CompilerDriver::CompileAll(jobject class_loader, TimingLogger* timings) { DCHECK(!Runtime::Current()->IsStarted()); std::unique_ptr<ThreadPool> thread_pool(new ThreadPool("Compiler driver thread pool", thread_count_ - 1)); + VLOG(compiler) << "Before precompile " << GetMemoryUsageString(); PreCompile(class_loader, dex_files, thread_pool.get(), timings); Compile(class_loader, dex_files, thread_pool.get(), timings); if (dump_stats_) { @@ -593,20 +598,25 @@ void CompilerDriver::Resolve(jobject class_loader, const std::vector<const DexFi void CompilerDriver::PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files, ThreadPool* thread_pool, TimingLogger* timings) { LoadImageClasses(timings); + VLOG(compiler) << "LoadImageClasses: " << GetMemoryUsageString(); Resolve(class_loader, dex_files, thread_pool, timings); + VLOG(compiler) << "Resolve: " << GetMemoryUsageString(); if (!compiler_options_->IsVerificationEnabled()) { - LOG(INFO) << "Verify none mode specified, skipping verification."; + VLOG(compiler) << "Verify none mode specified, skipping verification."; SetVerified(class_loader, dex_files, thread_pool, timings); return; } Verify(class_loader, dex_files, thread_pool, timings); + VLOG(compiler) << "Verify: " << GetMemoryUsageString(); InitializeClasses(class_loader, dex_files, thread_pool, timings); + VLOG(compiler) << "InitializeClasses: " << GetMemoryUsageString(); UpdateImageClasses(timings); + VLOG(compiler) << "UpdateImageClasses: " << GetMemoryUsageString(); } bool CompilerDriver::IsImageClass(const char* descriptor) const { @@ -2002,6 +2012,7 @@ void CompilerDriver::Compile(jobject class_loader, const std::vector<const DexFi CHECK(dex_file != nullptr); CompileDexFile(class_loader, *dex_file, dex_files, thread_pool, timings); } + VLOG(compiler) << "Compile: " << GetMemoryUsageString(); } void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, size_t class_def_index) { @@ -2128,6 +2139,7 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t bool compilation_enabled) { CompiledMethod* compiled_method = nullptr; uint64_t start_ns = kTimeCompileMethod ? NanoTime() : 0; + MethodReference method_ref(&dex_file, method_idx); if ((access_flags & kAccNative) != 0) { // Are we interpreting only and have support for generic JNI down calls? @@ -2141,7 +2153,6 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t } else if ((access_flags & kAccAbstract) != 0) { // Abstract methods don't have code. } else { - MethodReference method_ref(&dex_file, method_idx); bool compile = compilation_enabled && verification_results_->IsCandidateForCompilation(method_ref, access_flags); if (compile) { @@ -2178,16 +2189,18 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t // When compiling with PIC, there should be zero non-relative linker patches CHECK(!compile_pic || non_relative_linker_patch_count == 0u); - MethodReference ref(&dex_file, method_idx); - DCHECK(GetCompiledMethod(ref) == nullptr) << PrettyMethod(method_idx, dex_file); + DCHECK(GetCompiledMethod(method_ref) == nullptr) << PrettyMethod(method_idx, dex_file); { MutexLock mu(self, compiled_methods_lock_); - compiled_methods_.Put(ref, compiled_method); + compiled_methods_.Put(method_ref, compiled_method); non_relative_linker_patch_count_ += non_relative_linker_patch_count; } - DCHECK(GetCompiledMethod(ref) != nullptr) << PrettyMethod(method_idx, dex_file); + DCHECK(GetCompiledMethod(method_ref) != nullptr) << PrettyMethod(method_idx, dex_file); } + // Done compiling, delete the verified method to reduce native memory usage. + verification_results_->RemoveVerifiedMethod(method_ref); + if (self->IsExceptionPending()) { ScopedObjectAccess soa(self); LOG(FATAL) << "Unexpected exception compiling: " << PrettyMethod(method_idx, dex_file) << "\n" @@ -2337,4 +2350,21 @@ bool CompilerDriver::SkipCompilation(const std::string& method_name) { } return !compile; } + +std::string CompilerDriver::GetMemoryUsageString() const { + std::ostringstream oss; + const ArenaPool* arena_pool = GetArenaPool(); + gc::Heap* heap = Runtime::Current()->GetHeap(); + oss << "arena alloc=" << PrettySize(arena_pool->GetBytesAllocated()); + oss << " java alloc=" << PrettySize(heap->GetBytesAllocated()); +#ifdef HAVE_MALLOC_H + struct mallinfo info = mallinfo(); + const size_t allocated_space = static_cast<size_t>(info.uordblks); + const size_t free_space = static_cast<size_t>(info.fordblks); + oss << " native alloc=" << PrettySize(allocated_space) << " free=" + << PrettySize(free_space); +#endif + return oss.str(); +} + } // namespace art diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index d837dbc9cd..615e0d0db4 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -39,6 +39,7 @@ #include "thread_pool.h" #include "utils/arena_allocator.h" #include "utils/dedupe_set.h" +#include "dex/verified_method.h" namespace art { @@ -398,6 +399,9 @@ class CompilerDriver { // Should the compiler run on this method given profile information? bool SkipCompilation(const std::string& method_name); + // Get memory usage during compilation. + std::string GetMemoryUsageString() const; + private: // These flags are internal to CompilerDriver for collecting INVOKE resolution statistics. // The only external contract is that unresolved method has flags 0 and resolved non-0. diff --git a/compiler/driver/dex_compilation_unit.h b/compiler/driver/dex_compilation_unit.h index 84f57991c3..03ae489da1 100644 --- a/compiler/driver/dex_compilation_unit.h +++ b/compiler/driver/dex_compilation_unit.h @@ -102,6 +102,10 @@ class DexCompilationUnit { return verified_method_; } + void ClearVerifiedMethod() { + verified_method_ = nullptr; + } + const std::string& GetSymbol(); private: @@ -117,7 +121,7 @@ class DexCompilationUnit { const uint16_t class_def_idx_; const uint32_t dex_method_idx_; const uint32_t access_flags_; - const VerifiedMethod* const verified_method_; + const VerifiedMethod* verified_method_; std::string symbol_; }; diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 25d6db16b4..d7669e1104 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -25,10 +25,6 @@ #include <string> #include <vector> -#ifndef __APPLE__ -#include <malloc.h> // For mallinfo -#endif - #if defined(__linux__) && defined(__arm__) #include <sys/personality.h> #include <sys/utsname.h> @@ -1614,20 +1610,9 @@ class Dex2Oat FINAL { } void LogCompletionTime() { - std::ostringstream mallinfostr; -#ifdef HAVE_MALLOC_H - struct mallinfo info = mallinfo(); - const size_t allocated_space = static_cast<size_t>(info.uordblks); - const size_t free_space = static_cast<size_t>(info.fordblks); - mallinfostr << " native alloc=" << PrettySize(allocated_space) << " free=" - << PrettySize(free_space); -#endif - const ArenaPool* arena_pool = driver_->GetArenaPool(); - gc::Heap* heap = Runtime::Current()->GetHeap(); LOG(INFO) << "dex2oat took " << PrettyDuration(NanoTime() - start_ns_) - << " (threads: " << thread_count_ << ")" - << " arena alloc=" << PrettySize(arena_pool->GetBytesAllocated()) - << " java alloc=" << PrettySize(heap->GetBytesAllocated()) << mallinfostr.str(); + << " (threads: " << thread_count_ << ") " + << driver_->GetMemoryUsageString(); } std::unique_ptr<CompilerOptions> compiler_options_; |