Option to gnuplot dex layout

Display the portions of the dex file that are accessed by the classes in
the dex file.  Optionally limit the display to only those classes that
are present in a runtime profile.

Bug: 29921113
Change-Id: I2a998fba448fec6c23941d3b4358531b1336e1b3
Test: dexlayout test
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp
index 296cdb6..0987df7 100644
--- a/dexlayout/Android.bp
+++ b/dexlayout/Android.bp
@@ -20,6 +20,7 @@
         "dexlayout.cc",
         "dex_ir.cc",
         "dex_ir_builder.cc",
+        "dex_visualize.cc",
     ],
     cflags: ["-Wall"],
     shared_libs: [
diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h
index 6ae9f1c..f3d2c90 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -217,6 +217,17 @@
   uint32_t MethodIdsSize() const { return method_ids_.Size(); }
   uint32_t ClassDefsSize() const { return class_defs_.Size(); }
 
+  uint32_t StringDatasSize() const { return string_datas_.Size(); }
+  uint32_t TypeListsSize() const { return type_lists_.Size(); }
+  uint32_t EncodedArraySize() const { return encoded_array_items_.Size(); }
+  uint32_t AnnotationSize() const { return annotation_items_.Size(); }
+  uint32_t AnnotationSetSize() const { return annotation_set_items_.Size(); }
+  uint32_t AnnotationSetRefListsSize() const { return annotation_set_ref_lists_.Size(); }
+  uint32_t AnnotationsDirectorySize() const { return annotations_directory_items_.Size(); }
+  uint32_t DebugInfoSize() const { return debug_info_items_.Size(); }
+  uint32_t CodeItemsSize() const { return code_items_.Size(); }
+  uint32_t ClassDatasSize() const { return class_datas_.Size(); }
+
  private:
   EncodedValue* ReadEncodedValue(const uint8_t** data);
   EncodedValue* ReadEncodedValue(const uint8_t** data, uint8_t type, uint8_t length);
diff --git a/dexlayout/dex_ir_builder.cc b/dexlayout/dex_ir_builder.cc
index e6868d7..599f48b 100644
--- a/dexlayout/dex_ir_builder.cc
+++ b/dexlayout/dex_ir_builder.cc
@@ -24,6 +24,8 @@
 namespace art {
 namespace dex_ir {
 
+static void CheckAndSetRemainingOffsets(const DexFile& dex_file, Collections* collections);
+
 Header* DexIrBuilder(const DexFile& dex_file) {
   const DexFile::Header& disk_header = dex_file.GetHeader();
   Header* header = new Header(disk_header.magic_,
@@ -69,8 +71,87 @@
     collections.CreateClassDef(dex_file, i);
   }
 
+  CheckAndSetRemainingOffsets(dex_file, &collections);
+
   return header;
 }
 
+static void CheckAndSetRemainingOffsets(const DexFile& dex_file, Collections* collections) {
+  const DexFile::Header& disk_header = dex_file.GetHeader();
+  // Read MapItems and validate/set remaining offsets.
+  const DexFile::MapList* map =
+      reinterpret_cast<const DexFile::MapList*>(dex_file.Begin() + disk_header.map_off_);
+  const uint32_t count = map->size_;
+  for (uint32_t i = 0; i < count; ++i) {
+    const DexFile::MapItem* item = map->list_ + i;
+    switch (item->type_) {
+      case DexFile::kDexTypeHeaderItem:
+        CHECK_EQ(item->size_, 1u);
+        CHECK_EQ(item->offset_, 0u);
+        break;
+      case DexFile::kDexTypeStringIdItem:
+        CHECK_EQ(item->size_, collections->StringIdsSize());
+        CHECK_EQ(item->offset_, collections->StringIdsOffset());
+        break;
+      case DexFile::kDexTypeTypeIdItem:
+        CHECK_EQ(item->size_, collections->TypeIdsSize());
+        CHECK_EQ(item->offset_, collections->TypeIdsOffset());
+        break;
+      case DexFile::kDexTypeProtoIdItem:
+        CHECK_EQ(item->size_, collections->ProtoIdsSize());
+        CHECK_EQ(item->offset_, collections->ProtoIdsOffset());
+        break;
+      case DexFile::kDexTypeFieldIdItem:
+        CHECK_EQ(item->size_, collections->FieldIdsSize());
+        CHECK_EQ(item->offset_, collections->FieldIdsOffset());
+        break;
+      case DexFile::kDexTypeMethodIdItem:
+        CHECK_EQ(item->size_, collections->MethodIdsSize());
+        CHECK_EQ(item->offset_, collections->MethodIdsOffset());
+        break;
+      case DexFile::kDexTypeClassDefItem:
+        CHECK_EQ(item->size_, collections->ClassDefsSize());
+        CHECK_EQ(item->offset_, collections->ClassDefsOffset());
+        break;
+      case DexFile::kDexTypeMapList:
+        CHECK_EQ(item->size_, 1u);
+        CHECK_EQ(item->offset_, disk_header.map_off_);
+        break;
+      case DexFile::kDexTypeTypeList:
+        collections->SetTypeListsOffset(item->offset_);
+        break;
+      case DexFile::kDexTypeAnnotationSetRefList:
+        collections->SetAnnotationSetRefListsOffset(item->offset_);
+        break;
+      case DexFile::kDexTypeAnnotationSetItem:
+        collections->SetAnnotationSetOffset(item->offset_);
+        break;
+      case DexFile::kDexTypeClassDataItem:
+        collections->SetClassDatasOffset(item->offset_);
+        break;
+      case DexFile::kDexTypeCodeItem:
+        collections->SetCodeItemsOffset(item->offset_);
+        break;
+      case DexFile::kDexTypeStringDataItem:
+        collections->SetStringDatasOffset(item->offset_);
+        break;
+      case DexFile::kDexTypeDebugInfoItem:
+        collections->SetDebugInfoOffset(item->offset_);
+        break;
+      case DexFile::kDexTypeAnnotationItem:
+        collections->SetAnnotationOffset(item->offset_);
+        break;
+      case DexFile::kDexTypeEncodedArrayItem:
+        collections->SetEncodedArrayOffset(item->offset_);
+        break;
+      case DexFile::kDexTypeAnnotationsDirectoryItem:
+        collections->SetAnnotationsDirectoryOffset(item->offset_);
+        break;
+      default:
+        LOG(ERROR) << "Unknown map list item type.";
+    }
+  }
+}
+
 }  // namespace dex_ir
 }  // namespace art
diff --git a/dexlayout/dex_visualize.cc b/dexlayout/dex_visualize.cc
new file mode 100644
index 0000000..be7bade
--- /dev/null
+++ b/dexlayout/dex_visualize.cc
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Implementation file of the dex layout visualization.
+ *
+ * This is a tool to read dex files into an internal representation,
+ * reorganize the representation, and emit dex files with a better
+ * file layout.
+ */
+
+#include "dex_visualize.h"
+
+#include <inttypes.h>
+#include <stdio.h>
+
+#include <functional>
+#include <memory>
+#include <vector>
+
+#include "dex_ir.h"
+#include "dexlayout.h"
+#include "jit/offline_profiling_info.h"
+
+namespace art {
+
+struct FileSection {
+ public:
+  std::string name_;
+  uint16_t type_;
+  std::function<uint32_t(const dex_ir::Collections&)> size_fn_;
+  std::function<uint32_t(const dex_ir::Collections&)> offset_fn_;
+};
+
+static const std::vector<FileSection> kFileSections = {
+  {
+    "StringId",
+    DexFile::kDexTypeStringIdItem,
+    &dex_ir::Collections::StringIdsSize,
+    &dex_ir::Collections::StringIdsOffset
+  }, {
+    "TypeId",
+    DexFile::kDexTypeTypeIdItem,
+    &dex_ir::Collections::TypeIdsSize,
+    &dex_ir::Collections::TypeIdsOffset
+  }, {
+    "ProtoId",
+    DexFile::kDexTypeProtoIdItem,
+    &dex_ir::Collections::ProtoIdsSize,
+    &dex_ir::Collections::ProtoIdsOffset
+  }, {
+    "FieldId",
+    DexFile::kDexTypeFieldIdItem,
+    &dex_ir::Collections::FieldIdsSize,
+    &dex_ir::Collections::FieldIdsOffset
+  }, {
+    "MethodId",
+    DexFile::kDexTypeMethodIdItem,
+    &dex_ir::Collections::MethodIdsSize,
+    &dex_ir::Collections::MethodIdsOffset
+  }, {
+    "ClassDef",
+    DexFile::kDexTypeClassDefItem,
+    &dex_ir::Collections::ClassDefsSize,
+    &dex_ir::Collections::ClassDefsOffset
+  }, {
+    "StringData",
+    DexFile::kDexTypeStringDataItem,
+    &dex_ir::Collections::StringDatasSize,
+    &dex_ir::Collections::StringDatasOffset
+  }, {
+    "TypeList",
+    DexFile::kDexTypeTypeList,
+    &dex_ir::Collections::TypeListsSize,
+    &dex_ir::Collections::TypeListsOffset
+  }, {
+    "EncArr",
+    DexFile::kDexTypeEncodedArrayItem,
+    &dex_ir::Collections::EncodedArraySize,
+    &dex_ir::Collections::EncodedArrayOffset
+  }, {
+    "Annotation",
+    DexFile::kDexTypeAnnotationItem,
+    &dex_ir::Collections::AnnotationSize,
+    &dex_ir::Collections::AnnotationOffset
+  }, {
+    "AnnoSet",
+    DexFile::kDexTypeAnnotationSetItem,
+    &dex_ir::Collections::AnnotationSetSize,
+    &dex_ir::Collections::AnnotationSetOffset
+  }, {
+    "AnnoSetRL",
+    DexFile::kDexTypeAnnotationSetRefList,
+    &dex_ir::Collections::AnnotationSetRefListsSize,
+    &dex_ir::Collections::AnnotationSetRefListsOffset
+  }, {
+    "AnnoDir",
+    DexFile::kDexTypeAnnotationsDirectoryItem,
+    &dex_ir::Collections::AnnotationsDirectorySize,
+    &dex_ir::Collections::AnnotationsDirectoryOffset
+  }, {
+    "DebugInfo",
+    DexFile::kDexTypeDebugInfoItem,
+    &dex_ir::Collections::DebugInfoSize,
+    &dex_ir::Collections::DebugInfoOffset
+  }, {
+    "CodeItem",
+    DexFile::kDexTypeCodeItem,
+    &dex_ir::Collections::CodeItemsSize,
+    &dex_ir::Collections::CodeItemsOffset
+  }, {
+    "ClassData",
+    DexFile::kDexTypeClassDataItem,
+    &dex_ir::Collections::ClassDatasSize,
+    &dex_ir::Collections::ClassDatasOffset
+  }
+};
+
+class Dumper {
+ public:
+  // Colors are based on the type of the section in MapList.
+  Dumper(const dex_ir::Collections& collections, size_t dex_file_index) {
+    // Build the table that will map from offset to color
+    table_.emplace_back(DexFile::kDexTypeHeaderItem, 0u);
+    for (const FileSection& s : kFileSections) {
+      table_.emplace_back(s.type_, s.offset_fn_(collections));
+    }
+    // Sort into descending order by offset.
+    std::sort(table_.begin(),
+              table_.end(),
+              [](const SectionColor& a, const SectionColor& b) { return a.offset_ > b.offset_; });
+    // Open the file and emit the gnuplot prologue.
+    std::string dex_file_name("classes");
+    std::string out_file_base_name("layout");
+    if (dex_file_index > 0) {
+      out_file_base_name += std::to_string(dex_file_index + 1);
+      dex_file_name += std::to_string(dex_file_index + 1);
+    }
+    dex_file_name += ".dex";
+    std::string out_file_name(out_file_base_name + ".gnuplot");
+    std::string png_file_name(out_file_base_name + ".png");
+    out_file_ = fopen(out_file_name.c_str(), "w");
+    fprintf(out_file_, "set terminal png size 1920,1080\n");
+    fprintf(out_file_, "set output \"%s\"\n", png_file_name.c_str());
+    fprintf(out_file_, "set title \"%s\"\n", dex_file_name.c_str());
+    fprintf(out_file_, "set xlabel \"Page offset into dex\"\n");
+    fprintf(out_file_, "set ylabel \"ClassDef index\"\n");
+    fprintf(out_file_, "set xtics rotate out (");
+    fprintf(out_file_, "\"Header\" %d, ", 0);
+    bool printed_one = false;
+    for (const FileSection& s : kFileSections) {
+      if (s.size_fn_(collections) > 0) {
+        if (printed_one) {
+          fprintf(out_file_, ", ");
+        }
+        fprintf(out_file_, "\"%s\" %d", s.name_.c_str(), s.offset_fn_(collections) / kPageSize);
+        printed_one = true;
+      }
+    }
+    fprintf(out_file_, ")\n");
+    fprintf(out_file_,
+            "plot \"-\" using 1:2:3:4:5 with vector nohead linewidth 1 lc variable notitle\n");
+  }
+
+  int GetColor(uint32_t offset) const {
+    // The dread linear search to find the right section for the reference.
+    uint16_t section = 0;
+    for (uint16_t i = 0; i < table_.size(); ++i) {
+      if (table_[i].offset_ < offset) {
+        section = table_[i].type_;
+        break;
+      }
+    }
+    // And a lookup table from type to color.
+    ColorMapType::const_iterator iter = kColorMap.find(section);
+    if (iter != kColorMap.end()) {
+      return iter->second;
+    }
+    return 0;
+  }
+
+  void DumpAddressRange(uint32_t from, uint32_t size, int class_index) {
+    const uint32_t low_page = from / kPageSize;
+    const uint32_t high_page = (size > 0) ? (from + size - 1) / kPageSize : low_page;
+    const uint32_t size_delta = high_page - low_page;
+    fprintf(out_file_, "%d %d %d 0 %d\n", low_page, class_index, size_delta, GetColor(from));
+  }
+
+  void DumpAddressRange(const dex_ir::Item* item, int class_index) {
+    if (item != nullptr) {
+      DumpAddressRange(item->GetOffset(), item->GetSize(), class_index);
+    }
+  }
+
+  void DumpStringData(const dex_ir::StringData* string_data, int class_index) {
+    DumpAddressRange(string_data, class_index);
+  }
+
+  void DumpStringId(const dex_ir::StringId* string_id, int class_index) {
+    DumpAddressRange(string_id, class_index);
+    if (string_id == nullptr) {
+      return;
+    }
+    DumpStringData(string_id->DataItem(), class_index);
+  }
+
+  void DumpTypeId(const dex_ir::TypeId* type_id, int class_index) {
+    DumpAddressRange(type_id, class_index);
+    DumpStringId(type_id->GetStringId(), class_index);
+  }
+
+  void DumpFieldId(const dex_ir::FieldId* field_id, int class_index) {
+    DumpAddressRange(field_id, class_index);
+    if (field_id == nullptr) {
+      return;
+    }
+    DumpTypeId(field_id->Class(), class_index);
+    DumpTypeId(field_id->Type(), class_index);
+    DumpStringId(field_id->Name(), class_index);
+  }
+
+  void DumpFieldItem(const dex_ir::FieldItem* field, int class_index) {
+    DumpAddressRange(field, class_index);
+    if (field == nullptr) {
+      return;
+    }
+    DumpFieldId(field->GetFieldId(), class_index);
+  }
+
+  void DumpProtoId(const dex_ir::ProtoId* proto_id, int class_index) {
+    DumpAddressRange(proto_id, class_index);
+    if (proto_id == nullptr) {
+      return;
+    }
+    DumpStringId(proto_id->Shorty(), class_index);
+    const dex_ir::TypeIdVector& parameters = proto_id->Parameters();
+    for (const dex_ir::TypeId* t : parameters) {
+      DumpTypeId(t, class_index);
+    }
+    DumpTypeId(proto_id->ReturnType(), class_index);
+  }
+
+  void DumpMethodId(const dex_ir::MethodId* method_id, int class_index) {
+    DumpAddressRange(method_id, class_index);
+    if (method_id == nullptr) {
+      return;
+    }
+    DumpTypeId(method_id->Class(), class_index);
+    DumpProtoId(method_id->Proto(), class_index);
+    DumpStringId(method_id->Name(), class_index);
+  }
+
+  void DumpMethodItem(const dex_ir::MethodItem* method, const DexFile* dex_file, int class_index) {
+    if (profile_info_ != nullptr) {
+      uint32_t method_idx = method->GetMethodId()->GetIndex();
+      MethodReference mr(dex_file, method_idx);
+      if (!profile_info_->ContainsMethod(mr)) {
+        return;
+      }
+    }
+    DumpAddressRange(method, class_index);
+    if (method == nullptr) {
+      return;
+    }
+    DumpMethodId(method->GetMethodId(), class_index);
+    const dex_ir::CodeItem* code_item = method->GetCodeItem();
+    if (code_item != nullptr) {
+      DumpAddressRange(code_item, class_index);
+    }
+  }
+
+  ~Dumper() {
+    fclose(out_file_);
+  }
+
+ private:
+  struct SectionColor {
+   public:
+    SectionColor(uint16_t type, uint32_t offset) : type_(type), offset_(offset) { }
+    uint16_t type_;
+    uint32_t offset_;
+  };
+
+  using ColorMapType = std::map<uint16_t, int>;
+  const ColorMapType kColorMap = {
+    { DexFile::kDexTypeHeaderItem, 1 },
+    { DexFile::kDexTypeStringIdItem, 2 },
+    { DexFile::kDexTypeTypeIdItem, 3 },
+    { DexFile::kDexTypeProtoIdItem, 4 },
+    { DexFile::kDexTypeFieldIdItem, 5 },
+    { DexFile::kDexTypeMethodIdItem, 6 },
+    { DexFile::kDexTypeClassDefItem, 7 },
+    { DexFile::kDexTypeTypeList, 8 },
+    { DexFile::kDexTypeAnnotationSetRefList, 9 },
+    { DexFile::kDexTypeAnnotationSetItem, 10 },
+    { DexFile::kDexTypeClassDataItem, 11 },
+    { DexFile::kDexTypeCodeItem, 12 },
+    { DexFile::kDexTypeStringDataItem, 13 },
+    { DexFile::kDexTypeDebugInfoItem, 14 },
+    { DexFile::kDexTypeAnnotationItem, 15 },
+    { DexFile::kDexTypeEncodedArrayItem, 16 },
+    { DexFile::kDexTypeAnnotationsDirectoryItem, 16 }
+  };
+
+  std::vector<SectionColor> table_;
+  FILE* out_file_;
+
+  DISALLOW_COPY_AND_ASSIGN(Dumper);
+};
+
+/*
+ * Dumps a gnuplot data file showing the parts of the dex_file that belong to each class.
+ * If profiling information is present, it dumps only those classes that are marked as hot.
+ */
+void VisualizeDexLayout(dex_ir::Header* header, const DexFile* dex_file, size_t dex_file_index) {
+  std::unique_ptr<Dumper> dumper(new Dumper(header->GetCollections(), dex_file_index));
+
+  const uint32_t class_defs_size = header->GetCollections().ClassDefsSize();
+  for (uint32_t class_index = 0; class_index < class_defs_size; class_index++) {
+    dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(class_index);
+    if (profile_info_ != nullptr && !profile_info_->ContainsClass(*dex_file, class_index)) {
+      continue;
+    }
+    dumper->DumpAddressRange(class_def, class_index);
+    // Type id.
+    dumper->DumpTypeId(class_def->ClassType(), class_index);
+    // Superclass type id.
+    dumper->DumpTypeId(class_def->Superclass(), class_index);
+    // Interfaces.
+    // TODO(jeffhao): get TypeList from class_def to use Item interface.
+    static constexpr uint32_t kInterfaceSizeKludge = 8;
+    dumper->DumpAddressRange(class_def->InterfacesOffset(), kInterfaceSizeKludge, class_index);
+    // Source file info.
+    dumper->DumpStringId(class_def->SourceFile(), class_index);
+    // Annotations.
+    dumper->DumpAddressRange(class_def->Annotations(), class_index);
+    // TODO(sehr): walk the annotations and dump them.
+    // Class data.
+    dex_ir::ClassData* class_data = class_def->GetClassData();
+    if (class_data != nullptr) {
+      dumper->DumpAddressRange(class_data, class_index);
+      if (class_data->StaticFields()) {
+        for (auto& field_item : *class_data->StaticFields()) {
+          dumper->DumpFieldItem(field_item.get(), class_index);
+        }
+      }
+      if (class_data->InstanceFields()) {
+        for (auto& field_item : *class_data->InstanceFields()) {
+          dumper->DumpFieldItem(field_item.get(), class_index);
+        }
+      }
+      if (class_data->DirectMethods()) {
+        for (auto& method_item : *class_data->DirectMethods()) {
+          dumper->DumpMethodItem(method_item.get(), dex_file, class_index);
+        }
+      }
+      if (class_data->VirtualMethods()) {
+        for (auto& method_item : *class_data->VirtualMethods()) {
+          dumper->DumpMethodItem(method_item.get(), dex_file, class_index);
+        }
+      }
+    }
+  }  // for
+}
+
+}  // namespace art
diff --git a/dexlayout/dex_visualize.h b/dexlayout/dex_visualize.h
new file mode 100644
index 0000000..b1d2ed7
--- /dev/null
+++ b/dexlayout/dex_visualize.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Header file of the dexlayout utility.
+ *
+ * This is a tool to read dex files into an internal representation,
+ * reorganize the representation, and emit dex files with a better
+ * file layout.
+ */
+
+#ifndef ART_DEXLAYOUT_DEX_VISUALIZE_H_
+#define ART_DEXLAYOUT_DEX_VISUALIZE_H_
+
+#include <stddef.h>
+
+namespace art {
+
+class DexFile;
+namespace dex_ir {
+class Header;
+}  // namespace dex_ir
+
+void VisualizeDexLayout(dex_ir::Header* header, const DexFile* dex_file, size_t dex_file_index);
+
+}  // namespace art
+
+#endif  // ART_DEXLAYOUT_DEX_VISUALIZE_H_
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index 6f34a33..e614137 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -34,6 +34,8 @@
 #include "dex_ir_builder.h"
 #include "dex_file-inl.h"
 #include "dex_instruction-inl.h"
+#include "dex_visualize.h"
+#include "jit/offline_profiling_info.h"
 #include "os.h"
 #include "utils.h"
 
@@ -50,6 +52,11 @@
 FILE* out_file_ = stdout;
 
 /*
+ * Profile information file.
+ */
+ProfileCompilationInfo* profile_info_ = nullptr;
+
+/*
  * Flags for use with createAccessFlagStr().
  */
 enum AccessFor {
@@ -1587,13 +1594,18 @@
 /*
  * Dumps the requested sections of the file.
  */
-static void ProcessDexFile(const char* file_name, const DexFile* dex_file) {
+static void ProcessDexFile(const char* file_name, const DexFile* dex_file, size_t dex_file_index) {
   if (options_.verbose_) {
     fprintf(out_file_, "Opened '%s', DEX version '%.3s'\n",
             file_name, dex_file->GetHeader().magic_ + 4);
   }
   std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file));
 
+  if (options_.visualize_pattern_) {
+    VisualizeDexLayout(header.get(), dex_file, dex_file_index);
+    return;
+  }
+
   // Headers.
   if (options_.show_file_headers_) {
     DumpFileHeader(header.get());
@@ -1658,7 +1670,7 @@
     fprintf(out_file_, "Checksum verified\n");
   } else {
     for (size_t i = 0; i < dex_files.size(); i++) {
-      ProcessDexFile(file_name, dex_files[i].get());
+      ProcessDexFile(file_name, dex_files[i].get(), i);
     }
   }
   return 0;
diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h
index 736d230..c4892d2 100644
--- a/dexlayout/dexlayout.h
+++ b/dexlayout/dexlayout.h
@@ -28,6 +28,8 @@
 
 namespace art {
 
+class ProfileCompilationInfo;
+
 /* Supported output formats. */
 enum OutputFormat {
   kOutputPlain = 0,  // default
@@ -47,13 +49,16 @@
   bool show_file_headers_;
   bool show_section_headers_;
   bool verbose_;
+  bool visualize_pattern_;
   OutputFormat output_format_;
   const char* output_file_name_;
+  const char* profile_file_name_;
 };
 
 /* Prototypes. */
 extern struct Options options_;
 extern FILE* out_file_;
+extern ProfileCompilationInfo* profile_info_;
 int ProcessFile(const char* file_name);
 
 }  // namespace art
diff --git a/dexlayout/dexlayout_main.cc b/dexlayout/dexlayout_main.cc
index ec5edf4..f385b09 100644
--- a/dexlayout/dexlayout_main.cc
+++ b/dexlayout/dexlayout_main.cc
@@ -25,8 +25,12 @@
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 
 #include "base/logging.h"
+#include "jit/offline_profiling_info.h"
 #include "mem_map.h"
 
 namespace art {
@@ -37,9 +41,9 @@
  * Shows usage.
  */
 static void Usage(void) {
-  fprintf(stderr, "Copyright (C) 2007 The Android Open Source Project\n\n");
-  fprintf(stderr, "%s: [-a] [-c] [-d] [-e] [-f] [-h] [-i] [-l layout] [-o outfile] [-w]"
-                  " dexfile...\n\n", kProgramName);
+  fprintf(stderr, "Copyright (C) 2016 The Android Open Source Project\n\n");
+  fprintf(stderr, "%s: [-a] [-c] [-d] [-e] [-f] [-h] [-i] [-l layout] [-o outfile] [-p profile]"
+                  " [-s] [-w] dexfile...\n\n", kProgramName);
   fprintf(stderr, " -a : display annotations\n");
   fprintf(stderr, " -b : build dex_ir\n");
   fprintf(stderr, " -c : verify checksum and exit\n");
@@ -51,6 +55,8 @@
   fprintf(stderr, " -i : ignore checksum failures\n");
   fprintf(stderr, " -l : output layout, either 'plain' or 'xml'\n");
   fprintf(stderr, " -o : output file name (defaults to stdout)\n");
+  fprintf(stderr, " -p : profile file name (defaults to no profile)\n");
+  fprintf(stderr, " -s : visualize reference pattern\n");
   fprintf(stderr, " -w : output dex files\n");
 }
 
@@ -69,7 +75,7 @@
 
   // Parse all arguments.
   while (1) {
-    const int ic = getopt(argc, argv, "abcdefghil:o:w");
+    const int ic = getopt(argc, argv, "abcdefghil:o:p:sw");
     if (ic < 0) {
       break;  // done
     }
@@ -114,6 +120,13 @@
       case 'o':  // output file
         options_.output_file_name_ = optarg;
         break;
+      case 'p':  // profile file
+        options_.profile_file_name_ = optarg;
+        break;
+      case 's':  // visualize access pattern
+        options_.visualize_pattern_ = true;
+        options_.verbose_ = false;
+        break;
       case 'w':  // output dex files
         options_.output_dex_files_ = true;
         break;
@@ -146,6 +159,20 @@
     }
   }
 
+  // Open profile file.
+  if (options_.profile_file_name_) {
+    int profile_fd = open(options_.profile_file_name_, O_RDONLY);
+    if (profile_fd < 0) {
+      fprintf(stderr, "Can't open %s\n", options_.profile_file_name_);
+      return 1;
+    }
+    profile_info_ = new ProfileCompilationInfo();
+    if (!profile_info_->Load(profile_fd)) {
+      fprintf(stderr, "Can't read profile info from %s\n", options_.profile_file_name_);
+      return 1;
+    }
+  }
+
   // Process all files supplied on command line.
   int result = 0;
   while (optind < argc) {