Fri, 24 Oct 2014 10:28:19 -0700
8041984: CompilerThread seems to occupy all CPU in a very rare situation
Summary: Add new timeout checks to EA.
Reviewed-by: iveresov, drchase
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