From 09ed602e39d17c27f487d8e91c030312bdb8f9d2 Mon Sep 17 00:00:00 2001 From: Derek Bruening Date: Fri, 15 Mar 2024 16:32:11 -0400 Subject: [PATCH 01/14] Clarify docs on IR memory operands (#6708) Adds text clarifying that memory operands do not have their constituent registers listed as separate operands. This will show up in the online docs here: https://dynamorio.org/API_BT.html#sec_IR --- api/docs/bt.dox | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/api/docs/bt.dox b/api/docs/bt.dox index e03518a04f7..5767503453f 100644 --- a/api/docs/bt.dox +++ b/api/docs/bt.dox @@ -1,5 +1,5 @@ /* ********************************************************** - * Copyright (c) 2011-2023 Google, Inc. All rights reserved. + * Copyright (c) 2011-2024 Google, Inc. All rights reserved. * Copyright (c) 2007-2009 VMware, Inc. All rights reserved. * **********************************************************/ @@ -64,7 +64,8 @@ following sections: \section sec_IR Instruction Representation The primary data structures involved in instruction manipulation are -the #instr_t, which represents a single instruction, and the \c +the #opnd_t, which represents one operand; the #instr_t, which +represents a single instruction; and the \c #instrlist_t, which is a linked list of instructions. The header files dr_ir_instrlist.h and dr_ir_instr.h list a number of functions that operate on these data structures, including: @@ -89,6 +90,20 @@ a primary contributor to DynamoRIO's efficiency. The instruction representation includes all of the operands, whether implicit or explicit, and the condition code effects of each instruction. This allows for analysis of liveness of registers and condition codes. +The operands are split into sources and destinations. + +A memory reference is treated as one operand even when it uses +registers to compute its address: those constituent registers are not +listed as their own separate source operands (unless they are read for +other reasons such as updating the index register). This means that a +store to memory will have that store as a destination operand without +listing the store's addressing mode registers as source operands in +their own right. Tools interested in all registers inside such +operands can use opnd_get_num_regs_used() and opnd_get_reg_used() to +generically walk the registers inside an operand, or +instr_reads_from_reg() to determine whether an instruction reads a +register either as a source operand or as a component of a destination +memory reference. DynamoRIO's IR is mostly opaque to clients. Key data structures have their sizes exposed to allow for stack allocation, but their fields are opaque. In From 183f14e84e236a001fa98ee5eca456e518425d24 Mon Sep 17 00:00:00 2001 From: Brett Coon Date: Fri, 15 Mar 2024 15:38:38 -0700 Subject: [PATCH 02/14] i6686-opcodemix-intervals: Add OpcodeMix Intervals (#6706) Implements interval support for the opcode_mix analyzer. Adds snapshot support, primarily targeting instruction-count based snapshots. The most common opcodes and opcode categories are printed for each interval. Fixes #6686 --- ...fline-interval-opcode-mix-output.templatex | 12 ++ clients/drcachesim/tools/opcode_mix.cpp | 111 +++++++++++++++++- clients/drcachesim/tools/opcode_mix.h | 28 +++++ suite/tests/CMakeLists.txt | 3 + 4 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 clients/drcachesim/tests/offline-interval-opcode-mix-output.templatex diff --git a/clients/drcachesim/tests/offline-interval-opcode-mix-output.templatex b/clients/drcachesim/tests/offline-interval-opcode-mix-output.templatex new file mode 100644 index 00000000000..2071186a068 --- /dev/null +++ b/clients/drcachesim/tests/offline-interval-opcode-mix-output.templatex @@ -0,0 +1,12 @@ +Hello, world! + *Opcode mix tool results: + *[0-9]* : total executed instructions + *[1-9][0-9]* : *[a-z][ a-z]* + *[1-9][0-9]* : *[a-z][ a-z]* +.* +Printing unmerged per-shard interval results: +There were [0-9]* intervals created. +ID:1 ending at instruction 10000 has [0-9]* opcodes and [0-9]* categories. + *\[1\] Opcode: [ a-z]* \([0-9]*\) Count=[0-9]* PKI=[0-9\.]* + *\[2\] Opcode: [ a-z]* \([0-9]*\) Count=[0-9]* PKI=[0-9\.]* +.* diff --git a/clients/drcachesim/tools/opcode_mix.cpp b/clients/drcachesim/tools/opcode_mix.cpp index 8ac7ad25a17..995c810a578 100644 --- a/clients/drcachesim/tools/opcode_mix.cpp +++ b/clients/drcachesim/tools/opcode_mix.cpp @@ -42,6 +42,7 @@ #include #include +#include #include #include #include @@ -282,7 +283,9 @@ opcode_mix_t::get_category_names(uint category) const uint max_mask = 0x80000000; for (uint mask = 0x1; mask <= max_mask; mask <<= 1) { if (TESTANY(mask, category)) { - category_name += " "; + if (category_name.length() > 0) { + category_name += " "; + } category_name += instr_get_category_name(static_cast(mask)); } @@ -338,5 +341,111 @@ opcode_mix_t::print_results() return true; } +opcode_mix_t::interval_state_snapshot_t * +opcode_mix_t::generate_interval_snapshot(uint64_t interval_id) +{ + return generate_shard_interval_snapshot(&serial_shard_, interval_id); +} + +opcode_mix_t::interval_state_snapshot_t * +opcode_mix_t::generate_shard_interval_snapshot(void *shard_data, uint64_t interval_id) +{ + assert(shard_data != nullptr); + auto &shard = *reinterpret_cast(shard_data); + auto *snap = new snapshot_t; + snap->opcode_counts_ = shard.opcode_counts; + snap->category_counts_ = shard.category_counts; + return snap; +} + +bool +opcode_mix_t::finalize_interval_snapshots( + std::vector &interval_snapshots) +{ + // Loop through snapshots in reverse order, subtracting the *earlier* + // snapshot's cumulative values from this snapshot's cumulative values, to get + // deltas. The first snapshot needs no updates, obviously. + for (int i = static_cast(interval_snapshots.size()) - 1; i > 0; --i) { + auto &this_snap = *reinterpret_cast(interval_snapshots[i]); + auto &prior_snap = *reinterpret_cast(interval_snapshots[i - 1]); + for (auto &opc_count : this_snap.opcode_counts_) { + opc_count.second -= prior_snap.opcode_counts_[opc_count.first]; + } + for (auto &cat_count : this_snap.category_counts_) { + cat_count.second -= prior_snap.category_counts_[cat_count.first]; + } + } + return true; +} + +opcode_mix_t::interval_state_snapshot_t * +opcode_mix_t::combine_interval_snapshots( + const std::vector latest_shard_snapshots, + uint64_t interval_end_timestamp) +{ + snapshot_t *super_snap = new snapshot_t; + for (const interval_state_snapshot_t *base_snap : latest_shard_snapshots) { + const auto *snap = reinterpret_cast(base_snap); + // Skip nullptrs and snapshots from different intervals. + if (snap == nullptr || + snap->get_interval_end_timestamp() != interval_end_timestamp) { + continue; + } + for (const auto opc_count : snap->opcode_counts_) { + super_snap->opcode_counts_[opc_count.first] += opc_count.second; + } + for (const auto cat_count : snap->category_counts_) { + super_snap->category_counts_[cat_count.first] += cat_count.second; + } + } + return super_snap; +} + +bool +opcode_mix_t::print_interval_results( + const std::vector &interval_snapshots) +{ + // Number of opcodes and categories to print per interval. + constexpr int PRINT_TOP_N = 3; + std::cerr << "There were " << interval_snapshots.size() << " intervals created.\n"; + for (auto *base_snap : interval_snapshots) { + const auto *snap = reinterpret_cast(base_snap); + std::cerr << "ID:" << snap->get_interval_id() << " ending at instruction " + << snap->get_instr_count_cumulative() << " has " + << snap->opcode_counts_.size() << " opcodes" + << " and " << snap->category_counts_.size() << " categories.\n"; + std::vector> sorted(snap->opcode_counts_.begin(), + snap->opcode_counts_.end()); + std::sort(sorted.begin(), sorted.end(), cmp_val); + for (int i = 0; i < PRINT_TOP_N && i < static_cast(sorted.size()); ++i) { + std::cerr << " [" << i + 1 << "]" + << " Opcode: " << decode_opcode_name(sorted[i].first) << " (" + << sorted[i].first << ")" + << " Count=" << sorted[i].second << " PKI=" + << sorted[i].second * 1000.0 / snap->get_instr_count_delta() + << "\n"; + } + std::vector> sorted_cats(snap->category_counts_.begin(), + snap->category_counts_.end()); + std::sort(sorted_cats.begin(), sorted_cats.end(), cmp_val); + for (int i = 0; i < PRINT_TOP_N && i < static_cast(sorted_cats.size()); + ++i) { + std::cerr << " [" << i + 1 << "]" + << " Category=" << get_category_names(sorted_cats[i].first) + << " Count=" << sorted_cats[i].second << " PKI=" + << sorted_cats[i].second * 1000.0 / snap->get_instr_count_delta() + << "\n"; + } + } + return true; +} + +bool +opcode_mix_t::release_interval_snapshot(interval_state_snapshot_t *interval_snapshot) +{ + delete interval_snapshot; + return true; +} + } // namespace drmemtrace } // namespace dynamorio diff --git a/clients/drcachesim/tools/opcode_mix.h b/clients/drcachesim/tools/opcode_mix.h index 09619ff935b..526f27cdd43 100644 --- a/clients/drcachesim/tools/opcode_mix.h +++ b/clients/drcachesim/tools/opcode_mix.h @@ -82,6 +82,26 @@ class opcode_mix_t : public analysis_tool_t { std::string parallel_shard_error(void *shard_data) override; + // Interval support. + interval_state_snapshot_t * + generate_interval_snapshot(uint64_t interval_id) override; + interval_state_snapshot_t * + combine_interval_snapshots( + const std::vector latest_shard_snapshots, + uint64_t interval_end_timestamp) override; + bool + print_interval_results( + const std::vector &interval_snapshots) override; + bool + release_interval_snapshot(interval_state_snapshot_t *interval_snapshot) override; + interval_state_snapshot_t * + generate_shard_interval_snapshot(void *shard_data, uint64_t interval_id) override; + + // Convert the captured cumulative snapshots to deltas. + bool + finalize_interval_snapshots( + std::vector &interval_snapshots) override; + protected: std::string get_category_names(uint category); @@ -107,6 +127,14 @@ class opcode_mix_t : public analysis_tool_t { uint category; }; + class snapshot_t : public interval_state_snapshot_t { + public: + // Snapshot the counts as cumulative stats, and then converted them to deltas in + // finalize_interval_snapshots(). Printed interval results are all deltas. + std::unordered_map opcode_counts_; + std::unordered_map category_counts_; + }; + struct worker_data_t { std::unordered_map opcode_data_cache; }; diff --git a/suite/tests/CMakeLists.txt b/suite/tests/CMakeLists.txt index 7c4e0c73074..9855b91fe77 100644 --- a/suite/tests/CMakeLists.txt +++ b/suite/tests/CMakeLists.txt @@ -4081,6 +4081,9 @@ if (BUILD_CLIENTS) torunonly_drcacheoff(interval-instr-count-output ${ci_shared_app} "" "@-simulator_type@basic_counts@-interval_instr_count@10000" "") + torunonly_drcacheoff(interval-opcode-mix-output ${ci_shared_app} "" + "@-simulator_type@opcode_mix@-interval_instr_count@10000" "") + # As for the online test, we check that only 1 thread is in the final trace. torunonly_drcacheoff(max-global client.annotation-concurrency # Include function tracing to sanity test combining with delay and max. From 88d234b2848dedcbf0aabab26deff0ccd48fe1f4 Mon Sep 17 00:00:00 2001 From: Derek Bruening Date: Mon, 18 Mar 2024 18:10:10 -0400 Subject: [PATCH 03/14] i#6709: Update WIX version to 6.14 (#6710) Updates the PATH of our package build to find the new WIX version on the GA CI VM's. Tested: https://github.com/DynamoRIO/dynamorio/actions/runs/8308632272 Fixes #6709 --- .github/workflows/ci-package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-package.yml b/.github/workflows/ci-package.yml index 599ddadcd5c..62e88e22689 100644 --- a/.github/workflows/ci-package.yml +++ b/.github/workflows/ci-package.yml @@ -471,7 +471,7 @@ jobs: 7z x c:\projects\install\doxygen.zip -oc:\projects\install\doxygen > nul set PATH=c:\projects\install\doxygen;%PATH% dir "c:\Program Files (x86)\WiX Toolset"* - set PATH=C:\Program Files (x86)\WiX Toolset v3.11\bin;%PATH% + set PATH=C:\Program Files (x86)\WiX Toolset v3.14\bin;%PATH% call "C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Auxiliary/Build/vcvars32.bat" echo ------ Running suite ------ echo PATH is "%PATH%" From b2e6177bfd3b93497e353151d643e649061b0cd5 Mon Sep 17 00:00:00 2001 From: Yang Liu Date: Tue, 19 Mar 2024 19:21:54 +0800 Subject: [PATCH 04/14] i#3544 RV64: Fix patch_stub for unaligned stub_pc (#6711) To simplify codegen, we require the exit stub pc to be aligned to 4 bytes. If it is not aligned, we place a 2-byte `c.nop` at the beginning of the exit stub. Therefore, all functions that modify the exit stub should skip the possible `c.nop`. The wrongly implemented `patch_stub()` makes `unlink_branch()` not affect the exit stub, which makes the async signal handling error-prone. Before the fix, it hits the following assertion ~1/5 times when running `linux.signal0001` on a RISC-V machine, which indicates that the second signal comes from a different fragment after the unlinking, and the real reason is that the unlinking is not successful. ``` ASSERT signal.c:4954 info->interrupted == NULL || info->interrupted == f ``` It would be great if we could enable the signal tests in CI, but these tests do not work in QEMU for unknown reasons. Issue: #3544 Related: #2328 --- core/arch/riscv64/emit_utils.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/arch/riscv64/emit_utils.c b/core/arch/riscv64/emit_utils.c index dcdc5a0300d..0b423bdfedc 100644 --- a/core/arch/riscv64/emit_utils.c +++ b/core/arch/riscv64/emit_utils.c @@ -292,6 +292,9 @@ void patch_stub(fragment_t *f, cache_pc stub_pc, cache_pc target_pc, cache_pc target_prefix_pc, bool hot_patch) { + /* If stub_pc is not aligned to 4 bytes, the first instruction will be c.nop, see + * insert_exit_stub_other_flags(). */ + stub_pc = ALIGNED(stub_pc, 4) ? stub_pc : stub_pc + 2; ptr_int_t off = (ptr_int_t)target_pc - (ptr_int_t)stub_pc; if (off < 0x100000 && off > (ptr_int_t)0xFFFFFFFFFFF00000L) { /* target_pc is a near fragment. We can get there with a J (OP_jal, 21-bit signed From 8cdf1b1fa6aa4d323eb3baafa93aff387f8380ae Mon Sep 17 00:00:00 2001 From: Derek Bruening Date: Thu, 21 Mar 2024 00:21:20 -0400 Subject: [PATCH 05/14] i#6712: Add record_scheduler_t support for replay-as-traced (#6714) Adds record_scheduler_t (for the record_filter tool) support for replaying as-traced. The key change here is having record_reader_t's instruction ordinal, record_scheduler_t's output stream instruction ordinal, and record_scheduler_t's switch boundaries all consider the first in any sequence of encoding records or TRACE_MARKER_TYPE_BRANCH_TARGET markers to start an instruction instead of waiting for the instruction record. (Previously the scheduler switch point did consider encodings, but not branch targets, and the ordinals only considered instructions.) Moving the boundary back avoids splitting encodings from instructions when operating at instrution boundaries in the scheduler (encountered during replay, but this would also affect skipping for scheduler regions of interest). Adds tests of all 3 boundary types to the record_scheduler_t unit test. Adds a test of record_filter on the checked-in threadsig trace in as-traced replay mode. Fixes #6712 --- .../drcachesim/reader/record_file_reader.h | 22 ++++++++++++- clients/drcachesim/scheduler/scheduler.cpp | 32 +++++++++++-------- clients/drcachesim/scheduler/scheduler.h | 5 +++ .../tests/record_filter_as_traced.templatex | 10 ++++++ .../drcachesim/tests/scheduler_unit_tests.cpp | 24 +++++++++++++- suite/tests/CMakeLists.txt | 18 ++++++++++- 6 files changed, 95 insertions(+), 16 deletions(-) create mode 100644 clients/drcachesim/tests/record_filter_as_traced.templatex diff --git a/clients/drcachesim/reader/record_file_reader.h b/clients/drcachesim/reader/record_file_reader.h index a80cdeba581..e966bc51f4e 100644 --- a/clients/drcachesim/reader/record_file_reader.h +++ b/clients/drcachesim/reader/record_file_reader.h @@ -141,6 +141,15 @@ class record_reader_t : public std::iteratortype == TRACE_TYPE_ENCODING || + // The branch target marker sits between any encodings and the instr. + (record->type == TRACE_TYPE_MARKER && + record->size == TRACE_MARKER_TYPE_BRANCH_TARGET); + } + record_reader_t & operator++() { @@ -149,7 +158,13 @@ class record_reader_t : public std::iterator(cur_entry_.type))) + // We increment the instr count at the encoding as that avoids multiple + // problems with separating encodings from instrs when skipping (including + // for scheduler regions of interest) and when replaying schedules: anything + // using instr ordinals as boundaries. + if (!prev_record_was_pre_instr_ && + (record_is_pre_instr(&cur_entry_) || + type_is_instr(static_cast(cur_entry_.type)))) ++cur_instr_count_; else if (cur_entry_.type == TRACE_TYPE_MARKER) { switch (cur_entry_.size) { @@ -177,6 +192,7 @@ class record_reader_t : public std::iterator::record_type_is_encoding( return static_cast(record.type) == TRACE_TYPE_ENCODING; } -template <> -bool -scheduler_tmpl_t::record_type_is_instr_boundary( - trace_entry_t record, trace_entry_t prev_record) -{ - // Don't advance past encodings and split them from their associated instr. - return (record_type_is_instr(record) || record_type_is_encoding(record)) && - !record_type_is_encoding(prev_record); -} - template <> typename scheduler_tmpl_t::stream_status_t scheduler_tmpl_t::unread_last_record( @@ -447,6 +437,18 @@ scheduler_tmpl_t::record_type_is_marker( return true; } +template <> +bool +scheduler_tmpl_t::record_type_is_instr_boundary( + trace_entry_t record, trace_entry_t prev_record) +{ + // Don't advance past encodings or target markers and split them from their + // associated instr. + return (record_type_is_instr(record) || + record_reader_t::record_is_pre_instr(&record)) && + !record_reader_t::record_is_pre_instr(&prev_record); +} + template <> bool scheduler_tmpl_t::record_type_is_timestamp( @@ -563,7 +565,7 @@ scheduler_tmpl_t::stream_t::next_record(RecordType &reco std::lock_guard guard(*input->lock); if (!input->reader->is_record_synthetic()) ++cur_ref_count_; - if (scheduler_->record_type_is_instr(record)) + if (scheduler_->record_type_is_instr_boundary(record, prev_record_)) ++cur_instr_count_; VPRINT(scheduler_, 4, "stream record#=%" PRId64 ", instr#=%" PRId64 " (cur input %" PRId64 @@ -597,6 +599,7 @@ scheduler_tmpl_t::stream_t::next_record(RecordType &reco break; } } + prev_record_ = record; return sched_type_t::STATUS_OK; } @@ -1789,7 +1792,9 @@ scheduler_tmpl_t::clear_input_queue(input_info_t &input) // skip it all when skipping ahead in the input stream. int i = 0; while (!input.queue.empty()) { - assert(i == 0 || !record_type_is_instr(input.queue.front())); + assert(i == 0 || + (!record_type_is_instr(input.queue.front()) && + !record_type_is_encoding(input.queue.front()))); ++i; input.queue.pop_front(); } @@ -1809,7 +1814,8 @@ scheduler_tmpl_t::skip_instructions(output_ordinal_t out // For a skip of 0 we still need to clear non-instrs from the queue, but // should not have an instr in there. assert(skip_amount > 0 || input.queue.empty() || - !record_type_is_instr(input.queue.front())); + (!record_type_is_instr(input.queue.front()) && + !record_type_is_encoding(input.queue.front()))); clear_input_queue(input); input.reader->skip_instructions(skip_amount); if (*input.reader == *input.reader_end) { diff --git a/clients/drcachesim/scheduler/scheduler.h b/clients/drcachesim/scheduler/scheduler.h index 72c4ad9d4fd..fea81cc71ec 100644 --- a/clients/drcachesim/scheduler/scheduler.h +++ b/clients/drcachesim/scheduler/scheduler.h @@ -792,6 +792,10 @@ template class scheduler_tmpl_t { } /** * Returns the count of instructions from the start of the trace to this point. + * For record_scheduler_t, if any encoding records or the internal record + * TRACE_MARKER_TYPE_BRANCH_TARGET records are present prior to an instruction + * marker, the count will increase at the first of those records as they are + * considered part of the instruction. * If #SCHEDULER_USE_INPUT_ORDINALS is set, then this value matches the * instruction ordinal for the current input stream (and thus might decrease or * not change across records if the input changed). Otherwise, if multiple input @@ -1039,6 +1043,7 @@ template class scheduler_tmpl_t { uint64_t cache_line_size_ = 0; uint64_t chunk_instr_count_ = 0; uint64_t page_size_ = 0; + RecordType prev_record_ = {}; // Let the outer class update our state. friend class scheduler_tmpl_t; diff --git a/clients/drcachesim/tests/record_filter_as_traced.templatex b/clients/drcachesim/tests/record_filter_as_traced.templatex new file mode 100644 index 00000000000..e9e8f316122 --- /dev/null +++ b/clients/drcachesim/tests/record_filter_as_traced.templatex @@ -0,0 +1,10 @@ +Output .* entries from .* entries. +Schedule stats tool results: +.* +Core #0 schedule: .* +Core #1 schedule: .* +Core #2 schedule: .* +Core #3 schedule: .* +Core #4 schedule: .* +Core #5 schedule: .* +Core #6 schedule: .* diff --git a/clients/drcachesim/tests/scheduler_unit_tests.cpp b/clients/drcachesim/tests/scheduler_unit_tests.cpp index 5801bce250c..1b77dc5f113 100644 --- a/clients/drcachesim/tests/scheduler_unit_tests.cpp +++ b/clients/drcachesim/tests/scheduler_unit_tests.cpp @@ -3955,6 +3955,8 @@ test_record_scheduler() make_encoding(ENCODING_SIZE, ENCODING_IGNORE), make_instr(40), make_encoding(ENCODING_SIZE, ENCODING_IGNORE), + // Test a target marker between the encoding and the instr. + make_marker(TRACE_MARKER_TYPE_BRANCH_TARGET, 42), make_instr(60), // No encoding for repeated instr. make_instr(20), @@ -4006,8 +4008,17 @@ test_record_scheduler() check_next(stream0, record_scheduler_t::STATUS_OK, TRACE_TYPE_PID, PID_A); check_next(stream0, record_scheduler_t::STATUS_OK, TRACE_TYPE_MARKER); check_next(stream0, record_scheduler_t::STATUS_OK, TRACE_TYPE_MARKER); + // Test ordinals. + assert(stream0->get_instruction_ordinal() == 0); + assert(stream0->get_input_interface()->get_instruction_ordinal() == 0); check_next(stream0, record_scheduler_t::STATUS_OK, TRACE_TYPE_ENCODING); + // The encoding should have incremented the ordinal. + assert(stream0->get_instruction_ordinal() == 1); + assert(stream0->get_input_interface()->get_instruction_ordinal() == 1); check_next(stream0, record_scheduler_t::STATUS_OK, TRACE_TYPE_INSTR); + // The instr should not have further incremented it. + assert(stream0->get_instruction_ordinal() == 1); + assert(stream0->get_input_interface()->get_instruction_ordinal() == 1); check_next(stream0, record_scheduler_t::STATUS_OK, TRACE_TYPE_MARKER); check_next(stream0, record_scheduler_t::STATUS_OK, TRACE_TYPE_MARKER); check_next(stream0, record_scheduler_t::STATUS_OK, TRACE_TYPE_MARKER); @@ -4022,7 +4033,8 @@ test_record_scheduler() check_next(stream0, record_scheduler_t::STATUS_OK, TRACE_TYPE_INSTR); check_next(stream0, record_scheduler_t::STATUS_OK, TRACE_TYPE_ENCODING); check_next(stream0, record_scheduler_t::STATUS_OK, TRACE_TYPE_INSTR); - // Ensure the switch is *before* the encoding. + // Ensure the switch is *before* the encoding and target marker. + assert(stream0->get_input_interface()->get_instruction_ordinal() == 2); check_next(stream0, record_scheduler_t::STATUS_OK, TRACE_TYPE_THREAD, TID_A); check_next(stream0, record_scheduler_t::STATUS_OK, TRACE_TYPE_PID, PID_A); check_next(stream0, record_scheduler_t::STATUS_OK, TRACE_TYPE_ENCODING); @@ -4030,8 +4042,18 @@ test_record_scheduler() check_next(stream0, record_scheduler_t::STATUS_OK, TRACE_TYPE_THREAD, TID_B); check_next(stream0, record_scheduler_t::STATUS_OK, TRACE_TYPE_PID, PID_B); check_next(stream0, record_scheduler_t::STATUS_OK, TRACE_TYPE_ENCODING); + assert(stream0->get_instruction_ordinal() == 5); + assert(stream0->get_input_interface()->get_instruction_ordinal() == 3); + check_next(stream0, record_scheduler_t::STATUS_OK, TRACE_TYPE_MARKER); + assert(stream0->get_instruction_ordinal() == 5); + assert(stream0->get_input_interface()->get_instruction_ordinal() == 3); check_next(stream0, record_scheduler_t::STATUS_OK, TRACE_TYPE_INSTR); + // Should still be at the same count after the encoding, marker, and instr. + assert(stream0->get_instruction_ordinal() == 5); + assert(stream0->get_input_interface()->get_instruction_ordinal() == 3); check_next(stream0, record_scheduler_t::STATUS_OK, TRACE_TYPE_INSTR); + assert(stream0->get_instruction_ordinal() == 6); + assert(stream0->get_input_interface()->get_instruction_ordinal() == 4); check_next(stream0, record_scheduler_t::STATUS_OK, TRACE_TYPE_THREAD_EXIT); check_next(stream0, record_scheduler_t::STATUS_OK, TRACE_TYPE_THREAD, TID_A); check_next(stream0, record_scheduler_t::STATUS_OK, TRACE_TYPE_PID, PID_A); diff --git a/suite/tests/CMakeLists.txt b/suite/tests/CMakeLists.txt index 9855b91fe77..16e49335c25 100644 --- a/suite/tests/CMakeLists.txt +++ b/suite/tests/CMakeLists.txt @@ -4661,8 +4661,8 @@ if (BUILD_CLIENTS) "schedule_stats") endif () - # Test the trim filter. if (X86 AND X64 AND ZLIB_FOUND) + # Test the trim filter. set(zip_path "${PROJECT_SOURCE_DIR}/clients/drcachesim/tests/drmemtrace.allasm_x86_64.trace.zip") set(outdir ${PROJECT_BINARY_DIR}/trim_filter) @@ -4680,6 +4680,22 @@ if (BUILD_CLIENTS) "${drcachesim_path}@-simulator_type@record_filter@-trim_before_timestamp@13352268558646120@-trim_after_timestamp@13352268558646661@-indir@${srcdir}@-outdir@${outdir}") set(tool.drcacheoff.trim_basedir "${PROJECT_SOURCE_DIR}/clients/drcachesim/tests") set(tool.drcacheoff.trim_rawtemp ON) # no preprocessor + + # Test the record_filter in as-traced mode. + set(trace_dir + "${PROJECT_SOURCE_DIR}/clients/drcachesim/tests/drmemtrace.threadsig.x64.tracedir") + set(sched_file "${trace_dir}/cpu_schedule.bin.zip") + set(outdir ${CMAKE_CURRENT_BINARY_DIR}/filter_as_traced) + file(MAKE_DIRECTORY ${outdir}) + torunonly_api(tool.record_filter_as_traced "${drcachesim_path}" + "record_filter_as_traced" + "" "-simulator_type;schedule_stats;-indir;${outdir}" OFF OFF) + set(tool.record_filter_as_traced_runcmp "${CMAKE_CURRENT_SOURCE_DIR}/runmulti.cmake") + set(tool.record_filter_as_traced_precmd + "${drcachesim_path}@-simulator_type@record_filter@-cpu_schedule_file@${sched_file}@-core_sharded@-cores@7@-indir@${trace_dir}@-outdir@${outdir}") + set(tool.record_filter_as_traced_basedir + "${PROJECT_SOURCE_DIR}/clients/drcachesim/tests") + set(tool.record_filter_as_traced_rawtemp ON) # no preprocessor endif () if (AARCH64) From 781f15e8f1fab050f765fc76ddbba6b38b7017d0 Mon Sep 17 00:00:00 2001 From: Derek Bruening Date: Fri, 22 Mar 2024 15:49:16 -0400 Subject: [PATCH 06/14] i#6713: Remove same-input-same-start cpu_schedule entries (#6715) Removes same-input-same-start cpu_schedule entries when reading the schedule file in the scheduler. The scheduler cannot emulate a switch with no instructions in between in replay mode, and these same-start entries cause problems. Adds a scheduler unit test. Tested on a larger app in as-traced mode where there are many of these same-start entries and without this fix the scheduler advances too early, causing problems. Fixes #6713 --- clients/drcachesim/scheduler/scheduler.cpp | 145 ++++++++++++----- clients/drcachesim/scheduler/scheduler.h | 44 ++++- .../drcachesim/tests/scheduler_unit_tests.cpp | 151 ++++++++++++++++++ 3 files changed, 296 insertions(+), 44 deletions(-) diff --git a/clients/drcachesim/scheduler/scheduler.cpp b/clients/drcachesim/scheduler/scheduler.cpp index 47b2c680c46..b8b918d9de2 100644 --- a/clients/drcachesim/scheduler/scheduler.cpp +++ b/clients/drcachesim/scheduler/scheduler.cpp @@ -1091,9 +1091,9 @@ scheduler_tmpl_t::read_traced_schedule() uint64_t cur_cpu = std::numeric_limits::max(); // We also want to collapse same-cpu consecutive records so we start with // a temporary local vector. - std::vector> all_sched(outputs_.size()); + std::vector> all_sched(outputs_.size()); // Work around i#6107 by tracking counts sorted by timestamp for each input. - std::vector> input_sched(inputs_.size()); + std::vector> input_sched(inputs_.size()); while (options_.replay_as_traced_istream->read(reinterpret_cast(&entry), sizeof(entry))) { if (entry.cpu != cur_cpu) { @@ -1115,24 +1115,24 @@ scheduler_tmpl_t::read_traced_schedule() uint64_t timestamp = entry.timestamp; // Some entries have no instructions (there is an entry for each timestamp, and // a signal can come in after a prior timestamp with no intervening instrs). - assert(all_sched[cur_output].empty() || - all_sched[cur_output].back().type == schedule_record_t::DEFAULT); if (!all_sched[cur_output].empty() && - input == all_sched[cur_output].back().key.input && - start == all_sched[cur_output].back().value.start_instruction) { + input == all_sched[cur_output].back().input && + start == all_sched[cur_output].back().start_instruction) { VPRINT(this, 3, "Output #%d: as-read segment #%zu has no instructions: skipping\n", cur_output, all_sched[cur_output].size() - 1); continue; } - all_sched[cur_output].emplace_back(schedule_record_t::DEFAULT, input, start, 0, - timestamp); + all_sched[cur_output].emplace_back(true, input, start, timestamp); start2stop[input].insert(start); - input_sched[input].emplace_back(schedule_record_t::DEFAULT, input, start, 0, - timestamp); + input_sched[input].emplace_back(cur_output, all_sched[cur_output].size() - 1, + start, timestamp); } sched_type_t::scheduler_status_t res = check_and_fix_modulo_problem_in_schedule(input_sched, start2stop, all_sched); + if (res != sched_type_t::STATUS_SUCCESS) + return res; + res = remove_zero_instruction_segments(input_sched, all_sched); if (res != sched_type_t::STATUS_SUCCESS) return res; for (int output_idx = 0; output_idx < static_cast(outputs_.size()); @@ -1145,41 +1145,40 @@ scheduler_tmpl_t::read_traced_schedule() for (int sched_idx = 0; sched_idx < static_cast(all_sched[output_idx].size()); ++sched_idx) { auto &segment = all_sched[output_idx][sched_idx]; - auto find = - start2stop[segment.key.input].find(segment.value.start_instruction); + if (!segment.valid) + continue; + auto find = start2stop[segment.input].find(segment.start_instruction); ++find; - if (find == start2stop[segment.key.input].end()) + if (find == start2stop[segment.input].end()) segment.stop_instruction = std::numeric_limits::max(); else segment.stop_instruction = *find; VPRINT(this, 4, "as-read segment #%d: input=%d start=%" PRId64 " stop=%" PRId64 " time=%" PRId64 "\n", - sched_idx, segment.key.input, segment.value.start_instruction, + sched_idx, segment.input, segment.start_instruction, segment.stop_instruction, segment.timestamp); if (sched_idx + 1 < static_cast(all_sched[output_idx].size()) && - segment.key.input == all_sched[output_idx][sched_idx + 1].key.input && + segment.input == all_sched[output_idx][sched_idx + 1].input && segment.stop_instruction > - all_sched[output_idx][sched_idx + 1].value.start_instruction) { + all_sched[output_idx][sched_idx + 1].start_instruction) { // A second sanity check. error_string_ = "Invalid decreasing start field in schedule file"; return STATUS_ERROR_INVALID_PARAMETER; } else if (sched_idx + 1 < static_cast(all_sched[output_idx].size()) && - segment.key.input == - all_sched[output_idx][sched_idx + 1].key.input && + segment.input == all_sched[output_idx][sched_idx + 1].input && segment.stop_instruction == - all_sched[output_idx][sched_idx + 1].value.start_instruction) { + all_sched[output_idx][sched_idx + 1].start_instruction) { // Collapse into next. if (start_consec == -1) start_consec = sched_idx; } else { - schedule_record_t &toadd = start_consec >= 0 + schedule_output_tracker_t &toadd = start_consec >= 0 ? all_sched[output_idx][start_consec] : all_sched[output_idx][sched_idx]; outputs_[output_idx].record.emplace_back( - static_cast(toadd.type), - +toadd.key.input, +toadd.value.start_instruction, - +all_sched[output_idx][sched_idx].stop_instruction, +toadd.timestamp); + schedule_record_t::DEFAULT, toadd.input, toadd.start_instruction, + all_sched[output_idx][sched_idx].stop_instruction, toadd.timestamp); start_consec = -1; VDO(this, 3, { auto &added = outputs_[output_idx].record.back(); @@ -1212,12 +1211,71 @@ scheduler_tmpl_t::read_traced_schedule() return STATUS_SUCCESS; } +template +typename scheduler_tmpl_t::scheduler_status_t +scheduler_tmpl_t::remove_zero_instruction_segments( + std::vector> &input_sched, + std::vector> &all_sched) + +{ + // For a cpuid pair with no instructions in between, our + // instruction-ordinal-based control points cannot model both sides. + // For example: + // 5 0: 1294139 + // 6 0: 1294139 + // 7 0: 1294139 + // 8 0: 1294139 + // 9 0: 1294139 + // 10 0: 1294139 + // 11 0: 1294139 + // 12 0: 1294139 + // 13 1: 1294139 ifetch 3 byte(s) @ 0x0000563642cc5e75 8d 50 0b lea... + // That sequence has 2 different cpu_schedule file entries for that input + // starting at instruction 0, which causes confusion when determining endpoints. + // We just drop the older entry and keep the later one, which is the one bundled + // with actual instructions. + // + // Should we not have instruction-based control points? The skip and + // region-of-interest features were designed thinking about instructions, the more + // natural unit for microarchitectural simulators. It seemed like that was much more + // usable for a user, and translated to other venues like PMU counts. The scheduler + // replay features were also designed that way. But, that makes the infrastructure + // messy as the underlying records are not built that way. Xref i#6716 on an + // instruction-based iterator. + for (int input_idx = 0; input_idx < static_cast(inputs_.size()); + ++input_idx) { + std::sort( + input_sched[input_idx].begin(), input_sched[input_idx].end(), + [](const schedule_input_tracker_t &l, const schedule_input_tracker_t &r) { + return l.timestamp < r.timestamp; + }); + uint64_t prev_start = 0; + for (size_t i = 0; i < input_sched[input_idx].size(); ++i) { + uint64_t start = input_sched[input_idx][i].start_instruction; + assert(start >= prev_start); + if (i > 0 && start == prev_start) { + // Keep the newer one. + VPRINT(this, 1, "Dropping same-input=%d same-start=%" PRIu64 " entry\n", + input_idx, start); + all_sched[input_sched[input_idx][i - 1].output] + [static_cast( + input_sched[input_idx][i - 1].output_array_idx)] + .valid = false; + // If code after this used input_sched we would want to erase the + // entry, but we have no further use so we leave it. + } + prev_start = start; + } + } + return STATUS_SUCCESS; +} + template typename scheduler_tmpl_t::scheduler_status_t scheduler_tmpl_t::check_and_fix_modulo_problem_in_schedule( - std::vector> &input_sched, + std::vector> &input_sched, std::vector> &start2stop, - std::vector> &all_sched) + std::vector> &all_sched) { // Work around i#6107 where the counts in the file are incorrectly modulo the chunk @@ -1240,16 +1298,16 @@ scheduler_tmpl_t::check_and_fix_modulo_problem_in_schedu bool found_i6107 = false; for (int input_idx = 0; input_idx < static_cast(inputs_.size()); ++input_idx) { - std::sort(input_sched[input_idx].begin(), input_sched[input_idx].end(), - [](const schedule_record_t &l, const schedule_record_t &r) { - return l.timestamp < r.timestamp; - }); + std::sort( + input_sched[input_idx].begin(), input_sched[input_idx].end(), + [](const schedule_input_tracker_t &l, const schedule_input_tracker_t &r) { + return l.timestamp < r.timestamp; + }); uint64_t prev_start = 0; uint64_t add_to_start = 0; bool in_order = true; - for (const schedule_record_t &sched : input_sched[input_idx]) { - assert(sched.type == schedule_record_t::DEFAULT); - if (sched.value.start_instruction < prev_start) { + for (schedule_input_tracker_t &sched : input_sched[input_idx]) { + if (sched.start_instruction < prev_start) { // If within 50% of the end of the chunk we assume it's i#6107. if (prev_start * 2 > DEFAULT_CHUNK_SIZE) { add_to_start += DEFAULT_CHUNK_SIZE; @@ -1271,9 +1329,10 @@ scheduler_tmpl_t::check_and_fix_modulo_problem_in_schedu error_string_ = "Same timestamps not supported for i#6107 workaround"; return STATUS_ERROR_INVALID_PARAMETER; } - prev_start = sched.value.start_instruction; + prev_start = sched.start_instruction; timestamp2adjust[input_idx][sched.timestamp] = - sched.value.start_instruction + add_to_start; + sched.start_instruction + add_to_start; + sched.start_instruction += add_to_start; } } if (!found_i6107) @@ -1292,21 +1351,23 @@ scheduler_tmpl_t::check_and_fix_modulo_problem_in_schedu for (int sched_idx = 0; sched_idx < static_cast(all_sched[output_idx].size()); ++sched_idx) { auto &segment = all_sched[output_idx][sched_idx]; - auto it = timestamp2adjust[segment.key.input].find(segment.timestamp); - if (it == timestamp2adjust[segment.key.input].end()) { + if (!segment.valid) + continue; + auto it = timestamp2adjust[segment.input].find(segment.timestamp); + if (it == timestamp2adjust[segment.input].end()) { error_string_ = "Failed to find timestamp for i#6107 workaround"; return STATUS_ERROR_INVALID_PARAMETER; } - assert(it->second >= segment.value.start_instruction); - assert(it->second % DEFAULT_CHUNK_SIZE == segment.value.start_instruction); - if (it->second != segment.value.start_instruction) { + assert(it->second >= segment.start_instruction); + assert(it->second % DEFAULT_CHUNK_SIZE == segment.start_instruction); + if (it->second != segment.start_instruction) { VPRINT(this, 2, "Updating all_sched[%d][%d] input %d from %" PRId64 " to %" PRId64 "\n", - output_idx, sched_idx, segment.key.input, - segment.value.start_instruction, it->second); + output_idx, sched_idx, segment.input, segment.start_instruction, + it->second); } - segment.value.start_instruction = it->second; + segment.start_instruction = it->second; } } return STATUS_SUCCESS; diff --git a/clients/drcachesim/scheduler/scheduler.h b/clients/drcachesim/scheduler/scheduler.h index fea81cc71ec..f14e275943d 100644 --- a/clients/drcachesim/scheduler/scheduler.h +++ b/clients/drcachesim/scheduler/scheduler.h @@ -1331,6 +1331,41 @@ template class scheduler_tmpl_t { uint64_t wait_start_time = 0; }; + // Used for reading as-traced schedules. + struct schedule_output_tracker_t { + schedule_output_tracker_t(bool valid, input_ordinal_t input, + uint64_t start_instruction, uint64_t timestamp) + : valid(valid) + , input(input) + , start_instruction(start_instruction) + , stop_instruction(0) + , timestamp(timestamp) + { + } + // To support removing later-discovered-as-redundant entries without + // a linear erase operation we have a 'valid' flag. + bool valid; + input_ordinal_t input; + uint64_t start_instruction; + uint64_t stop_instruction; + uint64_t timestamp; + }; + // Used for reading as-traced schedules. + struct schedule_input_tracker_t { + schedule_input_tracker_t(output_ordinal_t output, uint64_t output_array_idx, + uint64_t start_instruction, uint64_t timestamp) + : output(output) + , output_array_idx(output_array_idx) + , start_instruction(start_instruction) + , timestamp(timestamp) + { + } + output_ordinal_t output; + uint64_t output_array_idx; + uint64_t start_instruction; + uint64_t timestamp; + }; + // Called just once at initialization time to set the initial input-to-output // mappings and state. scheduler_status_t @@ -1393,11 +1428,16 @@ template class scheduler_tmpl_t { scheduler_status_t read_traced_schedule(); + scheduler_status_t + remove_zero_instruction_segments( + std::vector> &input_sched, + std::vector> &all_sched); + scheduler_status_t check_and_fix_modulo_problem_in_schedule( - std::vector> &input_sched, + std::vector> &input_sched, std::vector> &start2stop, - std::vector> &all_sched); + std::vector> &all_sched); scheduler_status_t read_recorded_schedule(); diff --git a/clients/drcachesim/tests/scheduler_unit_tests.cpp b/clients/drcachesim/tests/scheduler_unit_tests.cpp index 1b77dc5f113..b217e3ad4ce 100644 --- a/clients/drcachesim/tests/scheduler_unit_tests.cpp +++ b/clients/drcachesim/tests/scheduler_unit_tests.cpp @@ -3260,6 +3260,156 @@ test_replay_as_traced_i6107_workaround() #endif } +static void +test_replay_as_traced_dup_start() +{ +#ifdef HAS_ZIP + // Test what i#6712 fixes: duplicate start entries. + std::cerr << "\n----------------\nTesting replay as-traced dup starts\n"; + + static constexpr int NUM_INPUTS = 3; + static constexpr int NUM_OUTPUTS = 2; + static constexpr int NUM_INSTRS = 6; + static constexpr memref_tid_t TID_A = 100; + static constexpr memref_tid_t TID_B = TID_A + 1; + static constexpr memref_tid_t TID_C = TID_A + 2; + static constexpr int CPU_0 = 6; + static constexpr int CPU_1 = 7; + static constexpr uint64_t TIMESTAMP_BASE = 100; + + std::vector inputs[NUM_INPUTS]; + for (int input_idx = 0; input_idx < NUM_INPUTS; input_idx++) { + memref_tid_t tid = TID_A + input_idx; + inputs[input_idx].push_back(make_thread(tid)); + inputs[input_idx].push_back(make_pid(1)); + // These timestamps do not line up with the schedule file but + // that does not cause problems and leaving it this way + // simplifies the testdata construction. + inputs[input_idx].push_back(make_timestamp(TIMESTAMP_BASE)); + for (int instr_idx = 0; instr_idx < NUM_INSTRS; ++instr_idx) { + inputs[input_idx].push_back(make_instr(42 + instr_idx)); + } + inputs[input_idx].push_back(make_exit(tid)); + } + + // Synthesize a cpu-schedule file with duplicate starts. + std::string cpu_fname = "tmp_test_cpu_i6712.zip"; + { + zipfile_ostream_t outfile(cpu_fname); + { + std::vector sched; + sched.emplace_back(TID_A, TIMESTAMP_BASE, CPU_0, 0); + sched.emplace_back(TID_B, TIMESTAMP_BASE + 2, CPU_0, 0); + // Simple dup start: non-consecutive but in same output. + sched.emplace_back(TID_A, TIMESTAMP_BASE + 4, CPU_0, 0); + sched.emplace_back(TID_B, TIMESTAMP_BASE + 5, CPU_0, 4); + std::ostringstream cpu_string; + cpu_string << CPU_0; + std::string err = outfile.open_new_component(cpu_string.str()); + assert(err.empty()); + if (!outfile.write(reinterpret_cast(sched.data()), + sched.size() * sizeof(sched[0]))) + assert(false); + } + { + std::vector sched; + // More complex dup start across outputs. + sched.emplace_back(TID_B, TIMESTAMP_BASE + 1, CPU_1, 0); + sched.emplace_back(TID_C, TIMESTAMP_BASE + 3, CPU_1, 0); + sched.emplace_back(TID_A, TIMESTAMP_BASE + 6, CPU_1, 4); + std::ostringstream cpu_string; + cpu_string << CPU_1; + std::string err = outfile.open_new_component(cpu_string.str()); + assert(err.empty()); + if (!outfile.write(reinterpret_cast(sched.data()), + sched.size() * sizeof(sched[0]))) + assert(false); + } + } + + // Replay the recorded schedule. + std::vector sched_inputs; + for (int input_idx = 0; input_idx < NUM_INPUTS; input_idx++) { + memref_tid_t tid = TID_A + input_idx; + std::vector readers; + readers.emplace_back( + std::unique_ptr(new mock_reader_t(inputs[input_idx])), + std::unique_ptr(new mock_reader_t()), tid); + sched_inputs.emplace_back(std::move(readers)); + } + scheduler_t::scheduler_options_t sched_ops(scheduler_t::MAP_TO_RECORDED_OUTPUT, + scheduler_t::DEPENDENCY_TIMESTAMPS, + scheduler_t::SCHEDULER_DEFAULTS, + /*verbosity=*/4); + zipfile_istream_t infile(cpu_fname); + sched_ops.replay_as_traced_istream = &infile; + scheduler_t scheduler; + if (scheduler.init(sched_inputs, NUM_OUTPUTS, std::move(sched_ops)) != + scheduler_t::STATUS_SUCCESS) + assert(false); + auto *stream0 = scheduler.get_stream(0); + auto *stream1 = scheduler.get_stream(1); + auto check_next = [](scheduler_t::stream_t *stream, + scheduler_t::stream_status_t expect_status, + memref_tid_t expect_tid = INVALID_THREAD_ID, + trace_type_t expect_type = TRACE_TYPE_READ) { + memref_t memref; + scheduler_t::stream_status_t status = stream->next_record(memref); + if (status != expect_status) { + std::cerr << "Expected status " << expect_status << " != " << status << "\n"; + assert(false); + } + if (status == scheduler_t::STATUS_OK) { + if (memref.marker.tid != expect_tid) { + std::cerr << "Expected tid " << expect_tid << " != " << memref.marker.tid + << "\n"; + assert(false); + } + if (memref.marker.type != expect_type) { + std::cerr << "Expected type " << expect_type + << " != " << memref.marker.type << "\n"; + assert(false); + } + } + }; + // We expect the 1st of the start-at-0 TID_A to be deleted; so we should + // start with TID_B (the 2nd of the start-at-0 TID_B). + check_next(stream0, scheduler_t::STATUS_OK, TID_B, TRACE_TYPE_MARKER); + check_next(stream0, scheduler_t::STATUS_OK, TID_B, TRACE_TYPE_INSTR); + check_next(stream0, scheduler_t::STATUS_OK, TID_B, TRACE_TYPE_INSTR); + check_next(stream0, scheduler_t::STATUS_OK, TID_B, TRACE_TYPE_INSTR); + // We should have removed the 1st start-at-0 B and start with C + // on cpu 1. + check_next(stream1, scheduler_t::STATUS_OK, TID_C, TRACE_TYPE_MARKER); + check_next(stream1, scheduler_t::STATUS_OK, TID_C, TRACE_TYPE_INSTR); + check_next(stream1, scheduler_t::STATUS_OK, TID_C, TRACE_TYPE_INSTR); + check_next(stream1, scheduler_t::STATUS_OK, TID_C, TRACE_TYPE_INSTR); + check_next(stream1, scheduler_t::STATUS_OK, TID_C, TRACE_TYPE_INSTR); + check_next(stream1, scheduler_t::STATUS_OK, TID_C, TRACE_TYPE_INSTR); + check_next(stream1, scheduler_t::STATUS_OK, TID_C, TRACE_TYPE_INSTR); + check_next(stream1, scheduler_t::STATUS_OK, TID_C, TRACE_TYPE_THREAD_EXIT); + // Now cpu 0 should run A. + check_next(stream0, scheduler_t::STATUS_OK, TID_A, TRACE_TYPE_MARKER); + check_next(stream0, scheduler_t::STATUS_OK, TID_A, TRACE_TYPE_INSTR); + check_next(stream0, scheduler_t::STATUS_OK, TID_A, TRACE_TYPE_INSTR); + check_next(stream0, scheduler_t::STATUS_OK, TID_A, TRACE_TYPE_INSTR); + // Cpu 0 now finishes with B. + check_next(stream0, scheduler_t::STATUS_OK, TID_B, TRACE_TYPE_INSTR); + check_next(stream0, scheduler_t::STATUS_OK, TID_B, TRACE_TYPE_INSTR); + check_next(stream0, scheduler_t::STATUS_OK, TID_B, TRACE_TYPE_INSTR); + check_next(stream0, scheduler_t::STATUS_OK, TID_B, TRACE_TYPE_THREAD_EXIT); + check_next(stream0, scheduler_t::STATUS_IDLE); + // Cpu 1 now finishes with A. + check_next(stream1, scheduler_t::STATUS_OK, TID_A, TRACE_TYPE_INSTR); + check_next(stream1, scheduler_t::STATUS_OK, TID_A, TRACE_TYPE_INSTR); + check_next(stream1, scheduler_t::STATUS_OK, TID_A, TRACE_TYPE_INSTR); + check_next(stream1, scheduler_t::STATUS_OK, TID_A, TRACE_TYPE_THREAD_EXIT); + check_next(stream1, scheduler_t::STATUS_EOF); + // Finalize. + check_next(stream0, scheduler_t::STATUS_EOF); +#endif +} + static void test_replay_as_traced_from_file(const char *testdir) { @@ -4095,6 +4245,7 @@ test_main(int argc, const char *argv[]) test_replay_as_traced_from_file(argv[1]); test_replay_as_traced(); test_replay_as_traced_i6107_workaround(); + test_replay_as_traced_dup_start(); test_inactive(); test_direct_switch(); test_kernel_switch_sequences(); From 8b3f9246861243809e2d11696fa1160a8fdca51e Mon Sep 17 00:00:00 2001 From: Derek Bruening Date: Tue, 26 Mar 2024 16:41:32 -0400 Subject: [PATCH 07/14] i#6727: Ignore wait records in record_filter (#6730) Updates record_filter to ignore TRACE_MARKER_TYPE_CORE_WAIT records. These are artificial timing records: we do not want to output them, nor consider them real input records. Adds a unit test. Fixes #6727 --- .../tests/record_filter_unit_tests.cpp | 44 ++++++++++++++++++- .../drcachesim/tools/filter/record_filter.cpp | 6 +++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/clients/drcachesim/tests/record_filter_unit_tests.cpp b/clients/drcachesim/tests/record_filter_unit_tests.cpp index 22907ae6851..0f7dd36975a 100644 --- a/clients/drcachesim/tests/record_filter_unit_tests.cpp +++ b/clients/drcachesim/tests/record_filter_unit_tests.cpp @@ -1052,6 +1052,48 @@ test_null_filter() return true; } +static bool +test_wait_filter() +{ + // Test that wait records (artificial timing during replay) are not preserved. + constexpr addr_t TID = 5; + constexpr addr_t PC_A = 0x1234; + constexpr addr_t ENCODING_A = 0x4321; + std::vector entries = { + { { TRACE_TYPE_HEADER, 0, { 0x1 } }, true, { true } }, + { { TRACE_TYPE_MARKER, TRACE_MARKER_TYPE_VERSION, { 0x2 } }, true, { true } }, + { { TRACE_TYPE_MARKER, + TRACE_MARKER_TYPE_FILETYPE, + { OFFLINE_FILE_TYPE_ENCODINGS } }, + true, + { true } }, + { { TRACE_TYPE_THREAD, 0, { TID } }, true, { true } }, + { { TRACE_TYPE_PID, 0, { 0x5 } }, true, { true } }, + { { TRACE_TYPE_MARKER, TRACE_MARKER_TYPE_CACHE_LINE_SIZE, { 0x6 } }, + true, + { true } }, + { { TRACE_TYPE_MARKER, TRACE_MARKER_TYPE_TIMESTAMP, { 100 } }, true, { true } }, + { { TRACE_TYPE_MARKER, TRACE_MARKER_TYPE_CPU_ID, { 0 } }, true, { true } }, + { { TRACE_TYPE_ENCODING, 2, { ENCODING_A } }, true, { true } }, + { { TRACE_TYPE_INSTR, 2, { PC_A } }, true, { true } }, + // Test wait and idle records. + { { TRACE_TYPE_MARKER, TRACE_MARKER_TYPE_CORE_WAIT, { 0 } }, true, { false } }, + { { TRACE_TYPE_MARKER, TRACE_MARKER_TYPE_CORE_WAIT, { 0 } }, true, { false } }, + { { TRACE_TYPE_MARKER, TRACE_MARKER_TYPE_CORE_IDLE, { 0 } }, true, { true } }, + { { TRACE_TYPE_MARKER, TRACE_MARKER_TYPE_CORE_WAIT, { 0 } }, true, { false } }, + { { TRACE_TYPE_MARKER, TRACE_MARKER_TYPE_CORE_IDLE, { 0 } }, true, { true } }, + { { TRACE_TYPE_THREAD_EXIT, 0, { TID } }, true, { true } }, + { { TRACE_TYPE_FOOTER, 0, { 0xa2 } }, true, { true } }, + }; + std::vector> filters; + auto record_filter = std::unique_ptr( + new test_record_filter_t(std::move(filters), 0, /*write_archive=*/true)); + if (!process_entries_and_check_result(record_filter.get(), entries, 0)) + return false; + fprintf(stderr, "test_wait_filter passed\n"); + return true; +} + int test_main(int argc, const char *argv[]) { @@ -1063,7 +1105,7 @@ test_main(int argc, const char *argv[]) droption_parser_t::usage_short(DROPTION_SCOPE_ALL).c_str()); } if (!test_cache_and_type_filter() || !test_chunk_update() || !test_trim_filter() || - !test_null_filter()) + !test_null_filter() || !test_wait_filter()) return 1; fprintf(stderr, "All done!\n"); return 0; diff --git a/clients/drcachesim/tools/filter/record_filter.cpp b/clients/drcachesim/tools/filter/record_filter.cpp index 22da3ae24fc..1d2480372c5 100644 --- a/clients/drcachesim/tools/filter/record_filter.cpp +++ b/clients/drcachesim/tools/filter/record_filter.cpp @@ -533,6 +533,12 @@ record_filter_t::process_markers(per_shard_t *per_shard, trace_entry_t &entry, "supported"; } break; + case TRACE_MARKER_TYPE_CORE_WAIT: + // These are artificial timing records: do not output them, nor consider + // them real input records. + output = false; + --per_shard->input_entry_count; + break; } } return ""; From ac8c41862193e76993c38a3b954b86a5798ec05e Mon Sep 17 00:00:00 2001 From: Brett Coon Date: Tue, 26 Mar 2024 17:43:37 -0700 Subject: [PATCH 08/14] i#6681: Fix Doxygen file generation for GitHub pages. (#6724) Doxygen 1.9.8 changed the way javascript menu files are generated, by inlining much of the menu hierarchy that was previously written to a separate file per page. Updates cmake rules to handle the new javascript. Also removes extra curly braces from a doxygen page that were inadvertently triggering GitHub's Liquid template expansion and removing the intended text. This fix was verified by building the embedded doxygen files, copying them to a local dynamorio.github.io workspace, running a Jekyll server to host the pages, and comparing the local site vs. the online dynamorio.org pages. Issue: #6681 --- api/docs/CMake_rundoxygen.cmake | 34 ++++++++++++++++++++++++++++++++- api/docs/test_suite.dox | 2 +- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/api/docs/CMake_rundoxygen.cmake b/api/docs/CMake_rundoxygen.cmake index 19b2f576bba..3dc5905372b 100644 --- a/api/docs/CMake_rundoxygen.cmake +++ b/api/docs/CMake_rundoxygen.cmake @@ -256,6 +256,11 @@ if (embeddable) endforeach () # We leverage the javascript menu from the non-embedded version. + # Menu hierarchy changes: + # (1) Remove the outer "DynamoRIO" layer. + # (2) Remove home page at the end. + # (3) Insert an "API Reference" layer around API details. + # (4) Move the "Extension API" menu inside "Build Your Own Tool". file(GLOB all_js ${CMAKE_CURRENT_BINARY_DIR}/../html/*.js) set(found_user_docs OFF) foreach (js ${all_js}) @@ -286,7 +291,31 @@ if (embeddable) message(FATAL_ERROR "Cannot find menu entry for page \"Extension API\"") endif () string(REGEX MATCH "\n[^\n]+\"Extension API\"[^\n]+\n" ext_entry "${string}") - string(REPLACE "${ext_entry}" "\n" string "${string}") + # If ext_entry ends with a [, the menu items are expanded inline and the + # whole Extension API menu can be moved within this file. + string(REGEX MATCH "\\[\n" ext_multiline "${ext_entry}") + if (ext_multiline) + # Extract everything up to but not including the newly-inserted API Reference. + string(REGEX REPLACE + "(\n[^\n]+\"Extension API\",.+)(\n\\[ \"API Reference\")" + "\\2" string "${string}") + # Remember the full Extension API match. + set(ext_entry ${CMAKE_MATCH_1}) + if (NOT ext_entry) + message(FATAL_ERROR "Cannot move menu entry for \"Extension API\"") + endif () + # Now insert the Extension API menu right above Disassembly Library. + if (NOT string MATCHES "Disassembly Library") + message(FATAL_ERROR "Cannot find menu entry for page \"Disassembly Library\"") + endif () + string(REGEX REPLACE "(\n[^\n]+\"Disassembly Library)" "${ext_entry}\\1" + string "${string}") + # Set the user_docs flag since we found its contents here. + set(found_user_docs ON) + else () + # Remove the 1-line Extension API string from this file. + string(REPLACE "${ext_entry}" "\n" string "${string}") + endif () else () # Remove name so we can inline. string(REGEX REPLACE "var [^\n]* =\n" "" string "${string}") @@ -319,6 +348,9 @@ if (embeddable) if (js MATCHES "page_user_docs.js") # CMake 3.6+ guarantees the glob is sorted lexicographically, so we've already # seen navtreedata.js. + if (found_user_docs) + message(FATAL_ERROR "Found unexpected \"page_user_docs\" menu file") + endif () set(found_user_docs ON) if (ext_entry) if (NOT string MATCHES "Disassembly Library") diff --git a/api/docs/test_suite.dox b/api/docs/test_suite.dox index c6f6e396ca7..0d1d2927f0c 100644 --- a/api/docs/test_suite.dox +++ b/api/docs/test_suite.dox @@ -94,7 +94,7 @@ failure email step". Be sure to match the surrounding indentation as indentation matters for .yml files. - name: Setup tmate session - if: ${{ failure() }} + if: failure() uses: mxschmitt/action-tmate@v3 Next, delete all the other workflow files in the ".github/workflows/" directory. From 7874be6cbdd4373422a6c6ed8702496a8ec673c6 Mon Sep 17 00:00:00 2001 From: Derek Bruening Date: Wed, 27 Mar 2024 00:56:47 -0400 Subject: [PATCH 09/14] i#6721: Read ahead in as-traced drmemtrace mode (#6722) Removes the exception for avoiding reading ahead to get the version and filetype for as-traced drmemtrace mode, as we need those values for the record_filter. Adds explicit error checking and error return up front to the record_filter for missing version info. Adjusts the scheduler unit test's record ordinal to account for the new read-ahead. Adds a test with a checked-in trace of hello,world (truncated to make it smaller) that ran on 4 different cores. The test only reproduces the problem if the read-ahead in open_reader() to find the tid is removed, which I did temporarily; I kept the test as it is also a good additional general test of other corner cases. To create a test that always reproduces in our suite we would need to combine a synthetic reader with use of the scheduler in as-traced mode, which none of our unit tests are set up for. The fix was further tested on large inputs in an internal setup which always passes a synthetic reader, where the problem reproduces every time without the fix. Fixes #6721 --- clients/drcachesim/scheduler/scheduler.cpp | 15 ++++++++----- .../cpu_schedule.bin.zip | Bin 0 -> 422 bytes ...memtrace.simple_app.1674735.1533.trace.zip | Bin 0 -> 161455 bytes .../serial_schedule.bin.gz | Bin 0 -> 37 bytes .../tests/record_filter_start_idle.templatex | 7 ++++++ .../drcachesim/tests/scheduler_unit_tests.cpp | 5 ++++- .../drcachesim/tools/filter/record_filter.cpp | 21 ++++++++++++++++++ suite/tests/CMakeLists.txt | 18 +++++++++++++++ 8 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 clients/drcachesim/tests/drmemtrace.as_traced.x64.tracedir/cpu_schedule.bin.zip create mode 100644 clients/drcachesim/tests/drmemtrace.as_traced.x64.tracedir/drmemtrace.simple_app.1674735.1533.trace.zip create mode 100644 clients/drcachesim/tests/drmemtrace.as_traced.x64.tracedir/serial_schedule.bin.gz create mode 100644 clients/drcachesim/tests/record_filter_start_idle.templatex diff --git a/clients/drcachesim/scheduler/scheduler.cpp b/clients/drcachesim/scheduler/scheduler.cpp index b8b918d9de2..2caa4e95635 100644 --- a/clients/drcachesim/scheduler/scheduler.cpp +++ b/clients/drcachesim/scheduler/scheduler.cpp @@ -809,10 +809,6 @@ scheduler_tmpl_t::set_initial_schedule( // The filetype, if present, is before the first timestamp. If we only need the // filetype we avoid going as far as the timestamp. bool gather_filetype = options_.read_inputs_in_init; - // Avoid reading ahead for replay as it makes the input ords not match in tests. - if (options_.mapping == MAP_TO_RECORDED_OUTPUT && - options_.replay_as_traced_istream != nullptr) - gather_filetype = false; if (gather_filetype || gather_timestamps) { sched_type_t::scheduler_status_t res = get_initial_input_content(gather_timestamps); @@ -1043,7 +1039,11 @@ scheduler_tmpl_t::read_recorded_schedule() } for (int i = 0; i < static_cast(outputs_.size()); ++i) { if (outputs_[i].record.empty()) { + // XXX i#6630: We should auto-set the output count and avoid + // having extra outputs; these complicate idle computations, etc. + VPRINT(this, 1, "output %d empty: returning eof up front\n", i); set_cur_input(i, INVALID_INPUT_ORDINAL); + outputs_[i].at_eof = true; } else if (outputs_[i].record[0].type == schedule_record_t::IDLE) { set_cur_input(i, INVALID_INPUT_ORDINAL); outputs_[i].waiting = true; @@ -1205,8 +1205,13 @@ scheduler_tmpl_t::read_traced_schedule() outputs_[output_idx].record[0].key.input); set_cur_input(output_idx, outputs_[output_idx].record[0].key.input); } - } else + } else { + // XXX i#6630: We should auto-set the output count and avoid + // having extra ouputs; these complicate idle computations, etc. + VPRINT(this, 1, "Output %d empty: returning eof up front\n", output_idx); + outputs_[output_idx].at_eof = true; set_cur_input(output_idx, INVALID_INPUT_ORDINAL); + } } return STATUS_SUCCESS; } diff --git a/clients/drcachesim/tests/drmemtrace.as_traced.x64.tracedir/cpu_schedule.bin.zip b/clients/drcachesim/tests/drmemtrace.as_traced.x64.tracedir/cpu_schedule.bin.zip new file mode 100644 index 0000000000000000000000000000000000000000..08a5225c8d7b4ac68d2c3d4b65d7b1b52ce5059f GIT binary patch literal 422 zcmWIWW@Zs#U|`??Vg`mni9*~Y15(*D0nOoS(IR%VMr+reu|vgZRZ=td z3Stu?dDG{A-t(U4Ij@uPyRQ5G<#(TRC!hQKy{?;)-gPq8YuBz(5uewtxlFK(1+rYb zcEjr0H5y{<>=x+bDJDVun|c}f#%!ulEyE?9gxU3bbjrY{GPj*(79wHoj+qI|)1m%* zl8hv#vDJ@Nlgc^n_PpH+*u0yL?)Y}lSZRQ^;9ZuA6!VTazis`UMT@2H&fT}nSSjuA z#wPkNLatY>kLI_!7NYXUe%Z}h?dC%FX3)W>_}$2{Y1hK=vHV0%=i!Hk?e9x^kM3p$ ztFMM~={fOTh%uIYj3iUSE>**c>FixVzSZ{nL1>o5BZS}M{RRMSL76%A@~irG4fVV{IBeyX z_3Zo4<&$$!7554oOg48m#hE#3TCA4|Jq(K4A)7 zcqZ9oXwSO^6NYSPiwyAig}##xfmTxBF3to(TsK4Mmp>o#rVv#7zaHK{ZVZl2b~b

6~2s6}C~B%I#H=Z&kG-^`EN}bp=F> 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

