summaryrefslogtreecommitdiff
path: root/runtime/trace.h
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/trace.h')
-rw-r--r--runtime/trace.h82
1 files changed, 71 insertions, 11 deletions
diff --git a/runtime/trace.h b/runtime/trace.h
index 86b8d00d515..b242d1596c4 100644
--- a/runtime/trace.h
+++ b/runtime/trace.h
@@ -33,6 +33,10 @@
#include "globals.h"
#include "instrumentation.h"
+namespace unix_file {
+class FdFile;
+} // namespace unix_file
+
namespace art {
class ArtField;
@@ -48,9 +52,10 @@ using ThreadIDBitSet = std::bitset<kMaxThreadIdNumber>;
enum TracingMode {
kTracingInactive,
- kMethodTracingActive,
- kSampleProfilingActive,
+ kMethodTracingActive, // Trace activity synchronous with method progress.
+ kSampleProfilingActive, // Trace activity captured by sampling thread.
};
+std::ostream& operator<<(std::ostream& os, const TracingMode& rhs);
// File format:
// header
@@ -94,6 +99,9 @@ enum TraceAction {
kTraceMethodActionMask = 0x03, // two bits
};
+// Class for recording event traces. Trace data is either collected
+// synchronously during execution (TracingMode::kMethodTracingActive),
+// or by a separate sampling thread (TracingMode::kSampleProfilingActive).
class Trace FINAL : public instrumentation::InstrumentationListener {
public:
enum TraceFlag {
@@ -115,10 +123,37 @@ class Trace FINAL : public instrumentation::InstrumentationListener {
static void SetDefaultClockSource(TraceClockSource clock_source);
- 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)
+ static void Start(const char* trace_filename,
+ size_t buffer_size,
+ int flags,
+ TraceOutputMode output_mode,
+ TraceMode trace_mode,
+ int interval_us)
+ REQUIRES(!Locks::mutator_lock_, !Locks::thread_list_lock_, !Locks::thread_suspend_count_lock_,
+ !Locks::trace_lock_);
+ static void Start(int trace_fd,
+ size_t buffer_size,
+ int flags,
+ TraceOutputMode output_mode,
+ TraceMode trace_mode,
+ int interval_us)
+ REQUIRES(!Locks::mutator_lock_, !Locks::thread_list_lock_, !Locks::thread_suspend_count_lock_,
+ !Locks::trace_lock_);
+ static void Start(std::unique_ptr<unix_file::FdFile>&& file,
+ size_t buffer_size,
+ int flags,
+ TraceOutputMode output_mode,
+ TraceMode trace_mode,
+ int interval_us)
+ REQUIRES(!Locks::mutator_lock_, !Locks::thread_list_lock_, !Locks::thread_suspend_count_lock_,
+ !Locks::trace_lock_);
+ static void StartDDMS(size_t buffer_size,
+ int flags,
+ TraceMode trace_mode,
+ int interval_us)
REQUIRES(!Locks::mutator_lock_, !Locks::thread_list_lock_, !Locks::thread_suspend_count_lock_,
!Locks::trace_lock_);
+
static void Pause() REQUIRES(!Locks::trace_lock_, !Locks::thread_list_lock_);
static void Resume() REQUIRES(!Locks::trace_lock_);
@@ -212,8 +247,11 @@ class Trace FINAL : public instrumentation::InstrumentationListener {
static bool IsTracingEnabled() REQUIRES(!Locks::trace_lock_);
private:
- Trace(File* trace_file, const char* trace_name, size_t buffer_size, int flags,
- TraceOutputMode output_mode, TraceMode trace_mode);
+ Trace(File* trace_file,
+ 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) REQUIRES(!Locks::trace_lock_);
@@ -282,7 +320,10 @@ class Trace FINAL : public instrumentation::InstrumentationListener {
// File to write trace data out to, null if direct to ddms.
std::unique_ptr<File> trace_file_;
- // Buffer to store trace data.
+ // Buffer to store trace data. In streaming mode, this is protected
+ // by the streaming_lock_. In non-streaming mode, reserved regions
+ // are atomically allocated (using cur_offset_) for log entries to
+ // be written.
std::unique_ptr<uint8_t[]> buf_;
// Flags enabling extra tracing of things such as alloc counts.
@@ -305,7 +346,27 @@ class Trace FINAL : public instrumentation::InstrumentationListener {
// Clock overhead.
const uint32_t clock_overhead_ns_;
- // Offset into buf_.
+ // Offset into buf_. The field is atomic to allow multiple writers
+ // to concurrently reserve space in the buffer. The newly written
+ // buffer contents are not read without some other form of thread
+ // synchronization, such as suspending all potential writers or
+ // acquiring *streaming_lock_. Reading cur_offset_ is thus never
+ // used to ensure visibility of any other objects, and all accesses
+ // are memory_order_relaxed.
+ //
+ // All accesses to buf_ in streaming mode occur whilst holding the
+ // streaming lock. In streaming mode, the buffer may be written out
+ // so cur_offset_ can move forwards and backwards.
+ //
+ // When not in streaming mode, the buf_ writes can come from
+ // multiple threads when the trace mode is kMethodTracing. When
+ // trace mode is kSampling, writes only come from the sampling
+ // thread.
+ //
+ // Reads to the buffer happen after the event sources writing to the
+ // buffer have been shutdown and all stores have completed. The
+ // stores are made visible in StopTracing() when execution leaves
+ // the ScopedSuspendAll block.
AtomicInteger cur_offset_;
// Did we overflow the buffer recording traces?
@@ -318,10 +379,9 @@ class Trace FINAL : public instrumentation::InstrumentationListener {
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_;
+ std::map<const DexFile*, DexIndexBitSet*> seen_methods_ GUARDED_BY(streaming_lock_);
+ std::unique_ptr<ThreadIDBitSet> seen_threads_ GUARDED_BY(streaming_lock_);
// Bijective map from ArtMethod* to index.
// Map from ArtMethod* to index in unique_methods_;