Initialization Code Runtime Reduction Effort
The highlighted comment was created in this revision.
Here I am going to post information on CPU performance of configuration, construction, drive, gun, and radar. Configuration is one time setting of parameters at beginning of first round. Construction is construction of the scenarios, drives, guns, etc. and loading them into my component chain, also a one time event at beginning of first round. Load stats is loading the previous set of statistics from disk so they can be updated and written back out at the end of the battle. Drive, gun, and radar times are averages and peaks over every tick for the entire battle.
In all I ran averages against 10 seasons.
12.2 is XanderCat 12.2, while 12.3 is the development version of XanderCat 12.3 with reductions to initialization by using static initialization blocks and whatever other improvements I can make. I don't have stats for 12.3 yet; hopefully I can edit this post once I have them.
12.2 Normal | 12.2 Shielding | 12.3 Normal | 12.3 Shielding | |
---|---|---|---|---|
Opponent | Tron | Virus | Tron | Virus |
Configure AVG | 0.454 | 0.478 | ||
Construction AVG | 1.304 | 1.353 | ||
Load Stats AVG | 3.730 | 3.686 | ||
Drive AVG | 0.478 | 0.031 | ||
Drive P1 | 12.51 | 5.25 | ||
Drive P2 | 11.91 | 4.70 | ||
Drive P3 | 11.46 | 4.55 | ||
Gun AVG | 0.465 | 0.153 | ||
Gun P1 | 7.12 | 7.17 | ||
Gun P2 | 6.03 | 5.13 | ||
Gun P3 | 5.65 | 4.26 | ||
Radar AVG | 0.0019 | 0.0018 | ||
Radar P1 | 0.10 | 0.28 | ||
Radar P2 | 0.06 | 0.14 | ||
Radar P3 | 0.04 | 0.04 |
I hadn't thought about it previously, but I can't help but wonder if the loading of battle statistics is one of the bigger problems with skipping turns at the beginning of the first round. On my system, the CPU hit is not all that dramatic, but it could be worse on other systems. Maybe I could defer loading the battle stats until the end of the battle? They are not really needed until the end. How much time does Robocode give at the end of battle for final processing like writing to files?
I can think of 2 factors which can mess up skipped turns. Dynamic overclocking and excessive amounts of client instances.
- Dynamic overclocking changes CPU speed based on load. If the Robocode engine CPU constant is calibrated for an overclocked CPU, then in the beginning of a battle, the reduced clock will provoke skipped turns.
- Too many client instances make them interfere with each other. Sometimes clients use 2 threads, sometimes only 1. When they use 2 and there isn't any idle core, they steal CPU from another instance and the slower processing speed can provoke skipped turns.
Some thoughts...
- For what it's worth, I tried to generate different CPU constants based on whether it was dynamic overclocking or not, but wasn't able to. Maybe the trigger threshold is well below what a single Robocode instance or the CPU constant calculation uses on my machine.
- While Robocode does use multiple threads - you might see 50% on two cores or 100% on one core - it only uses 1 at a time, so I'm not sure it's ever really stealing CPU.
- Since a lot of modern multi-core processors include hyperthreading, there should be some extra buffer such that using 1 Robocode per core is ok.
To me, the bigger problems are:
- Measuring CPU time for a single tick in nanoseconds is not nearly as accurate as we need it to be.
- There's always other system stuff that could use some CPU. Combine with the lack of accuracy and it's really dangerous to penalize for taking too long over a timeframe of just one tick.
I don't know, I agree that dynamic overclocking is theoretically a concern, but from what I can remember, skipped turns have been quirky since long before we all had huge multi-core machines with hyperthreading and dynamic overclocking.
Quirky like skipping more turns vs an opponent that uses a lot of CPU (but doesn't skip turns!), or skipping lots more turns in the first 50-100 ticks of a battle. Obviously you do some initialization in the first tick, but shouldn't the subsequent ticks be mostly unaffected by that? Seems like that was never the case and still isn't. I guess garbage collection being outside of the scope of Robocode's vision is the most likely culprit for all this. But it's pretty frustrating, in any case.
That's a good point I wasn't even thinking about. Looking at the log Wompi posted again, I can see that all setup was completed on turn 0, and turn 0 wasn't skipped.
Voidious -- did you check to see if XanderCat appeared to be skipping a lot of turns on your Ubuntu/OJDK machine?
I can try to improve the CPU performance of my wave surfing drive and guess factor guns, and that might help, but it doesn't really explain the huge number of skipped turns on the first round. In the meantime, if skipped turns is a problem on Voidious' machine, I suppose for now I could just modify my bullet shielding system to try to account for skipped turns.
Remembered a 3rd possible cause of skipped turns. The JVM executes all code in interpreted mode for a while until JIT compiler kicks in. And at least in Sun/Oracle JVMs, the default JIT mode, client or server, varies with OS.
Hmm... frustratingly, XanderCat seems to have a higher success rate vs Virus (the most problematic on my system) when running through the UI. I did catch one 56% score with only 2 skipped turns, though, which raises some doubt that skipped turns are the issue (or only issue). Running some more single-threaded seasons with RoboRunner now, in case it's something like a fresh reboot helped (after testing in Windows earlier).
I thought once about Robocode being more multi-thread friendly if the engine called Thread.yield() in strategic places, like between ticks. But I never posted this suggestion in sourceforge.
This way, most processing outside a Robocode instance would be done between ticks and not interfere with turn skipping.
About dynamic overclocking, here I delete config/robocode.properties and run a single instance, which will measure CPU constant at minimum possible speed. Then I copy the file to all other installations. Tried to disable dynamic overclocking as well, but my laptop doesn't have the option in the BIOS.