Revision: 24896
Author:   [email protected]
Date:     Mon Oct 27 10:12:16 2014 UTC
Log:      [turbofan] Reduce memory consumption of graph building

Allow reservation of additional input capacity when creating nodes to prevent switching to deque representation when adding well-known additional inputs.

Also ensure that only a single temporary buffer is used to create temporary input arrays before allocating nodes.

[email protected]

Review URL: https://codereview.chromium.org/644083003
https://code.google.com/p/v8/source/detail?r=24896

Modified:
 /branches/bleeding_edge/src/compiler/generic-node-inl.h
 /branches/bleeding_edge/src/compiler/generic-node.h
 /branches/bleeding_edge/src/compiler/graph-builder.cc
 /branches/bleeding_edge/src/compiler/graph-builder.h
 /branches/bleeding_edge/src/compiler/graph.cc
 /branches/bleeding_edge/src/compiler/node.h
 /branches/bleeding_edge/src/compiler/raw-machine-assembler.cc
 /branches/bleeding_edge/src/compiler/raw-machine-assembler.h
 /branches/bleeding_edge/test/cctest/compiler/graph-builder-tester.h
 /branches/bleeding_edge/test/cctest/compiler/simplified-graph-builder.cc
 /branches/bleeding_edge/test/cctest/compiler/simplified-graph-builder.h

