From fd99b5e33b69384548e0f1fbc26b7bd67007418b Mon Sep 17 00:00:00 2001 From: Enrico Deiana Date: Wed, 18 Sep 2024 16:47:49 -0700 Subject: [PATCH] i#6662 public traces, part 9: TLB simulator with v2p (#6961) We want to provide a virtual to physical mapping for the release of public traces to be used with our TLB simulator. We enable the TLB simulator to operate on the physical addresses provided by a v2p.textproto file, which is read by the previously added v2p_reader. Adds an end-to-end test "tool.drcacheoff.tlb_simulator_v2p" and a v2p.textproto mapping to clients/drcachesim/tests/drmemtrace.threadsig.aarch64.raw. Adds unit tests to check that the addresses used by the TLB simulator are the actual physical ones. Issue #6662 --- api/docs/release.dox | 7 + clients/drcachesim/CMakeLists.txt | 2 +- clients/drcachesim/analyzer_multi.cpp | 7 +- clients/drcachesim/common/options.cpp | 10 + clients/drcachesim/common/options.h | 1 + clients/drcachesim/common/trace_entry.h | 7 + clients/drcachesim/reader/v2p_reader.cpp | 20 +- clients/drcachesim/reader/v2p_reader.h | 3 +- clients/drcachesim/simulator/simulator.cpp | 26 +++ clients/drcachesim/simulator/simulator.h | 11 + .../drcachesim/simulator/tlb_simulator.cpp | 41 +++- clients/drcachesim/simulator/tlb_simulator.h | 2 + .../simulator/tlb_simulator_create.h | 2 + .../tests/config_reader_unit_test.cpp | 4 +- .../tests/config_reader_unit_test.h | 4 +- .../tests/drcachesim_unit_tests.cpp | 6 +- .../v2p.textproto | 50 +++++ .../tests/offline-tlb_simulator_v2p.templatex | 91 +++++++++ .../tests/tlb_simulator_unit_test.cpp | 190 ++++++++++++++++++ .../tests/tlb_simulator_unit_test.h | 47 +++++ .../drcachesim/tests/v2p_reader_unit_test.cpp | 18 +- .../drcachesim/tests/v2p_reader_unit_test.h | 4 +- suite/tests/CMakeLists.txt | 19 ++ 23 files changed, 542 insertions(+), 30 deletions(-) create mode 100644 clients/drcachesim/tests/drmemtrace.threadsig.aarch64.raw/v2p.textproto create mode 100644 clients/drcachesim/tests/offline-tlb_simulator_v2p.templatex create mode 100644 clients/drcachesim/tests/tlb_simulator_unit_test.cpp create mode 100644 clients/drcachesim/tests/tlb_simulator_unit_test.h diff --git a/api/docs/release.dox b/api/docs/release.dox index c98907efa6d..f43af9d3274 100644 --- a/api/docs/release.dox +++ b/api/docs/release.dox @@ -255,6 +255,13 @@ Further non-compatibility-affecting changes include: input_workload_t::times_of_interest to the drmemtrace scheduler. - Added v2p_reader_t to parse a virtual-to-physical mapping in textproto format and v2p_info_t to hold that mapping in memory. + - Added -v2p_file option to drcachesim TLB tool to set the path to a v2p.textproto file, + which provides a virtual to physical mapping of addresses for an offline trace. This + option overwrites both -page_size and + #dynamorio::drmemtrace::TRACE_MARKER_TYPE_PAGE_SIZE (if present) with the page size in + v2p.textproto. Option -use_physical (in offline mode) must also be set to use the + mapping in v2p.textproto (note that -use_physical during tracing is not necessary, nor + related to -use_physical offline). - Added -trace_instr_intervals_file option to the drmemtrace trace analysis tools framework. The file must be in CSV format containing a tracing interval per line where start and duration are expressed in number of instructions. diff --git a/clients/drcachesim/CMakeLists.txt b/clients/drcachesim/CMakeLists.txt index 5afbdf47fd0..81e54281312 100644 --- a/clients/drcachesim/CMakeLists.txt +++ b/clients/drcachesim/CMakeLists.txt @@ -805,7 +805,7 @@ if (BUILD_TESTS) add_executable(tool.drcachesim.unit_tests tests/drcachesim_unit_tests.cpp tests/cache_replacement_policy_unit_test.cpp tests/config_reader_unit_test.cpp - tests/v2p_reader_unit_test.cpp) + tests/v2p_reader_unit_test.cpp tests/tlb_simulator_unit_test.cpp) target_link_libraries(tool.drcachesim.unit_tests drmemtrace_simulator # Link test_helpers first, or else the zlib main takes over. drmemtrace_static drmemtrace_analyzer test_helpers ${zlib_libs}) diff --git a/clients/drcachesim/analyzer_multi.cpp b/clients/drcachesim/analyzer_multi.cpp index 90bd8290e86..ede111f7837 100644 --- a/clients/drcachesim/analyzer_multi.cpp +++ b/clients/drcachesim/analyzer_multi.cpp @@ -30,11 +30,13 @@ * DAMAGE. */ +#include "analysis_tool.h" #include "analyzer.h" #include "analyzer_multi.h" #include "common/options.h" #include "common/utils.h" #include "common/directory_iterator.h" +#include "tlb_simulator.h" #include "tracer/raw2trace_directory.h" #include "tracer/raw2trace.h" #include "reader/file_reader.h" @@ -214,7 +216,10 @@ analyzer_multi_t::create_analysis_tool_from_options(const std::string &tool) knobs.verbose = op_verbose.get_value(); knobs.cpu_scheduling = op_cpu_scheduling.get_value(); knobs.use_physical = op_use_physical.get_value(); - return tlb_simulator_create(knobs); + knobs.v2p_file = + get_aux_file_path(op_v2p_file.get_value(), DRMEMTRACE_V2P_FILENAME); + analysis_tool_t *tlb_simulator = tlb_simulator_create(knobs); + return tlb_simulator; } else if (tool == HISTOGRAM) { return histogram_tool_create(op_line_size.get_value(), op_report_top.get_value(), op_verbose.get_value()); diff --git a/clients/drcachesim/common/options.cpp b/clients/drcachesim/common/options.cpp index 8d8093b8c45..e20c9af2acc 100644 --- a/clients/drcachesim/common/options.cpp +++ b/clients/drcachesim/common/options.cpp @@ -286,6 +286,16 @@ droption_t op_virt2phys_freq( "The units are the number of memory accesses per forced access. A value of 0 " "uses the cached values for the entire application execution."); +droption_t op_v2p_file( + DROPTION_SCOPE_FRONTEND, "v2p_file", "", "Path to v2p.textproto for simulator tools", + "The " TLB " simulator can use v2p.textproto to translate virtual addresses to " + "physical ones during offline analysis. If the file is named v2p.textproto and is in " + "the same directory as the trace file, or a raw/ subdirectory below the trace file, " + "this parameter can be omitted. This option overwrites both -page_size and the page " + "size marker in the trace (if present) with the page size in v2p.textproto. The " + "option -use_physical (in offline mode) must be set to use the v2p.textproto " + "mapping. Note that -use_physical does not need to be set during tracing."); + droption_t op_cpu_scheduling( DROPTION_SCOPE_CLIENT, "cpu_scheduling", false, "Map threads to cores matching recorded cpu execution", diff --git a/clients/drcachesim/common/options.h b/clients/drcachesim/common/options.h index 1b5a01d6b54..4b376cca8bd 100644 --- a/clients/drcachesim/common/options.h +++ b/clients/drcachesim/common/options.h @@ -120,6 +120,7 @@ extern dynamorio::droption::droption_t op_instr_only_trace; extern dynamorio::droption::droption_t op_coherence; extern dynamorio::droption::droption_t op_use_physical; extern dynamorio::droption::droption_t op_virt2phys_freq; +extern dynamorio::droption::droption_t op_v2p_file; extern dynamorio::droption::droption_t op_cpu_scheduling; extern dynamorio::droption::droption_t op_max_trace_size; extern dynamorio::droption::droption_t diff --git a/clients/drcachesim/common/trace_entry.h b/clients/drcachesim/common/trace_entry.h index 096b3d32db3..1b97224485a 100644 --- a/clients/drcachesim/common/trace_entry.h +++ b/clients/drcachesim/common/trace_entry.h @@ -1479,6 +1479,13 @@ typedef struct _pt_data_buf_t pt_data_buf_t; */ #define DRMEMTRACE_KALLSYMS_FILENAME "kallsyms" +/** + * The name of the file in -offline mode where virtual to physical information is stored. + * This file contains a mapping from virtual to physical addresses, the page size used, + * the number of pages, and the number of bytes mapped. + */ +#define DRMEMTRACE_V2P_FILENAME "v2p.textproto" + } // namespace drmemtrace } // namespace dynamorio diff --git a/clients/drcachesim/reader/v2p_reader.cpp b/clients/drcachesim/reader/v2p_reader.cpp index e43f29401b4..c428b27f808 100644 --- a/clients/drcachesim/reader/v2p_reader.cpp +++ b/clients/drcachesim/reader/v2p_reader.cpp @@ -33,12 +33,10 @@ #include "v2p_reader.h" #include -#include -#include - #include #include #include +#include #include #include @@ -76,19 +74,8 @@ v2p_reader_t::get_value_from_line(std::string line, uint64_t &value) } std::string -v2p_reader_t::create_v2p_info_from_file(std::string path_to_file, v2p_info_t &v2p_info) +v2p_reader_t::create_v2p_info_from_file(std::istream &v2p_file, v2p_info_t &v2p_info) { - if (path_to_file.empty()) { - return "ERROR: Path to v2p.textproto is empty."; - } - - std::stringstream error_ss; - std::ifstream file(path_to_file); - if (!file.is_open()) { - error_ss << "ERROR: Failed to open " << path_to_file << "."; - return error_ss.str(); - } - const std::string page_size_key = "page_size"; const std::string page_count_key = "page_count"; const std::string bytes_mapped_key = "bytes_mapped"; @@ -98,8 +85,9 @@ v2p_reader_t::create_v2p_info_from_file(std::string path_to_file, v2p_info_t &v2 addr_t virtual_address = 0; uint64_t value = 0; std::string error_str; + std::stringstream error_ss; std::string line; - while (std::getline(file, line)) { + while (std::getline(v2p_file, line)) { // Ignore comments in v2p.textproto file. if (starts_with(line, "#")) continue; diff --git a/clients/drcachesim/reader/v2p_reader.h b/clients/drcachesim/reader/v2p_reader.h index 33cb6813e2c..39fb2d089e2 100644 --- a/clients/drcachesim/reader/v2p_reader.h +++ b/clients/drcachesim/reader/v2p_reader.h @@ -50,6 +50,7 @@ #include "trace_entry.h" #include +#include #include #include @@ -68,7 +69,7 @@ class v2p_reader_t { v2p_reader_t() = default; std::string - create_v2p_info_from_file(std::string path_to_file, v2p_info_t &v2p_info); + create_v2p_info_from_file(std::istream &v2p_file, v2p_info_t &v2p_info); private: std::string diff --git a/clients/drcachesim/simulator/simulator.cpp b/clients/drcachesim/simulator/simulator.cpp index 3ff54d803f5..9199de6bad3 100644 --- a/clients/drcachesim/simulator/simulator.cpp +++ b/clients/drcachesim/simulator/simulator.cpp @@ -37,6 +37,7 @@ #include #include +#include #include #include #include @@ -45,6 +46,7 @@ #include "options.h" #include "utils.h" #include "trace_entry.h" +#include "v2p_reader.h" namespace dynamorio { namespace drmemtrace { @@ -87,6 +89,26 @@ simulator_t::init_knobs(unsigned int num_cores, uint64_t skip_refs, uint64_t war } } +std::string +simulator_t::create_v2p_from_file(std::istream &v2p_file) +{ + // If we are not using physical addresses, we don't need a virtual to physical mapping + // at all. + if (!knob_use_physical_) + return ""; + + v2p_reader_t v2p_reader; + v2p_info_t v2p_info; + std::string error_str = v2p_reader.create_v2p_info_from_file(v2p_file, v2p_info); + if (!error_str.empty()) { + return error_str; + } + virt2phys_ = v2p_info.v2p_map; + page_size_ = static_cast(v2p_info.page_size); + use_v2p_file_ = true; + return ""; +} + std::string simulator_t::initialize_stream(memtrace_stream_t *serial_stream) { @@ -138,6 +160,10 @@ simulator_t::process_memref(const memref_t &memref) } if (!knob_use_physical_) return true; + // If we already have a virtual to physical mapping in a v2p file use that one and + // ignore the one in the trace, if any. + if (use_v2p_file_) + return true; if (memref.marker.marker_type == TRACE_MARKER_TYPE_PAGE_SIZE) { if (page_size_ != 0 && page_size_ != memref.marker.marker_value) { ERRMSG("Error: conflicting page size markers"); diff --git a/clients/drcachesim/simulator/simulator.h b/clients/drcachesim/simulator/simulator.h index 74779291041..78e434a6517 100644 --- a/clients/drcachesim/simulator/simulator.h +++ b/clients/drcachesim/simulator/simulator.h @@ -40,6 +40,7 @@ #include #include +#include #include #include @@ -71,6 +72,9 @@ class simulator_t : public analysis_tool_t { bool process_memref(const memref_t &memref) override; + virtual std::string + create_v2p_from_file(std::istream &v2p_file); + protected: // Initialize knobs. Success or failure is indicated by setting/resetting // the success variable. @@ -78,17 +82,22 @@ class simulator_t : public analysis_tool_t { init_knobs(unsigned int num_cores, uint64_t skip_refs, uint64_t warmup_refs, double warmup_fraction, uint64_t sim_refs, bool cpu_scheduling, bool use_physical, unsigned int verbose); + void print_core(int core) const; + int find_emptiest_core(std::vector &counts) const; + virtual int core_for_thread(memref_tid_t tid); + virtual void handle_thread_exit(memref_tid_t tid); addr_t virt2phys(addr_t virt) const; + memref_t memref2phys(memref_t memref) const; @@ -133,6 +142,8 @@ class simulator_t : public analysis_tool_t { size_t page_size_ = 0; std::unordered_map virt2phys_; addr_t prior_phys_addr_ = 0; + // Indicates whether the simulator uses a v2p file for virtual to physical mapping. + bool use_v2p_file_ = false; }; } // namespace drmemtrace diff --git a/clients/drcachesim/simulator/tlb_simulator.cpp b/clients/drcachesim/simulator/tlb_simulator.cpp index cdf75eaeb3e..f5ac4ff9e1b 100644 --- a/clients/drcachesim/simulator/tlb_simulator.cpp +++ b/clients/drcachesim/simulator/tlb_simulator.cpp @@ -34,6 +34,7 @@ #include +#include #include #include #include @@ -55,7 +56,27 @@ namespace drmemtrace { analysis_tool_t * tlb_simulator_create(const tlb_simulator_knobs_t &knobs) { - return new tlb_simulator_t(knobs); + if (knobs.v2p_file.empty()) + return new tlb_simulator_t(knobs); + + std::ifstream fin; + fin.open(knobs.v2p_file); + if (!fin.is_open()) { + ERRMSG("Failed to open the v2p file '%s'\n", knobs.v2p_file.c_str()); + return nullptr; + } + + tlb_simulator_t *sim = new tlb_simulator_t(knobs); + std::string error_str = sim->create_v2p_from_file(fin); + fin.close(); + + if (!error_str.empty()) { + delete sim; + ERRMSG("ERROR: v2p_reader failed with: %s\n", error_str.c_str()); + return nullptr; + } + + return sim; } tlb_simulator_t::tlb_simulator_t(const tlb_simulator_knobs_t &knobs) @@ -132,6 +153,24 @@ tlb_simulator_t::~tlb_simulator_t() delete[] lltlbs_; } +std::string +tlb_simulator_t::create_v2p_from_file(std::istream &v2p_file) +{ + // If we are not using physical addresses, we don't need a virtual to physical mapping + // at all. + if (!knobs_.use_physical) + return ""; + + std::string error_str = simulator_t::create_v2p_from_file(v2p_file); + if (!error_str.empty()) { + return error_str; + } + // Overwrite tlb_simulator_t.knobs_.page size with simulator_t.page_size, which is + // set to be the page size in v2p_file. + knobs_.page_size = page_size_; + return ""; +} + bool tlb_simulator_t::process_memref(const memref_t &memref) { diff --git a/clients/drcachesim/simulator/tlb_simulator.h b/clients/drcachesim/simulator/tlb_simulator.h index e739c374692..b8a82499da9 100644 --- a/clients/drcachesim/simulator/tlb_simulator.h +++ b/clients/drcachesim/simulator/tlb_simulator.h @@ -56,6 +56,8 @@ class tlb_simulator_t : public simulator_t { process_memref(const memref_t &memref) override; bool print_results() override; + std::string + create_v2p_from_file(std::istream &v2p_file) override; protected: // Create a tlb_t object with a specific replacement policy. diff --git a/clients/drcachesim/simulator/tlb_simulator_create.h b/clients/drcachesim/simulator/tlb_simulator_create.h index b022521fd30..74365ca7c9f 100644 --- a/clients/drcachesim/simulator/tlb_simulator_create.h +++ b/clients/drcachesim/simulator/tlb_simulator_create.h @@ -68,6 +68,7 @@ struct tlb_simulator_knobs_t { , sim_refs(1ULL << 63) , cpu_scheduling(false) , use_physical(false) + , v2p_file("") , verbose(0) { } @@ -86,6 +87,7 @@ struct tlb_simulator_knobs_t { uint64_t sim_refs; bool cpu_scheduling; bool use_physical; + std::string v2p_file; unsigned int verbose; }; diff --git a/clients/drcachesim/tests/config_reader_unit_test.cpp b/clients/drcachesim/tests/config_reader_unit_test.cpp index 946964cec5d..b1a495942aa 100644 --- a/clients/drcachesim/tests/config_reader_unit_test.cpp +++ b/clients/drcachesim/tests/config_reader_unit_test.cpp @@ -65,11 +65,11 @@ check_cache(const std::map &caches, std::string nam } void -unit_test_config_reader(const char *testdir) +unit_test_config_reader(const std::string &testdir) { cache_simulator_knobs_t knobs; std::map caches; - std::string file_path = std::string(testdir) + "/single_core.conf"; + std::string file_path = testdir + "/single_core.conf"; std::ifstream file_stream; file_stream.open(file_path); diff --git a/clients/drcachesim/tests/config_reader_unit_test.h b/clients/drcachesim/tests/config_reader_unit_test.h index ffbc4fa8324..a5b7b7be060 100644 --- a/clients/drcachesim/tests/config_reader_unit_test.h +++ b/clients/drcachesim/tests/config_reader_unit_test.h @@ -33,11 +33,13 @@ #ifndef _CONFIG_READER_UNIT_TEST_H_ #define _CONFIG_READER_UNIT_TEST_H_ 1 +#include + namespace dynamorio { namespace drmemtrace { void -unit_test_config_reader(const char *testdir); +unit_test_config_reader(const std::string &testdir); } // namespace drmemtrace } // namespace dynamorio diff --git a/clients/drcachesim/tests/drcachesim_unit_tests.cpp b/clients/drcachesim/tests/drcachesim_unit_tests.cpp index 749e9636534..0e765f4f27c 100644 --- a/clients/drcachesim/tests/drcachesim_unit_tests.cpp +++ b/clients/drcachesim/tests/drcachesim_unit_tests.cpp @@ -40,6 +40,7 @@ #include #include "config_reader_unit_test.h" #include "v2p_reader_unit_test.h" +#include "tlb_simulator_unit_test.h" #include "cache_replacement_policy_unit_test.h" #include "simulator/cache.h" #include "simulator/cache_lru.h" @@ -842,8 +843,9 @@ test_main(int argc, const char *argv[]) unit_test_exclusive_cache(); unit_test_cache_accessors(); - unit_test_config_reader(argv[1]); - unit_test_v2p_reader(argv[1]); + unit_test_config_reader(std::string(argv[1])); + unit_test_v2p_reader(std::string(argv[1])); + unit_test_tlb_simulator(std::string(argv[1])); unit_test_cache_associativity(); unit_test_cache_size(); unit_test_cache_line_size(); diff --git a/clients/drcachesim/tests/drmemtrace.threadsig.aarch64.raw/v2p.textproto b/clients/drcachesim/tests/drmemtrace.threadsig.aarch64.raw/v2p.textproto new file mode 100644 index 00000000000..d69a86ee8b3 --- /dev/null +++ b/clients/drcachesim/tests/drmemtrace.threadsig.aarch64.raw/v2p.textproto @@ -0,0 +1,50 @@ +# VirtualToPhysical +# Instance name: vm00_threadsig +# Generated: 2024-09-10T13:31:45.379962795-07:00 +address_mapping_group { + page_size: 2097152 + address_mapping { + virtual_address: 281464337858560 + physical_address: 10485760 + } + address_mapping { + virtual_address: 281464329469952 + physical_address: 8388608 + } + address_mapping { + virtual_address: 281464346247168 + physical_address: 12582912 + } + address_mapping { + virtual_address: 281474899116032 + physical_address: 18874368 + } + address_mapping { + virtual_address: 281464321081344 + physical_address: 6291456 + } + address_mapping { + virtual_address: 281464350441472 + physical_address: 14680064 + } + address_mapping { + virtual_address: 1895825408 + physical_address: 4194304 + } + address_mapping { + virtual_address: 4194304 + physical_address: 2097152 + } + address_mapping { + virtual_address: 281472940376064 + physical_address: 16777216 + } + information { + page_count: 9 + bytes_mapped: 18874368 + } +} +information { + page_count: 9 + bytes_mapped: 18874368 +} diff --git a/clients/drcachesim/tests/offline-tlb_simulator_v2p.templatex b/clients/drcachesim/tests/offline-tlb_simulator_v2p.templatex new file mode 100644 index 00000000000..d5170b9b1c3 --- /dev/null +++ b/clients/drcachesim/tests/offline-tlb_simulator_v2p.templatex @@ -0,0 +1,91 @@ +#ifdef AARCH64 +TLB simulation results: +Core #0 \(1 thread\(s\)\) + L1I stats: + Hits: *18[,\.]?577 + Misses: 141 + Compulsory misses: 50 + Invalidations: 0 + Miss rate: 0.75% + L1D stats: + Hits: *5[,\.]?947 + Misses: 138 + Compulsory misses: 45 + Invalidations: 0 + Miss rate: 2.27% + LL stats: + Hits: 200 + Misses: 79 + Compulsory misses: 79 + Invalidations: 0 + Local miss rate: 28.32% + Child hits: *24[,\.]?524 + Total miss rate: 0.32% +Core #1 \(2 thread\(s\)\) + L1I stats: + Hits: *53[,\.]?671 + Misses: 12 + Compulsory misses: 12 + Invalidations: 0 + Miss rate: 0.02% + L1D stats: + Hits: *12[,\.]?261 + Misses: 11 + Compulsory misses: 11 + Invalidations: 0 + Miss rate: 0.09% + LL stats: + Hits: 2 + Misses: 21 + Compulsory misses: 21 + Invalidations: 0 + Local miss rate: 91.30% + Child hits: *65[,\.]?932 + Total miss rate: 0.03% +Core #2 \(1 thread\(s\)\) + L1I stats: + Hits: *26[,\.]?827 + Misses: 12 + Compulsory misses: 12 + Invalidations: 0 + Miss rate: 0.04% + L1D stats: + Hits: *6[,\.]?126 + Misses: 9 + Compulsory misses: 9 + Invalidations: 0 + Miss rate: 0.15% + LL stats: + Hits: 2 + Misses: 19 + Compulsory misses: 19 + Invalidations: 0 + Local miss rate: 90.48% + Child hits: *32[,\.]?953 + Total miss rate: 0.06% +Core #3 \(1 thread\(s\)\) + L1I stats: + Hits: *26[,\.]?870 + Misses: 12 + Compulsory misses: 12 + Invalidations: 0 + Miss rate: 0.04% + L1D stats: + Hits: *6[,\.]?132 + Misses: 9 + Compulsory misses: 9 + Invalidations: 0 + Miss rate: 0.15% + LL stats: + Hits: 2 + Misses: 19 + Compulsory misses: 19 + Invalidations: 0 + Local miss rate: 90.48% + Child hits: *33[,\.]?002 + Total miss rate: 0.06% +#elif defined(X86) && defined(X64) +ERROR: failed to initialize analyzer: Directory setup failed: Failed sanity checks for thread log file .*/drmemtrace.threadsig.aarch64/raw/drmemtrace.threadsig..*.raw.gz: Architecture mismatch: trace recorded on aarch64 but tools built for x86_64 +#else +ERROR: failed to initialize analyzer: Failed to create analysis tool: Tool failed to initialize: Failed to load binaries: Failed to map module /tmp/nonexistent/threadsig +#endif diff --git a/clients/drcachesim/tests/tlb_simulator_unit_test.cpp b/clients/drcachesim/tests/tlb_simulator_unit_test.cpp new file mode 100644 index 00000000000..9cd59fd2092 --- /dev/null +++ b/clients/drcachesim/tests/tlb_simulator_unit_test.cpp @@ -0,0 +1,190 @@ +/* ********************************************************** + * Copyright (c) 2024 Google, LLC All rights reserved. + * **********************************************************/ + +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Google, Inc. nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE, LLC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include "tlb_simulator_unit_test.h" +#include "../simulator/tlb_simulator.h" +#include "../common/memref.h" +#include "trace_entry.h" + +namespace dynamorio { +namespace drmemtrace { + +class tlb_simulator_mock_t : public tlb_simulator_t { +public: + tlb_simulator_mock_t(const tlb_simulator_knobs_t &knobs) + : tlb_simulator_t(knobs) {}; + + bool + process_memref(const memref_t &memref) + { + // Process memref like tlb_simulator does. + bool result = tlb_simulator_t::process_memref(memref); + // Save address used by tlb_simulator, if any. + if (!type_has_address(memref.data.type)) { + return result; + } + const memref_t *simref = &memref; + memref_t phys_memref; + if (knobs_.use_physical) { + phys_memref = memref2phys(memref); + simref = &phys_memref; + } + addresses.insert(simref->data.addr); + // Return the result of tlb_simulator. + return result; + }; + + void + set_knob_use_physical(bool set) + { + // XXX: We should really consider unifying the common knobs between simulator_t + // and its derived classes like tlb_simulator_t. + // Set tlb_simulator_t knob. + knobs_.use_physical = set; + // Set simulator_t knob. + knob_use_physical_ = set; + }; + + std::unordered_set addresses; +}; + +static memref_t +generate_mem_ref(const addr_t addr, const addr_t pc) +{ + memref_t memref; + memref.data.type = TRACE_TYPE_READ; + memref.data.pid = 11111; + memref.data.tid = 22222; + memref.data.addr = addr; + memref.data.size = 8; + memref.data.pc = pc; + return memref; +} + +// Checks that the addresses the tlb simulator uses (in memrefs) are the same we expect +// in addresses. +static std::string +check_addresses(const std::vector &memrefs, + const std::unordered_set &addresses, + const std::string &v2p_file_path = "") +{ + tlb_simulator_knobs_t knobs; + tlb_simulator_mock_t tlb_simulator_mock(knobs); + + if (!v2p_file_path.empty()) { + tlb_simulator_mock.set_knob_use_physical(true); + std::ifstream fin; + fin.open(v2p_file_path); + if (!fin.is_open()) + return "Failed to open the v2p file '" + v2p_file_path + "'\n"; + std::string error_str = tlb_simulator_mock.create_v2p_from_file(fin); + fin.close(); + if (!error_str.empty()) + return "ERROR: v2p_reader failed with: " + error_str + "\n"; + } + + for (const memref_t &memref : memrefs) + tlb_simulator_mock.process_memref(memref); + + if (addresses.size() != tlb_simulator_mock.addresses.size()) { + return "ERROR: size mismatch. Expected " + std::to_string(addresses.size()) + + " got " + std::to_string(tlb_simulator_mock.addresses.size()) + ".\n"; + } + + for (const addr_t addr : addresses) { + if (tlb_simulator_mock.addresses.count(addr) == 0) + return "ERROR: address " + std::to_string(addr) + " not found.\n"; + } + + return ""; +} + +static void +tlb_simulator_check_addresses(const std::string &testdir) +{ + // virtual_addresses and physical_addresses are taken from an X64 trace, hence we + // enable this test only on X64 hosts. +#if defined(X86_64) || defined(AARCH64) + const std::string v2p_file_path = + testdir + "/drmemtrace.threadsig.aarch64.raw/v2p.textproto"; + const std::unordered_set virtual_addresses = { 0x0000fffffb73da60, + 0x00000000004a7a78, + 0x00000000004a5f20 }; + const std::unordered_set physical_addresses = { 0x000000000133da60, + 0x00000000002a7a78, + 0x00000000002a5f20 }; + std::vector memrefs; + // We don't care about exact PC values. + // Note: this will cause "Missing physical address marker for $PC" messages, which + // we ignore. + addr_t pc = 0; + for (const addr_t &addr : virtual_addresses) { + memrefs.push_back(generate_mem_ref(addr, pc)); + pc += 8; + } + + // Check that the addresses the tlb_simulator operates with are the same virtual + // addresses we created the memrefs with. + std::string error_str = check_addresses(memrefs, virtual_addresses); + if (!error_str.empty()) { + std::cerr << "ERROR: tlb_simulator_unit_test with virtual_addresses failed with: " + << error_str << "\n"; + exit(1); + } + + // Check that the addresses the tlb_simulator operates with are the same physical + // addresses we expect. + error_str = check_addresses(memrefs, physical_addresses, v2p_file_path); + if (!error_str.empty()) { + std::cerr + << "ERROR: tlb_simulator_unit_test with physical_addresses failed with: " + << error_str << "\n"; + exit(1); + } +#endif +} + +void +unit_test_tlb_simulator(const std::string &testdir) +{ + tlb_simulator_check_addresses(testdir); +} + +} // namespace drmemtrace +} // namespace dynamorio diff --git a/clients/drcachesim/tests/tlb_simulator_unit_test.h b/clients/drcachesim/tests/tlb_simulator_unit_test.h new file mode 100644 index 00000000000..417638b5155 --- /dev/null +++ b/clients/drcachesim/tests/tlb_simulator_unit_test.h @@ -0,0 +1,47 @@ +/* ********************************************************** + * Copyright (c) 2024 Google, Inc. All rights reserved. + * **********************************************************/ + +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Google, Inc. nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE, INC. OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#ifndef _TLB_SIMULATOR_UNIT_TEST_H_ +#define _TLB_SIMULATOR_UNIT_TEST_H_ 1 + +#include + +namespace dynamorio { +namespace drmemtrace { + +void +unit_test_tlb_simulator(const std::string &testdir); + +} // namespace drmemtrace +} // namespace dynamorio + +#endif /* _TLB_SIMULATOR_UNIT_TEST_H_ */ diff --git a/clients/drcachesim/tests/v2p_reader_unit_test.cpp b/clients/drcachesim/tests/v2p_reader_unit_test.cpp index 0381911a379..04454657035 100644 --- a/clients/drcachesim/tests/v2p_reader_unit_test.cpp +++ b/clients/drcachesim/tests/v2p_reader_unit_test.cpp @@ -30,10 +30,13 @@ * DAMAGE. */ +#include "v2p_reader_unit_test.h" + #include +#include #include #include -#include "v2p_reader_unit_test.h" + #include "reader/v2p_reader.h" namespace dynamorio { @@ -95,12 +98,19 @@ check_v2p_info(const v2p_info_t &v2p_info) } void -unit_test_v2p_reader(const char *testdir) +unit_test_v2p_reader(const std::string &testdir) { - std::string file_path = std::string(testdir) + "/v2p_example.textproto"; + std::string v2p_file_path = testdir + "/v2p_example.textproto"; v2p_info_t v2p_info; v2p_reader_t v2p_reader; - std::string error_str = v2p_reader.create_v2p_info_from_file(file_path, v2p_info); + std::ifstream fin; + fin.open(v2p_file_path); + if (!fin.is_open()) { + std::cerr << "Failed to open the v2p file '" << v2p_file_path << "'\n"; + exit(1); + } + std::string error_str = v2p_reader.create_v2p_info_from_file(fin, v2p_info); + fin.close(); if (!error_str.empty()) { std::cerr << "v2p_reader failed with: " << error_str << "\n"; exit(1); diff --git a/clients/drcachesim/tests/v2p_reader_unit_test.h b/clients/drcachesim/tests/v2p_reader_unit_test.h index 3152a99d280..6d53a28e42d 100644 --- a/clients/drcachesim/tests/v2p_reader_unit_test.h +++ b/clients/drcachesim/tests/v2p_reader_unit_test.h @@ -33,11 +33,13 @@ #ifndef _V2P_READER_UNIT_TEST_H_ #define _V2P_READER_UNIT_TEST_H_ 1 +#include + namespace dynamorio { namespace drmemtrace { void -unit_test_v2p_reader(const char *testdir); +unit_test_v2p_reader(const std::string &testdir); } // namespace drmemtrace } // namespace dynamorio diff --git a/suite/tests/CMakeLists.txt b/suite/tests/CMakeLists.txt index cfd936952d6..577fe842833 100644 --- a/suite/tests/CMakeLists.txt +++ b/suite/tests/CMakeLists.txt @@ -2114,6 +2114,25 @@ if (BUILD_CLIENTS) endif () endif () +if (AARCH64 AND UNIX AND ZLIB_FOUND) + # Test TLB simulator with a virtual to physical v2p.textproto mapping. + set(srcdir + ${PROJECT_SOURCE_DIR}/clients/drcachesim/tests/drmemtrace.threadsig.aarch64.raw) + set(locdir ${PROJECT_BINARY_DIR}/drmemtrace.threadsig.aarch64) + file(REMOVE_RECURSE ${locdir}) + file(MAKE_DIRECTORY ${locdir}) + file(COPY ${srcdir}/raw DESTINATION ${locdir}/) + get_target_path_for_execution(drcachesim_path drmemtrace_launcher + "${location_suffix}") + prefix_cmd_if_necessary(drcachesim_path ON ${drcachesim_path}) + torunonly_api(tool.drcacheoff.tlb_simulator_v2p "${drcachesim_path}" + "offline-tlb_simulator_v2p" "" + "-indir;${locdir};-tool;TLB;-alt_module_dir;${srcdir};-module_file;${locdir}/raw/modules.log;-v2p_file;${srcdir}/v2p.textproto;-use_physical" + OFF OFF) + set(tool.drcacheoff.tlb_simulator_v2p_basedir + "${PROJECT_SOURCE_DIR}/clients/drcachesim/tests") +endif () + if (DR_HOST_NOT_TARGET) # i#1684,i#4318: Test postprocessing and analysis with an alternate binary directory. # Limited to UNIX because the checked-in modules.log is in UNIX format