[erlang-questions] Deterministic playback of a simulation?

Richard Evans richardprideauxevans@REDACTED
Fri May 18 04:36:05 CEST 2012


I have a multiplayer simulation game running in erlang, involving
multiple characters making decisions etc. Each game instance uses a
few (currently, 4) erlang processes running concurrently,
communicating with an AI simulator written in C.

Everything is working well and I am enjoying using erlang.

But there is one thing I am finding tricky.

For QA purposes, I want to be able to record the exact sequence of
function-calls, so I can play the game back exactly,
deterministically.

My current approach is this: I have a global ets table storing a list
of function-calls. Then, whenever I was calling a function I want to
record - instead of calling the function directly - I call a procedure
which adds the function to the list of function-calls, and then calls
it:

call_and_store(Fun, Args) ->
    add_to_script(Fun, Args);
    apply(lobby, Fun, Args).

add_to_script(Fun, Args) ->
    Info = ets:info(script),
    {size, Size} = lists:keyfind(size, 1, Info),
    io:format("Inserting {~p,~p,~p}~n", [Size,Fun,Args]),
    ets:insert(script, {Size, Fun, Args}).

This approach does not seem to work well because of erlang's
pre-emptive scheduling. If two concurrent processes both invoke
call_and_store, then it is possible (and seems to actually be
happening) that erlang's pre-emptive scheduler may stop processing one
instance of call_and_store between execution of add_to_script and
execution of apply. If this happens, the order of execution and the
order of recorded function-calls will diverge, we don't have an
accurate recording of the set of function-calls, and we won't be able
to deterministically playback.

So my question is: is there a way to prevent the scheduler from
yielding during a block of code? Some way to insist the block is
called as one unit, like this:

call_and_store(Fun, Args) ->
	!!!prevent_yielding,
    add_to_script(Fun, Args);
    apply(lobby, Fun, Args),
	!!!allow_yielding.

My guess is: no. This does not seem very erlangy.

Alternatively, is there a different approach which can produce the
desired list of function-calls? My current approach seems to go
against the erlang grain, involving writing to a shared global table.
Is there a better, more erlangy, way of doing this?



thanks,
~Richard



More information about the erlang-questions mailing list