From 7ec2f1ca3cbd021848da75d5566f7239ce29676f Mon Sep 17 00:00:00 2001 From: Sebastien Hertz Date: Thu, 27 Mar 2014 20:06:47 +0100 Subject: Speed up single-stepping During single-stepping sequence, we need to deoptimize everything when we register a single-step event and undeoptimize everything when it is done. This causes a slow pattern where we continuously deoptimize-undeoptimize everything for each single-step. This CL introduces a special handling of single-step undeoptimization. We now delay the undeoptimization to the next resume (one thread or all threads) or the end of the debugging session. Indeed, a single-step event registration is always followed by a resume command. At the "resume" point, we know if a single-step event is registered and if we really need to undeoptimize. At the "registration" point, we know we did not undeoptimized everything so we don't need to deoptimize everything again. Therefore, in a sequence of single-steps, we only do a full deoptimization for the first single-step and a full undeoptimization for the last single-step. We update logs at deoptimization points so we can track more precisely. Note they are verbose logs that still must be enabled with -verbose:jdwp option. We also make some improvement inside instrumentation: * updates Instrumentation::ShouldNotifyMethodEnterExitEvents to comply with its name. * compute frame id only once when looking for the corresponding instrumentation frame. * compute the OatMethod once in ClassLinker::GetPortableOatCodeFor to avoid looking for it again. Bug: 13577964 Change-Id: If6fa198a676b515cd474b8c4d7bf7ef3626f2dc7 --- runtime/jdwp/jdwp_event.cc | 11 ++++++++++- runtime/jdwp/jdwp_handler.cc | 3 +++ runtime/jdwp/jdwp_main.cc | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-) (limited to 'runtime/jdwp') diff --git a/runtime/jdwp/jdwp_event.cc b/runtime/jdwp/jdwp_event.cc index 9b3ea2e..12370a4 100644 --- a/runtime/jdwp/jdwp_event.cc +++ b/runtime/jdwp/jdwp_event.cc @@ -248,7 +248,16 @@ void JdwpState::UnregisterEvent(JdwpEvent* pEvent) { Dbg::UnconfigureStep(pMod->step.threadId); } } - if (NeedsFullDeoptimization(pEvent->eventKind)) { + if (pEvent->eventKind == EK_SINGLE_STEP) { + // Special case for single-steps where we want to avoid the slow pattern deoptimize/undeoptimize + // loop between each single-step. In a IDE, this would happens each time the user click on the + // "single-step" button. Here we delay the full undeoptimization to the next resume + // (VM.Resume or ThreadReference.Resume) or the end of the debugging session (VM.Dispose or + // runtime shutdown). + // Therefore, in a singles-stepping sequence, only the first single-step will trigger a full + // deoptimization and only the last single-step will trigger a full undeoptimization. + Dbg::DelayFullUndeoptimization(); + } else if (NeedsFullDeoptimization(pEvent->eventKind)) { CHECK_EQ(req.kind, DeoptimizationRequest::kNothing); CHECK(req.method == nullptr); req.kind = DeoptimizationRequest::kFullUndeoptimization; diff --git a/runtime/jdwp/jdwp_handler.cc b/runtime/jdwp/jdwp_handler.cc index c2a2b54..3e8b697 100644 --- a/runtime/jdwp/jdwp_handler.cc +++ b/runtime/jdwp/jdwp_handler.cc @@ -291,6 +291,7 @@ static JdwpError VM_Suspend(JdwpState*, Request&, ExpandBuf*) */ static JdwpError VM_Resume(JdwpState*, Request&, ExpandBuf*) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + Dbg::ProcessDelayedFullUndeoptimizations(); Dbg::ResumeVM(); return ERR_NONE; } @@ -980,6 +981,8 @@ static JdwpError TR_Resume(JdwpState*, Request& request, ExpandBuf*) return ERR_NONE; } + Dbg::ProcessDelayedFullUndeoptimizations(); + Dbg::ResumeThread(thread_id); return ERR_NONE; } diff --git a/runtime/jdwp/jdwp_main.cc b/runtime/jdwp/jdwp_main.cc index 5fc0228..aeb4016 100644 --- a/runtime/jdwp/jdwp_main.cc +++ b/runtime/jdwp/jdwp_main.cc @@ -332,6 +332,8 @@ void JdwpState::ResetState() { CHECK(event_list_ == NULL); } + Dbg::ProcessDelayedFullUndeoptimizations(); + /* * Should not have one of these in progress. If the debugger went away * mid-request, though, we could see this. -- cgit v1.1