8041984: CompilerThread seems to occupy all CPU in a very rare situation

Fri, 24 Oct 2014 10:28:19 -0700

author
kvn
date
Fri, 24 Oct 2014 10:28:19 -0700
changeset 7299
90297adbda9d
parent 7298
ef9eda2c1abe
child 7300
03e6d34be1f5

8041984: CompilerThread seems to occupy all CPU in a very rare situation
Summary: Add new timeout checks to EA.
Reviewed-by: iveresov, drchase

src/share/vm/opto/c2_globals.hpp file | annotate | diff | comparison | revisions
src/share/vm/opto/escape.cpp file | annotate | diff | comparison | revisions
src/share/vm/opto/escape.hpp file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/vm/opto/c2_globals.hpp	Thu Oct 30 10:51:06 2014 +0100
     1.2 +++ b/src/share/vm/opto/c2_globals.hpp	Fri Oct 24 10:28:19 2014 -0700
     1.3 @@ -473,6 +473,9 @@
     1.4    product(bool, DoEscapeAnalysis, true,                                     \
     1.5            "Perform escape analysis")                                        \
     1.6                                                                              \
     1.7 +  product(double, EscapeAnalysisTimeout, 20. DEBUG_ONLY(+40.),              \
     1.8 +          "Abort EA when it reaches time limit (in sec)")                   \
     1.9 +                                                                            \
    1.10    develop(bool, ExitEscapeAnalysisOnTimeout, true,                          \
    1.11            "Exit or throw assert in EA when it reaches time limit")          \
    1.12                                                                              \
     2.1 --- a/src/share/vm/opto/escape.cpp	Thu Oct 30 10:51:06 2014 +0100
     2.2 +++ b/src/share/vm/opto/escape.cpp	Fri Oct 24 10:28:19 2014 -0700
     2.3 @@ -37,6 +37,8 @@
     2.4  
     2.5  ConnectionGraph::ConnectionGraph(Compile * C, PhaseIterGVN *igvn) :
     2.6    _nodes(C->comp_arena(), C->unique(), C->unique(), NULL),
     2.7 +  _in_worklist(C->comp_arena()),
     2.8 +  _next_pidx(0),
     2.9    _collecting(true),
    2.10    _verify(false),
    2.11    _compile(C),
    2.12 @@ -124,13 +126,19 @@
    2.13    if (C->root() != NULL) {
    2.14      ideal_nodes.push(C->root());
    2.15    }
    2.16 +  // Processed ideal nodes are unique on ideal_nodes list
    2.17 +  // but several ideal nodes are mapped to the phantom_obj.
    2.18 +  // To avoid duplicated entries on the following worklists
    2.19 +  // add the phantom_obj only once to them.
    2.20 +  ptnodes_worklist.append(phantom_obj);
    2.21 +  java_objects_worklist.append(phantom_obj);
    2.22    for( uint next = 0; next < ideal_nodes.size(); ++next ) {
    2.23      Node* n = ideal_nodes.at(next);
    2.24      // Create PointsTo nodes and add them to Connection Graph. Called
    2.25      // only once per ideal node since ideal_nodes is Unique_Node list.
    2.26      add_node_to_connection_graph(n, &delayed_worklist);
    2.27      PointsToNode* ptn = ptnode_adr(n->_idx);
    2.28 -    if (ptn != NULL) {
    2.29 +    if (ptn != NULL && ptn != phantom_obj) {
    2.30        ptnodes_worklist.append(ptn);
    2.31        if (ptn->is_JavaObject()) {
    2.32          java_objects_worklist.append(ptn->as_JavaObject());
    2.33 @@ -414,7 +422,7 @@
    2.34      }
    2.35      case Op_CreateEx: {
    2.36        // assume that all exception objects globally escape
    2.37 -      add_java_object(n, PointsToNode::GlobalEscape);
    2.38 +      map_ideal_node(n, phantom_obj);
    2.39        break;
    2.40      }
    2.41      case Op_LoadKlass:
    2.42 @@ -1065,13 +1073,8 @@
    2.43    // on graph complexity. Observed 8 passes in jvm2008 compiler.compiler.
    2.44    // Set limit to 20 to catch situation when something did go wrong and
    2.45    // bailout Escape Analysis.
    2.46 -  // Also limit build time to 30 sec (60 in debug VM).
    2.47 +  // Also limit build time to 20 sec (60 in debug VM), EscapeAnalysisTimeout flag.
    2.48  #define CG_BUILD_ITER_LIMIT 20
    2.49 -#ifdef ASSERT
    2.50 -#define CG_BUILD_TIME_LIMIT 60.0
    2.51 -#else
    2.52 -#define CG_BUILD_TIME_LIMIT 30.0
    2.53 -#endif
    2.54  
    2.55    // Propagate GlobalEscape and ArgEscape escape states and check that
    2.56    // we still have non-escaping objects. The method pushs on _worklist
    2.57 @@ -1082,12 +1085,13 @@
    2.58    // Now propagate references to all JavaObject nodes.
    2.59    int java_objects_length = java_objects_worklist.length();
    2.60    elapsedTimer time;
    2.61 +  bool timeout = false;
    2.62    int new_edges = 1;
    2.63    int iterations = 0;
    2.64    do {
    2.65      while ((new_edges > 0) &&
    2.66 -          (iterations++   < CG_BUILD_ITER_LIMIT) &&
    2.67 -          (time.seconds() < CG_BUILD_TIME_LIMIT)) {
    2.68 +           (iterations++ < CG_BUILD_ITER_LIMIT)) {
    2.69 +      double start_time = time.seconds();
    2.70        time.start();
    2.71        new_edges = 0;
    2.72        // Propagate references to phantom_object for nodes pushed on _worklist
    2.73 @@ -1096,7 +1100,26 @@
    2.74        for (int next = 0; next < java_objects_length; ++next) {
    2.75          JavaObjectNode* ptn = java_objects_worklist.at(next);
    2.76          new_edges += add_java_object_edges(ptn, true);
    2.77 +
    2.78 +#define SAMPLE_SIZE 4
    2.79 +        if ((next % SAMPLE_SIZE) == 0) {
    2.80 +          // Each 4 iterations calculate how much time it will take
    2.81 +          // to complete graph construction.
    2.82 +          time.stop();
    2.83 +          double stop_time = time.seconds();
    2.84 +          double time_per_iter = (stop_time - start_time) / (double)SAMPLE_SIZE;
    2.85 +          double time_until_end = time_per_iter * (double)(java_objects_length - next);
    2.86 +          if ((start_time + time_until_end) >= EscapeAnalysisTimeout) {
    2.87 +            timeout = true;
    2.88 +            break; // Timeout
    2.89 +          }
    2.90 +          start_time = stop_time;
    2.91 +          time.start();
    2.92 +        }
    2.93 +#undef SAMPLE_SIZE
    2.94 +
    2.95        }
    2.96 +      if (timeout) break;
    2.97        if (new_edges > 0) {
    2.98          // Update escape states on each iteration if graph was updated.
    2.99          if (!find_non_escaped_objects(ptnodes_worklist, non_escaped_worklist)) {
   2.100 @@ -1104,9 +1127,12 @@
   2.101          }
   2.102        }
   2.103        time.stop();
   2.104 +      if (time.seconds() >= EscapeAnalysisTimeout) {
   2.105 +        timeout = true;
   2.106 +        break;
   2.107 +      }
   2.108      }
   2.109 -    if ((iterations     < CG_BUILD_ITER_LIMIT) &&
   2.110 -        (time.seconds() < CG_BUILD_TIME_LIMIT)) {
   2.111 +    if ((iterations < CG_BUILD_ITER_LIMIT) && !timeout) {
   2.112        time.start();
   2.113        // Find fields which have unknown value.
   2.114        int fields_length = oop_fields_worklist.length();
   2.115 @@ -1119,18 +1145,21 @@
   2.116          }
   2.117        }
   2.118        time.stop();
   2.119 +      if (time.seconds() >= EscapeAnalysisTimeout) {
   2.120 +        timeout = true;
   2.121 +        break;
   2.122 +      }
   2.123      } else {
   2.124        new_edges = 0; // Bailout
   2.125      }
   2.126    } while (new_edges > 0);
   2.127  
   2.128    // Bailout if passed limits.
   2.129 -  if ((iterations     >= CG_BUILD_ITER_LIMIT) ||
   2.130 -      (time.seconds() >= CG_BUILD_TIME_LIMIT)) {
   2.131 +  if ((iterations >= CG_BUILD_ITER_LIMIT) || timeout) {
   2.132      Compile* C = _compile;
   2.133      if (C->log() != NULL) {
   2.134        C->log()->begin_elem("connectionGraph_bailout reason='reached ");
   2.135 -      C->log()->text("%s", (iterations >= CG_BUILD_ITER_LIMIT) ? "iterations" : "time");
   2.136 +      C->log()->text("%s", timeout ? "time" : "iterations");
   2.137        C->log()->end_elem(" limit'");
   2.138      }
   2.139      assert(ExitEscapeAnalysisOnTimeout, err_msg_res("infinite EA connection graph build (%f sec, %d iterations) with %d nodes and worklist size %d",
   2.140 @@ -1147,7 +1176,6 @@
   2.141  #endif
   2.142  
   2.143  #undef CG_BUILD_ITER_LIMIT
   2.144 -#undef CG_BUILD_TIME_LIMIT
   2.145  
   2.146    // Find fields initialized by NULL for non-escaping Allocations.
   2.147    int non_escaped_length = non_escaped_worklist.length();
   2.148 @@ -1271,8 +1299,8 @@
   2.149        }
   2.150      }
   2.151    }
   2.152 -  while(_worklist.length() > 0) {
   2.153 -    PointsToNode* use = _worklist.pop();
   2.154 +  for (int l = 0; l < _worklist.length(); l++) {
   2.155 +    PointsToNode* use = _worklist.at(l);
   2.156      if (PointsToNode::is_base_use(use)) {
   2.157        // Add reference from jobj to field and from field to jobj (field's base).
   2.158        use = PointsToNode::get_use_node(use)->as_Field();
   2.159 @@ -1319,6 +1347,8 @@
   2.160        add_field_uses_to_worklist(use->as_Field());
   2.161      }
   2.162    }
   2.163 +  _worklist.clear();
   2.164 +  _in_worklist.Reset();
   2.165    return new_edges;
   2.166  }
   2.167  
   2.168 @@ -1898,7 +1928,7 @@
   2.169      return;
   2.170    }
   2.171    Compile* C = _compile;
   2.172 -  ptadr = new (C->comp_arena()) LocalVarNode(C, n, es);
   2.173 +  ptadr = new (C->comp_arena()) LocalVarNode(this, n, es);
   2.174    _nodes.at_put(n->_idx, ptadr);
   2.175  }
   2.176  
   2.177 @@ -1909,7 +1939,7 @@
   2.178      return;
   2.179    }
   2.180    Compile* C = _compile;
   2.181 -  ptadr = new (C->comp_arena()) JavaObjectNode(C, n, es);
   2.182 +  ptadr = new (C->comp_arena()) JavaObjectNode(this, n, es);
   2.183    _nodes.at_put(n->_idx, ptadr);
   2.184  }
   2.185  
   2.186 @@ -1925,7 +1955,7 @@
   2.187      es = PointsToNode::GlobalEscape;
   2.188    }
   2.189    Compile* C = _compile;
   2.190 -  FieldNode* field = new (C->comp_arena()) FieldNode(C, n, es, offset, is_oop);
   2.191 +  FieldNode* field = new (C->comp_arena()) FieldNode(this, n, es, offset, is_oop);
   2.192    _nodes.at_put(n->_idx, field);
   2.193  }
   2.194  
   2.195 @@ -1939,7 +1969,7 @@
   2.196      return;
   2.197    }
   2.198    Compile* C = _compile;
   2.199 -  ptadr = new (C->comp_arena()) ArraycopyNode(C, n, es);
   2.200 +  ptadr = new (C->comp_arena()) ArraycopyNode(this, n, es);
   2.201    _nodes.at_put(n->_idx, ptadr);
   2.202    // Add edge from arraycopy node to source object.
   2.203    (void)add_edge(ptadr, src);
     3.1 --- a/src/share/vm/opto/escape.hpp	Thu Oct 30 10:51:06 2014 +0100
     3.2 +++ b/src/share/vm/opto/escape.hpp	Fri Oct 24 10:28:19 2014 -0700
     3.3 @@ -125,6 +125,8 @@
     3.4  class FieldNode;
     3.5  class ArraycopyNode;
     3.6  
     3.7 +class ConnectionGraph;
     3.8 +
     3.9  // ConnectionGraph nodes
    3.10  class PointsToNode : public ResourceObj {
    3.11    GrowableArray<PointsToNode*> _edges; // List of nodes this node points to
    3.12 @@ -137,6 +139,7 @@
    3.13  
    3.14    Node* const        _node;  // Ideal node corresponding to this PointsTo node.
    3.15    const int           _idx;  // Cached ideal node's _idx
    3.16 +  const uint         _pidx;  // Index of this node
    3.17  
    3.18  public:
    3.19    typedef enum {
    3.20 @@ -165,17 +168,9 @@
    3.21    } NodeFlags;
    3.22  
    3.23  
    3.24 -  PointsToNode(Compile *C, Node* n, EscapeState es, NodeType type):
    3.25 -    _edges(C->comp_arena(), 2, 0, NULL),
    3.26 -    _uses (C->comp_arena(), 2, 0, NULL),
    3.27 -    _node(n),
    3.28 -    _idx(n->_idx),
    3.29 -    _type((u1)type),
    3.30 -    _escape((u1)es),
    3.31 -    _fields_escape((u1)es),
    3.32 -    _flags(ScalarReplaceable) {
    3.33 -    assert(n != NULL && es != UnknownEscape, "sanity");
    3.34 -  }
    3.35 +  inline PointsToNode(ConnectionGraph* CG, Node* n, EscapeState es, NodeType type);
    3.36 +
    3.37 +  uint        pidx()   const { return _pidx; }
    3.38  
    3.39    Node* ideal_node()   const { return _node; }
    3.40    int          idx()   const { return _idx; }
    3.41 @@ -243,14 +238,14 @@
    3.42  
    3.43  class LocalVarNode: public PointsToNode {
    3.44  public:
    3.45 -  LocalVarNode(Compile *C, Node* n, EscapeState es):
    3.46 -    PointsToNode(C, n, es, LocalVar) {}
    3.47 +  LocalVarNode(ConnectionGraph *CG, Node* n, EscapeState es):
    3.48 +    PointsToNode(CG, n, es, LocalVar) {}
    3.49  };
    3.50  
    3.51  class JavaObjectNode: public PointsToNode {
    3.52  public:
    3.53 -  JavaObjectNode(Compile *C, Node* n, EscapeState es):
    3.54 -    PointsToNode(C, n, es, JavaObject) {
    3.55 +  JavaObjectNode(ConnectionGraph *CG, Node* n, EscapeState es):
    3.56 +    PointsToNode(CG, n, es, JavaObject) {
    3.57        if (es > NoEscape)
    3.58          set_scalar_replaceable(false);
    3.59      }
    3.60 @@ -262,8 +257,8 @@
    3.61    const bool  _is_oop; // Field points to object
    3.62          bool  _has_unknown_base; // Has phantom_object base
    3.63  public:
    3.64 -  FieldNode(Compile *C, Node* n, EscapeState es, int offs, bool is_oop):
    3.65 -    PointsToNode(C, n, es, Field),
    3.66 +  FieldNode(ConnectionGraph *CG, Node* n, EscapeState es, int offs, bool is_oop):
    3.67 +    PointsToNode(CG, n, es, Field),
    3.68      _offset(offs), _is_oop(is_oop),
    3.69      _has_unknown_base(false) {}
    3.70  
    3.71 @@ -284,8 +279,8 @@
    3.72  
    3.73  class ArraycopyNode: public PointsToNode {
    3.74  public:
    3.75 -  ArraycopyNode(Compile *C, Node* n, EscapeState es):
    3.76 -    PointsToNode(C, n, es, Arraycopy) {}
    3.77 +  ArraycopyNode(ConnectionGraph *CG, Node* n, EscapeState es):
    3.78 +    PointsToNode(CG, n, es, Arraycopy) {}
    3.79  };
    3.80  
    3.81  // Iterators for PointsTo node's edges:
    3.82 @@ -323,11 +318,14 @@
    3.83  
    3.84  
    3.85  class ConnectionGraph: public ResourceObj {
    3.86 +  friend class PointsToNode;
    3.87  private:
    3.88    GrowableArray<PointsToNode*>  _nodes; // Map from ideal nodes to
    3.89                                          // ConnectionGraph nodes.
    3.90  
    3.91    GrowableArray<PointsToNode*>  _worklist; // Nodes to be processed
    3.92 +  VectorSet                  _in_worklist;
    3.93 +  uint                         _next_pidx;
    3.94  
    3.95    bool            _collecting; // Indicates whether escape information
    3.96                                 // is still being collected. If false,
    3.97 @@ -353,6 +351,8 @@
    3.98    }
    3.99    uint nodes_size() const { return _nodes.length(); }
   3.100  
   3.101 +  uint next_pidx() { return _next_pidx++; }
   3.102 +
   3.103    // Add nodes to ConnectionGraph.
   3.104    void add_local_var(Node* n, PointsToNode::EscapeState es);
   3.105    void add_java_object(Node* n, PointsToNode::EscapeState es);
   3.106 @@ -396,15 +396,26 @@
   3.107    int add_java_object_edges(JavaObjectNode* jobj, bool populate_worklist);
   3.108  
   3.109    // Put node on worklist if it is (or was) not there.
   3.110 -  void add_to_worklist(PointsToNode* pt) {
   3.111 -    _worklist.push(pt);
   3.112 -    return;
   3.113 +  inline void add_to_worklist(PointsToNode* pt) {
   3.114 +    PointsToNode* ptf = pt;
   3.115 +    uint pidx_bias = 0;
   3.116 +    if (PointsToNode::is_base_use(pt)) {
   3.117 +      // Create a separate entry in _in_worklist for a marked base edge
   3.118 +      // because _worklist may have an entry for a normal edge pointing
   3.119 +      // to the same node. To separate them use _next_pidx as bias.
   3.120 +      ptf = PointsToNode::get_use_node(pt)->as_Field();
   3.121 +      pidx_bias = _next_pidx;
   3.122 +    }
   3.123 +    if (!_in_worklist.test_set(ptf->pidx() + pidx_bias)) {
   3.124 +      _worklist.append(pt);
   3.125 +    }
   3.126    }
   3.127  
   3.128    // Put on worklist all uses of this node.
   3.129 -  void add_uses_to_worklist(PointsToNode* pt) {
   3.130 -    for (UseIterator i(pt); i.has_next(); i.next())
   3.131 -      _worklist.push(i.get());
   3.132 +  inline void add_uses_to_worklist(PointsToNode* pt) {
   3.133 +    for (UseIterator i(pt); i.has_next(); i.next()) {
   3.134 +      add_to_worklist(i.get());
   3.135 +    }
   3.136    }
   3.137  
   3.138    // Put on worklist all field's uses and related field nodes.
   3.139 @@ -517,8 +528,8 @@
   3.140   }
   3.141    // Helper functions
   3.142    bool   is_oop_field(Node* n, int offset, bool* unsafe);
   3.143 - static Node* get_addp_base(Node *addp);
   3.144 - static Node* find_second_addp(Node* addp, Node* n);
   3.145 +  static Node* get_addp_base(Node *addp);
   3.146 +  static Node* find_second_addp(Node* addp, Node* n);
   3.147    // offset of a field reference
   3.148    int address_offset(Node* adr, PhaseTransform *phase);
   3.149  
   3.150 @@ -587,4 +598,17 @@
   3.151  #endif
   3.152  };
   3.153  
   3.154 +inline PointsToNode::PointsToNode(ConnectionGraph *CG, Node* n, EscapeState es, NodeType type):
   3.155 +  _edges(CG->_compile->comp_arena(), 2, 0, NULL),
   3.156 +  _uses (CG->_compile->comp_arena(), 2, 0, NULL),
   3.157 +  _node(n),
   3.158 +  _idx(n->_idx),
   3.159 +  _pidx(CG->next_pidx()),
   3.160 +  _type((u1)type),
   3.161 +  _escape((u1)es),
   3.162 +  _fields_escape((u1)es),
   3.163 +  _flags(ScalarReplaceable) {
   3.164 +  assert(n != NULL && es != UnknownEscape, "sanity");
   3.165 +}
   3.166 +
   3.167  #endif // SHARE_VM_OPTO_ESCAPE_HPP

mercurial