Commit cdf6d671 authored by Jasper Chapman-Black's avatar Jasper Chapman-Black Committed by Commit Bot

SuperSize: Caspian: Group dex methods by class

Bug: 1011921
Change-Id: Ieabbb0ba0b1727200d575f23ad9a5c6477b31557
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1884369Reviewed-by: default avatarAndrew Grieve <agrieve@chromium.org>
Commit-Queue: Jasper Chapman-Black <jaspercb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#710031}
parent a3b11f5a
......@@ -82,7 +82,7 @@ TreeNode* GetOrMakeParentNode(TreeNode* child_node) {
parent->id_path = parent_path;
parent->short_name_index = parent_path.find_last_of('/') + 1;
// TODO: Container type might be a component instead of a directory.
parent->containerType = ContainerType::kDirectory;
parent->container_type = ContainerType::kDirectory;
}
if (child_node->parent != parent) {
AttachToParent(child_node, parent);
......@@ -90,11 +90,90 @@ TreeNode* GetOrMakeParentNode(TreeNode* child_node) {
return parent;
}
/* Merges dex method symbols into containers based on the class of the dex
* method.
*/
void JoinDexMethodClasses(TreeNode* node) {
const bool is_file_node = node->container_type == ContainerType::kFile;
const bool has_dex =
node->node_stats.child_stats.count(SectionId::kDex) ||
node->node_stats.child_stats.count(SectionId::kDexMethod);
// Don't try to merge dex symbols for catch-all symbols under (No path).
const bool is_no_path = node->id_path == NO_NAME;
if (!is_file_node || !has_dex || is_no_path || node->children.empty()) {
return;
}
std::map<std::string_view, TreeNode*> java_class_containers;
std::vector<TreeNode*> other_symbols;
// Bucket dex symbols by their class.
for (TreeNode* child : node->children) {
// Unlike in .ndjson fields, Java classes loaded from .size files are just
// the classname, such as "android.support.v7.widget.toolbar".
// Method names contain the classname followed by the method definition,
// like "android.support.v7.widget.toolbar void onMeasure(int, int)".
const size_t split_index = child->id_path.find_first_of(' ');
// No return type / field type means it's a class node.
const bool is_class_node =
child->id_path.find_first_of(' ', child->short_name_index) ==
std::string_view::npos;
const bool has_class_prefix =
is_class_node || split_index != std::string_view::npos;
if (has_class_prefix) {
const std::string_view class_id_path =
split_index == std::string_view::npos
? child->id_path
: child->id_path.substr(0, split_index);
// Strip package from the node name for classes in .java files since the
// directory tree already shows it.
int short_name_index = child->short_name_index;
size_t java_idx = node->id_path.find(".java");
if (java_idx != std::string_view::npos) {
size_t dot_idx = class_id_path.find_last_of('.');
short_name_index += dot_idx + 1;
}
TreeNode*& class_node = java_class_containers[class_id_path];
if (class_node == nullptr) {
class_node = new TreeNode();
class_node->id_path = class_id_path;
class_node->src_path = node->src_path;
class_node->component = node->component;
class_node->short_name_index = short_name_index;
class_node->container_type = ContainerType::kJavaClass;
parents[class_node->id_path] = class_node;
}
// Adjust the dex method's short name so it starts after the " "
if (split_index != std::string_view::npos) {
child->short_name_index = split_index + 1;
}
child->parent = nullptr;
AttachToParent(child, class_node);
} else {
other_symbols.push_back(child);
}
}
node->children = other_symbols;
for (auto& iter : java_class_containers) {
TreeNode* container_node = iter.second;
// Delay setting the parent until here so that `_attachToParent`
// doesn't add method stats twice
container_node->parent = node;
node->children.push_back(container_node);
}
}
void AddFileEntry(const std::string_view source_path,
const std::vector<const Symbol*>& symbols) {
// Creates a single file node with a child for each symbol in that file.
TreeNode* file_node = new TreeNode();
file_node->containerType = ContainerType::kFile;
file_node->container_type = ContainerType::kFile;
if (source_path.empty()) {
file_node->id_path = NO_NAME;
} else {
......@@ -107,7 +186,7 @@ void AddFileEntry(const std::string_view source_path,
// Create symbol nodes.
for (const auto sym : symbols) {
TreeNode* symbol_node = new TreeNode();
symbol_node->containerType = ContainerType::kSymbol;
symbol_node->container_type = ContainerType::kSymbol;
symbol_node->id_path = sym->full_name;
symbol_node->size = sym->size;
symbol_node->node_stats =
......@@ -120,6 +199,8 @@ void AddFileEntry(const std::string_view source_path,
while (orphan_node != &root) {
orphan_node = GetOrMakeParentNode(orphan_node);
}
JoinDexMethodClasses(file_node);
}
void AddSymbolsAndFileNodes(SizeInfo* size_info) {
......@@ -143,7 +224,7 @@ bool LoadSizeFile(const char* compressed, size_t size) {
writer.reset(Json::StreamWriterBuilder().newStreamWriter());
ParseSizeInfo(compressed, size, &info);
// Build tree
root.containerType = ContainerType::kDirectory;
root.container_type = ContainerType::kDirectory;
root.id_path = "/";
parents[""] = &root;
AddSymbolsAndFileNodes(&info);
......
......@@ -30,7 +30,7 @@ SectionId SizeInfo::ShortSectionName(const char* section_name) {
} else if (!strcmp(section_name, ".dex")) {
ret = SectionId::kDex;
} else if (!strcmp(section_name, ".dex.method")) {
ret = SectionId::kDex;
ret = SectionId::kDexMethod;
} else if (!strcmp(section_name, ".other")) {
ret = SectionId::kOther;
} else if (!strcmp(section_name, ".rodata")) {
......@@ -61,8 +61,8 @@ void TreeNode::WriteIntoJson(Json::Value* out, int depth) {
(*out)["shortNameIndex"] = this->short_name_index;
// TODO: Put correct information.
std::string type;
if (containerType != ContainerType::kSymbol) {
type += static_cast<char>(containerType);
if (container_type != ContainerType::kSymbol) {
type += static_cast<char>(container_type);
}
SectionId biggest_section = this->node_stats.ComputeBiggestSection();
type += static_cast<char>(biggest_section);
......@@ -95,12 +95,12 @@ NodeStats::NodeStats(SectionId sectionId,
int32_t count,
int32_t highlight,
int32_t size) {
childStats[sectionId] = {count, highlight, size};
child_stats[sectionId] = {count, highlight, size};
}
void NodeStats::WriteIntoJson(Json::Value* out) const {
(*out) = Json::Value(Json::objectValue);
for (const auto kv : this->childStats) {
for (const auto kv : this->child_stats) {
const std::string sectionId = std::string(1, static_cast<char>(kv.first));
const Stat stats = kv.second;
(*out)[sectionId] = Json::Value(Json::objectValue);
......@@ -111,8 +111,8 @@ void NodeStats::WriteIntoJson(Json::Value* out) const {
}
NodeStats& NodeStats::operator+=(const NodeStats& other) {
for (const auto& it : other.childStats) {
childStats[it.first] += it.second;
for (const auto& it : other.child_stats) {
child_stats[it.first] += it.second;
}
return *this;
}
......@@ -120,7 +120,7 @@ NodeStats& NodeStats::operator+=(const NodeStats& other) {
SectionId NodeStats::ComputeBiggestSection() const {
SectionId ret = SectionId::kNone;
int32_t max = 0;
for (auto& pair : childStats) {
for (auto& pair : child_stats) {
if (pair.second.size > max) {
ret = pair.first;
max = pair.second.size;
......
......@@ -98,7 +98,7 @@ struct NodeStats {
NodeStats& operator+=(const NodeStats& other);
SectionId ComputeBiggestSection() const;
std::map<SectionId, Stat> childStats;
std::map<SectionId, Stat> child_stats;
};
struct TreeNode {
......@@ -120,7 +120,7 @@ struct TreeNode {
childStats,
*/
ContainerType containerType = ContainerType::kSymbol;
ContainerType container_type = ContainerType::kSymbol;
std::vector<TreeNode*> children;
TreeNode* parent = nullptr;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment