Implement the new method trace format
Implement the new method trace format. The new method tracing format can
be requested by passing appropriate flags. This CL also adds a test for
this format. More details about the new format are here:
go/method-tracing-format-v2
Bug: 259258187
Test: art/test.py -t 2246
Change-Id: I6dbdab8126703bc5f4d1fb6a6004f69e1cd5fe25
diff --git a/runtime/trace.cc b/runtime/trace.cc
index 29f67f0..533293c 100644
--- a/runtime/trace.cc
+++ b/runtime/trace.cc
@@ -21,10 +21,10 @@
#include "android-base/macros.h"
#include "android-base/stringprintf.h"
-
#include "art_method-inl.h"
#include "base/casts.h"
#include "base/enums.h"
+#include "base/leb128.h"
#include "base/os.h"
#include "base/stl_util.h"
#include "base/systrace.h"
@@ -53,6 +53,13 @@
namespace art HIDDEN {
+struct MethodTraceRecord {
+ ArtMethod* method;
+ TraceAction action;
+ uint32_t wall_clock_time;
+ uint32_t thread_cpu_time;
+};
+
using android::base::StringPrintf;
static constexpr size_t TraceActionBits = MinimumBitsToStore(
@@ -70,6 +77,22 @@
static const uint16_t kTraceRecordSizeDualClock = 14; // using v3 with two timestamps
static const size_t kNumTracePoolBuffers = 32;
+// Packet type encoding for the new method tracing format.
+static const int kThreadInfoHeaderV2 = 0;
+static const int kMethodInfoHeaderV2 = 1;
+static const int kEntryHeaderV2 = 2;
+static const int kSummaryHeaderV2 = 3;
+
+// Packet sizes for the new method trace format.
+static const uint16_t kTraceHeaderLengthV2 = 32;
+static const uint16_t kTraceRecordSizeSingleClockV2 = 6;
+static const uint16_t kTraceRecordSizeDualClockV2 = kTraceRecordSizeSingleClockV2 + 2;
+static const uint16_t kEntryHeaderSizeSingleClockV2 = 17;
+static const uint16_t kEntryHeaderSizeDualClockV2 = kEntryHeaderSizeSingleClockV2 + 4;
+
+static const uint16_t kTraceVersionSingleClockV2 = 4;
+static const uint16_t kTraceVersionDualClockV2 = 5;
+
TraceClockSource Trace::default_clock_source_ = kDefaultTraceClockSource;
Trace* volatile Trace::the_trace_ = nullptr;
@@ -310,14 +333,24 @@
#endif
}
-static uint16_t GetTraceVersion(TraceClockSource clock_source) {
- return (clock_source == TraceClockSource::kDual) ? kTraceVersionDualClock
- : kTraceVersionSingleClock;
+static uint16_t GetTraceVersion(TraceClockSource clock_source, int version) {
+ if (version == Trace::kFormatV1) {
+ return (clock_source == TraceClockSource::kDual) ? kTraceVersionDualClock :
+ kTraceVersionSingleClock;
+ } else {
+ return (clock_source == TraceClockSource::kDual) ? kTraceVersionDualClockV2 :
+ kTraceVersionSingleClockV2;
+ }
}
-static uint16_t GetRecordSize(TraceClockSource clock_source) {
- return (clock_source == TraceClockSource::kDual) ? kTraceRecordSizeDualClock
- : kTraceRecordSizeSingleClock;
+static uint16_t GetRecordSize(TraceClockSource clock_source, int version) {
+ if (version == Trace::kFormatV1) {
+ return (clock_source == TraceClockSource::kDual) ? kTraceRecordSizeDualClock :
+ kTraceRecordSizeSingleClock;
+ } else {
+ return (clock_source == TraceClockSource::kDual) ? kTraceRecordSizeDualClockV2 :
+ kTraceRecordSizeSingleClockV2;
+ }
}
static uint16_t GetNumEntries(TraceClockSource clock_source) {
@@ -791,6 +824,11 @@
}
}
+int GetTraceFormatVersionFromFlags(int flags) {
+ int version = (flags & Trace::kTraceFormatVersionFlagMask) >> Trace::kTraceFormatVersionShift;
+ return version;
+}
+
} // namespace
TraceWriter::TraceWriter(File* trace_file,
@@ -798,34 +836,46 @@
TraceClockSource clock_source,
size_t buffer_size,
int num_trace_buffers,
+ int trace_format_version,
uint32_t clock_overhead_ns)
: trace_file_(trace_file),
trace_output_mode_(output_mode),
clock_source_(clock_source),
buf_(new uint8_t[std::max(kMinBufSize, buffer_size)]()),
buffer_size_(std::max(kMinBufSize, buffer_size)),
+ trace_format_version_(trace_format_version),
start_time_(GetMicroTime(GetTimestamp())),
overflow_(false),
+ num_records_(0),
clock_overhead_ns_(clock_overhead_ns),
owner_tids_(num_trace_buffers),
tracing_lock_("tracing lock", LockLevel::kTracingStreamingLock) {
- uint16_t trace_version = GetTraceVersion(clock_source_);
+ uint16_t trace_version = GetTraceVersion(clock_source_, trace_format_version_);
if (output_mode == TraceOutputMode::kStreaming) {
trace_version |= 0xF0U;
}
- // Set up the beginning of the trace.
- memset(buf_.get(), 0, kTraceHeaderLength);
- Append4LE(buf_.get(), kTraceMagicValue);
- Append2LE(buf_.get() + 4, trace_version);
- Append2LE(buf_.get() + 6, kTraceHeaderLength);
- Append8LE(buf_.get() + 8, start_time_);
- if (trace_version >= kTraceVersionDualClock) {
- uint16_t record_size = GetRecordSize(clock_source_);
- Append2LE(buf_.get() + 16, record_size);
- }
- static_assert(18 <= kMinBufSize, "Minimum buffer size not large enough for trace header");
- cur_offset_ = kTraceHeaderLength;
+ // Set up the beginning of the trace.
+ if (trace_format_version_ == Trace::kFormatV1) {
+ memset(buf_.get(), 0, kTraceHeaderLength);
+ Append4LE(buf_.get(), kTraceMagicValue);
+ Append2LE(buf_.get() + 4, trace_version);
+ Append2LE(buf_.get() + 6, kTraceHeaderLength);
+ Append8LE(buf_.get() + 8, start_time_);
+ if (trace_version >= kTraceVersionDualClock) {
+ uint16_t record_size = GetRecordSize(clock_source_, trace_format_version_);
+ Append2LE(buf_.get() + 16, record_size);
+ }
+ static_assert(18 <= kMinBufSize, "Minimum buffer size not large enough for trace header");
+
+ cur_offset_ = kTraceHeaderLength;
+ } else {
+ memset(buf_.get(), 0, kTraceHeaderLengthV2);
+ Append4LE(buf_.get(), kTraceMagicValue);
+ Append2LE(buf_.get() + 4, trace_version);
+ Append8LE(buf_.get() + 6, start_time_);
+ cur_offset_ = kTraceHeaderLengthV2;
+ }
if (output_mode == TraceOutputMode::kStreaming) {
// Flush the header information to the file. We use a per thread buffer, so
@@ -863,6 +913,7 @@
stop_tracing_(false) {
CHECK_IMPLIES(trace_file == nullptr, output_mode == TraceOutputMode::kDDMS);
+ int trace_format_version = GetTraceFormatVersionFromFlags(flags_);
// In streaming mode, we only need a buffer big enough to store data per each
// thread buffer. In non-streaming mode this is specified by the user and we
// stop tracing when the buffer is full.
@@ -874,6 +925,7 @@
clock_source_,
buf_size,
kNumTracePoolBuffers,
+ trace_format_version,
GetClockOverheadNanoSeconds()));
}
@@ -903,7 +955,7 @@
std::ostringstream os;
os << StringPrintf("%cversion\n", kTraceTokenChar);
- os << StringPrintf("%d\n", GetTraceVersion(clock_source_));
+ os << StringPrintf("%d\n", GetTraceVersion(clock_source_, trace_format_version_));
os << StringPrintf("data-file-overflow=%s\n", overflow_ ? "true" : "false");
if (UseThreadCpuClock(clock_source_)) {
if (UseWallClock(clock_source_)) {
@@ -916,8 +968,7 @@
}
os << StringPrintf("elapsed-time-usec=%" PRIu64 "\n", elapsed);
if (trace_output_mode_ != TraceOutputMode::kStreaming) {
- size_t num_records = (final_offset - kTraceHeaderLength) / GetRecordSize(clock_source_);
- os << StringPrintf("num-method-calls=%zd\n", num_records);
+ os << StringPrintf("num-method-calls=%zd\n", num_records_);
}
os << StringPrintf("clock-call-overhead-nsec=%d\n", clock_overhead_ns_);
os << StringPrintf("vm=art\n");
@@ -927,10 +978,13 @@
os << "alloc-size=" << Runtime::Current()->GetStat(KIND_ALLOCATED_BYTES) << "\n";
os << "gc-count=" << Runtime::Current()->GetStat(KIND_GC_INVOCATIONS) << "\n";
}
- os << StringPrintf("%cthreads\n", kTraceTokenChar);
- DumpThreadList(os);
- os << StringPrintf("%cmethods\n", kTraceTokenChar);
- DumpMethodList(os);
+
+ if (trace_format_version_ == Trace::kFormatV1) {
+ os << StringPrintf("%cthreads\n", kTraceTokenChar);
+ DumpThreadList(os);
+ os << StringPrintf("%cmethods\n", kTraceTokenChar);
+ DumpMethodList(os);
+ }
os << StringPrintf("%cend\n", kTraceTokenChar);
std::string header(os.str());
@@ -940,15 +994,27 @@
// cannot be any writes to trace_file_ after finish tracing.
// Write a special token to mark the end of trace records and the start of
// trace summary.
- uint8_t buf[7];
- Append2LE(buf, 0);
- buf[2] = kOpTraceSummary;
- Append4LE(buf + 3, static_cast<uint32_t>(header.length()));
- // Write the trace summary. The summary is identical to the file header when
- // the output mode is not streaming (except for methods).
- if (!trace_file_->WriteFully(buf, sizeof(buf)) ||
- !trace_file_->WriteFully(header.c_str(), header.length())) {
- PLOG(WARNING) << "Failed streaming a tracing event.";
+ if (trace_format_version_ == Trace::kFormatV1) {
+ uint8_t buf[7];
+ Append2LE(buf, 0);
+ buf[2] = kOpTraceSummary;
+ Append4LE(buf + 3, static_cast<uint32_t>(header.length()));
+ // Write the trace summary. The summary is identical to the file header when
+ // the output mode is not streaming (except for methods).
+ if (!trace_file_->WriteFully(buf, sizeof(buf)) ||
+ !trace_file_->WriteFully(header.c_str(), header.length())) {
+ PLOG(WARNING) << "Failed streaming a tracing event.";
+ }
+ } else {
+ uint8_t buf[3];
+ buf[0] = kSummaryHeaderV2;
+ Append2LE(buf + 1, static_cast<uint32_t>(header.length()));
+ // Write the trace summary. Reports information about tracing mode, number of records and
+ // clock overhead in plain text format.
+ if (!trace_file_->WriteFully(buf, sizeof(buf)) ||
+ !trace_file_->WriteFully(header.c_str(), header.length())) {
+ PLOG(WARNING) << "Failed streaming a tracing event.";
+ }
}
} else {
if (trace_file_.get() == nullptr) {
@@ -1133,9 +1199,14 @@
static constexpr size_t kThreadNameHeaderSize = 7;
uint8_t header[kThreadNameHeaderSize];
- Append2LE(header, 0);
- header[2] = kOpNewThread;
- Append2LE(header + 3, GetThreadEncoding(thread->GetTid()));
+ if (trace_format_version_ == Trace::kFormatV1) {
+ Append2LE(header, 0);
+ header[2] = kOpNewThread;
+ Append2LE(header + 3, GetThreadEncoding(thread->GetTid()));
+ } else {
+ header[0] = kThreadInfoHeaderV2;
+ Append4LE(header + 1, thread->GetTid());
+ }
DCHECK(thread_name.length() < (1 << 16));
Append2LE(header + 5, static_cast<uint16_t>(thread_name.length()));
@@ -1172,20 +1243,34 @@
}
void TraceWriter::RecordMethodInfo(const std::string& method_info_line, uint32_t method_id) {
- std::string method_line(GetMethodLine(method_info_line, method_id));
// Write a special block with the name.
- static constexpr size_t kMethodNameHeaderSize = 5;
- uint8_t method_header[kMethodNameHeaderSize];
- DCHECK_LT(kMethodNameHeaderSize, kPerThreadBufSize);
- Append2LE(method_header, 0);
- method_header[2] = kOpNewMethod;
-
+ std::string method_line;
+ size_t header_size;
+ static constexpr size_t kMaxMethodNameHeaderSize = 7;
+ uint8_t method_header[kMaxMethodNameHeaderSize];
uint16_t method_line_length = static_cast<uint16_t>(method_line.length());
DCHECK(method_line.length() < (1 << 16));
- Append2LE(method_header + 3, method_line_length);
+ if (trace_format_version_ == Trace::kFormatV1) {
+ // Write a special block with the name.
+ static constexpr size_t kMethodNameHeaderSize = 5;
+ DCHECK_LT(kMethodNameHeaderSize, kPerThreadBufSize);
+ Append2LE(method_header, 0);
+ method_header[2] = kOpNewMethod;
+ method_line = GetMethodLine(method_info_line, method_id);
+ method_line_length = static_cast<uint16_t>(method_line.length());
+ Append2LE(method_header + 3, method_line_length);
+ header_size = kMethodNameHeaderSize;
+ } else {
+ method_line = method_info_line;
+ method_line_length = static_cast<uint16_t>(method_line.length());
+ method_header[0] = kMethodInfoHeaderV2;
+ Append4LE(method_header + 1, method_id);
+ Append2LE(method_header + 5, method_line_length);
+ header_size = 7;
+ }
const uint8_t* ptr = reinterpret_cast<const uint8_t*>(method_line.c_str());
- if (!trace_file_->WriteFully(method_header, kMethodNameHeaderSize) ||
+ if (!trace_file_->WriteFully(method_header, header_size) ||
!trace_file_->WriteFully(ptr, method_line_length)) {
PLOG(WARNING) << "Failed streaming a tracing event.";
}
@@ -1304,6 +1389,144 @@
return;
}
+void TraceWriter::ReadValuesFromRecord(uintptr_t* method_trace_entries,
+ size_t record_index,
+ MethodTraceRecord& record,
+ bool has_thread_cpu_clock,
+ bool has_wall_clock) {
+ uintptr_t method_and_action = method_trace_entries[record_index++];
+ record.method = reinterpret_cast<ArtMethod*>(method_and_action & kMaskTraceAction);
+ CHECK(record.method != nullptr);
+ record.action = DecodeTraceAction(method_and_action);
+
+ record.thread_cpu_time = 0;
+ record.wall_clock_time = 0;
+ if (has_thread_cpu_clock) {
+ record.thread_cpu_time = method_trace_entries[record_index++];
+ }
+ if (has_wall_clock) {
+ uint64_t timestamp = method_trace_entries[record_index++];
+ if (art::kRuntimePointerSize == PointerSize::k32) {
+ // On 32-bit architectures timestamp is stored as two 32-bit values.
+ uint64_t high_timestamp = method_trace_entries[record_index++];
+ timestamp = (high_timestamp << 32 | timestamp);
+ }
+ record.wall_clock_time = GetMicroTime(timestamp) - start_time_;
+ }
+}
+
+void TraceWriter::FlushEntriesFormatV1(
+ uintptr_t* method_trace_entries,
+ size_t tid,
+ const std::unordered_map<ArtMethod*, std::string>& method_infos,
+ size_t end_offset,
+ size_t* current_index,
+ uint8_t* buffer_ptr) {
+ uint16_t thread_id = GetThreadEncoding(tid);
+ bool has_thread_cpu_clock = UseThreadCpuClock(clock_source_);
+ bool has_wall_clock = UseWallClock(clock_source_);
+ size_t buffer_index = *current_index;
+ size_t num_entries = GetNumEntries(clock_source_);
+ const size_t record_size = GetRecordSize(clock_source_, trace_format_version_);
+
+ for (size_t entry_index = kPerThreadBufSize; entry_index != end_offset;) {
+ entry_index -= num_entries;
+
+ MethodTraceRecord record;
+ ReadValuesFromRecord(
+ method_trace_entries, entry_index, record, has_thread_cpu_clock, has_wall_clock);
+
+ auto [method_id, is_new_method] = GetMethodEncoding(record.method);
+ if (is_new_method && trace_output_mode_ == TraceOutputMode::kStreaming) {
+ RecordMethodInfo(method_infos.find(record.method)->second, method_id);
+ }
+
+ DCHECK_LT(buffer_index + record_size, buffer_size_);
+ EncodeEventEntry(buffer_ptr + buffer_index,
+ thread_id,
+ method_id,
+ record.action,
+ record.thread_cpu_time,
+ record.wall_clock_time);
+ buffer_index += record_size;
+ }
+ *current_index = buffer_index;
+}
+
+void TraceWriter::FlushEntriesFormatV2(
+ uintptr_t* method_trace_entries,
+ size_t tid,
+ const std::unordered_map<ArtMethod*, std::string>& method_infos,
+ size_t num_records,
+ size_t* current_index,
+ uint8_t* init_buffer_ptr) {
+ bool has_thread_cpu_clock = UseThreadCpuClock(clock_source_);
+ bool has_wall_clock = UseWallClock(clock_source_);
+ size_t num_entries = GetNumEntries(clock_source_);
+ uint32_t prev_wall_timestamp = 0;
+ uint32_t prev_thread_timestamp = 0;
+ int32_t init_method_action_encoding = 0;
+ bool is_first_entry = true;
+ uint8_t* current_buffer_ptr = init_buffer_ptr;
+ uint32_t header_size = (clock_source_ == TraceClockSource::kDual) ? kEntryHeaderSizeDualClockV2 :
+ kEntryHeaderSizeSingleClockV2;
+
+ size_t entry_index = kPerThreadBufSize;
+ for (size_t i = 0; i < num_records; i++) {
+ entry_index -= num_entries;
+
+ MethodTraceRecord record;
+ ReadValuesFromRecord(
+ method_trace_entries, entry_index, record, has_thread_cpu_clock, has_wall_clock);
+
+ // TODO(mythria): Explore the possibility of using method pointer instead of having an encoding.
+ // On 64-bit this means method ids would use 8 bytes but that is okay since we only encode the
+ // full method id in the header and then encode the diff against the method id in the header.
+ // The diff is usually expected to be small.
+ auto [method_id, is_new_method] = GetMethodEncoding(record.method);
+ if (is_new_method && trace_output_mode_ == TraceOutputMode::kStreaming) {
+ RecordMethodInfo(method_infos.find(record.method)->second, method_id);
+ }
+ DCHECK(method_id < (1 << (31 - TraceActionBits)));
+ uint32_t method_action_encoding = (method_id << TraceActionBits) | record.action;
+
+ if (is_first_entry) {
+ prev_wall_timestamp = record.wall_clock_time;
+ prev_thread_timestamp = record.thread_cpu_time;
+ init_method_action_encoding = method_action_encoding;
+ is_first_entry = false;
+
+ EncodeEventBlockHeader(init_buffer_ptr,
+ tid,
+ method_action_encoding,
+ prev_thread_timestamp,
+ prev_wall_timestamp,
+ num_records);
+ current_buffer_ptr += header_size;
+ } else {
+ current_buffer_ptr = EncodeSignedLeb128(current_buffer_ptr,
+ (method_action_encoding - init_method_action_encoding));
+
+ if (has_wall_clock) {
+ current_buffer_ptr =
+ EncodeUnsignedLeb128(current_buffer_ptr, (record.wall_clock_time - prev_wall_timestamp));
+ prev_wall_timestamp = record.wall_clock_time;
+ }
+
+ if (has_thread_cpu_clock) {
+ current_buffer_ptr =
+ EncodeUnsignedLeb128(current_buffer_ptr, (record.thread_cpu_time - prev_thread_timestamp));
+ prev_thread_timestamp = record.thread_cpu_time;
+ }
+ }
+ }
+
+ // Update the total size of the block excluding header size.
+ uint8_t* total_size_loc = init_buffer_ptr + header_size - 2;
+ Append2LE(total_size_loc, current_buffer_ptr - (init_buffer_ptr + header_size));
+ *current_index += current_buffer_ptr - init_buffer_ptr;
+}
+
void TraceWriter::FlushBuffer(uintptr_t* method_trace_entries,
size_t current_offset,
size_t tid,
@@ -1312,67 +1535,36 @@
// method id for each method. We do that by maintaining a map from id to method for each newly
// seen method. tracing_lock_ is required to serialize these.
MutexLock mu(Thread::Current(), tracing_lock_);
- size_t current_index;
+ size_t current_index = 0;
uint8_t* buffer_ptr = buf_.get();
size_t buffer_size = buffer_size_;
- if (trace_output_mode_ == TraceOutputMode::kStreaming) {
- // In streaming mode, we flush the data to file each time we flush the per-thread buffer.
- // Just reuse the entire buffer.
- current_index = 0;
- } else {
- // In non-streaming mode we only flush at the end, so retain the earlier data. If the buffer
- // is full we don't process any more entries.
- current_index = cur_offset_;
- }
- uint16_t thread_id = GetThreadEncoding(tid);
- bool has_thread_cpu_clock = UseThreadCpuClock(clock_source_);
- bool has_wall_clock = UseWallClock(clock_source_);
- const size_t record_size = GetRecordSize(clock_source_);
- DCHECK_LT(record_size, kPerThreadBufSize);
size_t num_entries = GetNumEntries(clock_source_);
size_t num_records = (kPerThreadBufSize - current_offset) / num_entries;
DCHECK_EQ((kPerThreadBufSize - current_offset) % num_entries, 0u);
+ const size_t record_size = GetRecordSize(clock_source_, trace_format_version_);
+ DCHECK_LT(record_size, kPerThreadBufSize);
- // Check if there is sufficient place in the buffer for non-streaming case. If not return early.
- if (cur_offset_ + record_size * num_records >= buffer_size &&
- trace_output_mode_ != TraceOutputMode::kStreaming) {
- overflow_ = true;
- return;
+ if (trace_output_mode_ != TraceOutputMode::kStreaming) {
+ // In non-streaming mode we only flush to file at the end, so retain the earlier data. If the
+ // buffer is full we don't process any more entries.
+ current_index = cur_offset_;
+
+ // Check if there is sufficient place in the buffer for non-streaming case. If not return early.
+ if (cur_offset_ + record_size * num_records >= buffer_size) {
+ overflow_ = true;
+ return;
+ }
}
+ num_records_ += num_records;
DCHECK_GT(buffer_size_, record_size * num_entries);
- for (size_t entry_index = kPerThreadBufSize; entry_index != current_offset;) {
- entry_index -= num_entries;
- size_t record_index = entry_index;
- uintptr_t method_and_action = method_trace_entries[record_index++];
- ArtMethod* method = reinterpret_cast<ArtMethod*>(method_and_action & kMaskTraceAction);
- CHECK(method != nullptr);
- TraceAction action = DecodeTraceAction(method_and_action);
- uint32_t thread_time = 0;
- uint32_t wall_time = 0;
- if (has_thread_cpu_clock) {
- thread_time = method_trace_entries[record_index++];
- }
- if (has_wall_clock) {
- uint64_t timestamp = method_trace_entries[record_index++];
- if (art::kRuntimePointerSize == PointerSize::k32) {
- // On 32-bit architectures timestamp is stored as two 32-bit values.
- uint64_t high_timestamp = method_trace_entries[record_index++];
- timestamp = (high_timestamp << 32 | timestamp);
- }
- wall_time = GetMicroTime(timestamp) - start_time_;
- }
-
- auto [method_id, is_new_method] = GetMethodEncoding(method);
- if (is_new_method && trace_output_mode_ == TraceOutputMode::kStreaming) {
- RecordMethodInfo(method_infos.find(method)->second, method_id);
- }
-
- DCHECK_LT(current_index + record_size, buffer_size);
- EncodeEventEntry(
- buffer_ptr + current_index, thread_id, method_id, action, thread_time, wall_time);
- current_index += record_size;
+ if (trace_format_version_ == Trace::kFormatV1) {
+ FlushEntriesFormatV1(
+ method_trace_entries, tid, method_infos, current_offset, ¤t_index, buffer_ptr);
+ } else {
+ FlushEntriesFormatV2(
+ method_trace_entries, tid, method_infos, num_records, ¤t_index, buffer_ptr);
}
if (trace_output_mode_ == TraceOutputMode::kStreaming) {
@@ -1469,6 +1661,30 @@
static_assert(kPacketSize == 2 + 4 + 4 + 4, "Packet size incorrect.");
}
+void TraceWriter::EncodeEventBlockHeader(uint8_t* ptr,
+ uint32_t thread_id,
+ uint32_t init_method_index,
+ uint32_t init_thread_clock,
+ uint32_t init_wall_clock,
+ uint16_t num_records) {
+ ptr[0] = kEntryHeaderV2;
+ Append4LE(ptr + 1, thread_id);
+ Append4LE(ptr + 5, init_method_index);
+ ptr += 9;
+
+ if (UseThreadCpuClock(clock_source_)) {
+ Append4LE(ptr, init_thread_clock);
+ ptr += 4;
+ }
+ if (UseWallClock(clock_source_)) {
+ Append4LE(ptr, init_wall_clock);
+ ptr += 4;
+ }
+ // This specifies the total number of records encoded in the block using lebs. We encode the first
+ // entry in the header, so the block contains one less than num_records.
+ Append2LE(ptr, num_records - 1);
+}
+
void TraceWriter::EnsureSpace(uint8_t* buffer,
size_t* current_index,
size_t buffer_size,
diff --git a/runtime/trace.h b/runtime/trace.h
index b6f047e..227955f 100644
--- a/runtime/trace.h
+++ b/runtime/trace.h
@@ -48,6 +48,8 @@
class ShadowFrame;
class Thread;
+struct MethodTraceRecord;
+
using DexIndexBitSet = std::bitset<65536>;
enum TracingMode {
@@ -146,6 +148,7 @@
TraceClockSource clock_source,
size_t buffer_size,
int num_trace_buffers,
+ int trace_format_version,
uint32_t clock_overhead_ns);
// This encodes all the events in the per-thread trace buffer and writes it to the trace file /
@@ -210,6 +213,25 @@
int GetMethodTraceIndex(uintptr_t* current_buffer);
private:
+ void ReadValuesFromRecord(uintptr_t* method_trace_entries,
+ size_t record_index,
+ MethodTraceRecord& record,
+ bool has_thread_cpu_clock,
+ bool has_wall_clock);
+
+ void FlushEntriesFormatV2(uintptr_t* method_trace_entries,
+ size_t tid,
+ const std::unordered_map<ArtMethod*, std::string>& method_infos,
+ size_t num_records,
+ size_t* current_index,
+ uint8_t* init_buffer_ptr) REQUIRES(tracing_lock_);
+
+ void FlushEntriesFormatV1(uintptr_t* method_trace_entries,
+ size_t tid,
+ const std::unordered_map<ArtMethod*, std::string>& method_infos,
+ size_t end_offset,
+ size_t* current_index,
+ uint8_t* buffer_ptr) REQUIRES(tracing_lock_);
// Get a 32-bit id for the method and specify if the method hasn't been seen before. If this is
// the first time we see this method record information (like method name, declaring class etc.,)
// about the method.
@@ -237,6 +259,15 @@
uint32_t thread_clock_diff,
uint32_t wall_clock_diff) REQUIRES(tracing_lock_);
+ // Encodes the header for the events block. This assumes that there is enough space reserved to
+ // encode the entry.
+ void EncodeEventBlockHeader(uint8_t* ptr,
+ uint32_t thread_id,
+ uint32_t method_index,
+ uint32_t init_thread_clock_time,
+ uint32_t init_wall_clock_time,
+ uint16_t num_records) REQUIRES(tracing_lock_);
+
// Ensures there is sufficient space in the buffer to record the requested_size. If there is not
// enough sufficient space the current contents of the buffer are written to the file and
// current_index is reset to 0. This doesn't check if buffer_size is big enough to hold the
@@ -291,12 +322,18 @@
// Size of buf_.
const size_t buffer_size_;
+ // Version of trace output
+ const int trace_format_version_;
+
// Time trace was created.
const uint64_t start_time_;
// Did we overflow the buffer recording traces?
bool overflow_;
+ // Total number of records flushed to file.
+ size_t num_records_;
+
// Clock overhead.
const uint32_t clock_overhead_ns_;
@@ -322,6 +359,11 @@
kTraceClockSourceThreadCpu = 0x100,
};
+ static const int kFormatV1 = 0;
+ static const int kFormatV2 = 1;
+ static const int kTraceFormatVersionFlagMask = 0b110;
+ static const int kTraceFormatVersionShift = 1;
+
enum class TraceMode {
kMethodTracing,
kSampling
diff --git a/test/2246-trace-v2/Android.bp b/test/2246-trace-v2/Android.bp
new file mode 100644
index 0000000..6655926
--- /dev/null
+++ b/test/2246-trace-v2/Android.bp
@@ -0,0 +1,40 @@
+// Generated by `regen-test-files`. Do not edit manually.
+
+// Build rules for ART run-test `2246-trace-v2`.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "art_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["art_license"],
+}
+
+// Test's Dex code.
+java_test {
+ name: "art-run-test-2246-trace-v2",
+ defaults: ["art-run-test-defaults"],
+ test_config_template: ":art-run-test-target-no-test-suite-tag-template",
+ srcs: ["src/**/*.java"],
+ data: [
+ ":art-run-test-2246-trace-v2-expected-stdout",
+ ":art-run-test-2246-trace-v2-expected-stderr",
+ ],
+}
+
+// Test's expected standard output.
+genrule {
+ name: "art-run-test-2246-trace-v2-expected-stdout",
+ out: ["art-run-test-2246-trace-v2-expected-stdout.txt"],
+ srcs: ["expected-stdout.txt"],
+ cmd: "cp -f $(in) $(out)",
+}
+
+// Test's expected standard error.
+genrule {
+ name: "art-run-test-2246-trace-v2-expected-stderr",
+ out: ["art-run-test-2246-trace-v2-expected-stderr.txt"],
+ srcs: ["expected-stderr.txt"],
+ cmd: "cp -f $(in) $(out)",
+}
diff --git a/test/2246-trace-v2/dump_trace.cc b/test/2246-trace-v2/dump_trace.cc
new file mode 100644
index 0000000..6a09492
--- /dev/null
+++ b/test/2246-trace-v2/dump_trace.cc
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2024 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 <stdio.h>
+
+#include <map>
+#include <memory>
+
+#include "base/leb128.h"
+#include "base/os.h"
+#include "base/unix_file/fd_file.h"
+#include "jni.h"
+
+namespace art {
+namespace {
+
+static const int kMagicValue = 0x574f4c53;
+static const int kVersionDualClock = 0xf5;
+static const int kThreadInfo = 0;
+static const int kMethodInfo = 1;
+static const int kTraceEntries = 2;
+static const int kTraceActionBits = 2;
+static const int kSummary = 3;
+
+int ReadNumber(int num_bytes, uint8_t* header) {
+ int number = 0;
+ for (int i = 0; i < num_bytes; i++) {
+ number += header[i] << (i * 8);
+ }
+ return number;
+}
+
+bool ProcessThreadOrMethodInfo(std::unique_ptr<File>& file, std::map<int, std::string>& name_map) {
+ uint8_t header[6];
+ if (!file->ReadFully(&header, sizeof(header))) {
+ printf("Couldn't read header\n");
+ return false;
+ }
+ int id = ReadNumber(4, header);
+ int length = ReadNumber(2, header + 4);
+
+ char* name = new char[length];
+ if (!file->ReadFully(name, length)) {
+ delete[] name;
+ return false;
+ }
+ std::string str(name, length);
+ std::replace(str.begin(), str.end(), '\t', ' ');
+ name_map.emplace(id, str);
+ delete[] name;
+ return true;
+}
+
+void print_trace_entry(const std::string& thread_name,
+ const std::string& method_name,
+ int* current_depth,
+ int event_type) {
+ std::string entry;
+ for (int i = 0; i < *current_depth; i++) {
+ entry.push_back('.');
+ }
+ if (event_type == 0) {
+ *current_depth += 1;
+ entry.append(".>> ");
+ } else if (event_type == 1) {
+ *current_depth -= 1;
+ entry.append("<< ");
+ } else if (event_type == 2) {
+ *current_depth -= 1;
+ entry.append("<<E ");
+ } else {
+ entry.append("?? ");
+ }
+ entry.append(thread_name);
+ entry.append(" ");
+ entry.append(method_name);
+ printf("%s", entry.c_str());
+}
+
+bool ProcessTraceEntries(std::unique_ptr<File>& file,
+ std::map<int, int>& current_depth_map,
+ std::map<int, std::string>& thread_map,
+ std::map<int, std::string>& method_map,
+ bool is_dual_clock,
+ const char* thread_name_filter) {
+ uint8_t header[20];
+ int header_size = is_dual_clock ? 20 : 16;
+ if (!file->ReadFully(header, header_size)) {
+ return false;
+ }
+
+ uint32_t thread_id = ReadNumber(4, header);
+ uint32_t method_value = ReadNumber(4, header + 4);
+ int offset = 8;
+ if (is_dual_clock) {
+ // Read timestamp.
+ ReadNumber(4, header + offset);
+ offset += 4;
+ }
+ // Read timestamp.
+ ReadNumber(4, header + offset);
+ offset += 4;
+ int num_records = ReadNumber(2, header + offset);
+ offset += 2;
+ int total_size = ReadNumber(2, header + offset);
+ uint8_t* buffer = new uint8_t[total_size];
+ if (!file->ReadFully(buffer, total_size)) {
+ delete[] buffer;
+ return false;
+ }
+
+ const uint8_t* current_buffer_ptr = buffer;
+ int32_t method_id = method_value >> kTraceActionBits;
+ uint8_t event_type = method_value & 0x3;
+ int current_depth = 0;
+ if (current_depth_map.find(thread_id) != current_depth_map.end()) {
+ // Get the current call stack depth. If it is the first method we are seeing on this thread
+ // then this map wouldn't haven an entry we start with the depth of 0.
+ current_depth = current_depth_map[thread_id];
+ }
+ std::string thread_name = thread_map[thread_id];
+ bool print_thread_events = (thread_name.compare(thread_name_filter) == 0);
+ if (method_map.find(method_id) == method_map.end()) {
+ LOG(FATAL) << "No entry for init method " << method_id;
+ }
+ if (print_thread_events) {
+ print_trace_entry(thread_name, method_map[method_id], ¤t_depth, event_type);
+ }
+ for (int i = 0; i < num_records; i++) {
+ int32_t diff = 0;
+ bool success = DecodeSignedLeb128Checked(¤t_buffer_ptr, buffer + total_size - 1, &diff);
+ if (!success) {
+ LOG(FATAL) << "Reading past the buffer???";
+ }
+ int32_t curr_method_value = method_value + diff;
+ method_id = curr_method_value >> kTraceActionBits;
+ event_type = curr_method_value & 0x3;
+ if (print_thread_events) {
+ print_trace_entry(thread_name, method_map[method_id], ¤t_depth, event_type);
+ }
+ // Read timestamps
+ DecodeUnsignedLeb128(¤t_buffer_ptr);
+ if (is_dual_clock) {
+ DecodeUnsignedLeb128(¤t_buffer_ptr);
+ }
+ }
+ current_depth_map[thread_id] = current_depth;
+ return true;
+}
+
+extern "C" JNIEXPORT void JNICALL Java_Main_dumpTrace(JNIEnv* env,
+ jclass,
+ jstring fileName,
+ jstring threadName) {
+ const char* file_name = env->GetStringUTFChars(fileName, nullptr);
+ const char* thread_name = env->GetStringUTFChars(threadName, nullptr);
+ std::map<int, std::string> thread_map;
+ std::map<int, std::string> method_map;
+ std::map<int, int> current_depth_map;
+
+ std::unique_ptr<File> file(OS::OpenFileForReading(file_name));
+ if (file == nullptr) {
+ printf("Couldn't open file\n");
+ return;
+ }
+
+ uint8_t header[32];
+ const bool success = file->ReadFully(&header, sizeof(header));
+ if (!success) {
+ printf("Couldn't read header\n");
+ return;
+ }
+ int magic_value = ReadNumber(4, header);
+ if (magic_value != kMagicValue) {
+ printf("Incorrect magic value\n");
+ return;
+ }
+ int version = ReadNumber(2, header + 4);
+ if (success) {
+ printf("version=%0x\n", version);
+ }
+
+ bool is_dual_clock = (version == kVersionDualClock);
+ bool has_entries = true;
+ while (has_entries) {
+ uint8_t entry_header;
+ if (!file->ReadFully(&entry_header, sizeof(entry_header))) {
+ break;
+ }
+ switch (entry_header) {
+ case kThreadInfo:
+ if (!ProcessThreadOrMethodInfo(file, thread_map)) {
+ has_entries = false;
+ }
+ break;
+ case kMethodInfo:
+ if (!ProcessThreadOrMethodInfo(file, method_map)) {
+ has_entries = false;
+ }
+ break;
+ case kTraceEntries:
+ ProcessTraceEntries(
+ file, current_depth_map, thread_map, method_map, is_dual_clock, thread_name);
+ break;
+ case kSummary:
+ has_entries = false;
+ break;
+ default:
+ printf("Invalid Header %d\n", entry_header);
+ has_entries = false;
+ break;
+ }
+ }
+
+ env->ReleaseStringUTFChars(fileName, file_name);
+ env->ReleaseStringUTFChars(threadName, thread_name);
+}
+
+} // namespace
+} // namespace art
diff --git a/test/2246-trace-v2/expected-stderr.txt b/test/2246-trace-v2/expected-stderr.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/2246-trace-v2/expected-stderr.txt
diff --git a/test/2246-trace-v2/expected-stdout.txt b/test/2246-trace-v2/expected-stdout.txt
new file mode 100644
index 0000000..53430a6
--- /dev/null
+++ b/test/2246-trace-v2/expected-stdout.txt
@@ -0,0 +1,773 @@
+JNI_OnLoad called
+***** streaming test - dual clock *******
+version=f5
+.>> TestThread2246 java.lang.Thread run ()V Thread.java
+..>> TestThread2246 Main$$ExternalSyntheticLambda0 run ()V D8$$SyntheticClass
+...>> TestThread2246 Main lambda$testTracing$0 (IZLMain;)V Main.java
+....>> TestThread2246 Main$VMDebug startMethodTracingV2 (Ljava/lang/String;Ljava/io/FileDescriptor;IIZIZ)V Main.java
+.....>> TestThread2246 java.lang.reflect.Method invoke (Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; Method.java
+......>> TestThread2246 dalvik.system.VMDebug startMethodTracing (Ljava/lang/String;Ljava/io/FileDescriptor;IIZIZ)V VMDebug.java
+.......>> TestThread2246 dalvik.system.VMDebug startMethodTracingFd (Ljava/lang/String;IIIZIZ)V VMDebug.java
+.......<< TestThread2246 dalvik.system.VMDebug startMethodTracingFd (Ljava/lang/String;IIIZIZ)V VMDebug.java
+......<< TestThread2246 dalvik.system.VMDebug startMethodTracing (Ljava/lang/String;Ljava/io/FileDescriptor;IIZIZ)V VMDebug.java
+.....<< TestThread2246 java.lang.reflect.Method invoke (Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; Method.java
+....<< TestThread2246 Main$VMDebug startMethodTracingV2 (Ljava/lang/String;Ljava/io/FileDescriptor;IIZIZ)V Main.java
+....>> TestThread2246 Main <init> ()V Main.java
+.....>> TestThread2246 java.lang.Object <init> ()V Object.java
+.....<< TestThread2246 java.lang.Object <init> ()V Object.java
+....<< TestThread2246 Main <init> ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWork ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWork ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main$VMDebug $noinline$stopMethodTracing ()V Main.java
+.....>> TestThread2246 java.lang.reflect.Method invoke (Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; Method.java
+......>> TestThread2246 dalvik.system.VMDebug stopMethodTracing ()V VMDebug.java
+version=f5
+.>> main Main main ([Ljava/lang/String;)V Main.java
+..>> main Main testTracing (ZII)V Main.java
+...>> main Main$VMDebug startMethodTracingV2 (Ljava/lang/String;Ljava/io/FileDescriptor;IIZIZ)V Main.java
+....>> main java.lang.reflect.Method invoke (Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; Method.java
+.....>> main dalvik.system.VMDebug startMethodTracing (Ljava/lang/String;Ljava/io/FileDescriptor;IIZIZ)V VMDebug.java
+......>> main dalvik.system.VMDebug startMethodTracingFd (Ljava/lang/String;IIIZIZ)V VMDebug.java
+......<< main dalvik.system.VMDebug startMethodTracingFd (Ljava/lang/String;IIIZIZ)V VMDebug.java
+.....<< main dalvik.system.VMDebug startMethodTracing (Ljava/lang/String;Ljava/io/FileDescriptor;IIZIZ)V VMDebug.java
+....<< main java.lang.reflect.Method invoke (Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; Method.java
+...<< main Main$VMDebug startMethodTracingV2 (Ljava/lang/String;Ljava/io/FileDescriptor;IIZIZ)V Main.java
+...>> main Main $noinline$doSomeWork ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWork ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main doSomeWorkThrow ()V Main.java
+....>> main Main callThrowFunction ()V Main.java
+.....>> main java.lang.Exception <init> (Ljava/lang/String;)V Exception.java
+......>> main java.lang.Throwable <init> (Ljava/lang/String;)V Throwable.java
+.......>> main java.lang.Object <init> ()V Object.java
+.......<< main java.lang.Object <init> ()V Object.java
+.......>> main java.util.Collections emptyList ()Ljava/util/List; Collections.java
+.......<< main java.util.Collections emptyList ()Ljava/util/List; Collections.java
+.......>> main java.lang.Throwable fillInStackTrace ()Ljava/lang/Throwable; Throwable.java
+........>> main java.lang.Throwable nativeFillInStackTrace ()Ljava/lang/Object; Throwable.java
+........<< main java.lang.Throwable nativeFillInStackTrace ()Ljava/lang/Object; Throwable.java
+.......<< main java.lang.Throwable fillInStackTrace ()Ljava/lang/Throwable; Throwable.java
+......<< main java.lang.Throwable <init> (Ljava/lang/String;)V Throwable.java
+.....<< main java.lang.Exception <init> (Ljava/lang/String;)V Exception.java
+....<<E main Main callThrowFunction ()V Main.java
+...<< main Main doSomeWorkThrow ()V Main.java
+...>> main Main$VMDebug $noinline$stopMethodTracing ()V Main.java
+....>> main java.lang.reflect.Method invoke (Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; Method.java
+.....>> main dalvik.system.VMDebug stopMethodTracing ()V VMDebug.java
+***** streaming test - wall clock *******
+version=f4
+.>> TestThread2246 java.lang.Thread run ()V Thread.java
+..>> TestThread2246 Main$$ExternalSyntheticLambda0 run ()V D8$$SyntheticClass
+...>> TestThread2246 Main lambda$testTracing$0 (IZLMain;)V Main.java
+....>> TestThread2246 Main$VMDebug startMethodTracingV2 (Ljava/lang/String;Ljava/io/FileDescriptor;IIZIZ)V Main.java
+.....>> TestThread2246 java.lang.reflect.Method invoke (Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; Method.java
+......>> TestThread2246 dalvik.system.VMDebug startMethodTracing (Ljava/lang/String;Ljava/io/FileDescriptor;IIZIZ)V VMDebug.java
+.......>> TestThread2246 dalvik.system.VMDebug startMethodTracingFd (Ljava/lang/String;IIIZIZ)V VMDebug.java
+.......<< TestThread2246 dalvik.system.VMDebug startMethodTracingFd (Ljava/lang/String;IIIZIZ)V VMDebug.java
+......<< TestThread2246 dalvik.system.VMDebug startMethodTracing (Ljava/lang/String;Ljava/io/FileDescriptor;IIZIZ)V VMDebug.java
+.....<< TestThread2246 java.lang.reflect.Method invoke (Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; Method.java
+....<< TestThread2246 Main$VMDebug startMethodTracingV2 (Ljava/lang/String;Ljava/io/FileDescriptor;IIZIZ)V Main.java
+....>> TestThread2246 Main <init> ()V Main.java
+.....>> TestThread2246 java.lang.Object <init> ()V Object.java
+.....<< TestThread2246 java.lang.Object <init> ()V Object.java
+....<< TestThread2246 Main <init> ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWork ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWork ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+.....>> TestThread2246 Main callOuterFunction ()V Main.java
+......>> TestThread2246 Main callLeafFunction ()V Main.java
+......<< TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callOuterFunction ()V Main.java
+.....>> TestThread2246 Main callLeafFunction ()V Main.java
+.....<< TestThread2246 Main callLeafFunction ()V Main.java
+....<< TestThread2246 Main $noinline$doSomeWorkJIT ()V Main.java
+....>> TestThread2246 Main$VMDebug $noinline$stopMethodTracing ()V Main.java
+.....>> TestThread2246 java.lang.reflect.Method invoke (Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; Method.java
+......>> TestThread2246 dalvik.system.VMDebug stopMethodTracing ()V VMDebug.java
+version=f4
+.>> main Main main ([Ljava/lang/String;)V Main.java
+..>> main Main testTracing (ZII)V Main.java
+...>> main Main$VMDebug startMethodTracingV2 (Ljava/lang/String;Ljava/io/FileDescriptor;IIZIZ)V Main.java
+....>> main java.lang.reflect.Method invoke (Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; Method.java
+.....>> main dalvik.system.VMDebug startMethodTracing (Ljava/lang/String;Ljava/io/FileDescriptor;IIZIZ)V VMDebug.java
+......>> main dalvik.system.VMDebug startMethodTracingFd (Ljava/lang/String;IIIZIZ)V VMDebug.java
+......<< main dalvik.system.VMDebug startMethodTracingFd (Ljava/lang/String;IIIZIZ)V VMDebug.java
+.....<< main dalvik.system.VMDebug startMethodTracing (Ljava/lang/String;Ljava/io/FileDescriptor;IIZIZ)V VMDebug.java
+....<< main java.lang.reflect.Method invoke (Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; Method.java
+...<< main Main$VMDebug startMethodTracingV2 (Ljava/lang/String;Ljava/io/FileDescriptor;IIZIZ)V Main.java
+...>> main Main $noinline$doSomeWork ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWork ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main $noinline$doSomeWorkJIT ()V Main.java
+....>> main Main callOuterFunction ()V Main.java
+.....>> main Main callLeafFunction ()V Main.java
+.....<< main Main callLeafFunction ()V Main.java
+....<< main Main callOuterFunction ()V Main.java
+....>> main Main callLeafFunction ()V Main.java
+....<< main Main callLeafFunction ()V Main.java
+...<< main Main $noinline$doSomeWorkJIT ()V Main.java
+...>> main Main doSomeWorkThrow ()V Main.java
+....>> main Main callThrowFunction ()V Main.java
+.....>> main java.lang.Exception <init> (Ljava/lang/String;)V Exception.java
+......>> main java.lang.Throwable <init> (Ljava/lang/String;)V Throwable.java
+.......>> main java.lang.Object <init> ()V Object.java
+.......<< main java.lang.Object <init> ()V Object.java
+.......>> main java.util.Collections emptyList ()Ljava/util/List; Collections.java
+.......<< main java.util.Collections emptyList ()Ljava/util/List; Collections.java
+.......>> main java.lang.Throwable fillInStackTrace ()Ljava/lang/Throwable; Throwable.java
+........>> main java.lang.Throwable nativeFillInStackTrace ()Ljava/lang/Object; Throwable.java
+........<< main java.lang.Throwable nativeFillInStackTrace ()Ljava/lang/Object; Throwable.java
+.......<< main java.lang.Throwable fillInStackTrace ()Ljava/lang/Throwable; Throwable.java
+......<< main java.lang.Throwable <init> (Ljava/lang/String;)V Throwable.java
+.....<< main java.lang.Exception <init> (Ljava/lang/String;)V Exception.java
+....<<E main Main callThrowFunction ()V Main.java
+...<< main Main doSomeWorkThrow ()V Main.java
+...>> main Main$VMDebug $noinline$stopMethodTracing ()V Main.java
+....>> main java.lang.reflect.Method invoke (Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; Method.java
+.....>> main dalvik.system.VMDebug stopMethodTracing ()V VMDebug.java
diff --git a/test/2246-trace-v2/info.txt b/test/2246-trace-v2/info.txt
new file mode 100644
index 0000000..fa93a97
--- /dev/null
+++ b/test/2246-trace-v2/info.txt
@@ -0,0 +1,2 @@
+Tests streaming method tracing. It verifies the format of the generated file is
+as expected.
diff --git a/test/2246-trace-v2/run.py b/test/2246-trace-v2/run.py
new file mode 100644
index 0000000..4c0d858
--- /dev/null
+++ b/test/2246-trace-v2/run.py
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# Copyright (C) 2024 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.
+
+
+def run(ctx, args):
+ # The expected output on non debuggable configurations isn't consistent.
+ # TODO(mythria): Investigate why the output is different and update the test to work for
+ # non debuggable runtimes too.
+ ctx.default_run(args, Xcompiler_option=["--debuggable"])
diff --git a/test/2246-trace-v2/src/Main.java b/test/2246-trace-v2/src/Main.java
new file mode 100644
index 0000000..b5ccb9d
--- /dev/null
+++ b/test/2246-trace-v2/src/Main.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.lang.reflect.Method;
+
+public class Main {
+ private static final String TEMP_FILE_NAME_PREFIX = "test";
+ private static final String TEMP_FILE_NAME_SUFFIX = ".trace";
+ private static final int WALL_CLOCK_FLAG = 0x010;
+ private static final int TRACE_OUTPUT_V2_FLAG = 0b010;
+ private static final int STREAMING_DUAL_CLOCK_VERSION = 1;
+ private static final int STREAMING_WALL_CLOCK_VERSION = 1;
+ private static File file;
+
+ public static void main(String[] args) throws Exception {
+ System.loadLibrary(args[0]);
+ String name = System.getProperty("java.vm.name");
+ if (!"Dalvik".equals(name)) {
+ System.out.println("This test is not supported on " + name);
+ return;
+ }
+
+ ensureJitCompiled(Main.class, "$noinline$doSomeWorkJIT");
+
+ System.out.println("***** streaming test - dual clock *******");
+ testTracing(
+ /* streaming=*/true, /* flags= */ 0, STREAMING_DUAL_CLOCK_VERSION);
+
+ System.out.println("***** streaming test - wall clock *******");
+ testTracing(
+ /* streaming=*/true, /* flags= */ WALL_CLOCK_FLAG, STREAMING_WALL_CLOCK_VERSION);
+ }
+
+ public static void testTracing(boolean streaming, int flags, int expected_version)
+ throws Exception {
+ Main m = new Main();
+ Thread t = new Thread(() -> {
+ try {
+ file = createTempFile();
+ FileOutputStream out_file = new FileOutputStream(file);
+ VMDebug.startMethodTracingV2(
+ file.getPath(), out_file.getFD(), 0, flags, false, 0, streaming);
+ Main m1 = new Main();
+ m1.$noinline$doSomeWork();
+ // Call JITed code multiple times to flush out any issues with timestamps.
+ for (int i = 0; i < 20; i++) {
+ m.$noinline$doSomeWorkJIT();
+ }
+ VMDebug.$noinline$stopMethodTracing();
+ out_file.close();
+ dumpTrace(file.getAbsolutePath(), "TestThread2246");
+ file.delete();
+ } catch (Exception e) {
+ System.out.println("Exception in thread " + e);
+ e.printStackTrace();
+ } finally {
+ file.delete();
+ }
+ }, "TestThread2246");
+ try {
+ if (VMDebug.getMethodTracingMode() != 0) {
+ VMDebug.$noinline$stopMethodTracing();
+ }
+
+ t.start();
+ t.join();
+
+ file = createTempFile();
+ FileOutputStream main_out_file = new FileOutputStream(file);
+ VMDebug.startMethodTracingV2(
+ file.getPath(), main_out_file.getFD(), 0, flags, false, 0, streaming);
+ m.$noinline$doSomeWork();
+ // Call JITed code multiple times to flush out any issues with timestamps.
+ for (int i = 0; i < 20; i++) {
+ m.$noinline$doSomeWorkJIT();
+ }
+ m.doSomeWorkThrow();
+ VMDebug.$noinline$stopMethodTracing();
+ main_out_file.close();
+ dumpTrace(file.getAbsolutePath(), "main");
+ file.delete();
+ } finally {
+ file.delete();
+ }
+ }
+
+ private static File createTempFile() throws Exception {
+ try {
+ return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
+ } catch (IOException e) {
+ System.setProperty("java.io.tmpdir", "/data/local/tmp");
+ try {
+ return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
+ } catch (IOException e2) {
+ System.setProperty("java.io.tmpdir", "/sdcard");
+ return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
+ }
+ }
+ }
+
+ public void callOuterFunction() {
+ callLeafFunction();
+ }
+
+ public void callLeafFunction() {}
+
+ public void $noinline$doSomeWork() {
+ callOuterFunction();
+ callLeafFunction();
+ }
+
+ public void $noinline$doSomeWorkJIT() {
+ callOuterFunction();
+ callLeafFunction();
+ }
+
+ public void callThrowFunction() throws Exception {
+ throw new Exception("test");
+ }
+
+ public void doSomeWorkThrow() {
+ try {
+ callThrowFunction();
+ } catch (Exception e) {
+ }
+ }
+
+ private static class VMDebug {
+ private static final Method startMethodTracingMethod;
+ private static final Method stopMethodTracingMethod;
+ private static final Method getMethodTracingModeMethod;
+ static {
+ try {
+ Class<?> c = Class.forName("dalvik.system.VMDebug");
+ startMethodTracingMethod = c.getDeclaredMethod("startMethodTracing", String.class,
+ FileDescriptor.class, Integer.TYPE, Integer.TYPE, Boolean.TYPE,
+ Integer.TYPE, Boolean.TYPE);
+ stopMethodTracingMethod = c.getDeclaredMethod("stopMethodTracing");
+ getMethodTracingModeMethod = c.getDeclaredMethod("getMethodTracingMode");
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static void startMethodTracingV2(String filename, FileDescriptor fd, int bufferSize,
+ int flags, boolean samplingEnabled, int intervalUs, boolean streaming)
+ throws Exception {
+ startMethodTracingMethod.invoke(null, filename, fd, bufferSize,
+ flags | TRACE_OUTPUT_V2_FLAG, samplingEnabled, intervalUs, streaming);
+ }
+ public static void $noinline$stopMethodTracing() throws Exception {
+ stopMethodTracingMethod.invoke(null);
+ }
+ public static int getMethodTracingMode() throws Exception {
+ return (int) getMethodTracingModeMethod.invoke(null);
+ }
+ }
+
+ private static native void ensureJitCompiled(Class<?> cls, String methodName);
+ private static native void dumpTrace(String fileName, String threadName);
+}
diff --git a/test/Android.bp b/test/Android.bp
index 5406dfd..1768340 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -924,6 +924,7 @@
"2040-huge-native-alloc/huge_native_buf.cc",
"2048-bad-native-registry/native_finalizer.cc",
"2235-JdkUnsafeTest/unsafe_test.cc",
+ "2246-trace-v2/dump_trace.cc",
"2262-miranda-methods/jni_invoke.cc",
"2270-mh-internal-hiddenapi-use/mh-internal-hidden-api.cc",
"common/runtime_state.cc",
diff --git a/test/knownfailures.json b/test/knownfailures.json
index f369f6c..b47a1a1 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -1238,6 +1238,7 @@
"2238-checker-polymorphic-recursive-inlining",
"2240-tracing-non-invokable-method",
"2246-trace-stream",
+ "2246-trace-v2",
"2254-class-value-before-and-after-u",
"2261-badcleaner-in-systemcleaner",
"2263-method-trace-jit",