* Copyright (c) 2023 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.
*/
* checks that the timestamp for second buffer in a new window is closer to the
* previous timestamp than the sleep time.
*/
#include <assert.h>
#include <chrono>
#include <iostream>
#include <string.h>
#include <thread>
#include "analysis_tool.h"
#include "dr_api.h"
#include "scheduler.h"
#include "tracer/raw2trace.h"
#include "tracer/raw2trace_directory.h"
namespace dynamorio {
namespace drmemtrace {
namespace {
constexpr int SECONDS_TO_SLEEP = 3;
constexpr int SECONDS_TO_TIMESTAMP = 1000000;
}
bool
my_setenv(const char *var, const char *value)
{
#ifdef UNIX
return setenv(var, value, 1 ) == 0;
#else
return SetEnvironmentVariable(var, value) == TRUE;
#endif
}
int
fib_with_sleep(int n)
{
dr_fprintf(STDERR, "Calculating fibonacci of: %d\n", n);
std::this_thread::sleep_for(std::chrono::seconds(SECONDS_TO_SLEEP));
if (n <= 1)
return 1;
return fib_with_sleep(n - 1) + fib_with_sleep(n - 2);
}
static std::string
post_process()
{
const char *raw_dir;
drmemtrace_status_t mem_res = drmemtrace_get_output_path(&raw_dir);
assert(mem_res == DRMEMTRACE_SUCCESS);
std::string outdir = std::string(raw_dir) + DIRSEP + "trace";
void *dr_context = dr_standalone_init();
raw2trace_directory_t dir;
if (!dr_create_dir(outdir.c_str())) {
std::cerr << "Failed to create output dir";
assert(false);
}
std::string dir_err = dir.initialize(raw_dir, outdir);
assert(dir_err.empty());
raw2trace_t raw2trace(dir.modfile_bytes_, dir.in_files_, dir.out_files_,
dir.out_archives_, dir.encoding_file_,
dir.serial_schedule_file_, dir.cpu_schedule_file_, dr_context,
0
#ifdef WINDOWS
* causes problems. We disable the pool for now.
*/
,
0
#endif
);
std::string error = raw2trace.do_conversion();
if (!error.empty()) {
std::cerr << "raw2trace failed: " << error << "\n";
assert(false);
}
dr_standalone_exit();
return outdir;
}
static std::string
gather_trace()
{
std::string dr_ops(
"-stderr_mask 0xc -client_lib ';;-offline -offline -trace_after_instrs 1000 "
"-trace_for_instrs 2500 -retrace_every_instrs 1000");
if (!my_setenv("DYNAMORIO_OPTIONS", dr_ops.c_str()))
std::cerr << "failed to set env var!\n";
dr_app_setup();
assert(!dr_app_running_under_dynamorio());
dr_app_start();
assert(dr_app_running_under_dynamorio());
fib_with_sleep(4);
dr_app_stop_and_cleanup();
assert(!dr_app_running_under_dynamorio());
return post_process();
}
int
test_main(int argc, const char *argv[])
{
std::string dir = gather_trace();
void *dr_context = dr_standalone_init();
scheduler_t scheduler;
std::vector<scheduler_t::input_workload_t> sched_inputs;
sched_inputs.emplace_back(dir);
if (scheduler.init(sched_inputs, 1, scheduler_t::make_scheduler_serial_options()) !=
scheduler_t::STATUS_SUCCESS) {
std::cerr << "Failed to initialize scheduler " << scheduler.get_error_string()
<< "\n";
exit(1);
}
auto *stream = scheduler.get_stream(0);
uint64_t prior_timestamp = 0;
while (true) {
memref_t memref;
scheduler_t::stream_status_t status = stream->next_record(memref);
if (status == scheduler_t::STATUS_EOF) {
break;
}
assert(status == scheduler_t::STATUS_OK);
if (memref.marker.type == TRACE_TYPE_MARKER &&
memref.marker.marker_type == TRACE_MARKER_TYPE_TIMESTAMP) {
if (prior_timestamp != 0) {
if ((memref.marker.marker_value - prior_timestamp) >
SECONDS_TO_SLEEP * SECONDS_TO_TIMESTAMP) {
std::cerr << "window_test FAILED\n";
exit(1);
}
break;
}
prior_timestamp = memref.marker.marker_value;
}
}
dr_standalone_exit();
std::cerr << "window_test passed\n";
return 0;
}
}
}