提交 787d4210 编写于 作者: K kvn

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

Summary: Add new timeout checks to EA.
Reviewed-by: iveresov, drchase
上级 f641d0b3
...@@ -473,6 +473,9 @@ ...@@ -473,6 +473,9 @@
product(bool, DoEscapeAnalysis, true, \ product(bool, DoEscapeAnalysis, true, \
"Perform escape analysis") \ "Perform escape analysis") \
\ \
product(double, EscapeAnalysisTimeout, 20. DEBUG_ONLY(+40.), \
"Abort EA when it reaches time limit (in sec)") \
\
develop(bool, ExitEscapeAnalysisOnTimeout, true, \ develop(bool, ExitEscapeAnalysisOnTimeout, true, \
"Exit or throw assert in EA when it reaches time limit") \ "Exit or throw assert in EA when it reaches time limit") \
\ \
......
...@@ -37,6 +37,8 @@ ...@@ -37,6 +37,8 @@
ConnectionGraph::ConnectionGraph(Compile * C, PhaseIterGVN *igvn) : ConnectionGraph::ConnectionGraph(Compile * C, PhaseIterGVN *igvn) :
_nodes(C->comp_arena(), C->unique(), C->unique(), NULL), _nodes(C->comp_arena(), C->unique(), C->unique(), NULL),
_in_worklist(C->comp_arena()),
_next_pidx(0),
_collecting(true), _collecting(true),
_verify(false), _verify(false),
_compile(C), _compile(C),
...@@ -124,13 +126,19 @@ bool ConnectionGraph::compute_escape() { ...@@ -124,13 +126,19 @@ bool ConnectionGraph::compute_escape() {
if (C->root() != NULL) { if (C->root() != NULL) {
ideal_nodes.push(C->root()); ideal_nodes.push(C->root());
} }
// Processed ideal nodes are unique on ideal_nodes list
// but several ideal nodes are mapped to the phantom_obj.
// To avoid duplicated entries on the following worklists
// add the phantom_obj only once to them.
ptnodes_worklist.append(phantom_obj);
java_objects_worklist.append(phantom_obj);
for( uint next = 0; next < ideal_nodes.size(); ++next ) { for( uint next = 0; next < ideal_nodes.size(); ++next ) {
Node* n = ideal_nodes.at(next); Node* n = ideal_nodes.at(next);
// Create PointsTo nodes and add them to Connection Graph. Called // Create PointsTo nodes and add them to Connection Graph. Called
// only once per ideal node since ideal_nodes is Unique_Node list. // only once per ideal node since ideal_nodes is Unique_Node list.
add_node_to_connection_graph(n, &delayed_worklist); add_node_to_connection_graph(n, &delayed_worklist);
PointsToNode* ptn = ptnode_adr(n->_idx); PointsToNode* ptn = ptnode_adr(n->_idx);
if (ptn != NULL) { if (ptn != NULL && ptn != phantom_obj) {
ptnodes_worklist.append(ptn); ptnodes_worklist.append(ptn);
if (ptn->is_JavaObject()) { if (ptn->is_JavaObject()) {
java_objects_worklist.append(ptn->as_JavaObject()); java_objects_worklist.append(ptn->as_JavaObject());
...@@ -414,7 +422,7 @@ void ConnectionGraph::add_node_to_connection_graph(Node *n, Unique_Node_List *de ...@@ -414,7 +422,7 @@ void ConnectionGraph::add_node_to_connection_graph(Node *n, Unique_Node_List *de
} }
case Op_CreateEx: { case Op_CreateEx: {
// assume that all exception objects globally escape // assume that all exception objects globally escape
add_java_object(n, PointsToNode::GlobalEscape); map_ideal_node(n, phantom_obj);
break; break;
} }
case Op_LoadKlass: case Op_LoadKlass:
...@@ -1065,13 +1073,8 @@ bool ConnectionGraph::complete_connection_graph( ...@@ -1065,13 +1073,8 @@ bool ConnectionGraph::complete_connection_graph(
// on graph complexity. Observed 8 passes in jvm2008 compiler.compiler. // on graph complexity. Observed 8 passes in jvm2008 compiler.compiler.
// Set limit to 20 to catch situation when something did go wrong and // Set limit to 20 to catch situation when something did go wrong and
// bailout Escape Analysis. // bailout Escape Analysis.
// Also limit build time to 30 sec (60 in debug VM). // Also limit build time to 20 sec (60 in debug VM), EscapeAnalysisTimeout flag.
#define CG_BUILD_ITER_LIMIT 20 #define CG_BUILD_ITER_LIMIT 20
#ifdef ASSERT
#define CG_BUILD_TIME_LIMIT 60.0
#else
#define CG_BUILD_TIME_LIMIT 30.0
#endif
// Propagate GlobalEscape and ArgEscape escape states and check that // Propagate GlobalEscape and ArgEscape escape states and check that
// we still have non-escaping objects. The method pushs on _worklist // we still have non-escaping objects. The method pushs on _worklist
...@@ -1082,12 +1085,13 @@ bool ConnectionGraph::complete_connection_graph( ...@@ -1082,12 +1085,13 @@ bool ConnectionGraph::complete_connection_graph(
// Now propagate references to all JavaObject nodes. // Now propagate references to all JavaObject nodes.
int java_objects_length = java_objects_worklist.length(); int java_objects_length = java_objects_worklist.length();
elapsedTimer time; elapsedTimer time;
bool timeout = false;
int new_edges = 1; int new_edges = 1;
int iterations = 0; int iterations = 0;
do { do {
while ((new_edges > 0) && while ((new_edges > 0) &&
(iterations++ < CG_BUILD_ITER_LIMIT) && (iterations++ < CG_BUILD_ITER_LIMIT)) {
(time.seconds() < CG_BUILD_TIME_LIMIT)) { double start_time = time.seconds();
time.start(); time.start();
new_edges = 0; new_edges = 0;
// Propagate references to phantom_object for nodes pushed on _worklist // Propagate references to phantom_object for nodes pushed on _worklist
...@@ -1096,7 +1100,26 @@ bool ConnectionGraph::complete_connection_graph( ...@@ -1096,7 +1100,26 @@ bool ConnectionGraph::complete_connection_graph(
for (int next = 0; next < java_objects_length; ++next) { for (int next = 0; next < java_objects_length; ++next) {
JavaObjectNode* ptn = java_objects_worklist.at(next); JavaObjectNode* ptn = java_objects_worklist.at(next);
new_edges += add_java_object_edges(ptn, true); new_edges += add_java_object_edges(ptn, true);
#define SAMPLE_SIZE 4
if ((next % SAMPLE_SIZE) == 0) {
// Each 4 iterations calculate how much time it will take
// to complete graph construction.
time.stop();
double stop_time = time.seconds();
double time_per_iter = (stop_time - start_time) / (double)SAMPLE_SIZE;
double time_until_end = time_per_iter * (double)(java_objects_length - next);
if ((start_time + time_until_end) >= EscapeAnalysisTimeout) {
timeout = true;
break; // Timeout
}
start_time = stop_time;
time.start();
}
#undef SAMPLE_SIZE
} }
if (timeout) break;
if (new_edges > 0) { if (new_edges > 0) {
// Update escape states on each iteration if graph was updated. // Update escape states on each iteration if graph was updated.
if (!find_non_escaped_objects(ptnodes_worklist, non_escaped_worklist)) { if (!find_non_escaped_objects(ptnodes_worklist, non_escaped_worklist)) {
...@@ -1104,9 +1127,12 @@ bool ConnectionGraph::complete_connection_graph( ...@@ -1104,9 +1127,12 @@ bool ConnectionGraph::complete_connection_graph(
} }
} }
time.stop(); time.stop();
if (time.seconds() >= EscapeAnalysisTimeout) {
timeout = true;
break;
}
} }
if ((iterations < CG_BUILD_ITER_LIMIT) && if ((iterations < CG_BUILD_ITER_LIMIT) && !timeout) {
(time.seconds() < CG_BUILD_TIME_LIMIT)) {
time.start(); time.start();
// Find fields which have unknown value. // Find fields which have unknown value.
int fields_length = oop_fields_worklist.length(); int fields_length = oop_fields_worklist.length();
...@@ -1119,18 +1145,21 @@ bool ConnectionGraph::complete_connection_graph( ...@@ -1119,18 +1145,21 @@ bool ConnectionGraph::complete_connection_graph(
} }
} }
time.stop(); time.stop();
if (time.seconds() >= EscapeAnalysisTimeout) {
timeout = true;
break;
}
} else { } else {
new_edges = 0; // Bailout new_edges = 0; // Bailout
} }
} while (new_edges > 0); } while (new_edges > 0);
// Bailout if passed limits. // Bailout if passed limits.
if ((iterations >= CG_BUILD_ITER_LIMIT) || if ((iterations >= CG_BUILD_ITER_LIMIT) || timeout) {
(time.seconds() >= CG_BUILD_TIME_LIMIT)) {
Compile* C = _compile; Compile* C = _compile;
if (C->log() != NULL) { if (C->log() != NULL) {
C->log()->begin_elem("connectionGraph_bailout reason='reached "); C->log()->begin_elem("connectionGraph_bailout reason='reached ");
C->log()->text("%s", (iterations >= CG_BUILD_ITER_LIMIT) ? "iterations" : "time"); C->log()->text("%s", timeout ? "time" : "iterations");
C->log()->end_elem(" limit'"); C->log()->end_elem(" limit'");
} }
assert(ExitEscapeAnalysisOnTimeout, err_msg_res("infinite EA connection graph build (%f sec, %d iterations) with %d nodes and worklist size %d", assert(ExitEscapeAnalysisOnTimeout, err_msg_res("infinite EA connection graph build (%f sec, %d iterations) with %d nodes and worklist size %d",
...@@ -1147,7 +1176,6 @@ bool ConnectionGraph::complete_connection_graph( ...@@ -1147,7 +1176,6 @@ bool ConnectionGraph::complete_connection_graph(
#endif #endif
#undef CG_BUILD_ITER_LIMIT #undef CG_BUILD_ITER_LIMIT
#undef CG_BUILD_TIME_LIMIT
// Find fields initialized by NULL for non-escaping Allocations. // Find fields initialized by NULL for non-escaping Allocations.
int non_escaped_length = non_escaped_worklist.length(); int non_escaped_length = non_escaped_worklist.length();
...@@ -1271,8 +1299,8 @@ int ConnectionGraph::add_java_object_edges(JavaObjectNode* jobj, bool populate_w ...@@ -1271,8 +1299,8 @@ int ConnectionGraph::add_java_object_edges(JavaObjectNode* jobj, bool populate_w
} }
} }
} }
while(_worklist.length() > 0) { for (int l = 0; l < _worklist.length(); l++) {
PointsToNode* use = _worklist.pop(); PointsToNode* use = _worklist.at(l);
if (PointsToNode::is_base_use(use)) { if (PointsToNode::is_base_use(use)) {
// Add reference from jobj to field and from field to jobj (field's base). // Add reference from jobj to field and from field to jobj (field's base).
use = PointsToNode::get_use_node(use)->as_Field(); use = PointsToNode::get_use_node(use)->as_Field();
...@@ -1319,6 +1347,8 @@ int ConnectionGraph::add_java_object_edges(JavaObjectNode* jobj, bool populate_w ...@@ -1319,6 +1347,8 @@ int ConnectionGraph::add_java_object_edges(JavaObjectNode* jobj, bool populate_w
add_field_uses_to_worklist(use->as_Field()); add_field_uses_to_worklist(use->as_Field());
} }
} }
_worklist.clear();
_in_worklist.Reset();
return new_edges; return new_edges;
} }
...@@ -1898,7 +1928,7 @@ void ConnectionGraph::add_local_var(Node *n, PointsToNode::EscapeState es) { ...@@ -1898,7 +1928,7 @@ void ConnectionGraph::add_local_var(Node *n, PointsToNode::EscapeState es) {
return; return;
} }
Compile* C = _compile; Compile* C = _compile;
ptadr = new (C->comp_arena()) LocalVarNode(C, n, es); ptadr = new (C->comp_arena()) LocalVarNode(this, n, es);
_nodes.at_put(n->_idx, ptadr); _nodes.at_put(n->_idx, ptadr);
} }
...@@ -1909,7 +1939,7 @@ void ConnectionGraph::add_java_object(Node *n, PointsToNode::EscapeState es) { ...@@ -1909,7 +1939,7 @@ void ConnectionGraph::add_java_object(Node *n, PointsToNode::EscapeState es) {
return; return;
} }
Compile* C = _compile; Compile* C = _compile;
ptadr = new (C->comp_arena()) JavaObjectNode(C, n, es); ptadr = new (C->comp_arena()) JavaObjectNode(this, n, es);
_nodes.at_put(n->_idx, ptadr); _nodes.at_put(n->_idx, ptadr);
} }
...@@ -1925,7 +1955,7 @@ void ConnectionGraph::add_field(Node *n, PointsToNode::EscapeState es, int offse ...@@ -1925,7 +1955,7 @@ void ConnectionGraph::add_field(Node *n, PointsToNode::EscapeState es, int offse
es = PointsToNode::GlobalEscape; es = PointsToNode::GlobalEscape;
} }
Compile* C = _compile; Compile* C = _compile;
FieldNode* field = new (C->comp_arena()) FieldNode(C, n, es, offset, is_oop); FieldNode* field = new (C->comp_arena()) FieldNode(this, n, es, offset, is_oop);
_nodes.at_put(n->_idx, field); _nodes.at_put(n->_idx, field);
} }
...@@ -1939,7 +1969,7 @@ void ConnectionGraph::add_arraycopy(Node *n, PointsToNode::EscapeState es, ...@@ -1939,7 +1969,7 @@ void ConnectionGraph::add_arraycopy(Node *n, PointsToNode::EscapeState es,
return; return;
} }
Compile* C = _compile; Compile* C = _compile;
ptadr = new (C->comp_arena()) ArraycopyNode(C, n, es); ptadr = new (C->comp_arena()) ArraycopyNode(this, n, es);
_nodes.at_put(n->_idx, ptadr); _nodes.at_put(n->_idx, ptadr);
// Add edge from arraycopy node to source object. // Add edge from arraycopy node to source object.
(void)add_edge(ptadr, src); (void)add_edge(ptadr, src);
......
...@@ -125,6 +125,8 @@ class LocalVarNode; ...@@ -125,6 +125,8 @@ class LocalVarNode;
class FieldNode; class FieldNode;
class ArraycopyNode; class ArraycopyNode;
class ConnectionGraph;
// ConnectionGraph nodes // ConnectionGraph nodes
class PointsToNode : public ResourceObj { class PointsToNode : public ResourceObj {
GrowableArray<PointsToNode*> _edges; // List of nodes this node points to GrowableArray<PointsToNode*> _edges; // List of nodes this node points to
...@@ -137,6 +139,7 @@ class PointsToNode : public ResourceObj { ...@@ -137,6 +139,7 @@ class PointsToNode : public ResourceObj {
Node* const _node; // Ideal node corresponding to this PointsTo node. Node* const _node; // Ideal node corresponding to this PointsTo node.
const int _idx; // Cached ideal node's _idx const int _idx; // Cached ideal node's _idx
const uint _pidx; // Index of this node
public: public:
typedef enum { typedef enum {
...@@ -165,17 +168,9 @@ public: ...@@ -165,17 +168,9 @@ public:
} NodeFlags; } NodeFlags;
PointsToNode(Compile *C, Node* n, EscapeState es, NodeType type): inline PointsToNode(ConnectionGraph* CG, Node* n, EscapeState es, NodeType type);
_edges(C->comp_arena(), 2, 0, NULL),
_uses (C->comp_arena(), 2, 0, NULL), uint pidx() const { return _pidx; }
_node(n),
_idx(n->_idx),
_type((u1)type),
_escape((u1)es),
_fields_escape((u1)es),
_flags(ScalarReplaceable) {
assert(n != NULL && es != UnknownEscape, "sanity");
}
Node* ideal_node() const { return _node; } Node* ideal_node() const { return _node; }
int idx() const { return _idx; } int idx() const { return _idx; }
...@@ -243,14 +238,14 @@ public: ...@@ -243,14 +238,14 @@ public:
class LocalVarNode: public PointsToNode { class LocalVarNode: public PointsToNode {
public: public:
LocalVarNode(Compile *C, Node* n, EscapeState es): LocalVarNode(ConnectionGraph *CG, Node* n, EscapeState es):
PointsToNode(C, n, es, LocalVar) {} PointsToNode(CG, n, es, LocalVar) {}
}; };
class JavaObjectNode: public PointsToNode { class JavaObjectNode: public PointsToNode {
public: public:
JavaObjectNode(Compile *C, Node* n, EscapeState es): JavaObjectNode(ConnectionGraph *CG, Node* n, EscapeState es):
PointsToNode(C, n, es, JavaObject) { PointsToNode(CG, n, es, JavaObject) {
if (es > NoEscape) if (es > NoEscape)
set_scalar_replaceable(false); set_scalar_replaceable(false);
} }
...@@ -262,8 +257,8 @@ class FieldNode: public PointsToNode { ...@@ -262,8 +257,8 @@ class FieldNode: public PointsToNode {
const bool _is_oop; // Field points to object const bool _is_oop; // Field points to object
bool _has_unknown_base; // Has phantom_object base bool _has_unknown_base; // Has phantom_object base
public: public:
FieldNode(Compile *C, Node* n, EscapeState es, int offs, bool is_oop): FieldNode(ConnectionGraph *CG, Node* n, EscapeState es, int offs, bool is_oop):
PointsToNode(C, n, es, Field), PointsToNode(CG, n, es, Field),
_offset(offs), _is_oop(is_oop), _offset(offs), _is_oop(is_oop),
_has_unknown_base(false) {} _has_unknown_base(false) {}
...@@ -284,8 +279,8 @@ public: ...@@ -284,8 +279,8 @@ public:
class ArraycopyNode: public PointsToNode { class ArraycopyNode: public PointsToNode {
public: public:
ArraycopyNode(Compile *C, Node* n, EscapeState es): ArraycopyNode(ConnectionGraph *CG, Node* n, EscapeState es):
PointsToNode(C, n, es, Arraycopy) {} PointsToNode(CG, n, es, Arraycopy) {}
}; };
// Iterators for PointsTo node's edges: // Iterators for PointsTo node's edges:
...@@ -323,11 +318,14 @@ public: ...@@ -323,11 +318,14 @@ public:
class ConnectionGraph: public ResourceObj { class ConnectionGraph: public ResourceObj {
friend class PointsToNode;
private: private:
GrowableArray<PointsToNode*> _nodes; // Map from ideal nodes to GrowableArray<PointsToNode*> _nodes; // Map from ideal nodes to
// ConnectionGraph nodes. // ConnectionGraph nodes.
GrowableArray<PointsToNode*> _worklist; // Nodes to be processed GrowableArray<PointsToNode*> _worklist; // Nodes to be processed
VectorSet _in_worklist;
uint _next_pidx;
bool _collecting; // Indicates whether escape information bool _collecting; // Indicates whether escape information
// is still being collected. If false, // is still being collected. If false,
...@@ -353,6 +351,8 @@ private: ...@@ -353,6 +351,8 @@ private:
} }
uint nodes_size() const { return _nodes.length(); } uint nodes_size() const { return _nodes.length(); }
uint next_pidx() { return _next_pidx++; }
// Add nodes to ConnectionGraph. // Add nodes to ConnectionGraph.
void add_local_var(Node* n, PointsToNode::EscapeState es); void add_local_var(Node* n, PointsToNode::EscapeState es);
void add_java_object(Node* n, PointsToNode::EscapeState es); void add_java_object(Node* n, PointsToNode::EscapeState es);
...@@ -396,15 +396,26 @@ private: ...@@ -396,15 +396,26 @@ private:
int add_java_object_edges(JavaObjectNode* jobj, bool populate_worklist); int add_java_object_edges(JavaObjectNode* jobj, bool populate_worklist);
// Put node on worklist if it is (or was) not there. // Put node on worklist if it is (or was) not there.
void add_to_worklist(PointsToNode* pt) { inline void add_to_worklist(PointsToNode* pt) {
_worklist.push(pt); PointsToNode* ptf = pt;
return; uint pidx_bias = 0;
if (PointsToNode::is_base_use(pt)) {
// Create a separate entry in _in_worklist for a marked base edge
// because _worklist may have an entry for a normal edge pointing
// to the same node. To separate them use _next_pidx as bias.
ptf = PointsToNode::get_use_node(pt)->as_Field();
pidx_bias = _next_pidx;
}
if (!_in_worklist.test_set(ptf->pidx() + pidx_bias)) {
_worklist.append(pt);
}
} }
// Put on worklist all uses of this node. // Put on worklist all uses of this node.
void add_uses_to_worklist(PointsToNode* pt) { inline void add_uses_to_worklist(PointsToNode* pt) {
for (UseIterator i(pt); i.has_next(); i.next()) for (UseIterator i(pt); i.has_next(); i.next()) {
_worklist.push(i.get()); add_to_worklist(i.get());
}
} }
// Put on worklist all field's uses and related field nodes. // Put on worklist all field's uses and related field nodes.
...@@ -517,8 +528,8 @@ private: ...@@ -517,8 +528,8 @@ private:
} }
// Helper functions // Helper functions
bool is_oop_field(Node* n, int offset, bool* unsafe); bool is_oop_field(Node* n, int offset, bool* unsafe);
static Node* get_addp_base(Node *addp); static Node* get_addp_base(Node *addp);
static Node* find_second_addp(Node* addp, Node* n); static Node* find_second_addp(Node* addp, Node* n);
// offset of a field reference // offset of a field reference
int address_offset(Node* adr, PhaseTransform *phase); int address_offset(Node* adr, PhaseTransform *phase);
...@@ -587,4 +598,17 @@ public: ...@@ -587,4 +598,17 @@ public:
#endif #endif
}; };
inline PointsToNode::PointsToNode(ConnectionGraph *CG, Node* n, EscapeState es, NodeType type):
_edges(CG->_compile->comp_arena(), 2, 0, NULL),
_uses (CG->_compile->comp_arena(), 2, 0, NULL),
_node(n),
_idx(n->_idx),
_pidx(CG->next_pidx()),
_type((u1)type),
_escape((u1)es),
_fields_escape((u1)es),
_flags(ScalarReplaceable) {
assert(n != NULL && es != UnknownEscape, "sanity");
}
#endif // SHARE_VM_OPTO_ESCAPE_HPP #endif // SHARE_VM_OPTO_ESCAPE_HPP
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册