diff options
| -rw-r--r-- | runtime/trace.cc | 412 | ||||
| -rw-r--r-- | runtime/trace.h | 42 | ||||
| -rw-r--r-- | test/2246-trace-v2/Android.bp | 40 | ||||
| -rw-r--r-- | test/2246-trace-v2/dump_trace.cc | 233 | ||||
| -rw-r--r-- | test/2246-trace-v2/expected-stderr.txt | 0 | ||||
| -rw-r--r-- | test/2246-trace-v2/expected-stdout.txt | 773 | ||||
| -rw-r--r-- | test/2246-trace-v2/info.txt | 2 | ||||
| -rw-r--r-- | test/2246-trace-v2/run.py | 22 | ||||
| -rw-r--r-- | test/2246-trace-v2/src/Main.java | 178 | ||||
| -rw-r--r-- | test/Android.bp | 1 | ||||
| -rw-r--r-- | test/knownfailures.json | 1 |
11 files changed, 1606 insertions, 98 deletions
diff --git a/runtime/trace.cc b/runtime/trace.cc index 29f67f075e..533293c291 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 kTraceRecordSizeSingleClock = 10; // using v2 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 @@ void Trace::SetDefaultClockSource(TraceClockSource clock_source) { #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 @@ TraceClockSource GetClockSourceFromFlags(int flags) { } } +int GetTraceFormatVersionFromFlags(int flags) { + int version = (flags & Trace::kTraceFormatVersionFlagMask) >> Trace::kTraceFormatVersionShift; + return version; +} + } // namespace TraceWriter::TraceWriter(File* trace_file, @@ -798,34 +836,46 @@ TraceWriter::TraceWriter(File* trace_file, 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"); + 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; + 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 @@ Trace::Trace(File* trace_file, 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 @@ Trace::Trace(File* trace_file, clock_source_, buf_size, kNumTracePoolBuffers, + trace_format_version, GetClockOverheadNanoSeconds())); } @@ -903,7 +955,7 @@ void TraceWriter::FinishTracing(int flags, bool flush_entries) { 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 @@ void TraceWriter::FinishTracing(int flags, bool flush_entries) { } 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 @@ void TraceWriter::FinishTracing(int flags, bool flush_entries) { 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 @@ void TraceWriter::FinishTracing(int flags, bool flush_entries) { // 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 @@ void TraceWriter::RecordThreadInfo(Thread* thread) { 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::PreProcessTraceForMethodInfos( } 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 @@ void TraceWriter::FlushBuffer(Thread* thread, bool is_sync, bool release) { 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 @@ void TraceWriter::FlushBuffer(uintptr_t* method_trace_entries, // 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; - } - - 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_; - } + 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_; - 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); + // 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_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; + DCHECK_GT(buffer_size_, record_size * num_entries); + if (trace_format_version_ == Trace::kFormatV1) { + FlushEntriesFormatV1( + method_trace_entries, tid, method_infos, current_offset, ¤t_index, buffer_ptr); + } else { + FlushEntriesFormatV2( + method_trace_entries, tid, method_infos, num_records, ¤t_index, buffer_ptr); } if (trace_output_mode_ == TraceOutputMode::kStreaming) { @@ -1469,6 +1661,30 @@ void TraceWriter::EncodeEventEntry(uint8_t* ptr, 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 b6f047e63e..227955ff2d 100644 --- a/runtime/trace.h +++ b/runtime/trace.h @@ -48,6 +48,8 @@ class DexFile; class ShadowFrame; class Thread; +struct MethodTraceRecord; + using DexIndexBitSet = std::bitset<65536>; enum TracingMode { @@ -146,6 +148,7 @@ class TraceWriter { 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 @@ class TraceWriter { 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 @@ class TraceWriter { 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 @@ class TraceWriter { // 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 @@ class Trace final : public instrumentation::InstrumentationListener { 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 0000000000..6655926552 --- /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 0000000000..6a094921fe --- /dev/null +++ b/test/2246-trace-v2/dump_trace.cc @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> + +#include <map> +#include <memory> + +#include "base/leb128.h" +#include "base/os.h" +#include "base/unix_file/fd_file.h" +#include "jni.h" + +namespace art { +namespace { + +static const int kMagicValue = 0x574f4c53; +static const int kVersionDualClock = 0xf5; +static const int kThreadInfo = 0; +static const int kMethodInfo = 1; +static const int kTraceEntries = 2; +static const int kTraceActionBits = 2; +static const int kSummary = 3; + +int ReadNumber(int num_bytes, uint8_t* header) { + int number = 0; + for (int i = 0; i < num_bytes; i++) { + number += header[i] << (i * 8); + } + return number; +} + +bool ProcessThreadOrMethodInfo(std::unique_ptr<File>& file, std::map<int, std::string>& name_map) { + uint8_t header[6]; + if (!file->ReadFully(&header, sizeof(header))) { + printf("Couldn't read header\n"); + return false; + } + int id = ReadNumber(4, header); + int length = ReadNumber(2, header + 4); + + char* name = new char[length]; + if (!file->ReadFully(name, length)) { + delete[] name; + return false; + } + std::string str(name, length); + std::replace(str.begin(), str.end(), '\t', ' '); + name_map.emplace(id, str); + delete[] name; + return true; +} + +void print_trace_entry(const std::string& thread_name, + const std::string& method_name, + int* current_depth, + int event_type) { + std::string entry; + for (int i = 0; i < *current_depth; i++) { + entry.push_back('.'); + } + if (event_type == 0) { + *current_depth += 1; + entry.append(".>> "); + } else if (event_type == 1) { + *current_depth -= 1; + entry.append("<< "); + } else if (event_type == 2) { + *current_depth -= 1; + entry.append("<<E "); + } else { + entry.append("?? "); + } + entry.append(thread_name); + entry.append(" "); + entry.append(method_name); + printf("%s", entry.c_str()); +} + +bool ProcessTraceEntries(std::unique_ptr<File>& file, + std::map<int, int>& current_depth_map, + std::map<int, std::string>& thread_map, + std::map<int, std::string>& method_map, + bool is_dual_clock, + const char* thread_name_filter) { + uint8_t header[20]; + int header_size = is_dual_clock ? 20 : 16; + if (!file->ReadFully(header, header_size)) { + return false; + } + + uint32_t thread_id = ReadNumber(4, header); + uint32_t method_value = ReadNumber(4, header + 4); + int offset = 8; + if (is_dual_clock) { + // Read timestamp. + ReadNumber(4, header + offset); + offset += 4; + } + // Read timestamp. + ReadNumber(4, header + offset); + offset += 4; + int num_records = ReadNumber(2, header + offset); + offset += 2; + int total_size = ReadNumber(2, header + offset); + uint8_t* buffer = new uint8_t[total_size]; + if (!file->ReadFully(buffer, total_size)) { + delete[] buffer; + return false; + } + + const uint8_t* current_buffer_ptr = buffer; + int32_t method_id = method_value >> kTraceActionBits; + uint8_t event_type = method_value & 0x3; + int current_depth = 0; + if (current_depth_map.find(thread_id) != current_depth_map.end()) { + // Get the current call stack depth. If it is the first method we are seeing on this thread + // then this map wouldn't haven an entry we start with the depth of 0. + current_depth = current_depth_map[thread_id]; + } + std::string thread_name = thread_map[thread_id]; + bool print_thread_events = (thread_name.compare(thread_name_filter) == 0); + if (method_map.find(method_id) == method_map.end()) { + LOG(FATAL) << "No entry for init method " << method_id; + } + if (print_thread_events) { + print_trace_entry(thread_name, method_map[method_id], ¤t_depth, event_type); + } + for (int i = 0; i < num_records; i++) { + int32_t diff = 0; + bool success = DecodeSignedLeb128Checked(¤t_buffer_ptr, buffer + total_size - 1, &diff); + if (!success) { + LOG(FATAL) << "Reading past the buffer???"; + } + int32_t curr_method_value = method_value + diff; + method_id = curr_method_value >> kTraceActionBits; + event_type = curr_method_value & 0x3; + if (print_thread_events) { + print_trace_entry(thread_name, method_map[method_id], ¤t_depth, event_type); + } + // Read timestamps + DecodeUnsignedLeb128(¤t_buffer_ptr); + if (is_dual_clock) { + DecodeUnsignedLeb128(¤t_buffer_ptr); + } + } + current_depth_map[thread_id] = current_depth; + return true; +} + +extern "C" JNIEXPORT void JNICALL Java_Main_dumpTrace(JNIEnv* env, + jclass, + jstring fileName, + jstring threadName) { + const char* file_name = env->GetStringUTFChars(fileName, nullptr); + const char* thread_name = env->GetStringUTFChars(threadName, nullptr); + std::map<int, std::string> thread_map; + std::map<int, std::string> method_map; + std::map<int, int> current_depth_map; + + std::unique_ptr<File> file(OS::OpenFileForReading(file_name)); + if (file == nullptr) { + printf("Couldn't open file\n"); + return; + } + + uint8_t header[32]; + const bool success = file->ReadFully(&header, sizeof(header)); + if (!success) { + printf("Couldn't read header\n"); + return; + } + int magic_value = ReadNumber(4, header); + if (magic_value != kMagicValue) { + printf("Incorrect magic value\n"); + return; + } + int version = ReadNumber(2, header + 4); + if (success) { + printf("version=%0x\n", version); + } + + bool is_dual_clock = (version == kVersionDualClock); + bool has_entries = true; + while (has_entries) { + uint8_t entry_header; + if (!file->ReadFully(&entry_header, sizeof(entry_header))) { + break; + } + switch (entry_header) { + case kThreadInfo: + if (!ProcessThreadOrMethodInfo(file, thread_map)) { + has_entries = false; + } + break; + case kMethodInfo: + if (!ProcessThreadOrMethodInfo(file, method_map)) { + has_entries = false; + } + break; + case kTraceEntries: + ProcessTraceEntries( + file, current_depth_map, thread_map, method_map, is_dual_clock, thread_name); + break; + case kSummary: + has_entries = false; + break; + default: + printf("Invalid Header %d\n", entry_header); + has_entries = false; + break; + } + } + + env->ReleaseStringUTFChars(fileName, file_name); + env->ReleaseStringUTFChars(threadName, thread_name); +} + +} // namespace +} // namespace art diff --git a/test/2246-trace-v2/expected-stderr.txt b/test/2246-trace-v2/expected-stderr.txt new file mode 100644 index 0000000000..e69de29bb2 --- /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 0000000000..53430a6195 --- /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 0000000000..fa93a971b4 --- /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 0000000000..4c0d8584f7 --- /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 0000000000..b5ccb9d0ec --- /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 5406dfd976..1768340530 100644 --- a/test/Android.bp +++ b/test/Android.bp @@ -924,6 +924,7 @@ cc_defaults { "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 f369f6c0b3..b47a1a1b35 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", |