Commit e73bde18 authored by Ross McIlroy's avatar Ross McIlroy Committed by Commit Bot

[TurboFan] Reduce memory usage of ControlEquivalence.

The Control Equivalance phase was taking a lot of memory by allocating a
large datastructure for every node even if the nodes were dead or wouldn't
participate in the control equivalence algorithm. Instead allocate the
data on-demand, and use the presense of the data as the flag for whether
the node participates in the algorithm.

Also remove DFS number field as it was unused.

This reduces the amount of memory used for a 10,000 node graph in the linked
bug from ~450KB to ~70KB. It also seems to reduce scheduling time by around
10% for local runs of Octane.

BUG=chromium:700364

Change-Id: Iedfdf4dff0a01463c5b6471513e6b69ef010b02d
Reviewed-on: https://chromium-review.googlesource.com/458219Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Commit-Queue: Ross McIlroy <rmcilroy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#44150}
parent d0f234d0
...@@ -15,7 +15,7 @@ namespace internal { ...@@ -15,7 +15,7 @@ namespace internal {
namespace compiler { namespace compiler {
void ControlEquivalence::Run(Node* exit) { void ControlEquivalence::Run(Node* exit) {
if (GetClass(exit) == kInvalidClass) { if (!Participates(exit) || GetClass(exit) == kInvalidClass) {
DetermineParticipation(exit); DetermineParticipation(exit);
RunUndirectedDFS(exit); RunUndirectedDFS(exit);
} }
...@@ -28,10 +28,6 @@ STATIC_CONST_MEMBER_DEFINITION const size_t ControlEquivalence::kInvalidClass; ...@@ -28,10 +28,6 @@ STATIC_CONST_MEMBER_DEFINITION const size_t ControlEquivalence::kInvalidClass;
void ControlEquivalence::VisitPre(Node* node) { void ControlEquivalence::VisitPre(Node* node) {
TRACE("CEQ: Pre-visit of #%d:%s\n", node->id(), node->op()->mnemonic()); TRACE("CEQ: Pre-visit of #%d:%s\n", node->id(), node->op()->mnemonic());
// Dispense a new pre-order number.
SetNumber(node, NewDFSNumber());
TRACE(" Assigned DFS number is %zu\n", GetNumber(node));
} }
...@@ -105,7 +101,7 @@ void ControlEquivalence::RunUndirectedDFS(Node* exit) { ...@@ -105,7 +101,7 @@ void ControlEquivalence::RunUndirectedDFS(Node* exit) {
++(entry.input); ++(entry.input);
if (NodeProperties::IsControlEdge(edge)) { if (NodeProperties::IsControlEdge(edge)) {
// Visit next control input. // Visit next control input.
if (!GetData(input)->participates) continue; if (!Participates(input)) continue;
if (GetData(input)->visited) continue; if (GetData(input)->visited) continue;
if (GetData(input)->on_stack) { if (GetData(input)->on_stack) {
// Found backedge if input is on stack. // Found backedge if input is on stack.
...@@ -135,7 +131,7 @@ void ControlEquivalence::RunUndirectedDFS(Node* exit) { ...@@ -135,7 +131,7 @@ void ControlEquivalence::RunUndirectedDFS(Node* exit) {
++(entry.use); ++(entry.use);
if (NodeProperties::IsControlEdge(edge)) { if (NodeProperties::IsControlEdge(edge)) {
// Visit next control use. // Visit next control use.
if (!GetData(use)->participates) continue; if (!Participates(use)) continue;
if (GetData(use)->visited) continue; if (GetData(use)->visited) continue;
if (GetData(use)->on_stack) { if (GetData(use)->on_stack) {
// Found backedge if use is on stack. // Found backedge if use is on stack.
...@@ -168,8 +164,8 @@ void ControlEquivalence::RunUndirectedDFS(Node* exit) { ...@@ -168,8 +164,8 @@ void ControlEquivalence::RunUndirectedDFS(Node* exit) {
void ControlEquivalence::DetermineParticipationEnqueue(ZoneQueue<Node*>& queue, void ControlEquivalence::DetermineParticipationEnqueue(ZoneQueue<Node*>& queue,
Node* node) { Node* node) {
if (!GetData(node)->participates) { if (!Participates(node)) {
GetData(node)->participates = true; AllocateData(node);
queue.push(node); queue.push(node);
} }
} }
...@@ -191,7 +187,7 @@ void ControlEquivalence::DetermineParticipation(Node* exit) { ...@@ -191,7 +187,7 @@ void ControlEquivalence::DetermineParticipation(Node* exit) {
void ControlEquivalence::DFSPush(DFSStack& stack, Node* node, Node* from, void ControlEquivalence::DFSPush(DFSStack& stack, Node* node, Node* from,
DFSDirection dir) { DFSDirection dir) {
DCHECK(GetData(node)->participates); DCHECK(Participates(node));
DCHECK(!GetData(node)->visited); DCHECK(!GetData(node)->visited);
GetData(node)->on_stack = true; GetData(node)->on_stack = true;
Node::InputEdges::iterator input = node->input_edges().begin(); Node::InputEdges::iterator input = node->input_edges().begin();
......
...@@ -38,7 +38,7 @@ class V8_EXPORT_PRIVATE ControlEquivalence final ...@@ -38,7 +38,7 @@ class V8_EXPORT_PRIVATE ControlEquivalence final
graph_(graph), graph_(graph),
dfs_number_(0), dfs_number_(0),
class_number_(1), class_number_(1),
node_data_(graph->NodeCount(), EmptyData(), zone) {} node_data_(graph->NodeCount(), zone) {}
// Run the main algorithm starting from the {exit} control node. This causes // Run the main algorithm starting from the {exit} control node. This causes
// the following iterations over control edges of the graph: // the following iterations over control edges of the graph:
...@@ -80,17 +80,21 @@ class V8_EXPORT_PRIVATE ControlEquivalence final ...@@ -80,17 +80,21 @@ class V8_EXPORT_PRIVATE ControlEquivalence final
// The stack is used during the undirected DFS walk. // The stack is used during the undirected DFS walk.
typedef ZoneStack<DFSStackEntry> DFSStack; typedef ZoneStack<DFSStackEntry> DFSStack;
struct NodeData { struct NodeData : ZoneObject {
explicit NodeData(Zone* zone)
: class_number(kInvalidClass),
blist(BracketList(zone)),
visited(false),
on_stack(false) {}
size_t class_number; // Equivalence class number assigned to node. size_t class_number; // Equivalence class number assigned to node.
size_t dfs_number; // Pre-order DFS number assigned to node.
bool visited; // Indicates node has already been visited.
bool on_stack; // Indicates node is on DFS stack during walk.
bool participates; // Indicates node participates in DFS walk.
BracketList blist; // List of brackets per node. BracketList blist; // List of brackets per node.
bool visited : 1; // Indicates node has already been visited.
bool on_stack : 1; // Indicates node is on DFS stack during walk.
}; };
// The per-node data computed during the DFS walk. // The per-node data computed during the DFS walk.
typedef ZoneVector<NodeData> Data; typedef ZoneVector<NodeData*> Data;
// Called at pre-visit during DFS walk. // Called at pre-visit during DFS walk.
void VisitPre(Node* node); void VisitPre(Node* node);
...@@ -126,32 +130,34 @@ class V8_EXPORT_PRIVATE ControlEquivalence final ...@@ -126,32 +130,34 @@ class V8_EXPORT_PRIVATE ControlEquivalence final
private: private:
NodeData* GetData(Node* node) { NodeData* GetData(Node* node) {
size_t const index = node->id(); size_t const index = node->id();
if (index >= node_data_.size()) node_data_.resize(index + 1, EmptyData()); if (index >= node_data_.size()) node_data_.resize(index + 1);
return &node_data_[index]; return node_data_[index];
}
void AllocateData(Node* node) {
size_t const index = node->id();
if (index >= node_data_.size()) node_data_.resize(index + 1);
node_data_[index] = new (zone_) NodeData(zone_);
} }
int NewClassNumber() { return class_number_++; } int NewClassNumber() { return class_number_++; }
int NewDFSNumber() { return dfs_number_++; } int NewDFSNumber() { return dfs_number_++; }
// Template used to initialize per-node data. bool Participates(Node* node) { return GetData(node) != nullptr; }
NodeData EmptyData() {
return {kInvalidClass, 0, false, false, false, BracketList(zone_)};
}
// Accessors for the DFS number stored within the per-node data.
size_t GetNumber(Node* node) { return GetData(node)->dfs_number; }
void SetNumber(Node* node, size_t number) {
GetData(node)->dfs_number = number;
}
// Accessors for the equivalence class stored within the per-node data. // Accessors for the equivalence class stored within the per-node data.
size_t GetClass(Node* node) { return GetData(node)->class_number; } size_t GetClass(Node* node) { return GetData(node)->class_number; }
void SetClass(Node* node, size_t number) { void SetClass(Node* node, size_t number) {
DCHECK(Participates(node));
GetData(node)->class_number = number; GetData(node)->class_number = number;
} }
// Accessors for the bracket list stored within the per-node data. // Accessors for the bracket list stored within the per-node data.
BracketList& GetBracketList(Node* node) { return GetData(node)->blist; } BracketList& GetBracketList(Node* node) {
DCHECK(Participates(node));
return GetData(node)->blist;
}
void SetBracketList(Node* node, BracketList& list) { void SetBracketList(Node* node, BracketList& list) {
DCHECK(Participates(node));
GetData(node)->blist = list; GetData(node)->blist = list;
} }
......
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