Skip to content

Commit

Permalink
i#6299: Collapse redundant entries in schedule files (#6301)
Browse files Browse the repository at this point in the history
Before, we wrote out a schedule file record for every timestamp. But for
scheduling we only need to know the thread switch points, so consecutive
same-thread records are superfluous. This will only get worse with more
timestamps from #6290. Here we collapse consecutive same-thread entries
in both the serial and cpu schedule files, and update the invariant
checker to allow either the old or new type of file.

On simple_app, before (2nd column is tid):

```
$ zcat drmemtrace.*.dir/trace/serial* | od -t d8 -A d -w32 | tail
0002464              1484994    13338489228331182        3               112619
0002496              1484994    13338489228331508        3               112619
0002528              1484994    13338489228337025        3               112886
0002560              1484994    13338489228337031        3               112886
0002592              1484994    13338489228360665        3               113878
0002624              1484994    13338489228360692        3               113878
0002656              1484994    13338489228437577        3               116138
0002688              1484994    13338489228437586        3               116138
0002720              1484994    13338489228520213        3               118090
0002752

$ unzip -p drmemtrace.*.dir/trace/cpu*.zip 3 | od -t d8 -A d -w32 | tail
000520              1484994    13338489228331182        3               112619
000540              1484994    13338489228331508        3               112619
000560              1484994    13338489228337025        3               112886
000580              1484994    13338489228337031        3               112886
0005a0              1484994    13338489228360665        3               113878
0005c0              1484994    13338489228360692        3               113878
0005e0              1484994    13338489228437577        3               116138
000600              1484994    13338489228437586        3               116138
000620              1484994    13338489228520213        3               118090
000640
```

After:
```
$ zcat drmemtrace.*.dir/trace/serial* | od -t d8 -A d -w32 | tail
0000000              1873100    13338569448213406       1                    0
0000032

$ unzip -p drmemtrace.*.dir/trace/cpu*.zip 1 | od -t d8 -A x -w32 | tail
000000              1873100    13338569448213406        1                    0
000020
```

Fixes #6299
  • Loading branch information
