> Guest software running in the Antithesis platform still experiences concurrency similar to a multi-core / multi-machine system, thanks to the process scheduling imposed by the guest OS
This might not exercise the full set of race conditions. When two threads are running simultaneously on separate cores (or hyper-threaded on the same core) they can interleave instructions at a much finer granularity than any OS time slicing would cause, even within instructions.
For example, could it find a race condition where two threads are executing INC [addr] on the same memory address, where context switching between instructions doesn't trigger it?
I'm not actually familiar with the details of hardware MMUs, but would they not enforce sequential access of the address? Or do MMUs allow parallel reads and writes?
That's why they retconned the lock prefix to not be an actual assertion of the #LOCK signal any more.
That's also why TileLink and AMBA include atomic ops like addition and bitwise ops in their coherency protocols rather than just 'claim region'.
That's also why you see newer archs like RISC-V and Arm64 that have both lr/sc style ops, in addition to direct atomic memory ops like amoadd.w, it better matches the primitives of the underlying memory system.
If anyone's interested, here's a publication that talks about it in more detail:
https://dspace.mit.edu/handle/1721.1/72082
The use of performance counters here also reminds me of another project I worked on called Kendo, which was a posix thread like replacement that used performance counters to enforce a deterministic interleaving of synchronization operations (mutexes, etc). The system could guarantee determinism for programs that didn't have race conditions. Back then, I found that counting instructions wasn't deterministic on the processors of the time, but counting store operations was. If anyone's interested in that work, here's the publication:
http://www.cag.csail.mit.edu/~mareko/asplos073-olszewski.pdf
"I’m necessarily leaving out a ton of detail, of course, both for the sake of brevity and competitive edge."
We currently run CI tests using QEMU VMs. These VMs comprise a few systems representative of those that we deploy to production.
Does adopting Antithesis mean that all non-containerized applications would need to be OCI-ified and every interaction would need to be mocked? There's a sort of combinatorial explosion that I'm concerned about when I'm thinking about testing/adding a new service to a system: All services on which it depends need to be mocked and all services which depend on it require creating a mocked version of it.
Seems like a lot of work. Can someone please help clarify things for me?
Also, how could we test the behavior of non-application code like drivers or the kernel itself?
> The Antithesis environment simulates one or more computers using a collection of containers, all running within a single virtual machine managed by our hypervisor.
No mocking needed, but everything needs to share the single VM.
And it sure sounds like they run a custom kernel in the guest, so this is not for kernelspace testing:
> Since the Antithesis platform controls the guest’s scheduler,
var_1 = 0
var_2 = 0
thread_a:
while true:
something_complex()
var_1 ++
thread_b:
while true:
something_complex()
var_2 ++
Under the quoted definition of determinism, for every point in time, var_1 and var_2 should have the same values across all executions. But this would seem to amount to ensuring that exactly the same number of instructions are executed each time a thread is scheduled.AFAIK this is possible by (mis)using performance counters.
"Just to let you know we're not actively working on Hermit in the team..."
https://github.com/facebookexperimental/hermit/issues/34#iss...
Maybe I got lucky but I reported some issues right around the time of their article publication [1] - Nov '22 - and they were pretty responsive then.
[1] https://developers.facebook.com/blog/post/2022/11/22/hermit-...
Or what if my bug is caused by bitflips in failing memory, that lead to impossible control flow paths being hit? Think something like:
if x != 0:
return 1/x
Failing with an error because x is 0.Not hypothetical scenarios, both real bugs I've had to troubleshoot in my career.
https://antithesis.com/docs/applications/reliability/fault_i...
If you know somebody who will pay money for us to prioritize this feature, let me know! Otherwise, I'm sure we'll get to it eventually. We have all kinds of crazy ideas for new faults.
Communication with the outside world is something that we obviously have to ban. This means that all of the inputs to your system are being provided by our platform, and that any dependencies have to be mocked, or run inside the hypervisor with you.
In practice this can cause friction for people with a ton of dependencies. Some of the most common things we've already mocked (for example we have an entire fake AWS that we can run in there with you), and if your dependency is one of our existing customers, we can probably work something out...
In a record-replay debugging product, you want to reproduce the execution of your system to translate what occurred in reality into the debugging lab.
In this product, the goal appears to be creating a deterministic environment so that you can precisely inject non-determinism/faults to probe the response of your product to the environment.
The former is about analyzing bugs your test found, the latter is about creating tests to produce bugs. In that context, your question is unrelated to the product. It does not seek to reproduce flaky tests, it seeks to help invent new and exciting flaky tests.
Congrats on the launch.
One day(^TM) I'm really keen to design a multi-core CPU architecture that allows for deterministic message passing between cores in such a way that you could get this kind of software working with true parallelism.
I am sad that you decided to give up on solving the multi-core parallelism issue, since each guest running on a single core is a dead giveaway to malware that they're not on a real machine, but it's understandable. I do wonder if that means that some class of bugs will be undetectable to this hypervisor, though.
The kinds of state space exploration we do are a lot more general than mutation testing. Our current product does exploration by (1) varying the space of faults, packet delivery times, thread schedules, etc., and (2) driving a customer-provided pseudo-randomized workload. We have plans to make both these mechanisms much more expressive, powerful, and configurable; and we have longer-term plans to add entirely new kinds of testing to the same platform.
Disclosure: I'm one of the co-founders of Antithesis.
> Back then Spanner wasn’t public yet and a lot of people misinterpreted the CAP theorem to say that a strongly consistent database couldn’t also be highly available in the face of network faults.
https://cloud.google.com/blog/products/databases/inside-clou...
especially as that builds off of the extensive work done on x86 counter determinism here: https://web.eece.maine.edu/~vweaver/projects/deterministic/
it turns out x86/amd chips many of the perf counter events are offset by the (unpredictable) interrupt count because the interrupt return instruction uop gets counted as both a user and kernel instruction. On many processors the retired store instruction avoids this issue.