diff --git a/src/hotspot/share/opto/block.cpp b/src/hotspot/share/opto/block.cpp index 7d3d4ec16f4f1..db8c3315b5ff2 100644 --- a/src/hotspot/share/opto/block.cpp +++ b/src/hotspot/share/opto/block.cpp @@ -27,6 +27,7 @@ #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "opto/block.hpp" +#include "opto/compile.hpp" #include "opto/cfgnode.hpp" #include "opto/chaitin.hpp" #include "opto/loopnode.hpp" @@ -1017,6 +1018,7 @@ void PhaseCFG::remove_unreachable_blocks() { get_block(i)->_pre_order--; } _blocks.remove(dead->_pre_order); + C->record_optimization_event(OptEvent_BlockElimination); _number_of_blocks--; // Update the successors' predecessor list and push new unreachable blocks. for (uint i = 0; i < dead->_num_succs; i++) { diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp index 0a4f231c49b36..62d7a2b3fff57 100644 --- a/src/hotspot/share/opto/c2_globals.hpp +++ b/src/hotspot/share/opto/c2_globals.hpp @@ -659,6 +659,9 @@ product(bool, TraceTypeProfile, false, DIAGNOSTIC, \ "Trace type profile") \ \ + develop(bool, TraceC2Optimizations, false, \ + "Trace selected C2 loop optimizations (counts only)") \ + \ develop(bool, PoisonOSREntry, true, \ "Detect abnormal calls to OSR code") \ \ diff --git a/src/hotspot/share/opto/callGenerator.cpp b/src/hotspot/share/opto/callGenerator.cpp index 483cb73110341..7613c2c0fd4ef 100644 --- a/src/hotspot/share/opto/callGenerator.cpp +++ b/src/hotspot/share/opto/callGenerator.cpp @@ -707,6 +707,7 @@ void CallGenerator::do_late_inline_helper() { C->env()->notice_inlined_method(inline_cg()->method()); } C->set_inlining_progress(true); + C->record_optimization_event(OptEvent_FunctionInlining); C->set_do_cleanup(kit.stopped()); // path is dead; needs cleanup kit.replace_call(call, result, true, do_asserts); } diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp index 0293f42d79123..617e3da47f4a1 100644 --- a/src/hotspot/share/opto/cfgnode.cpp +++ b/src/hotspot/share/opto/cfgnode.cpp @@ -30,6 +30,7 @@ #include "opto/addnode.hpp" #include "opto/castnode.hpp" #include "opto/cfgnode.hpp" +#include "opto/compile.hpp" #include "opto/connode.hpp" #include "opto/convertnode.hpp" #include "opto/loopnode.hpp" @@ -2157,10 +2158,11 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) { uin = unique_input(phase, true); } if (uin == top) { // Simplest case: no alive inputs. - if (can_reshape) // IGVN transformation + if (can_reshape) { // IGVN transformation return top; - else + } else { return nullptr; // Identity will return TOP + } } else if (uin != nullptr) { // Only one not-null unique input path is left. // Determine if this input is backedge of a loop. @@ -2279,8 +2281,9 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) { if( opt != nullptr ) { if( opt == unsafe_id || is_unsafe_data_reference(opt) ) { // Found dead loop. - if( can_reshape ) + if( can_reshape ) { return top; + } // We can't return top if we are in Parse phase - cut inputs only // to stop further optimizations for this phi. Identity will return TOP. assert(req() == 3, "only diamond merge phi here"); @@ -3135,4 +3138,3 @@ void BlackholeNode::format(PhaseRegAlloc* ra, outputStream* st) const { st->cr(); } #endif - diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 6babc13e1b315..598c56aa7c397 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -24,6 +24,7 @@ #include "asm/macroAssembler.hpp" #include "asm/macroAssembler.inline.hpp" +#include "ci/ciInstanceKlass.hpp" #include "ci/ciReplay.hpp" #include "classfile/javaClasses.hpp" #include "code/aotCodeCache.hpp" @@ -80,6 +81,7 @@ #include "opto/type.hpp" #include "opto/vector.hpp" #include "opto/vectornode.hpp" +#include "opto/c2_globals.hpp" #include "runtime/globals_extension.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/signature.hpp" @@ -90,6 +92,37 @@ #include "utilities/hashTable.hpp" #include "utilities/macros.hpp" +#ifndef PRODUCT +static const char* const optimization_event_names[OptEvent_Count] = { + "Loop Unrolling", + "Loop Peeling", + "Parallel Induction Variables", + "Split If", + "Loop Unswitching", + "Conditional Expression Elimination", + "Function Inlining", + "Deoptimization", + "Escape Analysis", + "Eliminate Locks", + "Locks Coarsening", + "Conditional Constant Propagation", + "Eliminate Autobox", + "Block Elimination", + "Null Check Elimination", + "Range Check Elimination", + "Optimize Ptr Compare", + "Merge Stores", + "Loop Predication", + "Auto Vectorization", + "Partial Peeling", + "Iterative GVN Iterations", + "Loop Iteration Split", + "Reassociate Invariants", + "Loop Intrinsification", + "Peephole" +}; +#endif + // -------------------- Compile::mach_constant_base_node ----------------------- // Constant table base node singleton. MachConstantBaseNode* Compile::mach_constant_base_node() { @@ -707,6 +740,10 @@ Compile::Compile(ciEnv* ci_env, ciMethod* target, int osr_bci, TraceTime t1("Total compilation time", &_t_totalCompilation, CITime, CITimeVerbose); TraceTime t2(nullptr, &_t_methodCompilation, CITime, false); +#ifndef PRODUCT + Copy::zero_to_bytes(_optimization_counters, sizeof(_optimization_counters)); +#endif + #if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY) bool print_opto_assembly = directive->PrintOptoAssemblyOption; // We can always print a disassembly, either abstract (hex dump) or @@ -891,6 +928,48 @@ Compile::Compile(ciEnv* ci_env, ciMethod* target, int osr_bci, // Now generate code Code_Gen(); +#ifndef PRODUCT + if (TraceC2Optimizations) { + if (method() == nullptr) { + // Skip C2 runtime stubs (notify_jvmti_vthread_mount_blob, …). + return; + } + bool printed_header = false; + stringStream ss; + for (int i = 0; i < OptEvent_Count; i++) { + int count = _optimization_counters[i]; + if (!printed_header) { + printed_header = true; + ResourceMark rm; + const char* holder_name = ""; + const char* method_name = ""; + const char* method_signature = ""; + int current_entry_bci = this->entry_bci(); + if (method() != nullptr) { + ciInstanceKlass* holder = method()->holder(); + if (holder != nullptr) { + holder_name = holder->name()->as_klass_external_name(); + } + method_name = method()->name()->as_utf8(); + method_signature = method()->signature()->as_symbol()->as_utf8(); + current_entry_bci = this->entry_bci(); + } else if (_stub_name != nullptr) { + method_name = _stub_name; + current_entry_bci = InvocationEntryBci; + } + const char* compilation_kind = is_osr_compilation() ? "OSR" : "non-OSR"; + ss.print_cr("OPTS_START"); + ss.print_cr("Opts|%s|%s|%s|%s|%d|%d", holder_name, method_name, method_signature, compilation_kind, current_entry_bci, _compile_id); + } + ss.print_cr("%s=%d", optimization_event_names[i], count); + } + if (printed_header) { + ss.print_cr("OPTS_END"); + ttyLocker ttyl; + tty->print_raw(ss.base()); + } + } +#endif } //------------------------------Compile---------------------------------------- @@ -964,6 +1043,10 @@ Compile::Compile(ciEnv* ci_env, _allowed_reasons(0) { C = this; +#ifndef PRODUCT + Copy::zero_to_bytes(_optimization_counters, sizeof(_optimization_counters)); +#endif + // try to reuse an existing stub { BlobId blob_id = StubInfo::blob(_stub_id); @@ -1010,12 +1093,68 @@ Compile::Compile(ciEnv* ci_env, NOT_PRODUCT( verify_graph_edges(); ) Code_Gen(); + +#ifndef PRODUCT + if (TraceC2Optimizations) { + if (method() == nullptr) { + // Skip C2 runtime stubs (notify_jvmti_vthread_mount_blob, …). + return; + } + bool printed_header = false; + stringStream ss; + for (int i = 0; i < OptEvent_Count; i++) { + int count = _optimization_counters[i]; + if (!printed_header) { + printed_header = true; + ResourceMark rm; + const char* holder_name = ""; + const char* method_name = ""; + const char* method_signature = ""; + int current_entry_bci = this->entry_bci(); + if (method() != nullptr) { + ciInstanceKlass* holder = method()->holder(); + if (holder != nullptr) { + holder_name = holder->name()->as_klass_external_name(); + } + method_name = method()->name()->as_utf8(); + method_signature = method()->signature()->as_symbol()->as_utf8(); + current_entry_bci = this->entry_bci(); + } else if (_stub_name != nullptr) { + method_name = _stub_name; + current_entry_bci = InvocationEntryBci; + } + const char* compilation_kind = is_osr_compilation() ? "OSR" : "non-OSR"; + ss.print_cr("OPTS_START"); + ss.print_cr("Opts|%s|%s|%s|%s|%d|%d", holder_name, method_name, method_signature, compilation_kind, current_entry_bci, _compile_id); + } + ss.print_cr("%s=%d", optimization_event_names[i], count); + } + if (printed_header) { + ss.print_cr("OPTS_END"); + ttyLocker ttyl; + tty->print_raw(ss.base()); + } + } +#endif + + // Insert printing here (see below) } Compile::~Compile() { delete _first_failure_details; }; + +#ifndef PRODUCT +void Compile::record_optimization_event(OptimizationEvent event) { + if (!TraceC2Optimizations) { + return; + } + assert((int)event >= 0 && (int)event < OptEvent_Count, "optimization event out of bounds"); + _optimization_counters[event]++; +} +#endif + //------------------------------Init------------------------------------------- // Prepare for a single compilation void Compile::Init(bool aliasing) { @@ -1926,15 +2065,20 @@ void Compile::process_for_merge_stores_igvn(PhaseIterGVN& igvn) { C->set_merge_stores_phase(); if (_for_merge_stores_igvn.length() > 0) { + bool performed_merge = false; while (_for_merge_stores_igvn.length() > 0) { Node* n = _for_merge_stores_igvn.pop(); n->remove_flag(Node::NodeFlags::Flag_for_merge_stores_igvn); igvn._worklist.push(n); + performed_merge = true; } igvn.optimize(); if (failing()) return; assert(_for_merge_stores_igvn.length() == 0, "no more delayed nodes allowed"); - print_method(PHASE_AFTER_MERGE_STORES, 3); + print_method(PHASE_AFTER_MERGE_STORES, 3); // INTERESTING + if (performed_merge) { + record_optimization_event(OptEvent_MergeStores); + } } } @@ -4835,6 +4979,7 @@ void Compile::add_coarsened_locks(GrowableArray& locks) { } } _coarsened_locks.append(locks_list); + record_optimization_event(OptEvent_LockCoarsening); } } diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index 845dcf0751277..dab60290341f5 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -110,6 +110,36 @@ enum LoopOptsMode { LoopOptsVerify }; +enum OptimizationEvent { + OptEvent_LoopUnrolling = 0, + OptEvent_LoopPeeling, + OptEvent_ParallelInductionVars, + OptEvent_SplitIf, + OptEvent_LoopUnswitching, + OptEvent_ConditionalExpressionElimination, + OptEvent_FunctionInlining, + OptEvent_Deoptimization, + OptEvent_EscapeAnalysis, + OptEvent_EliminateLocks, + OptEvent_LockCoarsening, + OptEvent_ConditionalConstantPropagation, + OptEvent_EliminateAutobox, + OptEvent_BlockElimination, + OptEvent_NullCheckElimination, + OptEvent_RangeCheckElimination, + OptEvent_OptimizePtrCompare, + OptEvent_MergeStores, + OptEvent_LoopPredication, + OptEvent_AutoVectorization, + OptEvent_PartialPeeling, + OptEvent_IterGVNIteration, + OptEvent_LoopIterationSplit, + OptEvent_ReassociateInvariants, + OptEvent_LoopIntrinsification, + OptEvent_Peephole, + OptEvent_Count +}; + // The type of all node counts and indexes. // It must hold at least 16 bits, but must also be fast to load and store. // This type, if less than 32 bits, could limit the number of possible nodes. @@ -389,6 +419,9 @@ class Compile : public Phase { GrowableArray _unstable_if_traps; // List of ifnodes after IGVN GrowableArray _coarsened_locks; // List of coarsened Lock and Unlock nodes ConnectionGraph* _congraph; +#ifndef PRODUCT + int _optimization_counters[OptEvent_Count]; +#endif #ifndef PRODUCT IdealGraphPrinter* _igv_printer; static IdealGraphPrinter* _debug_file_printer; @@ -888,6 +921,9 @@ class Compile : public Phase { _recent_alloc_ctl = ctl; _recent_alloc_obj = obj; } + + void record_optimization_event(OptimizationEvent event) PRODUCT_RETURN; + void record_dead_node(uint idx) { if (_dead_node_list.test_set(idx)) return; _dead_node_count++; } diff --git a/src/hotspot/share/opto/doCall.cpp b/src/hotspot/share/opto/doCall.cpp index 754b0fa8d1c14..d2ed3e14e906b 100644 --- a/src/hotspot/share/opto/doCall.cpp +++ b/src/hotspot/share/opto/doCall.cpp @@ -37,6 +37,7 @@ #include "opto/callGenerator.hpp" #include "opto/castnode.hpp" #include "opto/cfgnode.hpp" +#include "opto/compile.hpp" #include "opto/mulnode.hpp" #include "opto/parse.hpp" #include "opto/rootnode.hpp" @@ -704,6 +705,9 @@ void Parse::do_call() { if (cg->is_inline()) { // Accumulate has_loops estimate C->env()->notice_inlined_method(cg->method()); + if (!cg->is_late_inline()) { + C->record_optimization_event(OptEvent_FunctionInlining); + } } // Reset parser state from [new_]jvms, which now carries results of the call. diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 61aa009361fe2..49e2f591ff3b6 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -118,6 +118,7 @@ void ConnectionGraph::do_analysis(Compile *C, PhaseIterGVN *igvn) { if (congraph->compute_escape()) { // There are non escaping objects. C->set_congraph(congraph); + C->record_optimization_event(OptEvent_EscapeAnalysis); } // Cleanup. if (oop_null->outcnt() == 0) { @@ -3256,6 +3257,7 @@ void ConnectionGraph::optimize_ideal_graph(GrowableArray& ptr_cmp_worklis } } #endif + C->record_optimization_event(OptEvent_OptimizePtrCompare); igvn->replace_node(n, cmp); } } diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index 49c411843d5ae..0f688d9e2ea89 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -1309,6 +1309,7 @@ Node* GraphKit::null_check_common(Node* value, BasicType type, // If so, then the value is already null. if (t->higher_equal(TypePtr::NULL_PTR)) { NOT_PRODUCT(explicit_null_checks_elided++); + C->record_optimization_event(OptEvent_NullCheckElimination); return value; // Elided null assert quickly! } } else { @@ -1318,6 +1319,7 @@ Node* GraphKit::null_check_common(Node* value, BasicType type, if (t->meet(TypePtr::NULL_PTR) != t->remove_speculative()) { // same as: if (!TypePtr::NULL_PTR->higher_equal(t)) ... NOT_PRODUCT(explicit_null_checks_elided++); + C->record_optimization_event(OptEvent_NullCheckElimination); return value; // Elided null check quickly! } } @@ -2087,6 +2089,8 @@ Node* GraphKit::uncommon_trap(int trap_request, } if (stopped()) return nullptr; // trap reachable? + C->record_optimization_event(OptEvent_Deoptimization); + // Note: If ProfileTraps is true, and if a deopt. actually // occurs here, the runtime will make sure an MDO exists. There is // no need to call method()->ensure_method_data() at this point. diff --git a/src/hotspot/share/opto/ifnode.cpp b/src/hotspot/share/opto/ifnode.cpp index 83e975b95a26e..4227687817020 100644 --- a/src/hotspot/share/opto/ifnode.cpp +++ b/src/hotspot/share/opto/ifnode.cpp @@ -29,6 +29,7 @@ #include "opto/castnode.hpp" #include "opto/cfgnode.hpp" #include "opto/connode.hpp" +#include "opto/compile.hpp" #include "opto/loopnode.hpp" #include "opto/phaseX.hpp" #include "opto/predicates_enums.hpp" @@ -1794,7 +1795,8 @@ static int subsuming_bool_test_encode(Node* node) { Node* IfProjNode::Identity(PhaseGVN* phase) { // Can only optimize if cannot go the other way const TypeTuple *t = phase->type(in(0))->is_tuple(); - if (t == TypeTuple::IFNEITHER || (always_taken(t) && + bool taken = always_taken(t); + if (t == TypeTuple::IFNEITHER || (taken && // During parsing (GVN) we don't remove dead code aggressively. // Cut off dead branch and let PhaseRemoveUseless take care of it. (!phase->is_IterGVN() || @@ -1805,6 +1807,9 @@ Node* IfProjNode::Identity(PhaseGVN* phase) { // will cause this node to be reprocessed once the dead branch is killed. in(0)->outcnt() == 1))) { // IfNode control + if (taken) { + phase->C->record_optimization_event(OptEvent_ConditionalExpressionElimination); + } if (in(0)->is_BaseCountedLoopEnd()) { // CountedLoopEndNode may be eliminated by if subsuming, replace CountedLoopNode with LoopNode to // avoid mismatching between CountedLoopNode and CountedLoopEndNode in the following optimization. diff --git a/src/hotspot/share/opto/loopPredicate.cpp b/src/hotspot/share/opto/loopPredicate.cpp index 61a7ed29c3eb9..9486d157424ec 100644 --- a/src/hotspot/share/opto/loopPredicate.cpp +++ b/src/hotspot/share/opto/loopPredicate.cpp @@ -27,6 +27,7 @@ #include "opto/callnode.hpp" #include "opto/castnode.hpp" #include "opto/connode.hpp" +#include "opto/compile.hpp" #include "opto/convertnode.hpp" #include "opto/loopnode.hpp" #include "opto/matcher.hpp" @@ -1316,6 +1317,10 @@ bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree* loop) { head->verify_strip_mined(1); + if (hoisted) { + C->record_optimization_event(OptEvent_LoopPredication); + } + return hoisted; } diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index 9a21c7f5dda13..2e31fd7e29774 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -499,14 +499,25 @@ Node* IdealLoopTree::reassociate(Node* n1, PhaseIdealLoop *phase) { //---------------------reassociate_invariants----------------------------- // Reassociate invariant expressions: void IdealLoopTree::reassociate_invariants(PhaseIdealLoop *phase) { +#ifndef PRODUCT + bool changed = false; +#endif for (int i = _body.size() - 1; i >= 0; i--) { Node *n = _body.at(i); for (int j = 0; j < 5; j++) { Node* nn = reassociate(n, phase); if (nn == nullptr) break; +#ifndef PRODUCT + changed = true; +#endif n = nn; // again } } +#ifndef PRODUCT + if (changed) { + phase->C->record_optimization_event(OptEvent_ReassociateInvariants); + } +#endif } //------------------------------policy_peeling--------------------------------- @@ -777,6 +788,7 @@ void PhaseIdealLoop::peeled_dom_test_elim(IdealLoopTree* loop, Node_List& old_ne void PhaseIdealLoop::do_peeling(IdealLoopTree *loop, Node_List &old_new) { C->set_major_progress(); + C->record_optimization_event(OptEvent_LoopPeeling); // Peeling a 'main' loop in a pre/main/post situation obfuscates the // 'pre' loop from the main and the 'pre' can no longer have its // iterations adjusted. Therefore, we need to declare this loop as @@ -2186,6 +2198,7 @@ void PhaseIdealLoop::do_unroll(IdealLoopTree *loop, Node_List &old_new, bool adj } #endif + C->record_optimization_event(OptEvent_LoopUnrolling); C->print_method(PHASE_AFTER_LOOP_UNROLLING, 4, clone_head); } @@ -2629,6 +2642,7 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree* loop) { #endif assert(RangeCheckElimination, ""); + bool eliminated_range_check = false; CountedLoopNode *cl = loop->_head->as_CountedLoop(); // protect against stride not being a constant @@ -2802,6 +2816,7 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree* loop) { // sense of the test. C->print_method(PHASE_BEFORE_RANGE_CHECK_ELIMINATION, 4, iff); + eliminated_range_check = true; // Perform the limit computations in jlong to avoid overflow jlong lscale_con = scale_con; @@ -2981,6 +2996,9 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree* loop) { assert(is_dominator(new_limit_ctrl, get_ctrl(iffm->in(1)->in(1))), "control of cmp should be below control of updated input"); C->print_method(PHASE_AFTER_RANGE_CHECK_ELIMINATION, 4, cl); + if (eliminated_range_check) { + C->record_optimization_event(OptEvent_RangeCheckElimination); + } } // Adjust control for node and its inputs (and inputs of its inputs) to be above the pre end @@ -3485,7 +3503,11 @@ bool IdealLoopTree::iteration_split_impl(PhaseIdealLoop *phase, Node_List &old_n } else if (phase->duplicate_loop_backedge(this, old_new)) { return false; } else if (_head->is_LongCountedLoop()) { - phase->create_loop_nest(this, old_new); + if (phase->create_loop_nest(this, old_new)) { +#ifndef PRODUCT + phase->C->record_optimization_event(OptEvent_LoopIterationSplit); +#endif + } } return true; } @@ -3566,6 +3588,9 @@ bool IdealLoopTree::iteration_split_impl(PhaseIdealLoop *phase, Node_List &old_n if (should_rce || should_unroll) { if (cl->is_normal_loop()) { // Convert to 'pre/main/post' loops if (should_rce_long && phase->create_loop_nest(this, old_new)) { +#ifndef PRODUCT + phase->C->record_optimization_event(OptEvent_LoopIterationSplit); +#endif return true; } uint estimate = est_loop_clone_sz(3); @@ -3584,6 +3609,9 @@ bool IdealLoopTree::iteration_split_impl(PhaseIdealLoop *phase, Node_List &old_n } phase->insert_pre_post_loops(this, old_new, peel_only); +#ifndef PRODUCT + phase->C->record_optimization_event(OptEvent_LoopIterationSplit); +#endif } // Adjust the pre- and main-loop limits to let the pre and post loops run // with full checks, but the main-loop with no checks. Remove said checks @@ -3610,7 +3638,11 @@ bool IdealLoopTree::iteration_split_impl(PhaseIdealLoop *phase, Node_List &old_n } } if (should_rce_long) { - phase->create_loop_nest(this, old_new); + if (phase->create_loop_nest(this, old_new)) { +#ifndef PRODUCT + phase->C->record_optimization_event(OptEvent_LoopIterationSplit); +#endif + } } } return true; @@ -3665,6 +3697,11 @@ bool PhaseIdealLoop::do_intrinsify_fill() { IdealLoopTree* lpt = iter.current(); changed |= intrinsify_fill(lpt); } +#ifndef PRODUCT + if (changed) { + C->record_optimization_event(OptEvent_LoopIntrinsification); + } +#endif return changed; } diff --git a/src/hotspot/share/opto/loopUnswitch.cpp b/src/hotspot/share/opto/loopUnswitch.cpp index 287f8354dc1b9..121e9117bd465 100644 --- a/src/hotspot/share/opto/loopUnswitch.cpp +++ b/src/hotspot/share/opto/loopUnswitch.cpp @@ -405,6 +405,7 @@ void PhaseIdealLoop::do_unswitching(IdealLoopTree* loop, Node_List& old_new) { increment_unswitch_counts(original_head, new_head); NOT_PRODUCT(trace_loop_unswitching_result(unswitched_loop_selector, original_head, new_head);) + C->record_optimization_event(OptEvent_LoopUnswitching); C->print_method(PHASE_AFTER_LOOP_UNSWITCHING, 4, new_head); C->set_major_progress(); } @@ -689,4 +690,3 @@ void PhaseIdealLoop::increment_unswitch_counts(LoopNode* original_head, LoopNode original_head->set_unswitch_count(unswitch_count); new_head->set_unswitch_count(unswitch_count); } - diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index d04eb34aceea8..df76547a280d8 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -4441,6 +4441,7 @@ void PhaseIdealLoop::replace_parallel_iv(IdealLoopTree *loop) { set_ctrl(add, cl); _igvn.replace_node( phi2, add ); + C->record_optimization_event(OptEvent_ParallelInductionVars); // Sometimes an induction variable is unused if (add->outcnt() == 0) { _igvn.remove_dead_node(add); @@ -5291,6 +5292,9 @@ void PhaseIdealLoop::build_and_optimize() { for (LoopTreeIterator iter(_ltree_root); !iter.done(); iter.next()) { IdealLoopTree* lpt = iter.current(); AutoVectorizeStatus status = auto_vectorize(lpt, vshared); + if (status == AutoVectorizeStatus::Success) { + C->record_optimization_event(OptEvent_AutoVectorization); + } if (status == AutoVectorizeStatus::TriedAndFailed) { // We tried vectorization, but failed. From now on only unroll the loop. diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index 50b1ae0de8d3a..cdf345e73873f 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -1487,6 +1487,7 @@ void PhaseIdealLoop::split_if_with_blocks_post(Node *n) { tty->print_cr("Split-If"); } do_split_if(iff); + C->record_optimization_event(OptEvent_SplitIf); C->print_method(PHASE_AFTER_SPLIT_IF, 4, iff); return; } @@ -4182,6 +4183,7 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) { #endif C->print_method(PHASE_AFTER_PARTIAL_PEELING, 4, new_head_clone); + C->record_optimization_event(OptEvent_PartialPeeling); return true; } diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 90602bc2b35da..9c548bcbe89c6 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -1144,6 +1144,9 @@ bool PhaseMacroExpand::eliminate_allocate_node(AllocateNode *alloc) { } process_users_of_allocation(alloc); + if (boxing_alloc) { + C->record_optimization_event(OptEvent_EliminateAutobox); + } #ifndef PRODUCT if (PrintEliminateAllocations) { @@ -2187,6 +2190,7 @@ bool PhaseMacroExpand::eliminate_locking_node(AbstractLockNode *alock) { #endif alock->log_lock_optimization(C, "eliminate_lock"); + C->record_optimization_event(OptEvent_EliminateLocks); #ifndef PRODUCT if (PrintEliminateLocks) { @@ -2483,6 +2487,9 @@ void PhaseMacroExpand::eliminate_macro_nodes() { break; case Node::Class_CallStaticJava: success = eliminate_boxing_node(n->as_CallStaticJava()); + if (success) { + C->record_optimization_event(OptEvent_EliminateAutobox); + } break; case Node::Class_Lock: case Node::Class_Unlock: diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index b5b15275e219e..be6384757ebc1 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -1065,6 +1065,9 @@ void PhaseIterGVN::optimize() { remove_dead_node(n); } loop_count++; +#ifndef PRODUCT + C->record_optimization_event(OptEvent_IterGVNIteration); +#endif } NOT_PRODUCT(verify_PhaseIterGVN();) C->print_method(PHASE_AFTER_ITER_GVN, 3); @@ -3184,6 +3187,7 @@ Node *PhaseCCP::transform_once( Node *n ) { if( !n->is_Con() ) { if( t != Type::TOP ) { nn = makecon(t); // ConNode::make(t); + C->record_optimization_event(OptEvent_ConditionalConstantPropagation); NOT_PRODUCT( inc_constants(); ) } else if( n->is_Region() ) { // Unreachable region // Note: nn == C->top() @@ -3322,6 +3326,7 @@ void PhasePeephole::do_transform() { tty->print_cr("peephole number: %d", result); } inc_peepholes(); + C->record_optimization_event(OptEvent_Peephole); #endif // Set progress, start again progress = true;