Talk:XanderCat

From Robowiki
Revision as of 22:43, 25 May 2011 by Skotty (talk | contribs) (responded to GrubbmGait)
Jump to navigation Jump to search

Congrats on breaking the 50% barrier. Seems that you have the planning of your bot on scheme, now it's just the translation into the right code. One small remark: You don't have to have 'zillions of versions' present in the rumble, the details of older versions still are available when not in the participants list anymore. Comparisons between two versions are quite easy to do like [1] . Just click on your bot in the rankings, then the details and a few older versions are shown. Good luck with your further development! --GrubbmGait 08:37, 25 May 2011 (UTC)

Thanks GrubbmGait, though I'm not sure how much praise I deserve for being officially average. :-P I'm trying out a slightly revised version today, version 2.1. No major component changes, but it modifies the bullet firing parameters, driving parameters, some segmentation parameters, and has improved gun selection. Skotty 20:43, 25 May 2011 (UTC)

Contents

Thread titleRepliesLast modified
Wacky Version Problems with RoboJogger/RoboRunner104:29, 3 April 2017
New Garbage Collection Mitigation Strategy415:16, 26 October 2013
Garbage Collection and Skipped Turns2320:54, 24 October 2013
First page
First page
Previous page
Previous page
Last page
Last page

Wacky Version Problems with RoboJogger/RoboRunner

Forgot how slow this can go. :-/ I've been trying all day to record some new statistics using the Robocode means for saving file to disk, but I'm getting really bizarre version issues. I've been updating my robot version with each change -- 12.8.1, then 12.8.2, then 12.8.3. Each time I clear robot cache, package the new version, clear the old stats file that was saved from the prior version (as in, physically delete it, so I know the old stats are gone), and then run a new challenge with the new version. However, I keep getting garbage from older versions coming out in the results. Sometimes mixed, like it's randomly running different versions.

I've started trying to record the version information to the stats file each battle. I keep seeing this in the saved information:

Old: xander.cat.XanderCat 12.8.1*; New: xander.cat.XanderCat 12.8.7.

What that means, is it thinks the last battle was run with 12.8.1*, even though the entire challenge was run with 12.8.7. And that may actually be sort of true, because I'm getting some info in the stats file that I removed around version 12.8.4 but it shows up again, like it ran an older version for one or more of the prior battles.

At the moment, I'm totally confused by it. I'm not even sure how to debug it further at the moment.

Skotty (talk)04:13, 3 April 2017

As sometimes happen, writing about it made me figure it out. What was happening, that I didn't realize, was that the newer version of Robocode has an option to include the data files in the packaged robot, which is checked by default. So it was packaging data from an old version of XanderCat that I had run from Eclipse, which was totally screwing with my robot frameworks attempt to manage the robot data.

If you want to save any persistent data to the data files, make sure you uncheck the option to include data when packaging the robot!

Can't believe how much time I wasted figuring that out today.

Skotty (talk)04:29, 3 April 2017
 

New Garbage Collection Mitigation Strategy

I spent some time working on a system to pool frequently used objects in an attempt to mitigate the first round garbage collection problem my robot suffers from. My first attempt had some merit, but the changes involved are a lot more significant than I would like. I'm just not happy with it.

Recently, however, I came up with another idea that may be much simpler and effective. However, I still need to test out the idea. Instead of managing object pools, what if I just dump old objects into a "waste basket" that hangs onto those objects and releases them at a controlled pace -- probably slowly at first and releasing them faster as the rounds progress and the waste basket begins to fill up. Or perhaps empty the waste basket at safe times, like the end of a round or at times when XanderCat has a solid advantage already. This would use more memory overall but may be far simpler and less error prone. I'm going to sideline my prior pooled objects work and try this route for XanderCat 12.7.

Skotty (talk)17:56, 24 October 2013

Sounds like it has potential, but isn't your primary GC issue at the very beginning of the match? Or did we already conclude that was intractable?

Voidious (talk)19:52, 24 October 2013
 

That might work, but I have my doubts. Unless you're calling System.GC() all the time it seems likely that the garbage collector will wait for a bunch to pile up and do it in bursts regardless of how controlled of a pace you release your references at (and calling System.GC() all the time would also likely cause it's own issues). I'd say the real solution needs to involve just plain not using so many tiny objects in the first place.

(It's kind of one of my pet peeves about Java, that the language encourages extensive object use, yet if you use it "too extensively" the code will have performance issues to due excessive allocation/deallocation overhead. In some languages (such as C++) one has the option of combining multiple objects into the same block of allocation, but because all object instances are references in Java there's no such luxury, ironically meaning that high performance java code needs to use simpler/fewer OOP structures than high performance C++ code in order to match the performance)

