Print memory usage in dex2oat shutdown

Example on mako:
I/dex2oat (31071): dex2oat took 31.195s (threads: 2) arena alloc=1013KB java alloc=13MB native alloc=32MB free=1490KB

Bug: 18069309

Change-Id: I08eac00842be35d4e659bddc8513f2062be725c9

(cherry picked from commit 3029df6d212894647ba0e5c23443c40912c6ecc8)
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 437a1a9..d837dbc 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -340,6 +340,9 @@
   ArenaPool* GetArenaPool() {
     return &arena_pool_;
   }
+  const ArenaPool* GetArenaPool() const {
+    return &arena_pool_;
+  }
 
   bool WriteElf(const std::string& android_root,
                 bool is_host,
diff --git a/compiler/utils/arena_allocator.cc b/compiler/utils/arena_allocator.cc
index 004af98..a80ad93 100644
--- a/compiler/utils/arena_allocator.cc
+++ b/compiler/utils/arena_allocator.cc
@@ -189,6 +189,15 @@
   return ret;
 }
 
+size_t ArenaPool::GetBytesAllocated() const {
+  size_t total = 0;
+  MutexLock lock(Thread::Current(), lock_);
+  for (Arena* arena = free_arenas_; arena != nullptr; arena = arena->next_) {
+    total += arena->GetBytesAllocated();
+  }
+  return total;
+}
+
 void ArenaPool::FreeArenaChain(Arena* first) {
   if (UNLIKELY(RUNNING_ON_VALGRIND > 0)) {
     for (Arena* arena = first; arena != nullptr; arena = arena->next_) {
diff --git a/compiler/utils/arena_allocator.h b/compiler/utils/arena_allocator.h
index 6d21399..7f5bc9a 100644
--- a/compiler/utils/arena_allocator.h
+++ b/compiler/utils/arena_allocator.h
@@ -135,6 +135,10 @@
     return Size() - bytes_allocated_;
   }
 
+  size_t GetBytesAllocated() const {
+    return bytes_allocated_;
+  }
+
  private:
   size_t bytes_allocated_;
   uint8_t* memory_;
@@ -153,11 +157,12 @@
  public:
   ArenaPool();
   ~ArenaPool();
-  Arena* AllocArena(size_t size);
-  void FreeArenaChain(Arena* first);
+  Arena* AllocArena(size_t size) LOCKS_EXCLUDED(lock_);
+  void FreeArenaChain(Arena* first) LOCKS_EXCLUDED(lock_);
+  size_t GetBytesAllocated() const LOCKS_EXCLUDED(lock_);
 
  private:
-  Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+  mutable Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   Arena* free_arenas_ GUARDED_BY(lock_);
   DISALLOW_COPY_AND_ASSIGN(ArenaPool);
 };
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index cd78df1..d957d27 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -21,6 +21,7 @@
 
 #include <fstream>
 #include <iostream>
+#include <malloc.h>  // For mallinfo
 #include <sstream>
 #include <string>
 #include <vector>
@@ -450,10 +451,10 @@
       timings_(timings) {}
 
   ~Dex2Oat() {
+    LogCompletionTime();  // Needs to be before since it accesses the runtime.
     if (kIsDebugBuild || (RUNNING_ON_VALGRIND != 0)) {
       delete runtime_;  // See field declaration for why this is manual.
     }
-    LogCompletionTime();
   }
 
   // Parse the arguments from the command line. In case of an unrecognized option or impossible
@@ -1604,9 +1605,21 @@
     return ReadImageClasses(image_classes_stream);
   }
 
-  void LogCompletionTime() const {
+  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_ << ")";
+              << " (threads: " << thread_count_ << ")"
+              << " arena alloc=" << PrettySize(arena_pool->GetBytesAllocated())
+              << " java alloc=" << PrettySize(heap->GetBytesAllocated()) << mallinfostr.str();
   }
 
   std::unique_ptr<CompilerOptions> compiler_options_;