s!GP|vmJz5!7){d`z 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

M1-Qm}zK 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 z 1257604 @ <366987,87875,13331862029895453> " - "(<366986,87875,13331862029895453> => <1,0,0>) \n" + // The ordinal is really 1 ("<1,0,0>") but with the scheduler's readahead + // it becomes 2; easier to just check for that as trying to avoid readahead + // causes other problems with start-idle cores (i#6721). + "(<366986,87875,13331862029895453> => <2,0,0>) \n" "Core #4: 1257600 \nCore #5: 1257596 \nCore #6: 1257602 \n"; static constexpr int NUM_OUTPUTS = 7; // Matches the actual trace's core footprint. scheduler_t scheduler; diff --git a/clients/drcachesim/tools/filter/record_filter.cpp b/clients/drcachesim/tools/filter/record_filter.cpp index 1d2480372c5..af6add154ca 100644 --- a/clients/drcachesim/tools/filter/record_filter.cpp +++ b/clients/drcachesim/tools/filter/record_filter.cpp @@ -208,6 +208,10 @@ record_filter_t::initialize_shard_output(per_shard_t *per_shard, // Now synchronize determining the extension. auto lock = std::unique_lock(input_info_mutex_); if (!output_ext_.empty()) { + VPRINT(this, 2, + "Shard #%d using pre-set ext=%s, ver=%" PRIu64 ", type=%" PRIu64 "\n", + shard_stream->get_shard_index(), output_ext_.c_str(), version_, + filetype_); per_shard->output_path += output_ext_; lock.unlock(); } else if (!input_name.empty()) { @@ -218,12 +222,25 @@ record_filter_t::initialize_shard_output(per_shard_t *per_shard, // Set the other key input data. version_ = shard_stream->get_version(); filetype_ = add_to_filetype(shard_stream->get_filetype()); + if (version_ == 0) { + // We give up support for version 0 to have an up-front error check + // rather than having some output files with bad headers (i#6721). + return "Version not available at shard init time"; + } + VPRINT(this, 2, + "Shard #%d setting ext=%s, ver=%" PRIu64 ", type=%" PRIu64 "\n", + shard_stream->get_shard_index(), output_ext_.c_str(), version_, + filetype_); per_shard->output_path += output_ext_; lock.unlock(); input_info_cond_var_.notify_all(); } else { // We have to wait for another shard with an input to set output_ext_. input_info_cond_var_.wait(lock, [this] { return !output_ext_.empty(); }); + VPRINT(this, 2, + "Shard #%d waited for ext=%s, ver=%" PRIu64 ", type=%" PRIu64 "\n", + shard_stream->get_shard_index(), output_ext_.c_str(), version_, + filetype_); per_shard->output_path += output_ext_; lock.unlock(); } @@ -649,6 +666,10 @@ record_filter_t::process_delayed_encodings(per_shard_t *per_shard, trace_entry_t bool record_filter_t::parallel_shard_memref(void *shard_data, const trace_entry_t &input_entry) { + if (!success_) { + // Report an error that happened during shard init. + return false; + } per_shard_t *per_shard = reinterpret_cast(shard_data); ++per_shard->input_entry_count; trace_entry_t entry = input_entry; diff --git a/suite/tests/CMakeLists.txt b/suite/tests/CMakeLists.txt index 16e49335c25..2d9b08d7947 100644 --- a/suite/tests/CMakeLists.txt +++ b/suite/tests/CMakeLists.txt @@ -4696,6 +4696,24 @@ if (BUILD_CLIENTS) set(tool.record_filter_as_traced_basedir "${PROJECT_SOURCE_DIR}/clients/drcachesim/tests") set(tool.record_filter_as_traced_rawtemp ON) # no preprocessor + + # Test the record_filter in as-traced mode with start-idle cores. + # This checked-in partial-hello,world-trace ran on 4 different cores. + set(trace_dir + "${PROJECT_SOURCE_DIR}/clients/drcachesim/tests/drmemtrace.as_traced.x64.tracedir") + set(sched_file "${trace_dir}/cpu_schedule.bin.zip") + set(outdir ${CMAKE_CURRENT_BINARY_DIR}/filter_start_idle) + file(MAKE_DIRECTORY ${outdir}) + torunonly_api(tool.record_filter_start_idle "${drcachesim_path}" + "record_filter_start_idle" + "" "-simulator_type;schedule_stats;-indir;${outdir}" OFF OFF) + set(tool.record_filter_start_idle_runcmp "${CMAKE_CURRENT_SOURCE_DIR}/runmulti.cmake") + set(tool.record_filter_start_idle_precmd + "${drcachesim_path}@-simulator_type@record_filter@-cpu_schedule_file@${sched_file}@-core_sharded@-cores@4@-indir@${trace_dir}@-outdir@${outdir}") + set(tool.record_filter_start_idle_basedir + "${PROJECT_SOURCE_DIR}/clients/drcachesim/tests") + set(tool.record_filter_start_idle_rawtemp ON) # no preprocessor + endif () if (AARCH64) From c12310783ff175201ad1bfd1c88e0fc636537525 Mon Sep 17 00:00:00 2001 From: Derek Bruening Date: Wed, 27 Mar 2024 11:25:54 -0400 Subject: [PATCH 10/14] i#6599: Relax WOW64 drmemtrace syscall invariant (#6732) Relaxes a drmemtrace syscall invariant for WOW64 where raw2trace delays the "syscall" call across the 2nd set of timestamp;cpuid markers, breaking the drmemtrace invariant checker. A full solution requires #5949 to actually identify the syscall as such: the relaxations for this and prior changes are marked under that issue and will be removed when it is addressed, so we can consider #6599 closed. Tested manually on WOW64 where the tool.record_filter and tool.record_filter_bycore_uni tests fail reliably without this fix and pass with it. Removes several ignore-list entries added in the past for this issue. Issue: #5949, #6599 Fixes #6599 --- clients/drcachesim/tools/invariant_checker.cpp | 4 ++++ suite/runsuite_wrapper.pl | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/clients/drcachesim/tools/invariant_checker.cpp b/clients/drcachesim/tools/invariant_checker.cpp index 16eef9e1f27..137d865efc1 100644 --- a/clients/drcachesim/tools/invariant_checker.cpp +++ b/clients/drcachesim/tools/invariant_checker.cpp @@ -421,6 +421,9 @@ invariant_checker_t::parallel_shard_memref(void *shard_data, const memref_t &mem } #endif shard->expect_syscall_marker_ = false; + // TODO i#5949,i#6599: On WOW64 the "syscall" call is delayed by raw2trace + // acros the 2nd timestamp+cpuid; we disable this check until that is solved. +#if !defined(WINDOWS) || defined(X64) // We expect an immediately preceding timestamp + cpuid. if (shard->trace_version_ >= TRACE_ENTRY_VERSION_FREQUENT_TIMESTAMPS) { report_if_false( @@ -432,6 +435,7 @@ invariant_checker_t::parallel_shard_memref(void *shard_data, const memref_t &mem TRACE_MARKER_TYPE_TIMESTAMP, "Syscall marker not preceded by timestamp + cpuid"); } +#endif } if (memref.marker.type == TRACE_TYPE_MARKER && memref.marker.marker_type == TRACE_MARKER_TYPE_MAYBE_BLOCKING_SYSCALL) { diff --git a/suite/runsuite_wrapper.pl b/suite/runsuite_wrapper.pl index e9135e9331c..aa8ee95a113 100755 --- a/suite/runsuite_wrapper.pl +++ b/suite/runsuite_wrapper.pl @@ -246,10 +246,6 @@ 'code_api,thread_private,disable_traces|common.decode-stress' => 1, # i#1807 'code_api,thread_private,tracedump_binary|common.decode-stress' => 1, # i#1807 'code_api|client.file_io' => 1, # i#5802 - 'code_api|tool.drcacheoff.windows-invar' => 1, # i#6599 - 'code_api|tool.drcacheoff.invariant_checker' => 1, # i#6599 - 'code_api|tool.drcacheoff.getretaddr_record_replace_retaddr' => 1, # i#6599 - 'code_api|tool.record_filter' => 1, # i#6599 ); %ignore_failures_64 = ( From ea2bf8cc43597ee4987badadd74aa76293bac64c Mon Sep 17 00:00:00 2001 From: Derek Bruening Date: Wed, 27 Mar 2024 11:26:19 -0400 Subject: [PATCH 11/14] i#6081 cb assert: Ignore win32 drcacheoff.windows-timestamps failures (#6737) To get the post-merge suite green, we ignore failures in the code_api|tool.drcacheoff.windows-timestamps test on win32. That is a lower priority platform and there are just not enough maintainers for that platform to chase down these issues at this time. Issue: #6081 --- suite/runsuite_wrapper.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/suite/runsuite_wrapper.pl b/suite/runsuite_wrapper.pl index aa8ee95a113..d0fa7d32958 100755 --- a/suite/runsuite_wrapper.pl +++ b/suite/runsuite_wrapper.pl @@ -222,6 +222,7 @@ 'code_api|tool.drcacheoff.burst_traceopts' => 1, # i#4622 'code_api|tool.drcacheoff.burst_replaceall' => 1, # i#4622 'code_api|tool.drcacheoff.burst_static' => 1, # i#4486 + 'code_api|tool.drcacheoff.windows-timestamps' => 1, # i#6081 'code_api|api.symtest' => 1, # i#4131 'code_api|client.drwrap-test-detach' => 1, # i#4616 'code_api|client.cbr4' => 1, # i#4792 From d20abf46367b22cf2430efa140f4ec1aaeb29a19 Mon Sep 17 00:00:00 2001 From: Derek Bruening Date: Wed, 27 Mar 2024 13:50:25 -0400 Subject: [PATCH 12/14] i#6726 replay cpuid: Sort as-traced outputs by cpuid (#6729) Currently, in as-traced mode the output streams are assigned to the cores in the as-traced schedule file in file order. But that order is essentially random, which scrambles key arrangements like which core is on which socket. Here we sort by the recorded cpuid to recreate the same cpuid order as before. Adds a unit test. Also tested on larger cases with > 100 cores. Issue: #6726 --- clients/drcachesim/scheduler/scheduler.cpp | 106 ++++++++++++------ .../drcachesim/tests/scheduler_unit_tests.cpp | 98 +++++++++++++++- .../tests/simulate_as_traced.templatex | 96 ++++++++-------- 3 files changed, 211 insertions(+), 89 deletions(-) diff --git a/clients/drcachesim/scheduler/scheduler.cpp b/clients/drcachesim/scheduler/scheduler.cpp index 2caa4e95635..49b36a4559c 100644 --- a/clients/drcachesim/scheduler/scheduler.cpp +++ b/clients/drcachesim/scheduler/scheduler.cpp @@ -1081,8 +1081,9 @@ scheduler_tmpl_t::read_traced_schedule() tid2input[inputs_[i].tid] = i; } std::vector> start2stop(inputs_.size()); - // We number the outputs according to their order in the file. - // XXX i#5843: Should we support some direction from the user on this? Simulation + // We initially number the outputs according to their order in the file, and then + // sort by the stored cpuid below. + // XXX i#6726: Should we support some direction from the user on this? Simulation // may want to preserve the NUMA relationships and may need to set up its simulated // cores at init time, so it would prefer to partition by output stream identifier. // Maybe we could at least add the proposed memtrace_stream_t query for cpuid and @@ -1094,9 +1095,13 @@ scheduler_tmpl_t::read_traced_schedule() std::vector> all_sched(outputs_.size()); // Work around i#6107 by tracking counts sorted by timestamp for each input. std::vector> input_sched(inputs_.size()); + // These hold entries added in the on-disk (unsorted) order. + std::vector disk_ord2index; // Initially [i] holds i. + std::vector disk_ord2cpuid; // [i] holds cpuid for entry i. while (options_.replay_as_traced_istream->read(reinterpret_cast(&entry), sizeof(entry))) { if (entry.cpu != cur_cpu) { + // This is a zipfile component boundary: one conmponent per cpu. if (cur_cpu != std::numeric_limits::max()) { ++cur_output; if (cur_output >= static_cast(outputs_.size())) { @@ -1105,9 +1110,8 @@ scheduler_tmpl_t::read_traced_schedule() } } cur_cpu = entry.cpu; - VPRINT(this, 1, "Output #%d is as-traced CPU #%" PRId64 "\n", cur_output, - cur_cpu); - outputs_[cur_output].as_traced_cpuid = cur_cpu; + disk_ord2cpuid.push_back(cur_cpu); + disk_ord2index.push_back(cur_output); } input_ordinal_t input = tid2input[entry.thread]; // We'll fill in the stop ordinal in our second pass below. @@ -1135,16 +1139,49 @@ scheduler_tmpl_t::read_traced_schedule() res = remove_zero_instruction_segments(input_sched, all_sched); if (res != sched_type_t::STATUS_SUCCESS) return res; - for (int output_idx = 0; output_idx < static_cast(outputs_.size()); - ++output_idx) { + // Sort by cpuid to get a more natural ordering. + // Probably raw2trace should do this in the first place, but we have many + // schedule files already out there so we still need a sort here. + // If we didn't have cross-indices pointing at all_sched from input_sched, we + // would just sort all_sched: but instead we have to construct a separate + // ordering structure. + std::sort(disk_ord2index.begin(), disk_ord2index.end(), + [disk_ord2cpuid](const output_ordinal_t &l, const output_ordinal_t &r) { + return disk_ord2cpuid[l] < disk_ord2cpuid[r]; + }); + // disk_ord2index[i] used to hold i; now after sorting it holds the ordinal in + // the disk file that has the ith largest cpuid. We need to turn that into + // the output_idx ordinal for the cpu at ith ordinal in the disk file, for + // which we use a new vector disk_ord2output. + // E.g., if the original file was in this order disk_ord2cpuid = {6,2,3,7}, + // disk_ord2index after sorting would hold {1,2,0,3}, which we want to turn + // into disk_ord2output = {2,0,1,3}. + std::vector disk_ord2output(disk_ord2index.size()); + for (size_t i = 0; i < disk_ord2index.size(); ++i) { + disk_ord2output[disk_ord2index[i]] = static_cast(i); + } + for (int disk_idx = 0; disk_idx < static_cast(outputs_.size()); + ++disk_idx) { + if (disk_idx >= static_cast(disk_ord2index.size())) { + // XXX i#6630: We should auto-set the output count and avoid + // having extra ouputs; these complicate idle computations, etc. + VPRINT(this, 1, "Output %d empty: returning eof up front\n", disk_idx); + outputs_[disk_idx].at_eof = true; + set_cur_input(disk_idx, INVALID_INPUT_ORDINAL); + continue; + } + output_ordinal_t output_idx = disk_ord2output[disk_idx]; VPRINT(this, 1, "Read %zu as-traced records for output #%d\n", - all_sched[output_idx].size(), output_idx); + all_sched[disk_idx].size(), output_idx); + outputs_[output_idx].as_traced_cpuid = disk_ord2cpuid[disk_idx]; + VPRINT(this, 1, "Output #%d is as-traced CPU #%" PRId64 "\n", output_idx, + outputs_[output_idx].as_traced_cpuid); // Update the stop_instruction field and collapse consecutive entries while // inserting into the final location. int start_consec = -1; - for (int sched_idx = 0; - sched_idx < static_cast(all_sched[output_idx].size()); ++sched_idx) { - auto &segment = all_sched[output_idx][sched_idx]; + for (int sched_idx = 0; sched_idx < static_cast(all_sched[disk_idx].size()); + ++sched_idx) { + auto &segment = all_sched[disk_idx][sched_idx]; if (!segment.valid) continue; auto find = start2stop[segment.input].find(segment.start_instruction); @@ -1158,27 +1195,27 @@ scheduler_tmpl_t::read_traced_schedule() " time=%" PRId64 "\n", sched_idx, segment.input, segment.start_instruction, segment.stop_instruction, segment.timestamp); - if (sched_idx + 1 < static_cast(all_sched[output_idx].size()) && - segment.input == all_sched[output_idx][sched_idx + 1].input && + if (sched_idx + 1 < static_cast(all_sched[disk_idx].size()) && + segment.input == all_sched[disk_idx][sched_idx + 1].input && segment.stop_instruction > - all_sched[output_idx][sched_idx + 1].start_instruction) { + all_sched[disk_idx][sched_idx + 1].start_instruction) { // A second sanity check. error_string_ = "Invalid decreasing start field in schedule file"; return STATUS_ERROR_INVALID_PARAMETER; - } else if (sched_idx + 1 < static_cast(all_sched[output_idx].size()) && - segment.input == all_sched[output_idx][sched_idx + 1].input && + } else if (sched_idx + 1 < static_cast(all_sched[disk_idx].size()) && + segment.input == all_sched[disk_idx][sched_idx + 1].input && segment.stop_instruction == - all_sched[output_idx][sched_idx + 1].start_instruction) { + all_sched[disk_idx][sched_idx + 1].start_instruction) { // Collapse into next. if (start_consec == -1) start_consec = sched_idx; } else { schedule_output_tracker_t &toadd = start_consec >= 0 - ? all_sched[output_idx][start_consec] - : all_sched[output_idx][sched_idx]; + ? all_sched[disk_idx][start_consec] + : all_sched[disk_idx][sched_idx]; outputs_[output_idx].record.emplace_back( schedule_record_t::DEFAULT, toadd.input, toadd.start_instruction, - all_sched[output_idx][sched_idx].stop_instruction, toadd.timestamp); + all_sched[disk_idx][sched_idx].stop_instruction, toadd.timestamp); start_consec = -1; VDO(this, 3, { auto &added = outputs_[output_idx].record.back(); @@ -1193,24 +1230,19 @@ scheduler_tmpl_t::read_traced_schedule() } VPRINT(this, 1, "Collapsed duplicates for %zu as-traced records for output #%d\n", outputs_[output_idx].record.size(), output_idx); - if (!outputs_[output_idx].record.empty()) { - if (outputs_[output_idx].record[0].value.start_instruction != 0) { - VPRINT(this, 1, "Initial input for output #%d is: wait state\n", - output_idx); - set_cur_input(output_idx, INVALID_INPUT_ORDINAL); - outputs_[output_idx].waiting = true; - outputs_[output_idx].record_index = -1; - } else { - VPRINT(this, 1, "Initial input for output #%d is %d\n", output_idx, - outputs_[output_idx].record[0].key.input); - set_cur_input(output_idx, outputs_[output_idx].record[0].key.input); - } - } else { - // XXX i#6630: We should auto-set the output count and avoid - // having extra ouputs; these complicate idle computations, etc. - VPRINT(this, 1, "Output %d empty: returning eof up front\n", output_idx); - outputs_[output_idx].at_eof = true; + if (outputs_[output_idx].record.empty()) { + error_string_ = "Empty as-traced schedule"; + return STATUS_ERROR_INVALID_PARAMETER; + } + if (outputs_[output_idx].record[0].value.start_instruction != 0) { + VPRINT(this, 1, "Initial input for output #%d is: wait state\n", output_idx); set_cur_input(output_idx, INVALID_INPUT_ORDINAL); + outputs_[output_idx].waiting = true; + outputs_[output_idx].record_index = -1; + } else { + VPRINT(this, 1, "Initial input for output #%d is %d\n", output_idx, + outputs_[output_idx].record[0].key.input); + set_cur_input(output_idx, outputs_[output_idx].record[0].key.input); } } return STATUS_SUCCESS; diff --git a/clients/drcachesim/tests/scheduler_unit_tests.cpp b/clients/drcachesim/tests/scheduler_unit_tests.cpp index d42678d1816..54d6fc32993 100644 --- a/clients/drcachesim/tests/scheduler_unit_tests.cpp +++ b/clients/drcachesim/tests/scheduler_unit_tests.cpp @@ -3410,6 +3410,94 @@ test_replay_as_traced_dup_start() #endif } +static void +test_replay_as_traced_sort() +{ +#ifdef HAS_ZIP + // Test that outputs have the cpuids in sorted order. + std::cerr << "\n----------------\nTesting replay as-traced sorting\n"; + + static constexpr int NUM_INPUTS = 4; + static constexpr int NUM_OUTPUTS = NUM_INPUTS; // Required to be equal. + static constexpr int NUM_INSTRS = 2; + static constexpr memref_tid_t TID_BASE = 100; + static constexpr addr_t PC_BASE = 1000; + // Our unsorted cpuid order in the file. + static const std::vector CPUIDS = { 42, 7, 56, 3 }; + // Index into CPUIDS if sorted. + static const std::vector INDICES = { 3, 1, 0, 2 }; + static constexpr uint64_t TIMESTAMP_BASE = 100; + + std::vector inputs[NUM_INPUTS]; + for (int input_idx = 0; input_idx < NUM_INPUTS; input_idx++) { + memref_tid_t tid = TID_BASE + input_idx; + inputs[input_idx].push_back(make_thread(tid)); + inputs[input_idx].push_back(make_pid(1)); + // These timestamps do not line up with the schedule file but + // that does not cause problems and leaving it this way + // simplifies the testdata construction. + inputs[input_idx].push_back(make_timestamp(TIMESTAMP_BASE)); + inputs[input_idx].push_back( + make_marker(TRACE_MARKER_TYPE_CPU_ID, CPUIDS[input_idx])); + for (int instr_idx = 0; instr_idx < NUM_INSTRS; ++instr_idx) { + inputs[input_idx].push_back(make_instr(PC_BASE + instr_idx)); + } + inputs[input_idx].push_back(make_exit(tid)); + } + + // Synthesize a cpu-schedule file with unsorted entries (see CPUIDS above). + std::string cpu_fname = "tmp_test_cpu_i6721.zip"; + { + zipfile_ostream_t outfile(cpu_fname); + for (int i = 0; i < NUM_OUTPUTS; ++i) { + std::vector sched; + sched.emplace_back(TID_BASE + i, TIMESTAMP_BASE, CPUIDS[i], 0); + std::ostringstream cpu_string; + cpu_string << CPUIDS[i]; + std::string err = outfile.open_new_component(cpu_string.str()); + assert(err.empty()); + if (!outfile.write(reinterpret_cast(sched.data()), + sched.size() * sizeof(sched[0]))) + assert(false); + } + } + + // Replay the recorded schedule. + std::vector sched_inputs; + for (int i = 0; i < NUM_INPUTS; i++) { + memref_tid_t tid = TID_BASE + i; + std::vector readers; + readers.emplace_back(std::unique_ptr(new mock_reader_t(inputs[i])), + std::unique_ptr(new mock_reader_t()), tid); + sched_inputs.emplace_back(std::move(readers)); + } + scheduler_t::scheduler_options_t sched_ops(scheduler_t::MAP_TO_RECORDED_OUTPUT, + scheduler_t::DEPENDENCY_TIMESTAMPS, + scheduler_t::SCHEDULER_DEFAULTS, + /*verbosity=*/4); + zipfile_istream_t infile(cpu_fname); + sched_ops.replay_as_traced_istream = &infile; + scheduler_t scheduler; + if (scheduler.init(sched_inputs, NUM_OUTPUTS, std::move(sched_ops)) != + scheduler_t::STATUS_SUCCESS) + assert(false); + for (int i = 0; i < NUM_OUTPUTS; ++i) { + auto *stream = scheduler.get_stream(i); + memref_t memref; + scheduler_t::stream_status_t status = stream->next_record(memref); + if (status == scheduler_t::STATUS_OK) { + assert(memref.marker.tid == TID_BASE + INDICES[i]); + if (memref.marker.type == TRACE_TYPE_MARKER && + memref.marker.marker_type == TRACE_MARKER_TYPE_CPU_ID) { + assert(static_cast(memref.marker.marker_value) == + CPUIDS[INDICES[i]]); + } + } else + assert(status == scheduler_t::STATUS_EOF); + } +#endif +} + static void test_replay_as_traced_from_file(const char *testdir) { @@ -3420,14 +3508,15 @@ test_replay_as_traced_from_file(const char *testdir) std::string(testdir) + "/drmemtrace.threadsig.x64.tracedir/cpu_schedule.bin.zip"; // This checked-in trace has 8 threads on 7 cores. It doesn't have // much thread migration but our synthetic test above covers that. + // The outputs use the stored cores sorted by cpuid. static const char *const SCHED_STRING = - "Core #0: 1257598 \nCore #1: 1257603 \nCore #2: 1257601 \n" - "Core #3: 1257599 => 1257604 @ <366987,87875,13331862029895453> " + "Core #0: 1257602 \nCore #1: 1257600 \n" + "Core #2: 1257599 => 1257604 @ <366987,87875,13331862029895453> " // The ordinal is really 1 ("<1,0,0>") but with the scheduler's readahead // it becomes 2; easier to just check for that as trying to avoid readahead - // causes other problems with start-idle cores (i#6721). + // causes other problems (i#xxxx). "(<366986,87875,13331862029895453> => <2,0,0>) \n" - "Core #4: 1257600 \nCore #5: 1257596 \nCore #6: 1257602 \n"; + "Core #3: 1257596 \nCore #4: 1257603 \nCore #5: 1257601 \nCore #6: 1257598 \n"; static constexpr int NUM_OUTPUTS = 7; // Matches the actual trace's core footprint. scheduler_t scheduler; std::vector sched_inputs; @@ -4249,6 +4338,7 @@ test_main(int argc, const char *argv[]) test_replay_as_traced(); test_replay_as_traced_i6107_workaround(); test_replay_as_traced_dup_start(); + test_replay_as_traced_sort(); test_inactive(); test_direct_switch(); test_kernel_switch_sequences(); diff --git a/clients/drcachesim/tests/simulate_as_traced.templatex b/clients/drcachesim/tests/simulate_as_traced.templatex index 464b1cb3dcd..3a166565aac 100644 --- a/clients/drcachesim/tests/simulate_as_traced.templatex +++ b/clients/drcachesim/tests/simulate_as_traced.templatex @@ -1,42 +1,27 @@ Cache simulation results: -Core #0 \(traced CPU\(s\): #11\) +Core #0 \(traced CPU\(s\): #0\) L1I0 \(size=32768, assoc=8, block=64, LRU\) stats: - Hits: *88.?342 - Misses: 52 - Compulsory misses: 52 - Invalidations: 0 - Miss rate: 0.06% - L1D0 \(size=32768, assoc=8, block=64, LRU\) stats: - Hits: *188.?235 - Misses: 33 - Compulsory misses: 61 - Invalidations: 0 - Prefetch hits: 5 - Prefetch misses: 28 - Miss rate: 0.02% -Core #1 \(traced CPU\(s\): #9\) - L1I1 \(size=32768, assoc=8, block=64, LRU\) stats: - Hits: *94.?091 + Hits: *94.?083 Misses: 68 Compulsory misses: 68 Invalidations: 0 Miss rate: 0.07% - L1D1 \(size=32768, assoc=8, block=64, LRU\) stats: - Hits: *200.?175 + L1D0 \(size=32768, assoc=8, block=64, LRU\) stats: + Hits: *200.?172 Misses: 40 Compulsory misses: 70 Invalidations: 0 Prefetch hits: 10 Prefetch misses: 30 Miss rate: 0.02% -Core #2 \(traced CPU\(s\): #10\) - L1I2 \(size=32768, assoc=8, block=64, LRU\) stats: +Core #1 \(traced CPU\(s\): #1\) + L1I1 \(size=32768, assoc=8, block=64, LRU\) stats: Hits: *94.?076 Misses: 66 Compulsory misses: 66 Invalidations: 0 Miss rate: 0.07% - L1D2 \(size=32768, assoc=8, block=64, LRU\) stats: + L1D1 \(size=32768, assoc=8, block=64, LRU\) stats: Hits: *200.?168 Misses: 38 Compulsory misses: 67 @@ -44,14 +29,14 @@ Core #2 \(traced CPU\(s\): #10\) Prefetch hits: 9 Prefetch misses: 29 Miss rate: 0.02% -Core #3 \(traced CPU\(s\): #5\) - L1I3 \(size=32768, assoc=8, block=64, LRU\) stats: +Core #2 \(traced CPU\(s\): #5\) + L1I2 \(size=32768, assoc=8, block=64, LRU\) stats: Hits: *188.?232 Misses: 68 Compulsory misses: 68 Invalidations: 0 Miss rate: 0.04% - L1D3 \(size=32768, assoc=8, block=64, LRU\) stats: + L1D2 \(size=32768, assoc=8, block=64, LRU\) stats: Hits: *400.?362 Misses: 59 Compulsory misses: 105 @@ -59,29 +44,14 @@ Core #3 \(traced CPU\(s\): #5\) Prefetch hits: 13 Prefetch misses: 46 Miss rate: 0.01% -Core #4 \(traced CPU\(s\): #1\) - L1I4 \(size=32768, assoc=8, block=64, LRU\) stats: - Hits: *94.?076 - Misses: 66 - Compulsory misses: 66 - Invalidations: 0 - Miss rate: 0.07% - L1D4 \(size=32768, assoc=8, block=64, LRU\) stats: - Hits: *200.?168 - Misses: 38 - Compulsory misses: 67 - Invalidations: 0 - Prefetch hits: 9 - Prefetch misses: 29 - Miss rate: 0.02% -Core #5 \(traced CPU\(s\): #8\) - L1I5 \(size=32768, assoc=8, block=64, LRU\) stats: +Core #3 \(traced CPU\(s\): #8\) + L1I3 \(size=32768, assoc=8, block=64, LRU\) stats: Hits: *29.?568 Misses: 587 Compulsory misses: 575 Invalidations: 0 Miss rate: 1.95% - L1D5 \(size=32768, assoc=8, block=64, LRU\) stats: + L1D3 \(size=32768, assoc=8, block=64, LRU\) stats: Hits: *12.?893 Misses: 458 Compulsory misses: 717 @@ -89,21 +59,51 @@ Core #5 \(traced CPU\(s\): #8\) Prefetch hits: 106 Prefetch misses: 352 Miss rate: 3.43% -Core #6 \(traced CPU\(s\): #0\) - L1I6 \(size=32768, assoc=8, block=64, LRU\) stats: - Hits: *94.?083 +Core #4 \(traced CPU\(s\): #9\) + L1I4 \(size=32768, assoc=8, block=64, LRU\) stats: + Hits: *94.?091 Misses: 68 Compulsory misses: 68 Invalidations: 0 Miss rate: 0.07% - L1D6 \(size=32768, assoc=8, block=64, LRU\) stats: - Hits: *200.?172 + L1D4 \(size=32768, assoc=8, block=64, LRU\) stats: + Hits: *200.?175 Misses: 40 Compulsory misses: 70 Invalidations: 0 Prefetch hits: 10 Prefetch misses: 30 Miss rate: 0.02% +Core #5 \(traced CPU\(s\): #10\) + L1I5 \(size=32768, assoc=8, block=64, LRU\) stats: + Hits: *94.?076 + Misses: 66 + Compulsory misses: 66 + Invalidations: 0 + Miss rate: 0.07% + L1D5 \(size=32768, assoc=8, block=64, LRU\) stats: + Hits: *200.?168 + Misses: 38 + Compulsory misses: 67 + Invalidations: 0 + Prefetch hits: 9 + Prefetch misses: 29 + Miss rate: 0.02% +Core #6 \(traced CPU\(s\): #11\) + L1I6 \(size=32768, assoc=8, block=64, LRU\) stats: + Hits: *88.?342 + Misses: 52 + Compulsory misses: 52 + Invalidations: 0 + Miss rate: 0.06% + L1D6 \(size=32768, assoc=8, block=64, LRU\) stats: + Hits: *188.?235 + Misses: 33 + Compulsory misses: 61 + Invalidations: 0 + Prefetch hits: 5 + Prefetch misses: 28 + Miss rate: 0.02% LL \(size=8388608, assoc=16, block=64, LRU\) stats: Hits: 567 Misses: *1.?114 From 8e23247a8610e954584c9b8ad0481b058118e16e Mon Sep 17 00:00:00 2001 From: Derek Bruening Date: Wed, 27 Mar 2024 19:46:29 -0400 Subject: [PATCH 13/14] i#6734: Set filetype in record_filter start-idle shards (#6735) Sets the filetype for record_filter shards from the filetype_ var to ensure start-idle shards have the correct type. Switches to using opcode_mix in the tool.record_filter_bycore_uni test, which fails with encoding errors without this fix. Fixes #6734 --- clients/drcachesim/tests/record_filter_bycore_uni.templatex | 6 +----- clients/drcachesim/tools/filter/record_filter.cpp | 3 +++ suite/tests/CMakeLists.txt | 5 ++++- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/clients/drcachesim/tests/record_filter_bycore_uni.templatex b/clients/drcachesim/tests/record_filter_bycore_uni.templatex index 723ce48676b..ad3859c0e28 100644 --- a/clients/drcachesim/tests/record_filter_bycore_uni.templatex +++ b/clients/drcachesim/tests/record_filter_bycore_uni.templatex @@ -6,9 +6,5 @@ Hello, world! #endif Trace invariant checks passed Output .* entries from .* entries. -Schedule stats tool results: +Opcode mix tool results: .* -Core #0 schedule: .* -Core #1 schedule: .* -Core #2 schedule: .* -Core #3 schedule: .* diff --git a/clients/drcachesim/tools/filter/record_filter.cpp b/clients/drcachesim/tools/filter/record_filter.cpp index af6add154ca..22927192d06 100644 --- a/clients/drcachesim/tools/filter/record_filter.cpp +++ b/clients/drcachesim/tools/filter/record_filter.cpp @@ -213,6 +213,7 @@ record_filter_t::initialize_shard_output(per_shard_t *per_shard, shard_stream->get_shard_index(), output_ext_.c_str(), version_, filetype_); per_shard->output_path += output_ext_; + per_shard->filetype = static_cast(filetype_); lock.unlock(); } else if (!input_name.empty()) { size_t last_dot = input_name.rfind('.'); @@ -232,6 +233,7 @@ record_filter_t::initialize_shard_output(per_shard_t *per_shard, shard_stream->get_shard_index(), output_ext_.c_str(), version_, filetype_); per_shard->output_path += output_ext_; + per_shard->filetype = static_cast(filetype_); lock.unlock(); input_info_cond_var_.notify_all(); } else { @@ -242,6 +244,7 @@ record_filter_t::initialize_shard_output(per_shard_t *per_shard, shard_stream->get_shard_index(), output_ext_.c_str(), version_, filetype_); per_shard->output_path += output_ext_; + per_shard->filetype = static_cast(filetype_); lock.unlock(); } } else { diff --git a/suite/tests/CMakeLists.txt b/suite/tests/CMakeLists.txt index 2d9b08d7947..88eb0ab3328 100644 --- a/suite/tests/CMakeLists.txt +++ b/suite/tests/CMakeLists.txt @@ -4649,7 +4649,10 @@ if (BUILD_CLIENTS) # We assume the app name starts with "s" here to avoid colliding with # our output dir, while still letting the single precmd remove both. "${drcachesim_path}@-simulator_type@record_filter@-indir@${testname}.s*.dir/trace@-core_sharded@-cores@4@-outdir@${testname}.filtered.dir" - "schedule_stats") + # We run opcode_mix to test encodings. + # XXX i#6684: Once we have invariant_checker support, run it here (and ensure + # it checks encodings). + "opcode_mix") if (UNIX) # Windows multi-thread tests are too slow. set(testname "tool.record_filter_bycore_multi") From 98d55a6e4f0b516c9d1d914ce3c8e473cc70a6a5 Mon Sep 17 00:00:00 2001 From: Phil Ramsey Date: Thu, 28 Mar 2024 11:13:41 +0000 Subject: [PATCH 14/14] i#5365: Add "branch" parameter to runsuite.cmake (#6740) Currently runsuite.cmake assumes that "origin/master" is the branch to diff against. However sometimes this is not the case, e.g. for internal CI systems using their own branches. Add a "branch" parameter to runsuite.cmake, defaulting to "master", allowing a different source branch to be specified. Issue: #5365 --- suite/runsuite.cmake | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/suite/runsuite.cmake b/suite/runsuite.cmake index 09162bc8acd..6ed3a463baf 100644 --- a/suite/runsuite.cmake +++ b/suite/runsuite.cmake @@ -52,6 +52,7 @@ set(cross_android_only OFF) set(cross_riscv64_linux_only OFF) set(arg_debug_only OFF) # Only build the main debug builds. set(arg_nontest_only OFF) # Only build configs with no tests. +set(arg_branch "master") # branch to diff this patch against foreach (arg ${CTEST_SCRIPT_ARG}) if (${arg} STREQUAL "automated_ci") set(arg_automated_ci ON) @@ -78,6 +79,8 @@ foreach (arg ${CTEST_SCRIPT_ARG}) set(arg_debug_only ON) elseif (${arg} STREQUAL "nontest_only") set(arg_nontest_only ON) + elseif (${arg} MATCHES "^branch=") + string(REGEX REPLACE "^branch=" "" arg_branch "${arg}") endif () endforeach (arg) @@ -200,9 +203,10 @@ else () find_program(GIT git DOC "git client") if (GIT) # Included committed, staged, and unstaged changes. - # We assume "origin/master" contains the top-of-trunk. + # We assume "origin/master" contains the top-of-trunk, unless the "branch" + # parameter has been set. # We pass -U0 so clang-format-diff only complains about touched lines. - execute_process(COMMAND ${GIT} diff -U0 origin/master + execute_process(COMMAND ${GIT} diff -U0 origin/${arg_branch} WORKING_DIRECTORY "${CTEST_SOURCE_DIRECTORY}" RESULT_VARIABLE git_result ERROR_VARIABLE git_err