OSDN Git Service

Option to gnuplot dex layout
authorDavid Sehr <sehr@google.com>
Mon, 26 Sep 2016 14:44:04 +0000 (07:44 -0700)
committerDavid Sehr <sehr@google.com>
Tue, 4 Oct 2016 17:47:24 +0000 (10:47 -0700)
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

dexlayout/Android.bp
dexlayout/dex_ir.h
dexlayout/dex_ir_builder.cc
dexlayout/dex_visualize.cc [new file with mode: 0644]
dexlayout/dex_visualize.h [new file with mode: 0644]
dexlayout/dexlayout.cc
dexlayout/dexlayout.h
dexlayout/dexlayout_main.cc

index 296cdb6..0987df7 100644 (file)
@@ -20,6 +20,7 @@ art_cc_binary {
         "dexlayout.cc",
         "dex_ir.cc",
         "dex_ir_builder.cc",
+        "dex_visualize.cc",
     ],
     cflags: ["-Wall"],
     shared_libs: [
index 6ae9f1c..f3d2c90 100644 (file)
@@ -217,6 +217,17 @@ class Collections {
   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);
index e6868d7..599f48b 100644 (file)
@@ -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 @@ Header* DexIrBuilder(const DexFile& dex_file) {
     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 (file)
index 0000000..be7bade
--- /dev/null
@@ -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 (file)
index 0000000..b1d2ed7
--- /dev/null
@@ -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_
index 6f34a33..e614137 100644 (file)
@@ -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 @@ struct Options options_;
 FILE* out_file_ = stdout;
 
 /*
+ * Profile information file.
+ */
+ProfileCompilationInfo* profile_info_ = nullptr;
+
+/*
  * Flags for use with createAccessFlagStr().
  */
 enum AccessFor {
@@ -1587,13 +1594,18 @@ static void OutputDexFile(dex_ir::Header& header, const char* file_name) {
 /*
  * 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 @@ int ProcessFile(const char* file_name) {
     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;
index 736d230..c4892d2 100644 (file)
@@ -28,6 +28,8 @@
 
 namespace art {
 
+class ProfileCompilationInfo;
+
 /* Supported output formats. */
 enum OutputFormat {
   kOutputPlain = 0,  // default
@@ -47,13 +49,16 @@ struct Options {
   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
index ec5edf4..f385b09 100644 (file)
 #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 @@ static const char* kProgramName = "dexlayout";
  * 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 @@ static void Usage(void) {
   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 @@ int DexlayoutDriver(int argc, char** argv) {
 
   // 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 @@ int DexlayoutDriver(int argc, char** argv) {
       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 @@ int DexlayoutDriver(int argc, char** argv) {
     }
   }
 
+  // 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) {