=======================================
--- /branches/bleeding_edge/src/compiler/generic-node-inl.h Wed Oct 15 11:38:04 2014 UTC +++ /branches/bleeding_edge/src/compiler/generic-node-inl.h Mon Oct 27 10:12:16 2014 UTC
@@ -16,13 +16,16 @@
 namespace compiler {

 template <class B, class S>
-GenericNode<B, S>::GenericNode(GenericGraphBase* graph, int input_count)
+GenericNode<B, S>::GenericNode(GenericGraphBase* graph, int input_count,
+                               int reserve_input_count)
     : BaseClass(graph->zone()),
       input_count_(input_count),
+      reserve_input_count_(reserve_input_count),
       has_appendable_inputs_(false),
       use_count_(0),
       first_use_(NULL),
       last_use_(NULL) {
+  DCHECK(reserve_input_count <= kMaxReservedInputs);
   inputs_.static_ = reinterpret_cast<Input*>(this + 1);
   AssignUniqueID(graph);
 }
@@ -154,12 +157,18 @@

 template <class B, class S>
void GenericNode<B, S>::AppendInput(Zone* zone, GenericNode<B, S>* to_append) {
-  EnsureAppendableInputs(zone);
   Use* new_use = new (zone) Use;
   Input new_input;
   new_input.to = to_append;
   new_input.use = new_use;
-  inputs_.appendable_->push_back(new_input);
+  if (reserve_input_count_ > 0) {
+    DCHECK(!has_appendable_inputs_);
+    reserve_input_count_--;
+    inputs_.static_[input_count_] = new_input;
+  } else {
+    EnsureAppendableInputs(zone);
+    inputs_.appendable_->push_back(new_input);
+  }
   new_use->input_index = input_count_;
   new_use->from = this;
   to_append->AppendUse(new_use);
@@ -224,15 +233,17 @@
 }

 template <class B, class S>
-S* GenericNode<B, S>::New(GenericGraphBase* graph, int input_count,
-                          S** inputs) {
+S* GenericNode<B, S>::New(GenericGraphBase* graph, int input_count, S** inputs,
+                          bool has_extensible_inputs) {
   size_t node_size = sizeof(GenericNode);
-  size_t inputs_size = input_count * sizeof(Input);
+  size_t reserve_input_count =
+      has_extensible_inputs ? kDefaultReservedInputs : 0;
+  size_t inputs_size = (input_count + reserve_input_count) * sizeof(Input);
   size_t uses_size = input_count * sizeof(Use);
   int size = static_cast<int>(node_size + inputs_size + uses_size);
   Zone* zone = graph->zone();
   void* buffer = zone->New(size);
-  S* result = new (buffer) S(graph, input_count);
+  S* result = new (buffer) S(graph, input_count, reserve_input_count);
   Input* input =
reinterpret_cast<Input*>(reinterpret_cast<char*>(buffer) + node_size);
   Use* use =
=======================================
--- /branches/bleeding_edge/src/compiler/generic-node.h Wed Sep 24 09:28:56 2014 UTC +++ /branches/bleeding_edge/src/compiler/generic-node.h Mon Oct 27 10:12:16 2014 UTC
@@ -92,7 +92,8 @@

   bool OwnedBy(GenericNode* owner) const;

-  static S* New(GenericGraphBase* graph, int input_count, S** inputs);
+  static S* New(GenericGraphBase* graph, int input_count, S** inputs,
+                bool has_extensible_inputs);

  protected:
   friend class GenericGraphBase;
@@ -128,15 +129,21 @@

   void* operator new(size_t, void* location) { return location; }

-  GenericNode(GenericGraphBase* graph, int input_count);
+  GenericNode(GenericGraphBase* graph, int input_count,
+              int reserved_input_count);

  private:
   void AssignUniqueID(GenericGraphBase* graph);

   typedef ZoneDeque<Input> InputDeque;

+  static const int kReservedInputCountBits = 2;
+  static const int kMaxReservedInputs = (1 << kReservedInputCountBits) - 1;
+  static const int kDefaultReservedInputs = kMaxReservedInputs;
+
   NodeId id_;
-  int input_count_ : 31;
+  int input_count_ : 29;
+  unsigned int reserve_input_count_ : kReservedInputCountBits;
   bool has_appendable_inputs_ : 1;
   union {
// When a node is initially allocated, it uses a static buffer to hold its
=======================================
--- /branches/bleeding_edge/src/compiler/graph-builder.cc Tue Oct 21 14:44:50 2014 UTC +++ /branches/bleeding_edge/src/compiler/graph-builder.cc Mon Oct 27 10:12:16 2014 UTC
@@ -25,13 +25,26 @@
       common_(common),
       environment_(NULL),
       local_zone_(local_zone),
+      input_buffer_size_(0),
+      input_buffer_(NULL),
       current_context_(NULL),
-      exit_control_(NULL) {}
+      exit_control_(NULL) {
+  EnsureInputBufferSize(kInputBufferSizeIncrement);
+}
+
+
+Node** StructuredGraphBuilder::EnsureInputBufferSize(int size) {
+  if (size > input_buffer_size_) {
+    size += kInputBufferSizeIncrement;
+    input_buffer_ = local_zone()->NewArray<Node*>(size);
+  }
+  return input_buffer_;
+}


 Node* StructuredGraphBuilder::MakeNode(const Operator* op,
                                        int value_input_count,
-                                       Node** value_inputs) {
+ Node** value_inputs, bool incomplete) {
   DCHECK(op->InputCount() == value_input_count);

   bool has_context = OperatorProperties::HasContextInput(op);
@@ -44,14 +57,14 @@

   Node* result = NULL;
   if (!has_context && !has_framestate && !has_control && !has_effect) {
-    result = graph()->NewNode(op, value_input_count, value_inputs);
+ result = graph()->NewNode(op, value_input_count, value_inputs, incomplete);
   } else {
     int input_count_with_deps = value_input_count;
     if (has_context) ++input_count_with_deps;
     if (has_framestate) ++input_count_with_deps;
     if (has_control) ++input_count_with_deps;
     if (has_effect) ++input_count_with_deps;
-    Node** buffer = local_zone()->NewArray<Node*>(input_count_with_deps);
+    Node** buffer = EnsureInputBufferSize(input_count_with_deps);
     memcpy(buffer, value_inputs, kPointerSize * value_input_count);
     Node** current_input = buffer + value_input_count;
     if (has_context) {
@@ -69,7 +82,7 @@
     if (has_control) {
       *current_input++ = environment_->GetControlDependency();
     }
-    result = graph()->NewNode(op, input_count_with_deps, buffer);
+ result = graph()->NewNode(op, input_count_with_deps, buffer, incomplete);
     if (has_effect) {
       environment_->UpdateEffectDependency(result);
     }
@@ -125,7 +138,9 @@
   // placing a singleton merge as the new control dependency.
   if (this->IsMarkedAsUnreachable()) {
     Node* other_control = other->control_dependency_;
- control_dependency_ = graph()->NewNode(common()->Merge(1), other_control);
+    Node* inputs[] = {other_control};
+    control_dependency_ =
+ graph()->NewNode(common()->Merge(1), arraysize(inputs), inputs, true);
     effect_dependency_ = other->effect_dependency_;
     values_ = other->values_;
     return;
@@ -164,7 +179,7 @@

Node* StructuredGraphBuilder::NewPhi(int count, Node* input, Node* control) {
   const Operator* phi_op = common()->Phi(kMachAnyTagged, count);
-  Node** buffer = local_zone()->NewArray<Node*>(count + 1);
+  Node** buffer = EnsureInputBufferSize(count + 1);
   MemsetPointer(buffer, input, count);
   buffer[count] = control;
   return graph()->NewNode(phi_op, count + 1, buffer, true);
@@ -175,7 +190,7 @@
 Node* StructuredGraphBuilder::NewEffectPhi(int count, Node* input,
                                            Node* control) {
   const Operator* phi_op = common()->EffectPhi(count);
-  Node** buffer = local_zone()->NewArray<Node*>(count + 1);
+  Node** buffer = EnsureInputBufferSize(count + 1);
   MemsetPointer(buffer, input, count);
   buffer[count] = control;
   return graph()->NewNode(phi_op, count + 1, buffer, true);
@@ -197,7 +212,8 @@
   } else {
     // Control node is a singleton, introduce a merge.
     const Operator* op = common()->Merge(inputs);
-    control = graph()->NewNode(op, control, other);
+    Node* inputs[] = {control, other};
+    control = graph()->NewNode(op, arraysize(inputs), inputs, true);
   }
   return control;
 }
=======================================
--- /branches/bleeding_edge/src/compiler/graph-builder.h Tue Oct 21 14:44:50 2014 UTC +++ /branches/bleeding_edge/src/compiler/graph-builder.h Mon Oct 27 10:12:16 2014 UTC
@@ -24,42 +24,44 @@
   explicit GraphBuilder(Graph* graph) : graph_(graph) {}
   virtual ~GraphBuilder() {}

-  Node* NewNode(const Operator* op) {
-    return MakeNode(op, 0, static_cast<Node**>(NULL));
+  Node* NewNode(const Operator* op, bool incomplete = false) {
+    return MakeNode(op, 0, static_cast<Node**>(NULL), incomplete);
   }

- Node* NewNode(const Operator* op, Node* n1) { return MakeNode(op, 1, &n1); }
+  Node* NewNode(const Operator* op, Node* n1) {
+    return MakeNode(op, 1, &n1, false);
+  }

   Node* NewNode(const Operator* op, Node* n1, Node* n2) {
     Node* buffer[] = {n1, n2};
-    return MakeNode(op, arraysize(buffer), buffer);
+    return MakeNode(op, arraysize(buffer), buffer, false);
   }

   Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3) {
     Node* buffer[] = {n1, n2, n3};
-    return MakeNode(op, arraysize(buffer), buffer);
+    return MakeNode(op, arraysize(buffer), buffer, false);
   }

Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3, Node* n4) {
     Node* buffer[] = {n1, n2, n3, n4};
-    return MakeNode(op, arraysize(buffer), buffer);
+    return MakeNode(op, arraysize(buffer), buffer, false);
   }

   Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3, Node* n4,
                 Node* n5) {
     Node* buffer[] = {n1, n2, n3, n4, n5};
-    return MakeNode(op, arraysize(buffer), buffer);
+    return MakeNode(op, arraysize(buffer), buffer, false);
   }

   Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3, Node* n4,
                 Node* n5, Node* n6) {
     Node* nodes[] = {n1, n2, n3, n4, n5, n6};
-    return MakeNode(op, arraysize(nodes), nodes);
+    return MakeNode(op, arraysize(nodes), nodes, false);
   }

-  Node* NewNode(const Operator* op, int value_input_count,
-                Node** value_inputs) {
-    return MakeNode(op, value_input_count, value_inputs);
+ Node* NewNode(const Operator* op, int value_input_count, Node** value_inputs,
+                bool incomplete = false) {
+    return MakeNode(op, value_input_count, value_inputs, incomplete);
   }

   Graph* graph() const { return graph_; }
@@ -67,7 +69,7 @@
  protected:
   // Base implementation used by all factory methods.
   virtual Node* MakeNode(const Operator* op, int value_input_count,
-                         Node** value_inputs) = 0;
+                         Node** value_inputs, bool incomplete) = 0;

  private:
   Graph* graph_;
@@ -95,8 +97,8 @@
   // Helpers to create new control nodes.
   Node* NewIfTrue() { return NewNode(common()->IfTrue()); }
   Node* NewIfFalse() { return NewNode(common()->IfFalse()); }
-  Node* NewMerge() { return NewNode(common()->Merge(1)); }
-  Node* NewLoop() { return NewNode(common()->Loop(1)); }
+  Node* NewMerge() { return NewNode(common()->Merge(1), true); }
+  Node* NewLoop() { return NewNode(common()->Loop(1), true); }
   Node* NewBranch(Node* condition) {
     return NewNode(common()->Branch(), condition);
   }
@@ -110,7 +112,7 @@
   // ensures effect and control dependencies are wired up. The dependencies
   // tracked by the environment might be mutated.
   virtual Node* MakeNode(const Operator* op, int value_input_count,
-                         Node** value_inputs) FINAL;
+                         Node** value_inputs, bool incomplete) FINAL;

   Environment* environment() const { return environment_; }
   void set_environment(Environment* env) { environment_ = env; }
@@ -148,6 +150,10 @@
   // Zone local to the builder for data not leaking into the graph.
   Zone* local_zone_;

+  // Temporary storage for building node input lists.
+  int input_buffer_size_;
+  Node** input_buffer_;
+
   // Node representing the control dependency for dead code.
   SetOncePointer<Node> dead_control_;

@@ -157,6 +163,12 @@
   // Merge of all control nodes that exit the function body.
   Node* exit_control_;

+ // Growth increment for the temporary buffer used to construct input lists to
+  // new nodes.
+  static const int kInputBufferSizeIncrement = 64;
+
+  Node** EnsureInputBufferSize(int size);
+
   DISALLOW_COPY_AND_ASSIGN(StructuredGraphBuilder);
 };

=======================================
--- /branches/bleeding_edge/src/compiler/graph.cc Wed Oct 15 11:38:04 2014 UTC +++ /branches/bleeding_edge/src/compiler/graph.cc Mon Oct 27 10:12:16 2014 UTC
@@ -11,6 +11,7 @@
 #include "src/compiler/node-aux-data-inl.h"
 #include "src/compiler/node-properties.h"
 #include "src/compiler/node-properties-inl.h"
+#include "src/compiler/opcodes.h"
 #include "src/compiler/operator-properties.h"
 #include "src/compiler/operator-properties-inl.h"

@@ -29,12 +30,14 @@
 }


-Node* Graph::NewNode(
-    const Operator* op, int input_count, Node** inputs, bool incomplete) {
+Node* Graph::NewNode(const Operator* op, int input_count, Node** inputs,
+                     bool incomplete) {
   DCHECK_LE(op->InputCount(), input_count);
-  Node* result = Node::New(this, input_count, inputs);
+  Node* result = Node::New(this, input_count, inputs, incomplete);
   result->Initialize(op);
-  if (!incomplete) Decorate(result);
+  if (!incomplete) {
+    Decorate(result);
+  }
   return result;
 }

=======================================
--- /branches/bleeding_edge/src/compiler/node.h Wed Oct 15 11:38:04 2014 UTC
+++ /branches/bleeding_edge/src/compiler/node.h Mon Oct 27 10:12:16 2014 UTC
@@ -48,8 +48,8 @@
 // out-of-line indexed by the Node's id.
 class Node FINAL : public GenericNode<NodeData, Node> {
  public:
-  Node(GenericGraphBase* graph, int input_count)
-      : GenericNode<NodeData, Node>(graph, input_count) {}
+  Node(GenericGraphBase* graph, int input_count, int reserve_input_count)
+ : GenericNode<NodeData, Node>(graph, input_count, reserve_input_count) {}

   void Initialize(const Operator* op) { set_op(op); }

=======================================
--- /branches/bleeding_edge/src/compiler/raw-machine-assembler.cc Tue Oct 21 12:38:46 2014 UTC +++ /branches/bleeding_edge/src/compiler/raw-machine-assembler.cc Mon Oct 27 10:12:16 2014 UTC
@@ -151,10 +151,10 @@


 Node* RawMachineAssembler::MakeNode(const Operator* op, int input_count,
-                                    Node** inputs) {
+                                    Node** inputs, bool incomplete) {
   DCHECK(ScheduleValid());
   DCHECK(current_block_ != NULL);
-  Node* node = graph()->NewNode(op, input_count, inputs);
+  Node* node = graph()->NewNode(op, input_count, inputs, incomplete);
BasicBlock* block = op->opcode() == IrOpcode::kParameter ? schedule()->start() : CurrentBlock();
   schedule()->AddNode(block, node);
=======================================
--- /branches/bleeding_edge/src/compiler/raw-machine-assembler.h Tue Oct 14 11:57:06 2014 UTC +++ /branches/bleeding_edge/src/compiler/raw-machine-assembler.h Mon Oct 27 10:12:16 2014 UTC
@@ -416,8 +416,8 @@
   Schedule* Export();

  protected:
-  virtual Node* MakeNode(const Operator* op, int input_count,
-                         Node** inputs) FINAL;
+ virtual Node* MakeNode(const Operator* op, int input_count, Node** inputs,
+                         bool incomplete) FINAL;

   bool ScheduleValid() { return schedule_ != NULL; }

=======================================
--- /branches/bleeding_edge/test/cctest/compiler/graph-builder-tester.h Thu Sep 11 10:37:49 2014 UTC +++ /branches/bleeding_edge/test/cctest/compiler/graph-builder-tester.h Mon Oct 27 10:12:16 2014 UTC
@@ -27,8 +27,8 @@

  protected:
   virtual Node* MakeNode(const Operator* op, int value_input_count,
-                         Node** value_inputs) FINAL {
-    return graph()->NewNode(op, value_input_count, value_inputs);
+                         Node** value_inputs, bool incomplete) FINAL {
+ return graph()->NewNode(op, value_input_count, value_inputs, incomplete);
   }
 };

=======================================
--- /branches/bleeding_edge/test/cctest/compiler/simplified-graph-builder.cc Wed Sep 10 12:23:45 2014 UTC +++ /branches/bleeding_edge/test/cctest/compiler/simplified-graph-builder.cc Mon Oct 27 10:12:16 2014 UTC
@@ -45,7 +45,7 @@

 Node* SimplifiedGraphBuilder::MakeNode(const Operator* op,
                                        int value_input_count,
-                                       Node** value_inputs) {
+ Node** value_inputs, bool incomplete) {
   DCHECK(op->InputCount() == value_input_count);

   DCHECK(!OperatorProperties::HasContextInput(op));
@@ -58,7 +58,7 @@

   Node* result = NULL;
   if (!has_control && !has_effect) {
-    result = graph()->NewNode(op, value_input_count, value_inputs);
+ result = graph()->NewNode(op, value_input_count, value_inputs, incomplete);
   } else {
     int input_count_with_deps = value_input_count;
     if (has_control) ++input_count_with_deps;
@@ -72,7 +72,7 @@
     if (has_control) {
       *current_input++ = graph()->start();
     }
-    result = graph()->NewNode(op, input_count_with_deps, buffer);
+ result = graph()->NewNode(op, input_count_with_deps, buffer, incomplete);
     if (has_effect) {
       effect_ = result;
     }
=======================================
--- /branches/bleeding_edge/test/cctest/compiler/simplified-graph-builder.h Tue Oct 7 13:30:28 2014 UTC +++ /branches/bleeding_edge/test/cctest/compiler/simplified-graph-builder.h Mon Oct 27 10:12:16 2014 UTC
@@ -139,7 +139,7 @@

  protected:
   virtual Node* MakeNode(const Operator* op, int value_input_count,
-                         Node** value_inputs) FINAL;
+                         Node** value_inputs, bool incomplete) FINAL;

  private:
   Node* effect_;

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to