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, &current_index, buffer_ptr);
+  } else {
+    FlushEntriesFormatV2(
+        method_trace_entries, tid, method_infos, num_records, &current_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], &current_depth, event_type);
+  }
+  for (int i = 0; i < num_records; i++) {
+    int32_t diff = 0;
+    bool success = DecodeSignedLeb128Checked(&current_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], &current_depth, event_type);
+    }
+    // Read timestamps
+    DecodeUnsignedLeb128(&current_buffer_ptr);
+    if (is_dual_clock) {
+      DecodeUnsignedLeb128(&current_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",