The last few days I've been testing some stuff regarding my engine's time management. I've extended the simple time management with some of the things HGM mentioned in Rustic's progress topic (thanks again HGM) and some of my own ideas.
Then I set to testing the engine in Arena, at the time control of 2 minutes per game, +1 second increment, which CCRL currently uses for Blitz matches.
Let's just say it didn't go well. I've been testing against Dreamer 0.3, because it's on the CCRL-list at around 1600 Elo, and my engine keeps falling between 1600-1700 Elo in short matches against other engines, so I intend to start testing around the 1600-1650 mark.
Rustic's been losing almost every game on time.... except... in the end, it turns out it actually doesn't. Dreamer switches to a super-fast time control when it gets under 1 minute or so, almost moving instantly. I've been delaying doing this. For example (these things can change in the next few days):
1. I use about 0.3x of the alotted move time in iterative deepening. After that time, I abort the ID run.
2. The a/b search function can overshoot up to 3x the alotted time, if it happens to start running because 1. didn't cut it off. The less time the serach has, the lower this factor becomes.
3. When a certain MIN_TIME on the clock has been hit (10 seconds for now), the search stops exceeding the alotted time ("overshoot factor" = 1)
4. If no "moves to go" is given by UCI, the engine assumes that the game is 60 moves long.
5. It calculates its own moves to go as 60 - moves_played + 10 (to avoid that it spends too much time on the last few moves.)
6.- If the game is still going after 60 moves, the engine will always return 100 "moves to go", so the time/move will shorten with each move, and it'll be very fast.
7. If a critical time has been hit (2 seconds for now), and "increment" is being set, the search doesn't even consider "moves to go" and the clock time anymore. The moves available base-time is set to 0, and only the given increment will be used for searching. So Rustic should never drop under 2 seconds on the clock.
Still, Rustic is losing on time in Arena. I've dialed back the max_time factor in iterative deepening to 0.1x, so it only uses 0.1 times the amount of time alotted for the move. I've disabled the overshoot factor. I've set "moves to go" permanently to 100. Because Dreamer switches to moving almost instantly when it gets under a minute (and it has a hash table, which I don't), if it hasn't lost the game already by then, it only has to hold out on time and it'll win.
I got suspicious, and I put several "info string" prints into the code, to inform me about the allotted time per move, moves_to_go, moves_made,elapsed time where Rustic either aborts the search or stops iterative deepening, and so on... and everything checks out.
Very often, the "info string" comes in: "Iterative deepening aborted after 852 ms", or "search time up at 2572 ms (allotted 2572 ms)". Even so, I can still SEE Arena's clock ticking for 1-2 seconds before it actually finishes making the move and switches to the other engine. (It could also be specific to UCI-engines: Rustic is UCI for now, while Dreamer is XBoard.)
So today, I have restored my code to the point where it was two days ago, roughly as outlined in point 1-7 above, and installed CuteChess 1.20 (upgrading from my old 1.0). I've run a 20 game match between Dreamer and Rustic: GM2001 opening book (only 4 moves per side), no adjudication whatsoever except call it a draw if a game exceeds 250 moves.
As it turns out, Rustic completely obliterates Dreamer 0.3 in most games. It can keep up in search depth despite not having a hash table, and it often plays the entire game up to and including mating Dreamer in less than 45 seconds, so it still has 1 minute 15s on the clock when the game is over. (So I can actually slow down the time control management a lot, it seems...) If a game happens to get into the stage above 60 moves to go, where Rustic starts returning 100 moves to go all the time, or at the point where it drops decreasing its time on the clock by only using the increment, it can actually GAIN TIME on the clock, by getting that 1 second increment, and then not using all of it.
In fact, Rustic hasn't lost a single game on time. It wins most of them with a HUGE plus margin under CuteChess... the only games it loses against Dreamer 0.3, are the ones where it is up +0.05, and then does something exceedingly stupid like giving the opponent a passed pawn (which it doesn't know about yet) trying to avoid a draw... which it then will cost the game. I have to make a provision for that. I'll think about that later. (But I can live with this: it is expected behavior for now.)
In the end, it turns out that Rustic behaves _exactly_ as designed when running under CuteChess, and in Arena, it doesn't, because the GUI substracts time even after the engine has already stopped searching and provided its move, eventually getting the engine into time trouble.
Sorry. This has become something of a rant, because I feel I have wasted three evenings in tests that weren't necessary. I'm not going to use Arena for testing in matches. (I was planning on CuteChess anyway, as it can run many games at the same time.)

