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