Skip to content

Commit

Permalink
Merge branch 'master' into i3544-stolen-reg-test
Browse files Browse the repository at this point in the history
  • Loading branch information
ksco committed Mar 28, 2024
2 parents 700cfa5 + 2c6069d commit 147bbc8
Show file tree
Hide file tree
Showing 20 changed files with 594 additions and 143 deletions.
5 changes: 5 additions & 0 deletions api/docs/release.dox
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,11 @@ Further non-compatibility-affecting changes include:
#dynamorio::drmemtrace::analysis_tool_t to allow the tool to make holistic
adjustments to the interval snapshots after all have been generated, and before
they are used for merging across shards (potentially), and printing the results.
- Added -abort_on_invariant_error flag that instructs the invariant checker drmemtrace
analysis tool to abort trace analysis when a trace invariant error is found. This
is set to true by default to match the existing behavior of the invariant checker.
- Added a new instr API instr_is_xrstor() that tells whether an instruction is any
variant of the x86 xrstor opcode.

**************************************************
<hr>
Expand Down
3 changes: 2 additions & 1 deletion clients/drcachesim/analyzer_multi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,8 @@ analyzer_multi_t::create_invariant_checker()
}
return new invariant_checker_t(op_offline.get_value(), op_verbose.get_value(),
op_test_mode_name.get_value(),
serial_schedule_file_.get(), cpu_schedule_file_.get());
serial_schedule_file_.get(), cpu_schedule_file_.get(),
op_abort_on_invariant_error.get_value());
}

template <>
Expand Down
11 changes: 10 additions & 1 deletion clients/drcachesim/common/options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -931,7 +931,8 @@ droption_t<std::string> op_syscall_template_file(
"Path to the file that contains system call trace templates.",
"Path to the file that contains system call trace templates. "
"If set, system call traces will be injected from the file "
"into the resulting trace.");
"into the resulting trace. This is still experimental so the template file "
"format may change without backward compatibility.");

