Use of deterministic execution in testing and debugging of distributed software