diff --git a/clients/drcachesim/CMakeLists.txt b/clients/drcachesim/CMakeLists.txt index 6dfa9b3dd1160b84e5cd1fcfc4ed571a9e28ccde..f082e7641b1b50f035fedad76c2cca671639031a 100644 --- a/clients/drcachesim/CMakeLists.txt +++ b/clients/drcachesim/CMakeLists.txt @@ -77,6 +77,12 @@ add_library(simulator STATIC simulator/tlb_simulator.cpp ) +add_library(raw2trace STATIC + tracer/raw2trace.cpp + tracer/raw2trace_directory.cpp + ) +configure_DynamoRIO_standalone(raw2trace) + add_executable(drcachesim launcher.cpp analyzer.cpp @@ -87,15 +93,13 @@ add_executable(drcachesim ${zlib_reader} reader/ipc_reader.cpp simulator/analyzer_interface.cpp - # We embed the raw2trace conversion for convenience: - tracer/raw2trace.cpp tracer/instru.cpp tracer/instru_online.cpp ) # In order to embed raw2trace we need to be standalone: configure_DynamoRIO_standalone(drcachesim) # Link in our tools: -target_link_libraries(drcachesim simulator reuse_distance histogram reuse_time) +target_link_libraries(drcachesim simulator reuse_distance histogram reuse_time raw2trace) # To avoid dup symbol errors between drinjectlib and the drdecode brought in # by drfrontendlib we have to explicitly list drdecode up front: target_link_libraries(drcachesim drdecode drinjectlib drconfiglib drfrontendlib) @@ -164,10 +168,10 @@ install_client_header(tracer/drmemtrace.h) add_executable(drraw2trace tracer/raw2trace_launcher.cpp - tracer/raw2trace.cpp tracer/instru.cpp tracer/instru_online.cpp ) +target_link_libraries(drraw2trace raw2trace) # To avoid dup symbol errors on some VS builds we list drdecode before DR: target_link_libraries(drraw2trace drdecode) configure_DynamoRIO_standalone(drraw2trace) @@ -332,8 +336,23 @@ if (BUILD_TESTS) add_win32_flags(tool.drcacheoff.burst_threads) target_link_libraries(tool.drcacheoff.burst_threads ${libpthread}) - # FIXME i#2099: the weak symbol is not supported on Windows. if (UNIX) + if (NOT APPLE) + # uses ptrace and looks for linux-specific syscalls + add_executable(tool.drcacheoff.raw2trace_io tests/raw2trace_io.cpp + tracer/instru.cpp + tracer/instru_online.cpp) + configure_DynamoRIO_standalone(tool.drcacheoff.raw2trace_io) + add_win32_flags(tool.drcacheoff.raw2trace_io) + target_link_libraries(tool.drcacheoff.raw2trace_io raw2trace) + use_DynamoRIO_extension(tool.drcacheoff.raw2trace_io droption) + target_link_libraries(tool.drcacheoff.raw2trace_io drdecode) + use_DynamoRIO_extension(tool.drcacheoff.raw2trace_io drcovlib_static) + # Because we're leveraging instru_online code we have to link with drutil: + use_DynamoRIO_extension(tool.drcacheoff.raw2trace_io drutil_static) + endif () + + # FIXME i#2099: the weak symbol is not supported on Windows. add_executable(tool.drcacheoff.burst_client tests/burst_static.cpp) append_property_list(TARGET tool.drcacheoff.burst_client COMPILE_DEFINITIONS "TEST_APP_DR_CLIENT_MAIN") diff --git a/clients/drcachesim/analyzer_multi.cpp b/clients/drcachesim/analyzer_multi.cpp index 3a3c03e1ddb0b23d7a65f4e8f06a9db2262bb65b..c5033245884f4d1df20206a7e4248831fbf89a17 100644 --- a/clients/drcachesim/analyzer_multi.cpp +++ b/clients/drcachesim/analyzer_multi.cpp @@ -40,6 +40,7 @@ # include "reader/compressed_file_reader.h" #endif #include "reader/ipc_reader.h" +#include "tracer/raw2trace_directory.h" #include "tracer/raw2trace.h" analyzer_multi_t::analyzer_multi_t() @@ -65,8 +66,11 @@ analyzer_multi_t::analyzer_multi_t() trace_iter = existing; else { delete existing; - raw2trace_t raw2trace(op_indir.get_value(), tracefile); - raw2trace.do_conversion(); + raw2trace_directory_t dir(op_indir.get_value(), tracefile); + raw2trace_t raw2trace(dir.modfile_bytes, dir.thread_files, &dir.out_file); + std::string error = raw2trace.do_conversion(); + if (!error.empty()) + ERRMSG("raw2trace failed: %s", error.c_str()); trace_iter = new file_reader_t(tracefile.c_str()); } // We don't support a compressed file here (is_complete() is too hard diff --git a/clients/drcachesim/common/utils.h b/clients/drcachesim/common/utils.h index 0af5d00e9f22ae961fa32a130be1b6a37b3adf8e..6a32841872dd2a1d9dc3251ef3c7dc1dd04ef527 100644 --- a/clients/drcachesim/common/utils.h +++ b/clients/drcachesim/common/utils.h @@ -48,6 +48,7 @@ #define BUFFER_SIZE_ELEMENTS(buf) (BUFFER_SIZE_BYTES(buf) / sizeof(buf[0])) #define BUFFER_LAST_ELEMENT(buf) buf[BUFFER_SIZE_ELEMENTS(buf) - 1] #define NULL_TERMINATE_BUFFER(buf) BUFFER_LAST_ELEMENT(buf) = 0 +#define TESTANY(mask, var) (((mask) & (var)) != 0) #define BOOLS_MATCH(b1, b2) (!!(b1) == !!(b2)) diff --git a/clients/drcachesim/tests/raw2trace-simple.templatex b/clients/drcachesim/tests/raw2trace-simple.templatex new file mode 100644 index 0000000000000000000000000000000000000000..f8de8bd0aff8c2d30e6ddcc0d37f115f215ca824 --- /dev/null +++ b/clients/drcachesim/tests/raw2trace-simple.templatex @@ -0,0 +1,5 @@ +\[drmemtrace\]: Reading module file from memory +open|close +\[drmemtrace\]: Successfully read [0-9]+ modules +\[drmemtrace\]: Successfully converted [0-9]+ thread files +Processed diff --git a/clients/drcachesim/tests/raw2trace_io.cpp b/clients/drcachesim/tests/raw2trace_io.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bb8b92e63ce126510702e275adaaf86f41a3bc55 --- /dev/null +++ b/clients/drcachesim/tests/raw2trace_io.cpp @@ -0,0 +1,166 @@ +/* ********************************************************** + * Copyright (c) 2017 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. + */ + +/* This application processes a set of existing raw files with raw2trace_t. + * It uses ptrace to make sure raw2trace only interacts with the filesystem when expected + * -- it doesn't open/close any files outside of mapping modules (which should be local). + * + * XXX: We use ptrace as opposed to running under memtrace with replaced file operations + * because raw2trace uses drmodtrack, which doesn't isolate under static memtrace. + */ + +#include "droption.h" +#include "tracer/raw2trace.h" +#include "tracer/raw2trace_directory.h" +#include <cassert> +#include <errno.h> +#include <fcntl.h> +#include <iostream> +#include <string> +#include <sys/ptrace.h> +#include <sys/user.h> +#include <sys/wait.h> +#include <syscall.h> +#include <unistd.h> + +static droption_t<std::string> op_indir(DROPTION_SCOPE_FRONTEND, "indir", "", + "[Required] Directory with trace input files", + "Specifies a directory with raw files."); + +static droption_t<std::string> op_out(DROPTION_SCOPE_FRONTEND, "out", "", + "[Required] Path to output file", + "Specifies the path to the output file."); +#if defined(X64) +# define SYS_NUM(r) (r).orig_rax +#elif defined(X86) +# define SYS_NUM(r) (r).orig_eax +#else +# error "Test only supports x86" +#endif + +#ifndef LINUX +# error "Test only supports Linux" +#endif + +int +main(int argc, const char *argv[]) +{ + std::string parse_err; + if (!droption_parser_t::parse_argv(DROPTION_SCOPE_FRONTEND, argc, (const char **)argv, + &parse_err, NULL) || + op_indir.get_value().empty() || op_out.get_value().empty()) { + std::cerr << "Usage error: " << parse_err << "\nUsage:\n" + << droption_parser_t::usage_short(DROPTION_SCOPE_ALL); + return 1; + } + + /* Open input/output files outside of traced region. And explicitly don't destroy dir, + * so they never get closed. + */ + raw2trace_directory_t *dir = + new raw2trace_directory_t(op_indir.get_value(), op_out.get_value()); + + pid_t pid = fork(); + if (pid == -1) { + std::cerr << "Fork failed\n"; + return 1; + } + if (pid != 0) { + /* parent */ + long res; + int status; + while (true) { + int wait_res = waitpid(pid, &status, __WALL); + if (wait_res < 0) { + if (errno == EINTR) + continue; + perror("Failed waiting"); + return 1; + } + if (WIFEXITED(status)) + break; + user_regs_struct regs; + res = ptrace(PTRACE_GETREGS, pid, NULL, ®s); + if (res < 0) { + perror("ptrace failed"); + return 1; + } + /* We don't distinguish syscall entry/exit because orig_rax is set + * on both. + */ + if (SYS_NUM(regs) == __NR_open || SYS_NUM(regs) == __NR_openat || + SYS_NUM(regs) == __NR_creat) { + std::cerr << "open\n"; + } else if (SYS_NUM(regs) == __NR_close) { + std::cerr << "close\n"; + } + res = ptrace(PTRACE_SYSCALL, pid, NULL, 0); + if (res < 0) { + perror("ptrace failed"); + return 1; + } + } + if (WIFEXITED(status)) { + return 0; + } + res = ptrace(PTRACE_DETACH, pid, NULL, NULL); + if (res < 0) { + perror("ptrace failed"); + return 1; + } + std::cerr << "Detached\n"; + return 0; + } else { + /* child */ + long res = ptrace(PTRACE_TRACEME, 0, NULL, NULL); + if (res < 0) { + perror("ptrace me failed"); + return 1; + } + /* Force a wait until parent attaches, so we don't race on the fork. */ + raise(SIGSTOP); + + /* Sycalls below will be ptraced. We don't expect any open/close calls outside of + * raw2trace::read_and_map_modules(). + */ + raw2trace_t raw2trace(dir->modfile_bytes, dir->thread_files, &dir->out_file, + GLOBAL_DCONTEXT, 1); + std::string error = raw2trace.do_conversion(); + if (!error.empty()) { + std::cerr << "raw2trace failed " << error << "\n"; + return 1; + } + std::cerr << "Processed\n"; + return 0; + } + return 0; +} diff --git a/clients/drcachesim/tracer/raw2trace.cpp b/clients/drcachesim/tracer/raw2trace.cpp index 52cf258160f54a66628eebfdd33e482b707746a9..4ff3c1588349343f77d9f07b30a86476ca4d22f8 100644 --- a/clients/drcachesim/tracer/raw2trace.cpp +++ b/clients/drcachesim/tracer/raw2trace.cpp @@ -34,46 +34,23 @@ * by the cache simulator and other analysis tools. */ -#define UNICODE - #include "dr_api.h" -#include "droption.h" #include "drcovlib.h" -#include "dr_frontend.h" #include "raw2trace.h" #include "instru.h" #include "../common/memref.h" #include "../common/trace_entry.h" +#include <cstring> #include <fstream> +#include <sstream> #include <vector> -#ifdef UNIX -# include <dirent.h> /* opendir, readdir */ -# include <unistd.h> /* getcwd */ -#else -# include <windows.h> -# include <direct.h> /* _getcwd */ -# pragma comment(lib, "User32.lib") -#endif - -// XXX: currently the error handling and diagnostics are *not* modular: -// this class assumes an option op_verbose, and for errors it just -// prints directly and exits the process. -// The original plan was to have drcachesim launch this as a separate -// executable. -extern droption_t<unsigned int> op_verbose; - // XXX: DR should export this #define INVALID_THREAD_ID 0 -#define FATAL_ERROR(msg, ...) do { \ - fprintf(stderr, "ERROR: " msg "\n", ##__VA_ARGS__); \ - fflush(stderr); \ - exit(1); \ -} while (0) - -#define CHECK(val, msg, ...) do { \ - if (!(val)) FATAL_ERROR(msg, ##__VA_ARGS__); \ +// Assumes we return an error string by convention. +#define CHECK(val, msg) do { \ + if (!(val)) return msg; \ } while (0) #define WARN(msg, ...) do { \ @@ -82,14 +59,14 @@ extern droption_t<unsigned int> op_verbose; } while (0) #define VPRINT(level, ...) do { \ - if (op_verbose.get_value() >= (level)) { \ + if (this->verbosity >= (level)) { \ fprintf(stderr, "[drmemtrace]: "); \ fprintf(stderr, __VA_ARGS__); \ } \ } while (0) #define DO_VERBOSE(level, x) do { \ - if (op_verbose.get_value() >= (level)) { \ + if (this->verbosity >= (level)) { \ x \ } \ } while (0) @@ -98,24 +75,19 @@ extern droption_t<unsigned int> op_verbose; * Module list */ -void -raw2trace_t::read_and_map_modules(void) +std::string +raw2trace_t::read_and_map_modules(const char *module_map) { // Read and load all of the modules. - std::string modfilename = indir + std::string(DIRSEP) + - DRMEMTRACE_MODULE_LIST_FILENAME; uint num_mods; - VPRINT(1, "Reading module file %s\n", modfilename.c_str()); - file_t modfile = dr_open_file(modfilename.c_str(), DR_FILE_READ); - if (modfile == INVALID_FILE) - FATAL_ERROR("Failed to open module file %s", modfilename.c_str()); - if (drmodtrack_offline_read(modfile, NULL, NULL, &modhandle, &num_mods) != + VPRINT(1, "Reading module file from memory\n"); + if (drmodtrack_offline_read(INVALID_FILE, module_map, NULL, &modhandle, &num_mods) != DRCOVLIB_SUCCESS) - FATAL_ERROR("Failed to parse module file %s", modfilename.c_str()); + return "Failed to parse module file"; for (uint i = 0; i < num_mods; i++) { drmodtrack_info_t info = {sizeof(info),}; if (drmodtrack_offline_lookup(modhandle, i, &info) != DRCOVLIB_SUCCESS) - FATAL_ERROR("Failed to query module file"); + return "Failed to query module file"; if (strcmp(info.path, "<unknown>") == 0 || // i#2062: VDSO is hard to decode so for now we treat is as non-module. // FIXME: currently we're dropping the ifetch data: we need the tracer @@ -146,7 +118,7 @@ raw2trace_t::read_and_map_modules(void) if (strstr(info.path, "dynamorio") != NULL) modvec.push_back(module_t(info.path, info.start, NULL, 0)); else - FATAL_ERROR("Failed to map module %s", info.path); + return "Failed to map module " + std::string(info.path); } else { VPRINT(1, "Mapped module %d @" PFX " = %s\n", (int)modvec.size(), (ptr_uint_t)base_pc, info.path); @@ -155,13 +127,14 @@ raw2trace_t::read_and_map_modules(void) } } VPRINT(1, "Successfully read %d modules\n", num_mods); + return ""; } -void +std::string raw2trace_t::unmap_modules(void) { if (drmodtrack_offline_exit(modhandle) != DRCOVLIB_SUCCESS) - FATAL_ERROR("Failed to clean up module table data"); + return "Failed to clean up module table data"; for (std::vector<module_t>::iterator mvi = modvec.begin(); mvi != modvec.end(); ++mvi) { if (mvi->map_base != NULL && mvi->map_size != 0) { @@ -170,90 +143,9 @@ raw2trace_t::unmap_modules(void) WARN("Failed to unmap module %s", mvi->path); } } + return ""; } -/*************************************************************************** - * Directory iterator - */ - -// We open each thread log file in a vector so we can read from them simultaneously. -void -raw2trace_t::open_thread_log_file(const char *basename) -{ - char path[MAXIMUM_PATH]; - CHECK(basename[0] != '/', - "dir iterator entry %s should not be an absolute path\n", basename); - // Skip the module list log. - if (strcmp(basename, DRMEMTRACE_MODULE_LIST_FILENAME) == 0) - return; - // Skip any non-.raw in case someone put some other file in there. - if (strstr(basename, OUTFILE_SUFFIX) == NULL) - return; - if (dr_snprintf(path, BUFFER_SIZE_ELEMENTS(path), "%s%s%s", - indir.c_str(), DIRSEP, basename) <= 0) { - FATAL_ERROR("Failed to get full path of file %s", basename); - } - NULL_TERMINATE_BUFFER(path); - thread_files.push_back(new std::ifstream(path, std::ifstream::binary)); - if (!(*thread_files.back())) - FATAL_ERROR("Failed to open thread log file %s", path); - // Check version header. - offline_entry_t ver_entry; - if (!thread_files.back()->read((char*)&ver_entry, sizeof(ver_entry))) - FATAL_ERROR("Unable to read thread log file %s", path); - if (ver_entry.extended.type != OFFLINE_TYPE_EXTENDED || - ver_entry.extended.ext != OFFLINE_EXT_TYPE_HEADER) - FATAL_ERROR("Thread log file %s is corrupted: missing version entry", path); - if (ver_entry.extended.value != OFFLINE_FILE_VERSION) { - FATAL_ERROR("Version mismatch: expect %d vs %d in file %s", - OFFLINE_FILE_VERSION, (int)ver_entry.extended.value, path); - } - VPRINT(1, "Opened thread log file %s\n", path); -} - -#ifdef UNIX -void -raw2trace_t::open_thread_files() -{ - struct dirent *ent; - DIR *dir = opendir(indir.c_str()); - VPRINT(1, "Iterating dir %s\n", indir.c_str()); - if (dir == NULL) - FATAL_ERROR("Failed to list directory %s", indir.c_str()); - while ((ent = readdir(dir)) != NULL) - open_thread_log_file(ent->d_name); - closedir (dir); -} -#else -void -raw2trace_t::open_thread_files() -{ - HANDLE find = INVALID_HANDLE_VALUE; - WIN32_FIND_DATAW data; - char path[MAXIMUM_PATH]; - TCHAR wpath[MAXIMUM_PATH]; - VPRINT(1, "Iterating dir %s\n", indir.c_str()); - // Append \* - dr_snprintf(path, BUFFER_SIZE_ELEMENTS(path), "%s\\*", indir.c_str()); - NULL_TERMINATE_BUFFER(path); - if (drfront_char_to_tchar(path, wpath, BUFFER_SIZE_ELEMENTS(wpath)) != - DRFRONT_SUCCESS) - FATAL_ERROR("Failed to convert from utf-8 to utf-16"); - find = FindFirstFileW(wpath, &data); - if (find == INVALID_HANDLE_VALUE) - FATAL_ERROR("Failed to list directory %s\n", indir.c_str()); - do { - if (!TESTANY(data.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY)) { - if (drfront_tchar_to_char(data.cFileName, path, BUFFER_SIZE_ELEMENTS(path)) != - DRFRONT_SUCCESS) - FATAL_ERROR("Failed to convert from utf-16 to utf-8"); - open_thread_log_file(path); - } - } while (FindNextFile(find, &data) != 0); - FindClose(find); -} -#endif - /*************************************************************************** * Disassembly to fill in instr and memref entries */ @@ -271,14 +163,14 @@ instr_is_rep_string(instr_t *instr) #endif } -trace_entry_t * -raw2trace_t::append_memref(trace_entry_t *buf_in, uint tidx, instr_t *instr, +std::string +raw2trace_t::append_memref(INOUT trace_entry_t **buf_in, uint tidx, instr_t *instr, opnd_t ref, bool write) { - trace_entry_t *buf = buf_in; + trace_entry_t *buf = *buf_in; offline_entry_t in_entry; if (!thread_files[tidx]->read((char*)&in_entry, sizeof(in_entry))) - FATAL_ERROR("Trace ends mid-block"); + return "Trace ends mid-block"; if (in_entry.addr.type != OFFLINE_TYPE_MEMREF && in_entry.addr.type != OFFLINE_TYPE_MEMREF_HIGH) { // This happens when there are predicated memrefs in the bb. @@ -290,7 +182,7 @@ raw2trace_t::append_memref(trace_entry_t *buf_in, uint tidx, instr_t *instr, // Put back the entry. thread_files[tidx]->seekg(-(std::streamoff)sizeof(in_entry), thread_files[tidx]->cur); - return buf; + return ""; } if (instr_is_prefetch(instr)) { buf->type = instru_t::instr_to_prefetch_type(instr); @@ -308,12 +200,12 @@ raw2trace_t::append_memref(trace_entry_t *buf_in, uint tidx, instr_t *instr, // We take the full value, to handle low or high. buf->addr = (addr_t) in_entry.combined_value; VPRINT(4, "Appended memref to " PFX "\n", (ptr_uint_t)buf->addr); - ++buf; - return buf; + *buf_in = ++buf; + return ""; } -bool -raw2trace_t::append_bb_entries(uint tidx, offline_entry_t *in_entry) +std::string +raw2trace_t::append_bb_entries(uint tidx, offline_entry_t *in_entry, OUT bool *handled) { uint instr_count = in_entry->pc.instr_count; instr_t instr; @@ -326,7 +218,8 @@ raw2trace_t::append_bb_entries(uint tidx, offline_entry_t *in_entry) // Once that support is in we can remove the bool return value and handle // the memrefs up here. VPRINT(3, "Skipping ifetch for %u instrs not in a module\n", instr_count); - return false; + *handled = false; + return ""; } else { VPRINT(3, "Appending %u instrs in bb " PFX " in mod %u +" PIFX " = %s\n", instr_count, (ptr_uint_t)start_pc, (uint)in_entry->pc.modidx, @@ -387,30 +280,35 @@ raw2trace_t::append_bb_entries(uint tidx, offline_entry_t *in_entry) (instr_reads_memory(&instr) || instr_writes_memory(&instr))) { for (int i = 0; i < instr_num_srcs(&instr); i++) { if (opnd_is_memory_reference(instr_get_src(&instr, i))) { - buf = append_memref(buf, tidx, &instr, instr_get_src(&instr, i), - false); + std::string error = append_memref(&buf, tidx, &instr, + instr_get_src(&instr, i), false); + if (!error.empty()) + return error; } } for (int i = 0; i < instr_num_dsts(&instr); i++) { if (opnd_is_memory_reference(instr_get_dst(&instr, i))) { - buf = append_memref(buf, tidx, &instr, instr_get_dst(&instr, i), - true); + std::string error = append_memref(&buf, tidx, &instr, + instr_get_dst(&instr, i), true); + if (!error.empty()) + return error; } } } CHECK((size_t)(buf - buf_start) < MAX_COMBINED_ENTRIES, "Too many entries"); - if (!out_file.write((char*)buf_start, (buf - buf_start)*sizeof(trace_entry_t))) - FATAL_ERROR("Failed to write to output file"); + if (!out_file->write((char*)buf_start, (buf - buf_start)*sizeof(trace_entry_t))) + return "Failed to write to output file"; } instr_free(dcontext, &instr); - return true; + *handled = true; + return ""; } /*************************************************************************** * Top-level */ -void +std::string raw2trace_t::merge_and_process_thread_files() { // The current thread we're processing is tidx. If it's set to thread_files.size() @@ -440,9 +338,9 @@ raw2trace_t::merge_and_process_thread_files() if (times[i] == 0 && !thread_files[i]->eof()) { offline_entry_t entry; if (!thread_files[i]->read((char*)&entry, sizeof(entry))) - FATAL_ERROR("Failed to read from input file"); + return "Failed to read from input file"; if (entry.timestamp.type != OFFLINE_TYPE_TIMESTAMP) - FATAL_ERROR("Missing timestamp entry"); + return "Missing timestamp entry"; times[i] = entry.timestamp.usec; VPRINT(3, "Thread %u timestamp is @0x" ZHEX64_FORMAT_STRING "\n", (uint)tids[i], times[i]); @@ -464,8 +362,8 @@ raw2trace_t::merge_and_process_thread_files() if (size > 0) { // We have to write this now before we append any bb entries. CHECK((uint)size < MAX_COMBINED_ENTRIES, "Too many entries"); - if (!out_file.write((char*)buf_base, size)) - FATAL_ERROR("Failed to write to output file"); + if (!out_file->write((char*)buf_base, size)) + return "Failed to write to output file"; buf = buf_base; } size = 0; @@ -474,13 +372,16 @@ raw2trace_t::merge_and_process_thread_files() (uint)tids[tidx], (int)thread_files[tidx]->tellg()); if (!thread_files[tidx]->read((char*)&in_entry, sizeof(in_entry))) { if (thread_files[tidx]->eof()) { - // Rather than a FATAL_ERROR we try to continue to provide partial + // Rather than a fatal error we try to continue to provide partial // results in case the disk was full or there was some other issue. WARN("Input file for thread %d is truncated", (uint)tids[tidx]); in_entry.extended.type = OFFLINE_TYPE_EXTENDED; in_entry.extended.ext = OFFLINE_EXT_TYPE_FOOTER; - } else - FATAL_ERROR("Failed to read from file for thread %d", (uint)tids[tidx]); + } else { + std::stringstream ss; + ss << "Failed to read from file for thread " << (uint)tids[tidx]; + return ss.str(); + } } if (in_entry.extended.type == OFFLINE_TYPE_EXTENDED) { if (in_entry.extended.ext == OFFLINE_EXT_TYPE_FOOTER) { @@ -488,15 +389,18 @@ raw2trace_t::merge_and_process_thread_files() offline_entry_t entry; if (thread_files[tidx]->read((char*)&entry, sizeof(entry)) || !thread_files[tidx]->eof()) - FATAL_ERROR("Footer is not the final entry"); + return "Footer is not the final entry"; CHECK(tids[tidx] != INVALID_THREAD_ID, "Missing thread id"); VPRINT(2, "Thread %d exit\n", (uint)tids[tidx]); size += instru.append_thread_exit(buf, tids[tidx]); buf += size; --thread_count; tidx = (uint)thread_files.size(); // Request thread scan. - } else - FATAL_ERROR("Invalid extension type %d", (int)in_entry.extended.ext); + } else { + std::stringstream ss; + ss << "Invalid extension type " << (int)in_entry.extended.ext; + return ss.str(); + } } else if (in_entry.timestamp.type == OFFLINE_TYPE_TIMESTAMP) { VPRINT(2, "Thread %u timestamp 0x" ZHEX64_FORMAT_STRING "\n", (uint)tids[tidx], in_entry.timestamp.usec); @@ -517,10 +421,12 @@ raw2trace_t::merge_and_process_thread_files() buf += size; } else { // We should see an instr entry first - CHECK(false, "memref entry found outside of bb"); + return "memref entry found outside of bb"; } } else if (in_entry.pc.type == OFFLINE_TYPE_PC) { - last_bb_handled = append_bb_entries(tidx, &in_entry); + std::string result = append_bb_entries(tidx, &in_entry, &last_bb_handled); + if (!result.empty()) + return result; } else if (in_entry.tid.type == OFFLINE_TYPE_THREAD) { VPRINT(2, "Thread %u entry\n", (uint)in_entry.tid.tid); if (tids[tidx] == INVALID_THREAD_ID) @@ -535,68 +441,91 @@ raw2trace_t::merge_and_process_thread_files() offline_entry_t entry; if (!thread_files[tidx]->read((char*)&entry, sizeof(entry)) || entry.addr.type != OFFLINE_TYPE_IFLUSH) - FATAL_ERROR("Flush missing 2nd entry"); + return "Flush missing 2nd entry"; VPRINT(2, "Flush " PFX"-" PFX"\n", (ptr_uint_t)in_entry.addr.addr, (ptr_uint_t)entry.addr.addr); size += instru.append_iflush(buf, in_entry.addr.addr, (size_t)(entry.addr.addr - in_entry.addr.addr)); buf += size; - } else - FATAL_ERROR("Unknown trace type %d", (int)in_entry.timestamp.type); + } else { + std::stringstream ss; + ss << "Unknown trace type " << (int)in_entry.timestamp.type; + return ss.str(); + } if (size > 0) { CHECK((uint)size < MAX_COMBINED_ENTRIES, "Too many entries"); - if (!out_file.write((char*)buf_base, size)) - FATAL_ERROR("Failed to write to output file"); + if (!out_file->write((char*)buf_base, size)) + return "Failed to write to output file"; } } while (thread_count > 0); + return ""; } -void +std::string +raw2trace_t::check_thread_file(std::istream *f) +{ + // Check version header. + offline_entry_t ver_entry; + if (!f->read((char*)&ver_entry, sizeof(ver_entry))) { + return "Unable to read thread log file"; + } + if (ver_entry.extended.type != OFFLINE_TYPE_EXTENDED || + ver_entry.extended.ext != OFFLINE_EXT_TYPE_HEADER) { + return "Thread log file is corrupted: missing version entry"; + } + if (ver_entry.extended.value != OFFLINE_FILE_VERSION) { + std::stringstream ss; + ss << "Version mismatch: expect " << OFFLINE_FILE_VERSION << " vs " + << (int)ver_entry.extended.value; + return ss.str(); + } + return ""; +} + +std::string raw2trace_t::do_conversion() { + std::string error = read_and_map_modules(modmap); + if (!error.empty()) + return error; trace_entry_t entry; entry.type = TRACE_TYPE_HEADER; entry.size = 0; entry.addr = TRACE_ENTRY_VERSION; - if (!out_file.write((char*)&entry, sizeof(entry))) - FATAL_ERROR("Failed to write header to output file %s", outname.c_str()); + if (!out_file->write((char*)&entry, sizeof(entry))) + return "Failed to write header to output file"; - read_and_map_modules(); - open_thread_files(); merge_and_process_thread_files(); entry.type = TRACE_TYPE_FOOTER; entry.size = 0; entry.addr = 0; - if (!out_file.write((char*)&entry, sizeof(entry))) - FATAL_ERROR("Failed to write footer to output file %s", outname.c_str()); + if (!out_file->write((char*)&entry, sizeof(entry))) + return "Failed to write footer to output file"; + VPRINT(1, "Successfully converted %zu thread files\n", thread_files.size()); + return ""; } -raw2trace_t::raw2trace_t(std::string indir_in, std::string outname_in) - : indir(indir_in), outname(outname_in), prev_instr_was_rep_string(false), - instrs_are_separate(false) +raw2trace_t::raw2trace_t(const char *module_map_in, + const std::vector<std::istream*> &thread_files_in, + std::ostream *out_file_in, + void *dcontext_in, + unsigned int verbosity_in) + : modmap(module_map_in), thread_files(thread_files_in), out_file(out_file_in), + dcontext(dcontext_in), prev_instr_was_rep_string(false), instrs_are_separate(false), + verbosity(verbosity_in) { - // Support passing both base dir and raw/ subdir. - if (indir.find(OUTFILE_SUBDIR) == std::string::npos) - indir += std::string(DIRSEP) + OUTFILE_SUBDIR; - out_file.open(outname.c_str(), std::ofstream::binary); - if (!out_file) - FATAL_ERROR("Failed to open output file %s", outname.c_str()); - VPRINT(1, "Writing to %s\n", outname.c_str()); - - dcontext = dr_standalone_init(); + if (dcontext == NULL) { + dcontext = dr_standalone_init(); #ifdef ARM - // We keep the mode at ARM and rely on LSB=1 offsets in the modoffs fields - // to trigger Thumb decoding. - dr_set_isa_mode(dcontext, DR_ISA_ARM_A32, NULL); + // We keep the mode at ARM and rely on LSB=1 offsets in the modoffs fields + // to trigger Thumb decoding. + dr_set_isa_mode(dcontext, DR_ISA_ARM_A32, NULL); #endif + } } raw2trace_t::~raw2trace_t() { - out_file.close(); - for (std::vector<std::ifstream*>::iterator fi = thread_files.begin(); - fi != thread_files.end(); ++fi) - (*fi)->close(); unmap_modules(); } diff --git a/clients/drcachesim/tracer/raw2trace.h b/clients/drcachesim/tracer/raw2trace.h index 4af3b3fa108cf6351b776067c2e43fe73b9e8cf4..d736a3eaf9762afdb433806b7f939259729d69a7 100644 --- a/clients/drcachesim/tracer/raw2trace.h +++ b/clients/drcachesim/tracer/raw2trace.h @@ -38,7 +38,7 @@ #include "dr_api.h" #include "drmemtrace.h" -#include "../common/trace_entry.h" +#include "trace_entry.h" #include <fstream> #include <vector> @@ -58,32 +58,37 @@ struct module_t { class raw2trace_t { public: - raw2trace_t(std::string indir, std::string outname); + // module_map, thread_files and out_file are all owned and opened/closed by the + // caller. + raw2trace_t(const char *module_map, const std::vector<std::istream*> &thread_files, + std::ostream *out_file, void *dcontext = NULL, + unsigned int verbosity = 0); ~raw2trace_t(); - void do_conversion(); + // Returns non-empty error message on failure. + std::string do_conversion(); + static std::string check_thread_file(std::istream *f); private: - void read_and_map_modules(void); - void unmap_modules(void); - void open_thread_log_file(const char *basename); - void open_thread_files(); - void merge_and_process_thread_files(); - bool append_bb_entries(uint tidx, offline_entry_t *in_entry); - trace_entry_t *append_memref(trace_entry_t *buf_in, uint tidx, instr_t *instr, - opnd_t ref, bool write); + std::string read_and_map_modules(const char *module_map); + std::string unmap_modules(void); + std::string merge_and_process_thread_files(); + std::string append_bb_entries(uint tidx, offline_entry_t *in_entry, + OUT bool *handled); + std::string append_memref(INOUT trace_entry_t **buf_in, uint tidx, instr_t *instr, + opnd_t ref, bool write); - std::string indir; - std::string outname; - std::ofstream out_file; static const uint MAX_COMBINED_ENTRIES = 64; + const char *modmap; void *modhandle; std::vector<module_t> modvec; - std::vector<std::ifstream*> thread_files; + std::vector<std::istream*> thread_files; + std::ostream *out_file; void *dcontext; bool prev_instr_was_rep_string; // This indicates that each memref has its own PC entry and that each // icache entry does not need to be considered a memref PC entry as well. bool instrs_are_separate; + unsigned int verbosity; }; #endif /* _RAW2TRACE_H_ */ diff --git a/clients/drcachesim/tracer/raw2trace_directory.cpp b/clients/drcachesim/tracer/raw2trace_directory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ee6c1bc8f2cdb4b12564f8778d713cc755b9e6d0 --- /dev/null +++ b/clients/drcachesim/tracer/raw2trace_directory.cpp @@ -0,0 +1,184 @@ +/* ********************************************************** + * Copyright (c) 2017 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 VMWARE, 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. + */ + +/* raw2trace helper to iterate directories and open files. + * Separate from raw2trace_t, so that raw2trace doesn't depend on dr_frontend. + */ + +#include <cstring> +#include <iostream> +#include <vector> + +#ifdef UNIX +# include <dirent.h> /* opendir, readdir */ +# include <unistd.h> /* getcwd */ +#else +# define UNICODE +# define _UNICODE +# define WIN32_LEAN_AND_MEAN +# include <windows.h> +# include <direct.h> /* _getcwd */ +# pragma comment(lib, "User32.lib") +#endif + +#include "dr_api.h" +#include "dr_frontend.h" +#include "raw2trace.h" +#include "raw2trace_directory.h" +#include "utils.h" + +#define FATAL_ERROR(msg, ...) do { \ + fprintf(stderr, "ERROR: " msg "\n", ##__VA_ARGS__); \ + fflush(stderr); \ + exit(1); \ +} while (0) + +#define CHECK(val, msg, ...) do { \ + if (!(val)) FATAL_ERROR(msg, ##__VA_ARGS__); \ +} while (0) + +#define VPRINT(level, ...) do { \ + if (this->verbosity >= (level)) { \ + fprintf(stderr, "[drmemtrace]: "); \ + fprintf(stderr, __VA_ARGS__); \ + } \ +} while (0) + +#ifdef UNIX +void +raw2trace_directory_t::open_thread_files() +{ + struct dirent *ent; + DIR *dir = opendir(indir.c_str()); + VPRINT(1, "Iterating dir %s\n", indir.c_str()); + if (dir == NULL) + FATAL_ERROR("Failed to list directory %s", indir.c_str()); + while ((ent = readdir(dir)) != NULL) + open_thread_log_file(ent->d_name); + closedir (dir); +} +#else +void +raw2trace_directory_t::open_thread_files() +{ + HANDLE find = INVALID_HANDLE_VALUE; + WIN32_FIND_DATAW data; + char path[MAXIMUM_PATH]; + TCHAR wpath[MAXIMUM_PATH]; + VPRINT(1, "Iterating dir %s\n", indir.c_str()); + // Append \* + dr_snprintf(path, BUFFER_SIZE_ELEMENTS(path), "%s\\*", indir.c_str()); + NULL_TERMINATE_BUFFER(path); + if (drfront_char_to_tchar(path, wpath, BUFFER_SIZE_ELEMENTS(wpath)) != + DRFRONT_SUCCESS) + FATAL_ERROR("Failed to convert from utf-8 to utf-16"); + find = FindFirstFileW(wpath, &data); + if (find == INVALID_HANDLE_VALUE) + FATAL_ERROR("Failed to list directory %s\n", indir.c_str()); + do { + if (!TESTANY(data.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY)) { + if (drfront_tchar_to_char(data.cFileName, path, BUFFER_SIZE_ELEMENTS(path)) != + DRFRONT_SUCCESS) + FATAL_ERROR("Failed to convert from utf-16 to utf-8"); + open_thread_log_file(path); + } + } while (FindNextFile(find, &data) != 0); + FindClose(find); +} +#endif + +void +raw2trace_directory_t::open_thread_log_file(const char *basename) +{ + char path[MAXIMUM_PATH]; + CHECK(basename[0] != '/', + "dir iterator entry %s should not be an absolute path\n", basename); + // Skip the module list log. + if (strcmp(basename, DRMEMTRACE_MODULE_LIST_FILENAME) == 0) + return; + // Skip any non-.raw in case someone put some other file in there. + if (strstr(basename, OUTFILE_SUFFIX) == NULL) + return; + if (dr_snprintf(path, BUFFER_SIZE_ELEMENTS(path), "%s%s%s", + indir.c_str(), DIRSEP, basename) <= 0) { + FATAL_ERROR("Failed to get full path of file %s", basename); + } + NULL_TERMINATE_BUFFER(path); + thread_files.push_back(new std::ifstream(path, std::ifstream::binary)); + if (!(*thread_files.back())) + FATAL_ERROR("Failed to open thread log file %s", path); + std::string error = raw2trace_t::check_thread_file(thread_files.back()); + if (!error.empty()) { + FATAL_ERROR("Failed sanity checks for thread log file %s: %s", path, + error.c_str()); + } + VPRINT(1, "Opened thread log file %s\n", path); +} + +raw2trace_directory_t::raw2trace_directory_t(const std::string &indir_in, + const std::string &outname_in, + unsigned int verbosity_in) + : indir(indir_in), outname(outname_in), verbosity(verbosity_in) +{ + // Support passing both base dir and raw/ subdir. + if (indir.find(OUTFILE_SUBDIR) == std::string::npos) + indir += std::string(DIRSEP) + OUTFILE_SUBDIR; + std::string modfilename = indir + std::string(DIRSEP) + + DRMEMTRACE_MODULE_LIST_FILENAME; + modfile = dr_open_file(modfilename.c_str(), DR_FILE_READ); + if (modfile == INVALID_FILE) + FATAL_ERROR("Failed to open module file %s", modfilename.c_str()); + uint64 modfile_size; + if (!dr_file_size(modfile, &modfile_size)) + FATAL_ERROR("Failed to get module file size: %s", modfilename.c_str()); + size_t modfile_size_ = (size_t)modfile_size; + modfile_bytes = new char[modfile_size_]; + if (dr_read_file(modfile, modfile_bytes, modfile_size_) < (ssize_t)modfile_size_) + FATAL_ERROR("Didn't read whole module file %s", modfilename.c_str()); + + out_file.open(outname.c_str(), std::ofstream::binary); + if (!out_file) + FATAL_ERROR("Failed to open output file %s", outname.c_str()); + VPRINT(1, "Writing to %s\n", outname.c_str()); + + open_thread_files(); +} + +raw2trace_directory_t::~raw2trace_directory_t() +{ + delete[] modfile_bytes; + dr_close_file(modfile); + for (std::vector<std::istream*>::iterator fi = thread_files.begin(); + fi != thread_files.end(); ++fi) { + delete *fi; + } +} diff --git a/clients/drcachesim/tracer/raw2trace_directory.h b/clients/drcachesim/tracer/raw2trace_directory.h new file mode 100644 index 0000000000000000000000000000000000000000..afbe75a65385f049f13b31810e564800d9c72b85 --- /dev/null +++ b/clients/drcachesim/tracer/raw2trace_directory.h @@ -0,0 +1,61 @@ +/* ********************************************************** + * Copyright (c) 2017 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 VMWARE, 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 _RAW2TRACE_HELPER_H_ +#define _RAW2TRACE_HELPER_H_ 1 + +#endif /* _RAW2TRACE_HELPER_H_ */ + +#include <fstream> +#include <string> +#include <vector> + +#include "dr_api.h" + +class raw2trace_directory_t { +public: + raw2trace_directory_t(const std::string &indir, const std::string &outname, + unsigned int verbosity = 0); + ~raw2trace_directory_t(); + + char *modfile_bytes; + std::vector<std::istream*> thread_files; + std::ofstream out_file; + +private: + void open_thread_files(); + void open_thread_log_file(const char *basename); + file_t modfile; + std::string indir; + std::string outname; + unsigned int verbosity; +}; diff --git a/clients/drcachesim/tracer/raw2trace_launcher.cpp b/clients/drcachesim/tracer/raw2trace_launcher.cpp index 54eab671cf256b33adecc72a4e867eb1ee1126be..49000f96086521a16fa180c14497376b225ef723 100644 --- a/clients/drcachesim/tracer/raw2trace_launcher.cpp +++ b/clients/drcachesim/tracer/raw2trace_launcher.cpp @@ -39,16 +39,10 @@ # include <windows.h> #endif -#include "dr_api.h" #include "droption.h" #include "dr_frontend.h" #include "raw2trace.h" - -#define FATAL_ERROR(msg, ...) do { \ - fprintf(stderr, "ERROR: " msg "\n", ##__VA_ARGS__); \ - fflush(stderr); \ - exit(1); \ -} while (0) +#include "raw2trace_directory.h" static droption_t<std::string> op_indir (DROPTION_SCOPE_FRONTEND, "indir", "", "[Required] Directory with trace input files", @@ -58,11 +52,16 @@ static droption_t<std::string> op_out (DROPTION_SCOPE_FRONTEND, "out", "", "[Required] Path to output file", "Specifies the path to the output file."); -// Non-static for use by raw2trace.cpp -droption_t<unsigned int> op_verbose +static droption_t<unsigned int> op_verbose (DROPTION_SCOPE_FRONTEND, "verbose", 0, "Verbosity level for diagnostic output", "Verbosity level for diagnostic output."); +#define FATAL_ERROR(msg, ...) do { \ + fprintf(stderr, "ERROR: " msg "\n", ##__VA_ARGS__); \ + fflush(stderr); \ + exit(1); \ +} while (0) + int _tmain(int argc, const TCHAR *targv[]) { @@ -80,7 +79,14 @@ _tmain(int argc, const TCHAR *targv[]) FATAL_ERROR("Usage error: %s\nUsage:\n%s", parse_err.c_str(), droption_parser_t::usage_short(DROPTION_SCOPE_ALL).c_str()); } - raw2trace_t raw2trace(op_indir.get_value(), op_out.get_value()); - raw2trace.do_conversion(); + + raw2trace_directory_t dir(op_indir.get_value(), op_out.get_value(), + op_verbose.get_value()); + raw2trace_t raw2trace(dir.modfile_bytes, dir.thread_files, &dir.out_file, NULL, + op_verbose.get_value()); + std::string error = raw2trace.do_conversion(); + if (!error.empty()) + FATAL_ERROR("Conversion failed: %s", error.c_str()); + return 0; } diff --git a/suite/tests/CMakeLists.txt b/suite/tests/CMakeLists.txt index 10de686d2bc9df578ebe231328ecd61193289445..72929231adff3a37f8511ba221ec82a910dfd756 100644 --- a/suite/tests/CMakeLists.txt +++ b/suite/tests/CMakeLists.txt @@ -2563,6 +2563,29 @@ if (CLIENT_INTERFACE) torunonly_drcacheoff(burst_threads tool.drcacheoff.burst_threads "" "") set(tool.drcacheoff.burst_threads_nodr ON) + if (NOT APPPLE) + # Test that raw2trace doesn't do more IO than it should. + get_target_path_for_execution(raw2trace_io_path tool.drcacheoff.raw2trace_io) + prefix_cmd_if_necessary(raw2trace_io_path ON ${raw2trace_io_path}) + macro (torunonly_raw2trace testname exetgt extra_ops app_args) + torunonly_ci(tool.raw2trace.${testname} ${exetgt} drcachesim + "raw2trace-${testname}.c" # for templatex basename + "-offline ${extra_ops}" "" "${app_args}") + set(tool.raw2trace.${testname}_toolname "drcachesim") + set(tool.raw2trace.${testname}_basedir + "${PROJECT_SOURCE_DIR}/clients/drcachesim/tests") + set(tool.raw2trace.${testname}_rawtemp ON) # no preprocessor + set(tool.raw2trace.${testname}_runcmp + "${CMAKE_CURRENT_SOURCE_DIR}/runmulti.cmake") + set(tool.raw2trace.${testname}_precmd + "foreach@${CMAKE_COMMAND}@-E@remove_directory@drmemtrace.${exetgt}.*.dir") + set(tool.raw2trace.${testname}_postcmd + "${raw2trace_io_path}@-indir@drmemtrace.${exetgt}.*.dir@-out@drraw2trace.${exetgt}.out") + endmacro() + # actual trace processing not important -- set a very small limit for speed + torunonly_raw2trace(simple ${ci_shared_app} "-max_trace_size 8K" "") + endif() + # FIXME i#2099: the weak symbol is not supported not work on Windows torunonly_drcacheoff(burst_client tool.drcacheoff.burst_client "" "") set(tool.drcacheoff.burst_client_nodr ON)