From 518f32f1e64b84191145ef775c2b26d8b7e3018a Mon Sep 17 00:00:00 2001 From: Abhinav Anil Sharma Date: Thu, 28 Mar 2024 17:04:40 -0400 Subject: [PATCH] i#6508 context switches: Add invariant checker unit tests Adds some invariant checker unit tests for kernel context switch traces. Adjusts some invariant checks to account for kernel context switch traces. Issue: #6508 --- .../tests/invariant_checker_test.cpp | 69 ++++++++++++++++++- .../drcachesim/tools/invariant_checker.cpp | 30 ++++++-- clients/drcachesim/tools/invariant_checker.h | 2 + 3 files changed, 96 insertions(+), 5 deletions(-) diff --git a/clients/drcachesim/tests/invariant_checker_test.cpp b/clients/drcachesim/tests/invariant_checker_test.cpp index ea61ff41892..f17edea4e12 100644 --- a/clients/drcachesim/tests/invariant_checker_test.cpp +++ b/clients/drcachesim/tests/invariant_checker_test.cpp @@ -2941,6 +2941,72 @@ check_exit_found(void) return true; } +bool +check_kernel_context_switch_trace(void) +{ + std::cerr << "Testing kernel context switch traces\n"; + { + std::vector memrefs = { + gen_marker(TID_A, TRACE_MARKER_TYPE_CACHE_LINE_SIZE, 64), + gen_marker(TID_A, TRACE_MARKER_TYPE_PAGE_SIZE, 4096), + gen_marker(TID_A, TRACE_MARKER_TYPE_VERSION, TRACE_ENTRY_VERSION_BRANCH_INFO), + gen_instr(TID_A, /*pc=*/1), + gen_marker(TID_A, TRACE_MARKER_TYPE_CONTEXT_SWITCH_START, 0), + gen_instr(TID_A, /*pc=*/10), + gen_instr(TID_A, /*pc=*/11), + gen_marker(TID_A, TRACE_MARKER_TYPE_CONTEXT_SWITCH_END, 0), + gen_instr(TID_A, /*pc=*/2), + gen_exit(TID_A), + }; + if (!run_checker(memrefs, false)) + return false; + } + { + std::vector memrefs = { + gen_marker(TID_A, TRACE_MARKER_TYPE_CACHE_LINE_SIZE, 64), + gen_marker(TID_A, TRACE_MARKER_TYPE_PAGE_SIZE, 4096), + gen_marker(TID_A, TRACE_MARKER_TYPE_VERSION, TRACE_ENTRY_VERSION_BRANCH_INFO), + gen_instr(TID_A, /*pc=*/1), + gen_marker(TID_A, TRACE_MARKER_TYPE_CONTEXT_SWITCH_START, 0), + gen_instr(TID_A, /*pc=*/10), + gen_instr(TID_A, /*pc=*/11), + gen_marker(TID_A, TRACE_MARKER_TYPE_CONTEXT_SWITCH_END, 0), + gen_instr(TID_A, /*pc=*/3), + gen_exit(TID_A), + }; + if (!run_checker(memrefs, true, + { "Non-explicit control flow has no marker", TID_A, + /*ref_ordinal=*/9, /*last_timestamp=*/0, + /*instrs_since_last_timestamp=*/4 }, + "Failed to catch PC discontinuity after context switch trace")) { + return false; + } + } + { + std::vector memrefs = { + gen_marker(TID_A, TRACE_MARKER_TYPE_CACHE_LINE_SIZE, 64), + gen_marker(TID_A, TRACE_MARKER_TYPE_PAGE_SIZE, 4096), + gen_marker(TID_A, TRACE_MARKER_TYPE_VERSION, TRACE_ENTRY_VERSION_BRANCH_INFO), + gen_instr(TID_A, /*pc=*/1), + gen_marker(TID_A, TRACE_MARKER_TYPE_CONTEXT_SWITCH_START, 0), + gen_instr(TID_A, /*pc=*/10), + gen_instr(TID_A, /*pc=*/12), + gen_marker(TID_A, TRACE_MARKER_TYPE_CONTEXT_SWITCH_END, 0), + gen_instr(TID_A, /*pc=*/2), + gen_exit(TID_A), + }; + if (!run_checker( + memrefs, true, + { "Non-explicit control flow has no marker", TID_A, + /*ref_ordinal=*/7, /*last_timestamp=*/0, + /*instrs_since_last_timestamp=*/3 }, + "Failed to catch PC discontinuity inside context switch trace")) { + return false; + } + } + return true; +} + bool check_kernel_syscall_trace(void) { @@ -3377,7 +3443,8 @@ test_main(int argc, const char *argv[]) check_branch_decoration() && check_filter_endpoint() && check_timestamps_increase_monotonically() && check_read_write_records_match_operands() && check_exit_found() && - check_kernel_syscall_trace() && check_has_instructions()) { + check_kernel_syscall_trace() && check_has_instructions() && + check_kernel_context_switch_trace()) { std::cerr << "invariant_checker_test passed\n"; return 0; } diff --git a/clients/drcachesim/tools/invariant_checker.cpp b/clients/drcachesim/tools/invariant_checker.cpp index 5ebca63f8a7..24bc62ae36d 100644 --- a/clients/drcachesim/tools/invariant_checker.cpp +++ b/clients/drcachesim/tools/invariant_checker.cpp @@ -536,12 +536,29 @@ invariant_checker_t::parallel_shard_memref(void *shard_data, const memref_t &mem shard->pre_syscall_trace_instr_ = {}; } } + if (memref.marker.type == TRACE_TYPE_MARKER && + memref.marker.marker_type == TRACE_MARKER_TYPE_CONTEXT_SWITCH_START) { + report_if_false(shard, !shard->between_kernel_context_switch_markers_, + "Nested kernel context switch traces are not expected"); + shard->pre_context_switch_trace_instr_ = shard->prev_instr_; + shard->between_kernel_context_switch_markers_ = true; + } + if (memref.marker.type == TRACE_TYPE_MARKER && + memref.marker.marker_type == TRACE_MARKER_TYPE_CONTEXT_SWITCH_END) { + report_if_false(shard, shard->between_kernel_context_switch_markers_, + "Found kernel context switch trace end without start"); + shard->between_kernel_context_switch_markers_ = false; + // For future checks, pretend that the previous instr was the instr just + // before the context switch trace start. + if (shard->pre_context_switch_trace_instr_.memref.instr.addr > 0) { + shard->prev_instr_ = shard->pre_context_switch_trace_instr_; + shard->pre_context_switch_trace_instr_ = {}; + } + } if (!is_a_unit_test(shard)) { - // XXX: between_kernel_syscall_trace_markers_ does not track the - // TRACE_MARKER_TYPE_CONTEXT_SWITCH_* markers. If the invariant checker is run - // with dynamic injection of context switch sequences this will throw an error. report_if_false(shard, - shard->between_kernel_syscall_trace_markers_ == + (shard->between_kernel_syscall_trace_markers_ || + shard->between_kernel_context_switch_markers_) == shard->stream->is_record_kernel(), "Stream is_record_kernel() inaccurate"); } @@ -1353,6 +1370,11 @@ invariant_checker_t::check_for_pc_discontinuity( (shard->prev_entry_.marker.type == TRACE_TYPE_MARKER && shard->prev_entry_.marker.marker_type == TRACE_MARKER_TYPE_SYSCALL_TRACE_START)) || + // First instr of kernel context switch trace. + (shard->between_kernel_context_switch_markers_ && + (shard->prev_entry_.marker.type == TRACE_TYPE_MARKER && + shard->prev_entry_.marker.marker_type == + TRACE_MARKER_TYPE_CONTEXT_SWITCH_START)) || // String loop. (prev_instr_trace_pc == cur_pc && (cur_memref_info.memref.instr.type == TRACE_TYPE_INSTR_NO_FETCH || diff --git a/clients/drcachesim/tools/invariant_checker.h b/clients/drcachesim/tools/invariant_checker.h index 90fbe0f0059..3903f7a2b1d 100644 --- a/clients/drcachesim/tools/invariant_checker.h +++ b/clients/drcachesim/tools/invariant_checker.h @@ -230,7 +230,9 @@ class invariant_checker_t : public analysis_tool_t { int expected_read_records_ = 0; int expected_write_records_ = 0; bool between_kernel_syscall_trace_markers_ = false; + bool between_kernel_context_switch_markers_ = false; instr_info_t pre_syscall_trace_instr_; + instr_info_t pre_context_switch_trace_instr_; // Relevant when -no_abort_on_invariant_error. uint64_t error_count_ = 0; };