// Record filter options.
droption_t<uint64_t> op_filter_stop_timestamp(
Expand Down Expand Up @@ -976,5 +977,13 @@ droption_t<uint64_t> op_trim_after_timestamp(
"Removes all records from the first TRACE_MARKER_TYPE_TIMESTAMP marker with "
"timestamp larger than the specified value.");

droption_t<bool> op_abort_on_invariant_error(
DROPTION_SCOPE_ALL, "abort_on_invariant_error", true,
"Abort invariant checker when a trace invariant error is found.",
"When set to true, the trace invariant checker analysis tool aborts when a trace "
"invariant error is found. Otherwise it prints the error and continues. Also, the "
"total invariant error count is printed at the end; a non-zero error count does not "
"affect the exit code of the analyzer.");

} // namespace drmemtrace
} // namespace dynamorio
1 change: 1 addition & 0 deletions clients/drcachesim/common/options.h
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ extern dynamorio::droption::droption_t<std::string> op_filter_trace_types;
extern dynamorio::droption::droption_t<std::string> op_filter_marker_types;
extern dynamorio::droption::droption_t<uint64_t> op_trim_before_timestamp;
extern dynamorio::droption::droption_t<uint64_t> op_trim_after_timestamp;
extern dynamorio::droption::droption_t<bool> op_abort_on_invariant_error;

} // namespace drmemtrace
} // namespace dynamorio
Expand Down
7 changes: 4 additions & 3 deletions clients/drcachesim/common/trace_entry.h
Original file line number Diff line number Diff line change
Expand Up @@ -940,9 +940,10 @@ typedef enum {
OFFLINE_FILE_TYPE_BIMODAL_FILTERED_WARMUP = 0x2000,
/**
* Indicates an offline trace that contains trace templates for some system calls.
* The individual traces are separated by a #TRACE_MARKER_TYPE_SYSCALL marker which
* also specifies what system call the following trace belongs to. This file can be
* used with -syscall_template_file to raw2trace to create a
* The individual traces are enclosed within a pair of
* #TRACE_MARKER_TYPE_SYSCALL_TRACE_START and #TRACE_MARKER_TYPE_SYSCALL_TRACE_END
* markers which also specify what system call the contained trace belongs to. This
* file can be used with -syscall_template_file to raw2trace to create an
* #OFFLINE_FILE_TYPE_KERNEL_SYSCALLS trace. See the sample file written by the
* burst_syscall_inject.cpp test for more details on the expected format for the
* system call template file.
Expand Down
106 changes: 69 additions & 37 deletions clients/drcachesim/scheduler/scheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1081,8 +1081,9 @@ scheduler_tmpl_t<RecordType, ReaderType>::read_traced_schedule()
tid2input[inputs_[i].tid] = i;
}
std::vector<std::set<uint64_t>> 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
Expand All @@ -1094,9 +1095,13 @@ scheduler_tmpl_t<RecordType, ReaderType>::read_traced_schedule()
std::vector<std::vector<schedule_output_tracker_t>> all_sched(outputs_.size());
// Work around i#6107 by tracking counts sorted by timestamp for each input.
std::vector<std::vector<schedule_input_tracker_t>> input_sched(inputs_.size());
// These hold entries added in the on-disk (unsorted) order.
std::vector<output_ordinal_t> disk_ord2index; // Initially [i] holds i.
std::vector<uint64_t> disk_ord2cpuid; // [i] holds cpuid for entry i.
while (options_.replay_as_traced_istream->read(reinterpret_cast<char *>(&entry),
sizeof(entry))) {
if (entry.cpu != cur_cpu) {
// This is a zipfile component boundary: one conmponent per cpu.
if (cur_cpu != std::numeric_limits<uint64_t>::max()) {
++cur_output;
if (cur_output >= static_cast<int>(outputs_.size())) {
Expand All @@ -1105,9 +1110,8 @@ scheduler_tmpl_t<RecordType, ReaderType>::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.
Expand Down Expand Up @@ -1135,16 +1139,49 @@ scheduler_tmpl_t<RecordType, ReaderType>::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<output_ordinal_t>(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<output_ordinal_t> disk_ord2output(disk_ord2index.size());
for (size_t i = 0; i < disk_ord2index.size(); ++i) {
disk_ord2output[disk_ord2index[i]] = static_cast<output_ordinal_t>(i);
}
for (int disk_idx = 0; disk_idx < static_cast<output_ordinal_t>(outputs_.size());
++disk_idx) {
if (disk_idx >= static_cast<int>(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<int>(all_sched[output_idx].size()); ++sched_idx) {
auto &segment = all_sched[output_idx][sched_idx];
for (int sched_idx = 0; sched_idx < static_cast<int>(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);
Expand All @@ -1158,27 +1195,27 @@ scheduler_tmpl_t<RecordType, ReaderType>::read_traced_schedule()
" time=%" PRId64 "\n",
sched_idx, segment.input, segment.start_instruction,
segment.stop_instruction, segment.timestamp);
if (sched_idx + 1 < static_cast<int>(all_sched[output_idx].size()) &&
segment.input == all_sched[output_idx][sched_idx + 1].input &&
if (sched_idx + 1 < static_cast<int>(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<int>(all_sched[output_idx].size()) &&
segment.input == all_sched[output_idx][sched_idx + 1].input &&
} else if (sched_idx + 1 < static_cast<int>(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();
Expand All @@ -1193,24 +1230,19 @@ scheduler_tmpl_t<RecordType, ReaderType>::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;
Expand Down
22 changes: 18 additions & 4 deletions clients/drcachesim/tests/burst_syscall_inject.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* **********************************************************
* Copyright (c) 2016-2023 Google, Inc. All rights reserved.
* Copyright (c) 2016-2024 Google, Inc. All rights reserved.
* **********************************************************/

/*
Expand Down Expand Up @@ -141,16 +141,22 @@ write_system_call_template(void *dr_context)
trace_entry_t to_write = *reinterpret_cast<trace_entry_t *>(buf_at);
write_trace_entry(writer, to_write);
}
write_trace_entry(writer, make_marker(TRACE_MARKER_TYPE_CACHE_LINE_SIZE, 64));
write_trace_entry(writer, make_marker(TRACE_MARKER_TYPE_PAGE_SIZE, 4096));

// Write the trace template for SYS_getpid.
write_trace_entry(writer, make_marker(TRACE_MARKER_TYPE_SYSCALL, SYS_getpid));
write_trace_entry(writer,
make_marker(TRACE_MARKER_TYPE_SYSCALL_TRACE_START, SYS_getpid));
// Just a random instruction.
instr_in_getpid = XINST_CREATE_nop(dr_context);
write_instr_entry(dr_context, writer, instr_in_getpid,
reinterpret_cast<app_pc>(PC_SYSCALL_GETPID));
write_trace_entry(writer,
make_marker(TRACE_MARKER_TYPE_SYSCALL_TRACE_END, SYS_getpid));

// Write the trace template for SYS_gettid.
write_trace_entry(writer, make_marker(TRACE_MARKER_TYPE_SYSCALL, SYS_gettid));
write_trace_entry(writer,
make_marker(TRACE_MARKER_TYPE_SYSCALL_TRACE_START, SYS_gettid));
// Just a random instruction.
#ifdef X86
# define TEST_REG DR_REG_XDX
Expand All @@ -167,7 +173,14 @@ write_system_call_template(void *dr_context)
write_trace_entry(
writer,
make_memref(READ_MEMADDR_GETTID, TRACE_TYPE_READ, opnd_size_in_bytes(OPSZ_PTR)));
write_trace_entry(writer,
make_marker(TRACE_MARKER_TYPE_SYSCALL_TRACE_END, SYS_gettid));

// Write footer.
dynamorio::drmemtrace::trace_entry_t thread_exit = {
dynamorio::drmemtrace::TRACE_TYPE_THREAD_EXIT, 0, { /*tid=*/1 }
};
write_trace_entry(writer, thread_exit);
write_trace_entry(writer, make_footer());
std::cerr << "Done writing system call trace template\n";
return syscall_trace_template_file;
Expand Down Expand Up @@ -406,7 +419,8 @@ test_main(int argc, const char *argv[])
std::cerr << "Getting basic counts for system call trace template\n";
basic_counts_t::counters_t template_counts = get_basic_counts(syscall_trace_template);
if (!(template_counts.instrs == 2 && template_counts.encodings == 2 &&
template_counts.syscall_number_markers == 2)) {
// We only have trace start and end markers, no syscall number markers.
template_counts.syscall_number_markers == 0)) {
std::cerr << "Unexpected counts in system call trace template: "
<< syscall_trace_template << ": #instrs: " << template_counts.instrs
<< ", #encodings: " << template_counts.encodings
Expand Down
Loading

0 comments on commit 147bbc8

Please sign in to comment.