Rednaxela (talk)17:20, 25 October 2013

Also a pet peeve of mine about Robocode at this point. It has a really strict time limit per turn with a programming language that doesn't give you much control at that small of a scope. And even if it did, a rolling average would be soooo much nicer, and skipped turns are such a burden to deal with.

Voidious (talk)18:28, 25 October 2013
 

Automated garbage collection is about getting the job done faster/cheaper. Machine code always has more potential for performance than any language and/or paradigm. But in practice, due to overwhelming complexity issues, lower level languages tend to deliver worse software overall.

If you want high performance Java, increase the size of the heap, and/or change the ratio between regions, which solves 99% of garbage collection issues.

We could make it standard in RoboRumble to have a heap optimized for real-time. Using "-Xmn511m -Xmx512m" or "-Xmn1023m -Xmx1024m" in roborumble.bat would do the job very well. Not as fun as programmatic object pooling systems though.

MN (talk)15:16, 26 October 2013
 
 

Garbage Collection and Skipped Turns

Starting a new thread to discuss my efforts to deal with the skipped turn issue that is apparently related to garbage collection eating up allowed run time. This was previously discussed in thread "Shielding Success Rates Mystery", for anyone who wants to see where it all started.

I purposely did not contribute to the rumble over the last few days after the pairings for XanderCat 12.6 were lost. I originally ran many of the original pairings on my PC that does not have the skipped turns issue. Most of the re-run pairings were likely run by Voidious, whose system does exhibit the skipped turns issue.

The difference between the two is quite significant. With clients that don't exhibit the skipped turns issue, XanderCat achieved an APS of 87.7. With clients that do exhibit the shipped turns issue, XanderCat achieved an APS of 86.5. The difference -- 1.2 APS -- is quite significant. With the current rumble participants, it makes the difference between 5th and 8th place.

Most of the difference is due to the skipped turns causing the bullet shielding system to fail much of the time. But likely the skipped turns in general -- ignoring the bullet shielding -- also contribute a small amount.

I had previously fixed a few performance bottlenecks to make XanderCat run quite a bit faster (v 12.3), with much lower turn time peaks, but this only achieved a marginal improvement. I now need to shift to figuring out how to reduce the amount of garbage my framework apparently creates. This is not a real easy problem to address, because it is a very unique Java problem that rarely ever needs to be addressed in the real world, so there is not a lot of information or research available online to help on this.

I think one thing I can do is to eliminate as many intermediate local variables as I can. For example, variables with only method scope that are used to break something into multiple easier to maintain steps. These extra method scope variables may be contributing to the garbage collection, especially in the first round. Eliminating them may help to fix the problem, but at the expensive of either combining multiple lines together into more complex lines or making the variables have a wider than necessary scope (declaring them as part of the class), thus eating more memory overall but eliminating the possibility of it triggering garbage collection.

I don't know if these steps will help, but I will probably give it a try. I am also not sure if there are other ways to reduce garbage collection, but maybe I will come across some other ideas. I may actually create a second branch in my source tree for this work, something I never thought I would do for Robocode. I want to keep the current version, as I think it will constitute better code and perhaps someday the garbage collection issue will be addressed by changes to Robocode itself; but if my garbage reduction efforts work, for now I will operate off of a garbage reduced branch.

Skotty23:43, 3 April 2013

This seems like a really crappy thing to push onto you as a bot author. I do think our time is probably better spent coming up with a proposal to change Robocode itself and submitting that (as idea, design, or code) to Fnl. There could be a very simple and elegant solution that would work, like "allow 10x the CPU constant for the first 100 ticks". (Disabling CPU limits in first 100 ticks seems problematic, since you want to at least interrupt bots that hit infinite loops.) Another idea is having Robocode run its own GC cycle right before the match starts, in case bots are being penalized for GC of the game engine.

I'll try to get to another round of tests and find out how much I need to raise the CPU constant to get normal performance out of XanderCat.

Voidious00:39, 4 April 2013
 

I've had to deal with this quite a bit when writing games in c#. Similar to Java the GC can case obvious stalls. The easiest way is to stop calling the "new" function at run time by using pooling. For instance at the start of a match, or a round create a container object which contains N pooled objects which you know you create often, eg wave objects. At the point you wish to use one, take it from the pool, initialise it, use it, then return it to the pool when finished at any point later on.

Because you have not called new, and then nulled the object, the memory used does not go up, it stays constant, thus no GC is run. It's obviously impractical to pool everything so you just do the worst offenders which are things that you create often and throw away.

Wolfman01:30, 4 April 2013