derekbruening authored Sep 7, 2023
1 parent 7deb851 commit 739d983
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 21 deletions.
63 changes: 47 additions & 16 deletions clients/drcachesim/tools/invariant_checker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -893,6 +893,12 @@ invariant_checker_t::check_schedule_data(per_shard_t *global)
return l.thread < r.thread;
};
std::sort(serial.begin(), serial.end(), schedule_entry_comparator);
// After i#6299, these files collapse same-thread entries.
std::vector<schedule_entry_t> serial_redux;
for (const auto &entry : serial) {
if (serial_redux.empty() || entry.thread != serial_redux.back().thread)
serial_redux.push_back(entry);
}
// For entries with the same timestamp, the order can differ. We could
// identify each such sequence and collect it into a set but it is simpler to
// read the whole file and sort it the same way.
Expand All @@ -909,24 +915,34 @@ invariant_checker_t::check_schedule_data(per_shard_t *global)
<< " records from the file and observed " << serial.size()
<< " transition in the trace\n";
}
report_if_false(global, serial_file.size() == serial.size(),
"Serial schedule entry count does not match trace");
for (int i = 0; i < static_cast<int>(serial.size()) &&
// We created both types of schedule and select which to compare against.
std::vector<schedule_entry_t> *tomatch;
if (serial_file.size() == serial.size())
tomatch = &serial;
else if (serial_file.size() == serial_redux.size())
tomatch = &serial_redux;
else {
report_if_false(global, false,
"Serial schedule entry count does not match trace");
return;
}
for (int i = 0; i < static_cast<int>(tomatch->size()) &&
i < static_cast<int>(serial_file.size());
++i) {
global->ref_count_ = serial_file[i].start_instruction;
global->tid_ = serial_file[i].thread;
if (knob_verbose_ >= 1) {
std::cerr << "Saw T" << serial[i].thread << " on " << serial[i].cpu
<< " @" << serial[i].timestamp << " "
<< serial[i].start_instruction << " vs file T"
std::cerr << "Saw T" << (*tomatch)[i].thread << " on "
<< (*tomatch)[i].cpu << " @" << (*tomatch)[i].timestamp << " "
<< (*tomatch)[i].start_instruction << " vs file T"
<< serial_file[i].thread << " on " << serial_file[i].cpu << " @"
<< serial_file[i].timestamp << " "
<< serial_file[i].start_instruction << "\n";
}
report_if_false(global,
memcmp(&serial[i], &serial_file[i], sizeof(serial[i])) == 0,
"Serial schedule entry does not match trace");
report_if_false(
global,
memcmp(&(*tomatch)[i], &serial_file[i], sizeof((*tomatch)[i])) == 0,
"Serial schedule entry does not match trace");
}
}
if (cpu_schedule_file_ == nullptr)
Expand All @@ -948,17 +964,32 @@ invariant_checker_t::check_schedule_data(per_shard_t *global)
return l.thread < r.thread;
return l.timestamp < r.timestamp;
});
report_if_false(global, keyval.second.size() == cpu2sched[keyval.first].size(),
"Cpu schedule entry count does not match trace");
for (int i = 0; i < static_cast<int>(cpu2sched[keyval.first].size()) &&
// After i#6299, these files collapse same-thread entries.
// We create both types of schedule and select which to compare against.
std::vector<schedule_entry_t> redux;
for (const auto &entry : cpu2sched[keyval.first]) {
if (redux.empty() || entry.thread != redux.back().thread)
redux.push_back(entry);
}
std::vector<schedule_entry_t> *tomatch;
if (keyval.second.size() == cpu2sched[keyval.first].size())
tomatch = &cpu2sched[keyval.first];
else if (keyval.second.size() == redux.size())
tomatch = &redux;
else {
report_if_false(global, false,
"Cpu schedule entry count does not match trace");
return;
}
for (int i = 0; i < static_cast<int>(tomatch->size()) &&
i < static_cast<int>(keyval.second.size());
++i) {
global->ref_count_ = keyval.second[i].start_instruction;
global->tid_ = keyval.second[i].thread;
report_if_false(global,
memcmp(&cpu2sched[keyval.first][i], &keyval.second[i],
sizeof(keyval.second[i])) == 0,
"Cpu schedule entry does not match trace");
report_if_false(
global,
memcmp(&(*tomatch)[i], &keyval.second[i], sizeof(keyval.second[i])) == 0,
"Cpu schedule entry does not match trace");
}
}
}
Expand Down
22 changes: 17 additions & 5 deletions clients/drcachesim/tracer/raw2trace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1276,9 +1276,16 @@ raw2trace_t::aggregate_and_write_schedule_files()
[](const schedule_entry_t &l, const schedule_entry_t &r) {
return l.timestamp < r.timestamp;
});
// Collapse same-thread entries.
std::vector<schedule_entry_t> serial_redux;
for (const auto &entry : serial) {
if (serial_redux.empty() || entry.thread != serial_redux.back().thread)
serial_redux.push_back(entry);
}
if (serial_schedule_file_ != nullptr) {
if (!serial_schedule_file_->write(reinterpret_cast<const char *>(serial.data()),
serial.size() * sizeof(serial[0])))
if (!serial_schedule_file_->write(
reinterpret_cast<const char *>(serial_redux.data()),
serial_redux.size() * sizeof(serial_redux[0])))
return "Failed to write to serial schedule file";
}
if (cpu_schedule_file_ == nullptr)
Expand All @@ -1288,14 +1295,19 @@ raw2trace_t::aggregate_and_write_schedule_files()
[](const schedule_entry_t &l, const schedule_entry_t &r) {
return l.timestamp < r.timestamp;
});
// Collapse same-thread entries.
std::vector<schedule_entry_t> redux;
for (const auto &entry : keyval.second) {
if (redux.empty() || entry.thread != redux.back().thread)
redux.push_back(entry);
}
std::ostringstream stream;
stream << keyval.first;
std::string err = cpu_schedule_file_->open_new_component(stream.str());
if (!err.empty())
return err;
if (!cpu_schedule_file_->write(
reinterpret_cast<const char *>(keyval.second.data()),
keyval.second.size() * sizeof(keyval.second[0])))
if (!cpu_schedule_file_->write(reinterpret_cast<const char *>(redux.data()),
redux.size() * sizeof(redux[0])))
return "Failed to write to cpu schedule file";
}
return "";
Expand Down

0 comments on commit 739d983

Please sign in to comment.