diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/cpp-define-generator/constant_lockword.def | 22 | ||||
| -rw-r--r-- | tools/dexanalyze/dexanalyze.cc | 13 | ||||
| -rw-r--r-- | tools/dexanalyze/dexanalyze_experiments.cc | 22 | ||||
| -rw-r--r-- | tools/dexanalyze/dexanalyze_experiments.h | 3 | ||||
| -rwxr-xr-x | tools/run-jdwp-tests.sh | 4 | ||||
| -rw-r--r-- | tools/tracefast-plugin/Android.bp | 108 | ||||
| -rw-r--r-- | tools/tracefast-plugin/tracefast.cc | 177 |
7 files changed, 333 insertions, 16 deletions
diff --git a/tools/cpp-define-generator/constant_lockword.def b/tools/cpp-define-generator/constant_lockword.def index 08d588505d..977d1ca12d 100644 --- a/tools/cpp-define-generator/constant_lockword.def +++ b/tools/cpp-define-generator/constant_lockword.def @@ -23,23 +23,29 @@ #define DEFINE_LOCK_WORD_EXPR(macro_name, type, constant_field_name) \ DEFINE_EXPR(LOCK_WORD_ ## macro_name, type, art::LockWord::constant_field_name) +// FIXME: The naming is inconsistent, the `Shifted` -> `_SHIFTED` suffix is sometimes missing. DEFINE_LOCK_WORD_EXPR(STATE_SHIFT, int32_t, kStateShift) -DEFINE_LOCK_WORD_EXPR(STATE_MASK, uint32_t, kStateMaskShifted) +DEFINE_LOCK_WORD_EXPR(STATE_MASK_SHIFTED, uint32_t, kStateMaskShifted) DEFINE_LOCK_WORD_EXPR(READ_BARRIER_STATE_SHIFT, int32_t, kReadBarrierStateShift) -DEFINE_LOCK_WORD_EXPR(READ_BARRIER_STATE_MASK, uint32_t, kReadBarrierStateMaskShifted) +DEFINE_LOCK_WORD_EXPR(READ_BARRIER_STATE_MASK, uint32_t, kReadBarrierStateMaskShifted) DEFINE_LOCK_WORD_EXPR(READ_BARRIER_STATE_MASK_TOGGLED, uint32_t, kReadBarrierStateMaskShiftedToggled) -DEFINE_LOCK_WORD_EXPR(THIN_LOCK_COUNT_ONE, int32_t, kThinLockCountOne) +DEFINE_LOCK_WORD_EXPR(THIN_LOCK_COUNT_SIZE, int32_t, kThinLockCountSize) +DEFINE_LOCK_WORD_EXPR(THIN_LOCK_COUNT_SHIFT, int32_t, kThinLockCountShift) +DEFINE_LOCK_WORD_EXPR(THIN_LOCK_COUNT_MASK_SHIFTED, uint32_t, kThinLockCountMaskShifted) +DEFINE_LOCK_WORD_EXPR(THIN_LOCK_COUNT_ONE, uint32_t, kThinLockCountOne) +DEFINE_LOCK_WORD_EXPR(THIN_LOCK_OWNER_MASK_SHIFTED, uint32_t, kThinLockOwnerMaskShifted) -DEFINE_LOCK_WORD_EXPR(STATE_FORWARDING_ADDRESS, uint32_t, kStateForwardingAddress) +DEFINE_LOCK_WORD_EXPR(STATE_FORWARDING_ADDRESS, uint32_t, kStateForwardingAddress) DEFINE_LOCK_WORD_EXPR(STATE_FORWARDING_ADDRESS_OVERFLOW, uint32_t, kStateForwardingAddressOverflow) DEFINE_LOCK_WORD_EXPR(STATE_FORWARDING_ADDRESS_SHIFT, uint32_t, kForwardingAddressShift) -DEFINE_LOCK_WORD_EXPR(GC_STATE_MASK_SHIFTED, uint32_t, kGCStateMaskShifted) +DEFINE_LOCK_WORD_EXPR(GC_STATE_MASK_SHIFTED, uint32_t, kGCStateMaskShifted) DEFINE_LOCK_WORD_EXPR(GC_STATE_MASK_SHIFTED_TOGGLED, uint32_t, kGCStateMaskShiftedToggled) -DEFINE_LOCK_WORD_EXPR(GC_STATE_SHIFT, int32_t, kGCStateShift) +DEFINE_LOCK_WORD_EXPR(GC_STATE_SIZE, int32_t, kGCStateSize) +DEFINE_LOCK_WORD_EXPR(GC_STATE_SHIFT, int32_t, kGCStateShift) -DEFINE_LOCK_WORD_EXPR(MARK_BIT_SHIFT, int32_t, kMarkBitStateShift) -DEFINE_LOCK_WORD_EXPR(MARK_BIT_MASK_SHIFTED, uint32_t, kMarkBitStateMaskShifted) +DEFINE_LOCK_WORD_EXPR(MARK_BIT_SHIFT, int32_t, kMarkBitStateShift) +DEFINE_LOCK_WORD_EXPR(MARK_BIT_MASK_SHIFTED, uint32_t, kMarkBitStateMaskShifted) #undef DEFINE_LOCK_WORD_EXPR diff --git a/tools/dexanalyze/dexanalyze.cc b/tools/dexanalyze/dexanalyze.cc index 58b1fc7ba3..46c48520e3 100644 --- a/tools/dexanalyze/dexanalyze.cc +++ b/tools/dexanalyze/dexanalyze.cc @@ -30,7 +30,10 @@ namespace art { class DexAnalyze { - static const int kExitCodeUsageError = 1; + static constexpr int kExitCodeUsageError = 1; + static constexpr int kExitCodeFailedToOpenFile = 2; + static constexpr int kExitCodeFailedToOpenDex = 3; + static constexpr int kExitCodeFailedToProcessDex = 4; static void StdoutLogger(android::base::LogId, android::base::LogSeverity, @@ -135,10 +138,10 @@ class DexAnalyze { Analysis cumulative(&options); for (const std::string& filename : options.filenames_) { std::string content; - // TODO: once added, use an api to android::base to read a std::vector<uint8_t>. + // TODO: once added, use an API to android::base to read a std::vector<uint8_t>. if (!android::base::ReadFileToString(filename.c_str(), &content)) { LOG(ERROR) << "ReadFileToString failed for " + filename << std::endl; - return 2; + return kExitCodeFailedToOpenFile; } std::vector<std::unique_ptr<const DexFile>> dex_files; const DexFileLoader dex_file_loader; @@ -150,14 +153,14 @@ class DexAnalyze { &error_msg, &dex_files)) { LOG(ERROR) << "OpenAll failed for " + filename << " with " << error_msg << std::endl; - return 3; + return kExitCodeFailedToOpenDex; } for (std::unique_ptr<const DexFile>& dex_file : dex_files) { if (options.dump_per_input_dex_) { Analysis current(&options); if (!current.ProcessDexFile(*dex_file)) { LOG(ERROR) << "Failed to process " << filename << " with error " << error_msg; - return 4; + return kExitCodeFailedToProcessDex; } LOG(INFO) << "Analysis for " << dex_file->GetLocation() << std::endl; current.Dump(LOG_STREAM(INFO)); diff --git a/tools/dexanalyze/dexanalyze_experiments.cc b/tools/dexanalyze/dexanalyze_experiments.cc index bfeb4b9d72..adc515472d 100644 --- a/tools/dexanalyze/dexanalyze_experiments.cc +++ b/tools/dexanalyze/dexanalyze_experiments.cc @@ -26,6 +26,7 @@ #include "dex/code_item_accessors-inl.h" #include "dex/dex_instruction-inl.h" #include "dex/standard_dex_file.h" +#include "dex/utf-inl.h" namespace art { @@ -48,8 +49,20 @@ void AnalyzeStrings::ProcessDexFile(const DexFile& dex_file) { std::vector<std::string> strings; for (size_t i = 0; i < dex_file.NumStringIds(); ++i) { uint32_t length = 0; - const char* data = - dex_file.GetStringDataAndUtf16Length(dex_file.GetStringId(dex::StringIndex(i)), &length); + const char* data = dex_file.StringDataAndUtf16LengthByIdx(dex::StringIndex(i), &length); + // Analyze if the string has any UTF16 chars. + bool have_wide_char = false; + const char* ptr = data; + for (size_t j = 0; j < length; ++j) { + have_wide_char = have_wide_char || GetUtf16FromUtf8(&ptr) >= 0x100; + } + if (have_wide_char) { + wide_string_bytes_ += 2 * length; + } else { + ascii_string_bytes_ += length; + } + string_data_bytes_ += ptr - data; + strings.push_back(data); } // Note that the strings are probably already sorted. @@ -88,6 +101,11 @@ void AnalyzeStrings::ProcessDexFile(const DexFile& dex_file) { } void AnalyzeStrings::Dump(std::ostream& os, uint64_t total_size) const { + os << "Total string data bytes " << Percent(string_data_bytes_, total_size) << "\n"; + os << "UTF-16 string data bytes " << Percent(wide_string_bytes_, total_size) << "\n"; + os << "ASCII string data bytes " << Percent(ascii_string_bytes_, total_size) << "\n"; + + // Prefix based strings. os << "Total shared prefix bytes " << Percent(total_prefix_savings_, total_size) << "\n"; os << "Prefix dictionary cost " << Percent(total_prefix_dict_, total_size) << "\n"; os << "Prefix table cost " << Percent(total_prefix_table_, total_size) << "\n"; diff --git a/tools/dexanalyze/dexanalyze_experiments.h b/tools/dexanalyze/dexanalyze_experiments.h index 6f70f5d166..0fb4d32005 100644 --- a/tools/dexanalyze/dexanalyze_experiments.h +++ b/tools/dexanalyze/dexanalyze_experiments.h @@ -41,6 +41,9 @@ class AnalyzeStrings : public Experiment { void Dump(std::ostream& os, uint64_t total_size) const; private: + int64_t wide_string_bytes_ = 0u; + int64_t ascii_string_bytes_ = 0u; + int64_t string_data_bytes_ = 0u; int64_t total_prefix_savings_ = 0u; int64_t total_prefix_dict_ = 0u; int64_t total_prefix_table_ = 0u; diff --git a/tools/run-jdwp-tests.sh b/tools/run-jdwp-tests.sh index d376cad9da..eebc09278a 100755 --- a/tools/run-jdwp-tests.sh +++ b/tools/run-jdwp-tests.sh @@ -360,7 +360,9 @@ echo "Killing stalled dalvikvm processes..." if [[ $mode == "host" ]]; then pkill -9 -f /bin/dalvikvm else - adb shell pkill -9 -f /bin/dalvikvm + # Tests may run on older Android versions where pkill requires "-l SIGNAL" + # rather than "-SIGNAL". + adb shell pkill -l 9 -f /bin/dalvikvm fi echo "Done." 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 |