That seems like a great approach. And you can even create the pools in a static block, which I'm pretty sure runs before the match starts and won't count against any of your CPU time.

Voidious04:44, 4 April 2013
 

Speaking of static blocks, I've noticed that they get run on Robocode/rumble startup for every single bot, which is partly why it takes so long to start when there are lots of bots in the /robocode/robots directory. I also suspect that code in static blocks isn't subject to the security manager, since it can print to the main console. Does somebody feel like writing a test bot to see if this theory is correct?

Skilgannon10:56, 4 April 2013
 

Local variables are stored in the stack and not the heap, so they don't affect garbage collection.

You should look after "new" abuse, like Wolfman said. Although sometimes the instantiation is implicit and simply searching for the "new" keyword doesn't always work.

There are heap profiling tools which locate automatically where too many objects are being instantiated.

MN04:33, 4 April 2013
 

Local variables are stored on the stack but any time you use new it will go on the heap afaik:

public void MyFunc(Object a) {

  Object b = a; // Variable b is on the stack, pointing at a.
  b = new Object(); // Memory allocated on heap, referenced by variable b on the stack

}

This is my understanding of it. Please correct me if I am wrong!

Wolfman07:57, 4 April 2013
 

This is correct.

My understanding of the snippet above is that you have 3 variables. 2 local in the stack (references "a" and "b") and 1 in the heap (Object instance).

Some variables stay in the stack only, like primitives (double, float, int...).

MN15:46, 4 April 2013

Where would a primitive array like an int[] end up?

Tkiesel16:17, 4 April 2013

Java treats an array as an object, so on the heap.

However, these days the JVM is more intelligent than you guys are giving it credit for, eg. it has Escape Analysis to determine if objects should be put on the stack if they stay local.

Skilgannon16:25, 4 April 2013

Didn´t know about escape analysis.

What I usually do to take in account all optimizations, even those I don´t know about, is to use profiling tools. Measure what is really happening, instead of looking at the code and guessing.

MN17:08, 4 April 2013

I've actually been debating writing a Robocode simulator to make robot profiling much easier. What it would do is to pretend to run a robot battle with your robot against either another opponent, or perhaps some imaginary robot, using a combination of mock objects and simulation. It would run without any security at all, no sandbox, nor would their be skipped turns, so you would only want to run it with trusted robots. But it would be much easier to run a profiler against. The simulated battle may not be a perfect simulation, but as long as it's close, it should work and be useful.

Skotty23:06, 5 April 2013
 

When I do profiling in Robocode, I run a battle of a bot against itself. Then I filter the results by package so engine data is filtered out and only data from my bots appear in the profiling report.

MN01:10, 6 April 2013
 
 

Yes. However anything that you are creating during a function and keeping hold of for a few frames and then releasing is going to be allocating on the stack. Stuff like "Wave" objects, "Bullet" objects or whatever else you use in your bot will cause GC stalls if you create lots, use for a while and then null. This is where the pooling comes into force. I would definitely recommend pooling objects such as waves etc if you are having trouble with stalls and then go from there.

-wolfman

Wolfman16:32, 4 April 2013
 

See, my bot always had a skipped turns problem, and now you're giving me a possible solution. You're drawing me right back in to wanting to start Robocoding again, dangit! *laughing*

Tkiesel16:39, 4 April 2013

Yes, yes, come to the dark side, make your code ugly but fast, like mine :-p

Skilgannon16:42, 4 April 2013
 

Although its more likely that the stall is caused by your code running too slow rather than blaming it on the GC imho. Can you use eclipse to profile execution and memory of robots? Anyone know? If so a wiki page would be lovely :)

Wolfman17:16, 4 April 2013
 
 

Arrays are objects in java:

public void func() {

  int[] myArray; // myArray variable on the stack
  myArray = new int[5]; // Array object allocated on heap, referenced by myArray variable on the stack

}

Note that member variables of objects are obviously going to take up memory on the heap not the stack - eg if you have 30 primitive member variables (ints, doubles etc) of a class and call new on that class, it will take up more memory allocation than a class that has 1 primitive member variable.

However allocating 30 local primitive variables during a function call allocates those primitive types on the stack alongside you local member reference variables.

Wolfman16:28, 4 April 2013
 

While I am not the saddest person here that this has happened to you (as my robot is right above yours in the rankings with only a little APS between it and yours). But I know I would hate it if this happened to me. However I have tried to design things from the ground up in more recent robots to limit object creation and destruction.

At one point I even reused old objects (aforementioned pooling) instead of creating new ones. That didn't make it into the current version however.

Chase20:54, 24 October 2013
 
First page
First page
Previous page
Previous page
Last page
Last page