diff options
Diffstat (limited to 'runtime/trace.h')
| -rw-r--r-- | runtime/trace.h | 186 |
1 files changed, 153 insertions, 33 deletions
diff --git a/runtime/trace.h b/runtime/trace.h index ead1c29c72..69e6acc899 100644 --- a/runtime/trace.h +++ b/runtime/trace.h @@ -17,10 +17,13 @@ #ifndef ART_RUNTIME_TRACE_H_ #define ART_RUNTIME_TRACE_H_ +#include <bitset> +#include <map> #include <memory> #include <ostream> #include <set> #include <string> +#include <unordered_map> #include <vector> #include "atomic.h" @@ -32,38 +35,106 @@ namespace art { -namespace mirror { - class ArtField; - class ArtMethod; -} // namespace mirror - +class ArtField; +class ArtMethod; +class DexFile; class Thread; +using DexIndexBitSet = std::bitset<65536>; +using ThreadIDBitSet = std::bitset<65536>; + enum TracingMode { kTracingInactive, kMethodTracingActive, kSampleProfilingActive, }; +// File format: +// header +// record 0 +// record 1 +// ... +// +// Header format: +// u4 magic ('SLOW') +// u2 version +// u2 offset to data +// u8 start date/time in usec +// u2 record size in bytes (version >= 2 only) +// ... padding to 32 bytes +// +// Record format v1: +// u1 thread ID +// u4 method ID | method action +// u4 time delta since start, in usec +// +// Record format v2: +// u2 thread ID +// u4 method ID | method action +// u4 time delta since start, in usec +// +// Record format v3: +// u2 thread ID +// u4 method ID | method action +// u4 time delta since start, in usec +// u4 wall time since start, in usec (when clock == "dual" only) +// +// 32 bits of microseconds is 70 minutes. +// +// All values are stored in little-endian order. + +enum TraceAction { + kTraceMethodEnter = 0x00, // method entry + kTraceMethodExit = 0x01, // method exit + kTraceUnroll = 0x02, // method exited by exception unrolling + // 0x03 currently unused + kTraceMethodActionMask = 0x03, // two bits +}; + class Trace FINAL : public instrumentation::InstrumentationListener { public: enum TraceFlag { kTraceCountAllocs = 1, }; + enum class TraceOutputMode { + kFile, + kDDMS, + kStreaming + }; + + enum class TraceMode { + kMethodTracing, + kSampling + }; + + ~Trace(); + static void SetDefaultClockSource(TraceClockSource clock_source); - static void Start(const char* trace_filename, int trace_fd, int buffer_size, int flags, - bool direct_to_ddms, bool sampling_enabled, int interval_us) + static void Start(const char* trace_filename, int trace_fd, size_t buffer_size, int flags, + TraceOutputMode output_mode, TraceMode trace_mode, int interval_us) LOCKS_EXCLUDED(Locks::mutator_lock_, Locks::thread_list_lock_, Locks::thread_suspend_count_lock_, Locks::trace_lock_); + static void Pause() LOCKS_EXCLUDED(Locks::trace_lock_, Locks::thread_list_lock_); + static void Resume() LOCKS_EXCLUDED(Locks::trace_lock_); + + // Stop tracing. This will finish the trace and write it to file/send it via DDMS. static void Stop() LOCKS_EXCLUDED(Locks::mutator_lock_, Locks::thread_list_lock_, Locks::trace_lock_); - static void Shutdown() LOCKS_EXCLUDED(Locks::trace_lock_); + // Abort tracing. This will just stop tracing and *not* write/send the collected data. + static void Abort() + LOCKS_EXCLUDED(Locks::mutator_lock_, + Locks::thread_list_lock_, + Locks::trace_lock_); + static void Shutdown() + LOCKS_EXCLUDED(Locks::mutator_lock_, + Locks::thread_list_lock_, + Locks::trace_lock_); static TracingMode GetMethodTracingMode() LOCKS_EXCLUDED(Locks::trace_lock_); bool UseWallClock(); @@ -71,63 +142,94 @@ class Trace FINAL : public instrumentation::InstrumentationListener { void MeasureClockOverhead(); uint32_t GetClockOverheadNanoSeconds(); - void CompareAndUpdateStackTrace(Thread* thread, std::vector<mirror::ArtMethod*>* stack_trace) + void CompareAndUpdateStackTrace(Thread* thread, std::vector<ArtMethod*>* stack_trace) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // InstrumentationListener implementation. void MethodEntered(Thread* thread, mirror::Object* this_object, - mirror::ArtMethod* method, uint32_t dex_pc) + ArtMethod* method, uint32_t dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE; void MethodExited(Thread* thread, mirror::Object* this_object, - mirror::ArtMethod* method, uint32_t dex_pc, + ArtMethod* method, uint32_t dex_pc, const JValue& return_value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE; void MethodUnwind(Thread* thread, mirror::Object* this_object, - mirror::ArtMethod* method, uint32_t dex_pc) + ArtMethod* method, uint32_t dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE; void DexPcMoved(Thread* thread, mirror::Object* this_object, - mirror::ArtMethod* method, uint32_t new_dex_pc) + ArtMethod* method, uint32_t new_dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE; void FieldRead(Thread* thread, mirror::Object* this_object, - mirror::ArtMethod* method, uint32_t dex_pc, mirror::ArtField* field) + ArtMethod* method, uint32_t dex_pc, ArtField* field) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE; void FieldWritten(Thread* thread, mirror::Object* this_object, - mirror::ArtMethod* method, uint32_t dex_pc, mirror::ArtField* field, + ArtMethod* method, uint32_t dex_pc, ArtField* field, const JValue& field_value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE; - void ExceptionCaught(Thread* thread, const ThrowLocation& throw_location, - mirror::ArtMethod* catch_method, uint32_t catch_dex_pc, - mirror::Throwable* exception_object) + void ExceptionCaught(Thread* thread, mirror::Throwable* exception_object) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE; + void BackwardBranch(Thread* thread, ArtMethod* method, int32_t dex_pc_offset) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE; - // Reuse an old stack trace if it exists, otherwise allocate a new one. - static std::vector<mirror::ArtMethod*>* AllocStackTrace(); + static std::vector<ArtMethod*>* AllocStackTrace(); // Clear and store an old stack trace for later use. - static void FreeStackTrace(std::vector<mirror::ArtMethod*>* stack_trace); + static void FreeStackTrace(std::vector<ArtMethod*>* stack_trace); // Save id and name of a thread before it exits. static void StoreExitingThreadInfo(Thread* thread); + static TraceOutputMode GetOutputMode() LOCKS_EXCLUDED(Locks::trace_lock_); + static TraceMode GetMode() LOCKS_EXCLUDED(Locks::trace_lock_); + static size_t GetBufferSize() LOCKS_EXCLUDED(Locks::trace_lock_); + private: - explicit Trace(File* trace_file, int buffer_size, int flags, bool sampling_enabled); + Trace(File* trace_file, const char* trace_name, size_t buffer_size, int flags, + TraceOutputMode output_mode, TraceMode trace_mode); // The sampling interval in microseconds is passed as an argument. static void* RunSamplingThread(void* arg) LOCKS_EXCLUDED(Locks::trace_lock_); + static void StopTracing(bool finish_tracing, bool flush_file) + LOCKS_EXCLUDED(Locks::mutator_lock_, + Locks::thread_list_lock_, + Locks::trace_lock_); void FinishTracing() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void ReadClocks(Thread* thread, uint32_t* thread_clock_diff, uint32_t* wall_clock_diff); - void LogMethodTraceEvent(Thread* thread, mirror::ArtMethod* method, + void LogMethodTraceEvent(Thread* thread, ArtMethod* method, instrumentation::Instrumentation::InstrumentationEvent event, - uint32_t thread_clock_diff, uint32_t wall_clock_diff); + uint32_t thread_clock_diff, uint32_t wall_clock_diff) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Methods to output traced methods and threads. - void GetVisitedMethods(size_t end_offset, std::set<mirror::ArtMethod*>* visited_methods); - void DumpMethodList(std::ostream& os, const std::set<mirror::ArtMethod*>& visited_methods) + void GetVisitedMethods(size_t end_offset, std::set<ArtMethod*>* visited_methods); + void DumpMethodList(std::ostream& os, const std::set<ArtMethod*>& visited_methods) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void DumpThreadList(std::ostream& os) LOCKS_EXCLUDED(Locks::thread_list_lock_); - // Singleton instance of the Trace or NULL when no method tracing is active. + // Methods to register seen entitites in streaming mode. The methods return true if the entity + // is newly discovered. + bool RegisterMethod(ArtMethod* method) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) EXCLUSIVE_LOCKS_REQUIRED(streaming_lock_); + bool RegisterThread(Thread* thread) + EXCLUSIVE_LOCKS_REQUIRED(streaming_lock_); + + // Copy a temporary buffer to the main buffer. Used for streaming. Exposed here for lock + // annotation. + void WriteToBuf(const uint8_t* src, size_t src_size) + EXCLUSIVE_LOCKS_REQUIRED(streaming_lock_); + + uint32_t EncodeTraceMethod(ArtMethod* method) LOCKS_EXCLUDED(unique_methods_lock_); + uint32_t EncodeTraceMethodAndAction(ArtMethod* method, TraceAction action) + LOCKS_EXCLUDED(unique_methods_lock_); + ArtMethod* DecodeTraceMethod(uint32_t tmid) LOCKS_EXCLUDED(unique_methods_lock_); + std::string GetMethodLine(ArtMethod* method) LOCKS_EXCLUDED(unique_methods_lock_) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + void DumpBuf(uint8_t* buf, size_t buf_size, TraceClockSource clock_source) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + // Singleton instance of the Trace or null when no method tracing is active. static Trace* volatile the_trace_ GUARDED_BY(Locks::trace_lock_); // The default profiler clock source. @@ -137,24 +239,27 @@ class Trace FINAL : public instrumentation::InstrumentationListener { static pthread_t sampling_pthread_; // Used to remember an unused stack trace to avoid re-allocation during sampling. - static std::unique_ptr<std::vector<mirror::ArtMethod*>> temp_stack_trace_; + static std::unique_ptr<std::vector<ArtMethod*>> temp_stack_trace_; - // File to write trace data out to, NULL if direct to ddms. + // File to write trace data out to, null if direct to ddms. std::unique_ptr<File> trace_file_; // Buffer to store trace data. - std::unique_ptr<uint8_t> buf_; + std::unique_ptr<uint8_t[]> buf_; // Flags enabling extra tracing of things such as alloc counts. const int flags_; - // True if traceview should sample instead of instrumenting method entry/exit. - const bool sampling_enabled_; + // The kind of output for this tracing. + const TraceOutputMode trace_output_mode_; + + // The tracing method. + const TraceMode trace_mode_; const TraceClockSource clock_source_; // Size of buf_. - const int buffer_size_; + const size_t buffer_size_; // Time trace was created. const uint64_t start_time_; @@ -171,6 +276,21 @@ class Trace FINAL : public instrumentation::InstrumentationListener { // Map of thread ids and names that have already exited. SafeMap<pid_t, std::string> exited_threads_; + // Sampling profiler sampling interval. + int interval_us_; + + // Streaming mode data. + std::string streaming_file_name_; + Mutex* streaming_lock_; + std::map<const DexFile*, DexIndexBitSet*> seen_methods_; + std::unique_ptr<ThreadIDBitSet> seen_threads_; + + // Bijective map from ArtMethod* to index. + // Map from ArtMethod* to index in unique_methods_; + Mutex* unique_methods_lock_ ACQUIRED_AFTER(streaming_lock_); + std::unordered_map<ArtMethod*, uint32_t> art_method_id_map_ GUARDED_BY(unique_methods_lock_); + std::vector<ArtMethod*> unique_methods_ GUARDED_BY(unique_methods_lock_); + DISALLOW_COPY_AND_ASSIGN(Trace); }; |