Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Record and replay architected timer accesses on arm64 #3852

Merged
merged 1 commit into from
Oct 18, 2024

Conversation

pcc
Copy link
Contributor

@pcc pcc commented Oct 17, 2024

This works using the recently added support for prctl(PR_SET_TSC) on arm64 which is due to be released in kernel version 6.12.

Fixes #3740

@pcc
Copy link
Contributor Author

pcc commented Oct 17, 2024

The new tests will need to be skipped on arm64 if the prctl is not supported; that's what's causing the CI failure.

@@ -230,7 +230,7 @@ DiversionSession::DiversionResult DiversionSession::diversion_step(
auto special_instruction = special_instruction_at(t, t->ip());
if (special_instruction.opcode == SpecialInstOpcode::X86_RDTSC) {
size_t len = special_instruction_len(special_instruction.opcode);
uint64_t rdtsc_value = next_rdtsc_value();
uint64_t rdtsc_value = next_timer_counter();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Normally for a change of this size it would be better to split out the renaming into its own commit, but I don't think we need to do this now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack

@@ -1114,6 +1114,14 @@ void Task::post_exec_syscall(const std::string& original_exe_file) {
remote.infallible_syscall(syscall_number_for_arch_prctl(arch()),
ARCH_SET_CPUID, 0);
}
if (arch() == aarch64) {
if (remote.syscall(syscall_number_for_prctl(remote.task()->arch()),
PR_SET_TSC, PR_TSC_SIGSEGV, 0, 0) != 0) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why aren't we doing this from set_up_process_arch() in Task.cc where we do it for x86?

And I think we need to change Task::reenable_cpuid_tsc() to work for ARM too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why aren't we doing this from set_up_process_arch() in Task.cc where we do it for x86?

That's because the arm64 prctl does not preserve this state across an execve.

And I think we need to change Task::reenable_cpuid_tsc() to work for ARM too.

Done.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's because the arm64 prctl does not preserve this state across an execve.

Is this intentionally different from x86? Because that difference sounds very unfortunate :-(

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it would have been difficult to follow x86 here because PR_SET_TSC on arm64 is 64-bit only and it's not clear what should happen when a 64-bit process execs a 32-bit process which then execs a 64-bit process.

I think of the x86 behavior as a mistake (which was corrected when ARCH_SET_CPUID was added), PR_SET_TSC is really a property of the code running in a process and not necessarily that of the child processes.

void breakpoint(void) {}

int main(void) {
initial_cntfrq = cntfrq();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this test should detect whether the kernel supports PR_SET_TSC.

One way to do that would be to give it a command-line option (something simple like "any arguments at all") that checks whether PR_SET_TSC is EINVAL and returns an exit code indicating that. Then we can call it (not under rr) from arch_timer.run and skip the test if that PR_SET_TSC is not supported.

Another way to do it would be in record_syscall.cc --- make PR_SET_TSC return EINVAL if the underlying kernel doesn't support it. Then the test can call PR_SET_TSC and bail out with EXIT-SUCCESS if it gets EINVAL. This would be good... currently when running under rr PR_SET_TSC claims to work even if it actually doesn't.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's go with the first option. We've already had to accept that if prctl(PR_SET_TSC) isn't implemented in the kernel, things will be slightly broken, and prctl(PR_SET_TSC) not functioning correctly inside the recorded process is probably less of a problem than the nondeterministic timers.

Since we need to skip two tests (arm/arch_timer and prctl_tsc) , I decided to do the test as part of a separate program that is called by both tests' .run scripts.

In the process of doing so I discovered that I had added the new test to the wrong list so it wasn't actually running the .run script (which turned out to have a bug which meant that it would always fail), so I fixed that as well.

This works using the recently added support for prctl(PR_SET_TSC) on
arm64 which is due to be released in kernel version 6.12.

Fixes rr-debugger#3740
@rocallahan rocallahan merged commit 6e374de into rr-debugger:master Oct 18, 2024
5 checks passed
@rocallahan
Copy link
Collaborator

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Divergence with tcmalloc on arm64
2 participants