diff options
Diffstat (limited to 'tools/tracefast-plugin')
| -rw-r--r-- | tools/tracefast-plugin/Android.bp | 108 | ||||
| -rw-r--r-- | tools/tracefast-plugin/tracefast.cc | 177 |
2 files changed, 285 insertions, 0 deletions
diff --git a/tools/tracefast-plugin/Android.bp b/tools/tracefast-plugin/Android.bp new file mode 100644 index 0000000000..1d7dd302c0 --- /dev/null +++ b/tools/tracefast-plugin/Android.bp @@ -0,0 +1,108 @@ +// +// Copyright (C) 2018 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Build variants {target,host} x {debug,ndebug} x {32,64} + +cc_defaults { + name: "tracefast-defaults", + host_supported: true, + srcs: ["tracefast.cc"], + defaults: ["art_defaults"], + + // Note that this tool needs to be built for both 32-bit and 64-bit since it requires + // to be same ISA as what it is attached to. + compile_multilib: "both", + + shared_libs: [ + "libbase", + ], + target: { + android: { + shared_libs: [ + "libcutils", + ], + }, + darwin: { + enabled: false, + }, + }, + header_libs: [ + "libnativehelper_header_only", + ], + multilib: { + lib32: { + suffix: "32", + }, + lib64: { + suffix: "64", + }, + }, + symlink_preferred_arch: true, +} + +cc_defaults { + name: "tracefast-interpreter-defaults", + defaults: ["tracefast-defaults"], + cflags: ["-DTRACEFAST_INTERPRETER=1"], +} + +cc_defaults { + name: "tracefast-trampoline-defaults", + defaults: ["tracefast-defaults"], + cflags: ["-DTRACEFAST_TRAMPOLINE=1"], +} + +art_cc_library { + name: "libtracefast-interpreter", + defaults: ["tracefast-interpreter-defaults"], + shared_libs: [ + "libart", + "libartbase", + ], +} + +art_cc_library { + name: "libtracefast-interpreterd", + defaults: [ + "art_debug_defaults", + "tracefast-interpreter-defaults", + ], + shared_libs: [ + "libartd", + "libartbased", + ], +} + +art_cc_library { + name: "libtracefast-trampoline", + defaults: ["tracefast-trampoline-defaults"], + shared_libs: [ + "libart", + "libartbase", + ], +} + +art_cc_library { + name: "libtracefast-trampolined", + defaults: [ + "art_debug_defaults", + "tracefast-trampoline-defaults", + ], + shared_libs: [ + "libartd", + "libartbased", + ], +} diff --git a/tools/tracefast-plugin/tracefast.cc b/tools/tracefast-plugin/tracefast.cc new file mode 100644 index 0000000000..ed6ac3d199 --- /dev/null +++ b/tools/tracefast-plugin/tracefast.cc @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "gc/scoped_gc_critical_section.h" +#include "instrumentation.h" +#include "runtime.h" +#include "runtime_callbacks.h" +#include "scoped_thread_state_change-inl.h" +#include "thread-inl.h" +#include "thread_list.h" + +namespace tracefast { + +#if ((!defined(TRACEFAST_INTERPRETER) && !defined(TRACEFAST_TRAMPOLINE)) || \ + (defined(TRACEFAST_INTERPRETER) && defined(TRACEFAST_TRAMPOLINE))) +#error Must set one of TRACEFAST_TRAMPOLINE or TRACEFAST_INTERPRETER during build +#endif + + +#ifdef TRACEFAST_INTERPRETER +static constexpr const char* kTracerInstrumentationKey = "tracefast_INTERPRETER"; +static constexpr bool kNeedsInterpreter = true; +#else // defined(TRACEFAST_TRAMPOLINE) +static constexpr const char* kTracerInstrumentationKey = "tracefast_TRAMPOLINE"; +static constexpr bool kNeedsInterpreter = false; +#endif // TRACEFAST_INITERPRETER + +class Tracer FINAL : public art::instrumentation::InstrumentationListener { + public: + Tracer() {} + + void MethodEntered(art::Thread* thread ATTRIBUTE_UNUSED, + art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED, + art::ArtMethod* method ATTRIBUTE_UNUSED, + uint32_t dex_pc ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { } + + void MethodExited(art::Thread* thread ATTRIBUTE_UNUSED, + art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED, + art::ArtMethod* method ATTRIBUTE_UNUSED, + uint32_t dex_pc ATTRIBUTE_UNUSED, + art::Handle<art::mirror::Object> return_value ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { } + + void MethodExited(art::Thread* thread ATTRIBUTE_UNUSED, + art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED, + art::ArtMethod* method ATTRIBUTE_UNUSED, + uint32_t dex_pc ATTRIBUTE_UNUSED, + const art::JValue& return_value ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { } + + void MethodUnwind(art::Thread* thread ATTRIBUTE_UNUSED, + art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED, + art::ArtMethod* method ATTRIBUTE_UNUSED, + uint32_t dex_pc ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { } + + void DexPcMoved(art::Thread* thread ATTRIBUTE_UNUSED, + art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED, + art::ArtMethod* method ATTRIBUTE_UNUSED, + uint32_t new_dex_pc ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { } + + void FieldRead(art::Thread* thread ATTRIBUTE_UNUSED, + art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED, + art::ArtMethod* method ATTRIBUTE_UNUSED, + uint32_t dex_pc ATTRIBUTE_UNUSED, + art::ArtField* field ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { } + + void FieldWritten(art::Thread* thread ATTRIBUTE_UNUSED, + art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED, + art::ArtMethod* method ATTRIBUTE_UNUSED, + uint32_t dex_pc ATTRIBUTE_UNUSED, + art::ArtField* field ATTRIBUTE_UNUSED, + art::Handle<art::mirror::Object> field_value ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { } + + void FieldWritten(art::Thread* thread ATTRIBUTE_UNUSED, + art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED, + art::ArtMethod* method ATTRIBUTE_UNUSED, + uint32_t dex_pc ATTRIBUTE_UNUSED, + art::ArtField* field ATTRIBUTE_UNUSED, + const art::JValue& field_value ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { } + + void ExceptionThrown(art::Thread* thread ATTRIBUTE_UNUSED, + art::Handle<art::mirror::Throwable> exception_object ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { } + + void ExceptionHandled(art::Thread* self ATTRIBUTE_UNUSED, + art::Handle<art::mirror::Throwable> throwable ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { } + + void Branch(art::Thread* thread ATTRIBUTE_UNUSED, + art::ArtMethod* method ATTRIBUTE_UNUSED, + uint32_t dex_pc ATTRIBUTE_UNUSED, + int32_t dex_pc_offset ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { } + + void InvokeVirtualOrInterface(art::Thread* thread ATTRIBUTE_UNUSED, + art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED, + art::ArtMethod* caller ATTRIBUTE_UNUSED, + uint32_t dex_pc ATTRIBUTE_UNUSED, + art::ArtMethod* callee ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { } + + void WatchedFramePop(art::Thread* thread ATTRIBUTE_UNUSED, + const art::ShadowFrame& frame ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { } + + private: + DISALLOW_COPY_AND_ASSIGN(Tracer); +}; + +Tracer gEmptyTracer; + +static void StartTracing() REQUIRES(!art::Locks::mutator_lock_, + !art::Locks::thread_list_lock_, + !art::Locks::thread_suspend_count_lock_) { + art::Thread* self = art::Thread::Current(); + art::Runtime* runtime = art::Runtime::Current(); + art::gc::ScopedGCCriticalSection gcs(self, + art::gc::kGcCauseInstrumentation, + art::gc::kCollectorTypeInstrumentation); + art::ScopedSuspendAll ssa("starting fast tracing"); + runtime->GetInstrumentation()->AddListener(&gEmptyTracer, + art::instrumentation::Instrumentation::kMethodEntered | + art::instrumentation::Instrumentation::kMethodExited | + art::instrumentation::Instrumentation::kMethodUnwind); + runtime->GetInstrumentation()->EnableMethodTracing(kTracerInstrumentationKey, kNeedsInterpreter); +} + +class TraceFastPhaseCB : public art::RuntimePhaseCallback { + public: + TraceFastPhaseCB() {} + + void NextRuntimePhase(art::RuntimePhaseCallback::RuntimePhase phase) + OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { + if (phase == art::RuntimePhaseCallback::RuntimePhase::kInit) { + art::ScopedThreadSuspension sts(art::Thread::Current(), + art::ThreadState::kWaitingForMethodTracingStart); + StartTracing(); + } + } +}; +TraceFastPhaseCB gPhaseCallback; + +// The plugin initialization function. +extern "C" bool ArtPlugin_Initialize() REQUIRES_SHARED(art::Locks::mutator_lock_) { + art::Runtime* runtime = art::Runtime::Current(); + art::ScopedThreadSuspension stsc(art::Thread::Current(), + art::ThreadState::kWaitingForMethodTracingStart); + art::ScopedSuspendAll ssa("Add phase callback"); + runtime->GetRuntimeCallbacks()->AddRuntimePhaseCallback(&gPhaseCallback); + return true; +} + +extern "C" bool ArtPlugin_Deinitialize() { + // Don't need to bother doing anything. + return true; +} + +} // namespace tracefast |