carykh/PrisonersDilemmaTournament

Using time.time() to limit approximate duration of strategy call

Wout12345 opened this issue · 3 comments

There are several ways agents might want to use as much time as possible to improve their performance (training neural networks/other machine learning, Monte Carlo tree search, ...). I read that a reasonable goal is to finish your turn in 10 ms. Can we import the standard time library so we can just approximately limit the time taken? E.g. as follows:

def strategy(history, memory):
    start = time()
    
    # Do some stuff ...
    
    while time() - start < 0.01:
        # The more stuff we do here, the better ...
    
    # Do some stuff ...
    
    return choice, memory

I’d presume that if you have a valid reason to go over 10ms it shouldn’t be that big of an issue. Spending something like 10s however is a sign that you’re doing something wrong/inefficient

I’d presume that if you have a valid reason to go over 10ms it shouldn’t be that big of an issue. Spending something like 10s however is a sign that you’re doing something wrong/inefficient

I would say that you should definitely try to stay under 10ms per turn (which will be at least 2 seconds just on your strategy for one round). As it is, running the final pool will probably take days even with multiprocessing. If your strategy is slower than 10ms, you're really going to be slowing that down and could risk being removed due to taking too long.

Also, you should generally use time.perf_counter for something like this instead of time.time. It might have a finer resolution and won't be affected if your system clock changes (although that's unlikely in this case).

There are several ways agents might want to use as much time as possible to improve their performance (training neural networks/other machine learning, Monte Carlo tree search, ...). I read that a reasonable goal is to finish your turn in 10 ms.

When you state to finish your turn in 10ms I assume it per call of the strategy method. 10ms is a lot of time, unless you are running the tournament in a raspberry pi, the time it takes might depend a lot on the hardware where it is running. With that in mind this could create a hardware dependency on the performance of such strategy...

I consider my agent implementation to be on the heavy side and it takes 0.13ms per turn (it was taking twice that before optimizing the code) when running it in a modern CPU against a bunch of different strategies. I even scrapped the idea of doing some sort of probabilistic inference to find out what would be the most profitable probable play to do due to concerns for the performance of the whole tournament.

The only way I see for it taking more than 10ms per turn would be with some sort of online learning agent, but I don't think 200 trades is enough for it to profit from it, specially since the learning would be lost after the paired match ended. The rules don't forbid such behavior (as it doesn't count as "being intentionally inefficient with loops or sleep() commands"), but it is sure a concern when comes to it.

I would say that people should use common sense when designing their agent.

For reference, in my machine, the implementation of the some strategies take the following time per turn (per call of strategy):

  • AlwaysCooperate/AlwaysDefect take around 0.75μs
  • grimTrigger takes around 1.00μs
  • most of the TitForTat and similars take around 1.20μs
  • random takes around 1.40μs
  • short but complex strategy implementations, like advanced detectives or windowed scans take something between 10 to 20μs
  • my own agent - that I consider it to be quite heavy - takes around 130μs, while my colleagues made ones take around 35μs

(μs = microseconds or 0.001ms or 10^-6 seconds)

For me 10ms looks like an eternity...