Collect and output a few dex2oat statistics.

Not sure how useful this is. Suggestions welcome.

Change-Id: I339de66a9964d18b11a482f549e891a57831e10e
diff --git a/src/compiler.cc b/src/compiler.cc
index 647a8ed..2f9b3ed 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -42,6 +42,13 @@
     : instruction_set_(instruction_set),
       jni_compiler_(instruction_set),
       image_(image),
+      dex_file_count_(0),
+      class_count_(0),
+      abstract_method_count_(0),
+      native_method_count_(0),
+      regular_method_count_(0),
+      instruction_count_(0),
+      start_ns_(NanoTime()),
       image_classes_(image_classes) {
   CHECK(!Runtime::Current()->IsStarted());
   if (!image_) {
@@ -53,6 +60,18 @@
   STLDeleteValues(&compiled_classes_);
   STLDeleteValues(&compiled_methods_);
   STLDeleteValues(&compiled_invoke_stubs_);
+  if (dex_file_count_ > 0) {
+    uint64_t duration_ns = NanoTime() - start_ns_;
+    uint64_t duration_ms = NsToMs(duration_ns);
+    LOG(INFO) << "Compiled files:" << dex_file_count_
+              << " classes:" << class_count_
+              << " methods:(abstract:" << abstract_method_count_
+              << " native:" << native_method_count_
+              << " regular:" << regular_method_count_ << ")"
+              << " instructions:" << instruction_count_
+              << " (took " << duration_ms << "ms, "
+              << (duration_ns/instruction_count_) << " ns/instruction)";
+  }
 }
 
 ByteArray* Compiler::CreateResolutionStub(InstructionSet instruction_set,
@@ -361,6 +380,7 @@
 }
 
 void Compiler::CompileDexFile(const ClassLoader* class_loader, const DexFile& dex_file) {
+  ++dex_file_count_;
   for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs(); class_def_index++) {
     const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
     CompileClass(class_def, class_loader, dex_file);
@@ -372,6 +392,7 @@
   if (SkipClass(class_loader, dex_file, class_def)) {
     return;
   }
+  ++class_count_;
   const byte* class_data = dex_file.GetClassData(class_def);
   if (class_data == NULL) {
     // empty class, probably a marker interface
@@ -404,14 +425,24 @@
                              uint32_t method_idx, const ClassLoader* class_loader,
                              const DexFile& dex_file) {
   CompiledMethod* compiled_method = NULL;
+  uint64_t start_ns = NanoTime();
   if ((access_flags & kAccNative) != 0) {
+    ++native_method_count_;
     compiled_method = jni_compiler_.Compile(access_flags, method_idx, class_loader, dex_file);
     CHECK(compiled_method != NULL);
   } else if ((access_flags & kAccAbstract) != 0) {
+    ++abstract_method_count_;
   } else {
+    ++regular_method_count_;
+    instruction_count_ += code_item->insns_size_in_code_units_;
     compiled_method = oatCompileMethod(*this, code_item, access_flags, method_idx, class_loader,
                                        dex_file, kThumb2);
-    CHECK(compiled_method != NULL);
+    CHECK(compiled_method != NULL) << PrettyMethod(method_idx, dex_file);
+  }
+  uint64_t duration_ms = NsToMs(NanoTime() - start_ns);
+  if (duration_ms > 10) {
+    LOG(WARNING) << "Compilation of " << PrettyMethod(method_idx, dex_file)
+                 << " took " << duration_ms << "ms";
   }
 
   if (compiled_method != NULL) {
@@ -441,7 +472,7 @@
 static std::string MakeInvokeStubKey(bool is_static, const char* shorty) {
   std::string key(shorty);
   if (is_static) {
-    key += "$";  // musn't be a shorty type character
+    key += "$";  // Must not be a shorty type character.
   }
   return key;
 }