Page 16 of 21
Re: Java AI Interface for Spring
Posted: 22 Aug 2009, 17:50
by hughperkins
btw, i did the refactor and the java interface. it is written all over the place

Nice!

I'm very impressed so far, although I'll be more impressed once I get it compiling / running :-DDD
The main problem with the java interface is, that if the java code fails to compile, it wont retry to compile it again. this has to do with CMakes inability to handle Java sources well (SCons is not really better there, though).
so if it fails, you best trigger a rebuild with touch AI/Interfaces/Java/src/native/JavaBridge.c.
if you dont want to/have to build all of spring, this should be enough:
An issue I have is that to actually build Spring itself seems to need a
lot of dependencies, about 500 meg or so, which is a lot with a 4gigabyte ssd hard-disk
Is there some way of getting cmake to run without needing to bring in the whole set of dependencies for Spring? I just need to build the AI stuff right? which probably doesn't need 10 billion boost libraries and so on I guess?
Re: Java AI Interface for Spring
Posted: 23 Aug 2009, 08:50
by hoijui
:D ouh man!
ein leidensgenosse!!
i am also cronically short on resources like memory, HD space and CPU time. soo.. lucky you, i can understand you there

you are right, in that for only compiling the Java interface, and probably one of the Java AIs for testing, you would not need most of the dependencies that spring needs (no boost, no SDL, no openAL, ...).
The build system is just not made for this situation :/
There are two possibilities t ochange that:
1. We allow cmake configure on spring to succeed, even if the system does not meet springs requirements, but only the java interfaces, or any other part of it that can be compiled stand alone.
As 99.9% of the ppl compiling spring, want to compile the engine, this approach is only going to cause more confusion for users, i think; the other devs would not like it.

2. The whole build system (i am thinking on CMake) would have ot be refactored. Globally interesting configure stuff, like initializing variables like SYNCDEBUG or BINDIR and LIBDIR, plus CMAKE_CXX_FLAGS and CMAKE_CXX_FLAGS_DEBUG, would have to be moved to separate files, which could be included by submodules (like the java interface) when they are configured stand alone.
the second approach seems to be better to me, though i dont know how much trouble it would casue if you use the global and the submodule configure in the same repo.
anyway.. neither of the two is going to happen soon, i think, so you are still not so lucky, sorry. the best option for you, it seems, is to beg the repository maintainer to include the java interface. for Ubuntu, it is YokoZar, and the related topic is here:
http://springrts.com/phpbb/viewtopic.ph ... 26#p372126
... i did hte begging myself already, as you can see.
Re: Java AI Interface for Spring
Posted: 23 Aug 2009, 14:13
by hughperkins
Contents:
1. building without needing spring dependencies
2. dynamic java loader
1. building without needing spring dependencies
Ok, so in the end I hacked the CMakeLists.txt files: the one in spring root, and the one in rts. The one in rts is needed to build streflop.
And that worked.
As you say, I suppose the long-term solution is to have the Java interface as part of all distributions of a release.
Otherwise, perhaps we could be able to turn on a switch, maybe through some kind of environment variable, like BUILD_AI_ONLY or something perhaps, so that only the AIs are built?
Here are the hacked cmakelist files in case they are useful:
From root:
http://pastebin.com/f3fbdd13c
From rts:
http://pastebin.com/f6d9e4ac5
2. dynamic java loader
It takes several minutes for Spring to start up on my machine, so it makes development quite tedious. It would be nice to be able to reload an AI dynamically, and here is a draft proof-of-concept solution.
Once loaded, one just types in chat:
+reload-ai
... to reload the ai, after tweaking and rebuilding the underlying ai.
Longer-term, I see there as being two possibilities for making this generally available and stable:
1. just publish it as an ai, and specify the path to another ai in the chat:
+reload-ai MySuperAI 0.1
Possibly, one could specify a default ai in a config file.
2. Possibly integrate it into the java interface itself.
I kind of feel the first solution may be the best, because it keeps the java interface KISS, which is generally a good thing on the whole.
Anyway, here is a draft, proof-of-concept solution, and I'll just put this out there, and maybe someone might pick this up and make it into something more rigorous and stable?
http://manageddreams.com/Hugh1.tar.bz2
Architecture:
Java Interface -> SkirmishAI.jar -> (via Loader.loadOOAI) UnderlyingAI.jar
Both SkirmishAI.jar and UnderlyingAI.jar contain a derivative of AAOI.
SkirmishAI's AAOI delegates all the methods through to UnderlyingAI's AAOI implementation, at least, it should. At the moment, about half the AAOI methods are delegated through, eg:
Code: Select all
@Override
public int unitCreated(Unit unit, int builder) {
try {
if( underlyingAI != null ) {
return underlyingAI.unitCreated( unit, builder );
}
} catch( Exception e ) {
System.out.println("exception on unitCreated:");
e.printStackTrace();
}
return 0;
}
Re: Java AI Interface for Spring
Posted: 23 Aug 2009, 15:21
by hoijui
:D
this already exists
there is no aireload, but there is /aikill and /aicontrol, which issued in this order, are equal to an ai reload. actually i will make an /aireload, is very easy to do of course, with these two commands already there.
as said, you should autojoin the #ai channel in the lobby, it will save you time
there are also some Java AI projects that do it similarly as you do it. though they are not as general as your idea.
i dont see much advantages in your solution, except that it saves the time to reload the JVM when reloading an AI, but this could be easyly prevented through running a NullJavaAI on an other team, and just reloading your own AI with /aikill /aicontrol.
to use these commands, just use them in the ingame chat. you should get a short command description, explaining the arguments.
Re: Java AI Interface for Spring
Posted: 23 Aug 2009, 17:19
by hughperkins
there is /aikill and /aicontrol, which issued in this order, are equal to an ai reload
Oh! Cool! That sounds good!
It doesn't seem to work for me. I guess I need a later version of the Java Interface? I'm using the source-code in the 0.79.1.2 tarball.
Re: Java AI Interface for Spring
Posted: 23 Aug 2009, 17:32
by imbaczek
upgrade to 0.80.2.
Re: Java AI Interface for Spring
Posted: 27 Aug 2009, 16:01
by hughperkins
Hi Robin,
Contents
======
1. Impressed with Java Interface
2. Drawing functions
3. Stability of OOAI interface
1. Impressed with Java Interface
====================
Wow, so far I find the Java OO interface extremely impressive. I'm very impressed with it. I don't know how efficient it is (haven't checked or tested yet), but I really like that the events come down containing "Unit"s rather than integer ids. I really like that you've factored things down, so we do aicallback.getMap().something or aicallback.getGame().something-something.
2. Drawing functions
=============
Could we possibly add the following two functions please? I use them in my C# AI, that I am in the process of porting to Java. I've ported 33 classes, there are 25 left, so it's well in progress.
The two functions, which I find very useful, are:
Code: Select all
aicallback.DrawUnit(targetunitname.toUpperCase(), buildsite, 0.0, 200, aicallback.getGame().getMyAllyTeam(), true, true);
and:
Code: Select all
figuregroup = aicallback.CreateLineFigure(new AIFloat3((x + 1) * multiplier, elevation, y * multiplier), new AIFloat3((x + 1) * multiplier, elevation, (y + 1) * multiplier), 10, false, 200, figuregroup);
3. Stability of OOAI interface
==================
One other point: I notice that a couple of the OOAI events have had WeaponDef weaponDef, boolean paralyzed added to them. Don't suppose... could it be possible to start providing backwards compatibility on the interface from this point on? In other words, in the future, if something changes, let's say we have a new parameter "int photonPower", then the interface could change from:
Code: Select all
OOAI{
...
int UnitAttacked( Unit unit, Unit attacker, ... , boolean paralyzed );
...
}
to:
Code: Select all
OOAI{
...
int UnitAttacked( Unit unit, Unit attacker, ... , boolean paralyzed );
int UnitAttacked( Unit unit, Unit attacker, ... , boolean paralyzed, int photonPower );
...
}
... this way, as long as we extend the adapter class AbstractOOAI, then AIs written in Java will be stable, and won't break at each release, which is the opposite of the current situation with C++ AIs et al.
If you could do this, then the number of working Java AIs would naturally increase over time, which would make the Java AI interface look really good, and make AI developers like myself really happy!
Eventually the old events would probably need to be deleted of course, but maybe if you could keep them around for two years before doing so, then it could make developing AIs in Java really fulfilling, rather than spending one's life continually keeping up with interface changes
Hugh
Re: Java AI Interface for Spring
Posted: 27 Aug 2009, 16:33
by hoijui
thanks!

i actually am a Java programer, and i though if i do all this ugly work, then the interface should really be Java like in the end, and not look like a java accessible C interface. Of course there are still things that are not properly Java, and they will remain most likely. Some data types in hte C interface are unsigned, and csaue Java has no unsinged types, you will have to take the twos compliment of these values in java, and not forget to use a bigger data type (eg int instead of short). This is the csae for the raw resource map, for example.
the two draw things you miss are already possible. You have to do that through commands.
You find them under the oo subpackage, and you have to send them to the engine through the callback.HandleCommand() message.
In case you are interested, and for reference, the Java interface is nearly exclusively generated from three C++ headers. If someone asks me what function does what, i usually search in these three files:
rts/ExternalAI/Interface/SSkirmishAICallback.h.h
rts/ExternalAI/Interface/AISCommands.h
rts/ExternalAI/Interface/AISEvents.h
The other thing...
it wont happen. The Java interface is auto generated for mthe C interface, and auto generating backwards compatibility is not possible.
It could work with putting the backwards compatibility into the C interface, but.. that will siply not happen casue .. spring devs (including me) will never adhere to such a strategy, cause we would be too bored, or simply casue we will not remember to do it.
Anyway, if you want your AI to stay compatible, you will have to update it anyway, spring is too dynamic to do something like real backwards compatibility. The way to go is detecting incompatibility, which is still not implemented for AIs. I know i should do that one day, but it is boring work, and needs lots of testing(-time) and in the end will not really make you think like you did somethign worthwhile.
If your AI is good, an used by lots of ppl, then it will easily find maintainers even if you are not around to do this all the time. This works well for the current AIs.
Re: Java AI Interface for Spring
Posted: 31 Aug 2009, 16:49
by hughperkins
Hi Robin,
Contents:
1. AI Maintenance
2. Overriding OOAIFactory.handleEvent
3. Line drawing functions
1. AI Maintenance
If your AI is good, an used by lots of ppl, then it will easily find maintainers even if you are not around to do this all the time. This works well for the current AIs.
Ok, that makes a certain amount of sense, and is fairly reassuring to me.
2. Overriding OOAIFactory.handleEvent
There is a function in OOAIFactory called "handleEvent". I think that if I just copy and paste this into my OOAI instance, then any additions to the Event objects will not affect the ability of the code to compile? And then the method calls themselves will be effectively "frozen" into my code and immune to future modfiications?
However, at the moment I can't do that since OOAIFactory is final

To what extent could it be possible to change it to no longer be final?
3. Line drawing functions
the two draw things you miss are already possible
Ok super! The drawing unit function works great!
I have an issue with the line drawing functions at the moment.
- if I use new AddLineDrawAICommand(startpos, endpos), then the line stays on the map for the duration of the game

which means that functions to overlay various maps on the game-map, like metal, movement type categorizations (sea vs land vs steep land vs impassable land), tend to very quickly become an illegible mess.
- on the other hand CreateLineFigureDrawerAICommand( startpos, endpos, 2, false, 200, -1, -1) , crashes for me:
http://pastebin.org/13683
To what extent could it be possible to tweak CreateLineFigureDrawerAICommand so that it doesn't give a segmentation fault?
Alternatively, what options are available for deleting lines created using AddLineDrawAICommand, or for deleting everything drawn on the screen, for example, once a second?
Hugh
Re: Java AI Interface for Spring
Posted: 01 Sep 2009, 17:09
by hoijui
If i get you right with the OOAIFactory, what you want is to not it at all.
Have a look at NullJavaAI. You should be able to mix the Two concepts, eg useing the Event receiving style of NullJavaAI together with the OOAICallback.
though... i have not yet tried it.
maybe i got you wrong.
come to #ai
For removing a line, use the RemovePointDrawAICommand and give it one of the two end-points of the line.
I can see that this is not obvious

The reason it works this way, is that it simply woorks hte same way as for humans:
You erase in a location, and then all things aroudn there are deleted (points, lines markers.. i think).
So there is possibility for improvement in the AI API here, but .. dont expect this to change anywhere soon
about CreateLineFigureDrawerAICommand:
the docu says:
Code: Select all
/// how many frames a figure should live before being auto-removed, 0 means no removal
int lifeTime;
/// use 0 to get a new group
int figureGroupId;
/// the new group
int ret_newFigureGroupId;
so you should use 0 for the second last param, not -1, and if this does not help, use width = 1 (no idea if different width's are supported).
If both of this does not help, i would need further info from you. i cnat do anything wiht the stack trace you gave me.
...well maybe i could, if i had the eaxct smae version of spring you have, and would try translating the addresses by hand...
would like not to do that

Re: Java AI Interface for Spring
Posted: 02 Sep 2009, 06:20
by hughperkins
1. Re: Erasing line drawing
2. Performance: Eek!
1. Re: Erasing line drawing
Ok, well as a workaround for now, I've turned off all dynamic line drawing, for example, I no longer display the AI's losmap as it changes, but only on demand, and then I have a command to erease the lines from the whole map. It's not ideal, but it's ok for now.
I'll give the changes in parameters a whirl, but I did try a couple of values before, and I suspect it's something to do with the parameter named "ret_somethingsomething" being some sort of allocation parameter, that's not being allocated, and hence the segmentation fault?
2. Performance: Eek!
Ok, so I got my ai entirely ported from C# into java, and started to tinker with it. It was very slow, and I started to look into why.
I wrote a performance test, and here is the test and the results:
http://pastebin.com/f29ddf1a0
The result is the number of iterations of the test that were completed in one second.
The control test shows that the basic timing loop runs 50 million times a second, which is fast enough that other test results can be taken directly at face value.
The test of aicallback.getUnitDefs() was excellent. I assume you are caching the results of this somewhere since it is static data?
The test of aicallback.getFriendlyUnits() was pretty low, but I'm going to leave that for the moment, and move on to:
unit.getPos(). This ran 5000 times a second, for a duration of 200 microseconds per getPos call :-O
To put that into perspective, imagine we have a single loop like this, and 200 friendly mobile units:
Code: Select all
for( Unit unit : friendlymobileunits ) {
AIFloat3 pos = unit.getPos();
// do nothing here for now
}
This loop, on its own, with nothing inside it would take:
200 * 200 microseconds = 40000 microseconds = 40 milliseconds to run
30 frames, just for this loop would take 30 * 40 milliseconds = 1.2 seconds :-O
That's .... fairly slow!
The same is true for getUnitDef, but I can cache that per unit. Caching the pos is not really an option.
I assume the speed is a fundamental limitation of JNA, and there is nothing that can be done about it?
Kind of a shame though ....

((((
Hugh
Re: Java AI Interface for Spring
Posted: 02 Sep 2009, 06:35
by hughperkins
Robin,
Addendum: there seems to be something called "JNA Direct Mapping:
https://jna.dev.java.net/#performance
https://jna.dev.java.net/#direct
... it looks like this gives roughly a x10 boost in performance, which sounds definitely worth having!
From the links above: "The calling overhead for a single native call using JNA interface mapping can be an order of magnitude (~10X) greater time than equivalent custom JNI [...]. In raw terms, the calling overhead is on the order of hundreds of microseconds instead of tens of microseconds."
That seems to correspond roughly to the a posteriorae getPos execution time in the tests above?
A couple of questions:
- to what extent does JavaInterface v0.1 use JNA Direct Mapping?
- don't suppose... how realistic could it be for you to add in JNA Direct Mapping, at least for certain frequently called functions, like, at a minimum for example, unit.getPos() ?
Hugh
Re: Java AI Interface for Spring
Posted: 02 Sep 2009, 11:29
by hoijui
...and again, you could probably have saved yourself quite some time if you had talked to me in advance

!!!! #ai !!!!
I already had a look at JNA's direct mapping, and i remember it beeing unusable for the interface, but i will have an other look at it maybe.
The slowdown, i suppose, does not come from the use of JNA, but from the extensive logging of the Java AI Interface that is on by default.
I did this cause it is still kind of in beta state (as there are no release AIs yet, except the Null*JavaAI ones, which are hardly a good test, and not used for testing by the masses anyway). You can disable/lower all the logging from the config files in your spring install under:
Code: Select all
AI/Interfaces/Java/0.1/interface.properties
AI/Interfaces/Java/0.1/jvm.properties
In the first, make sure to have a log level of 5 or lower. i think only 8 or more would cause anything near performance relevant output.
The JVM properties is where yo want to disable all logging and debugging options (both ";" and "#" can be used to out-comment stuff).
I am pretty sure that this will speed up the slow things at factors in the range of 10x or more.
Re: Java AI Interface for Spring
Posted: 02 Sep 2009, 21:34
by cranphin
Heeey!! :)
I was just about to say something about unit.getPos, and unit.getDef XD
These seem to eat up by far the biggest chunk of time in my kaik port, on a quick initial profiler run (See the attached pic. :) ).
I'll cache positions per frame I guess, this will atleast lessen the damage a bit :)
UnitDefs can be cached for as long as a unit lives, which should help too :)
Might be usefull integrating this in the Unit class or so though, OOAI, something :)
But yes, it'd be very nice if this can be solved/improved in the jna layer too, mayby the jna devs have some ideas?
This is important, the performance hit this gets can kill the whole idea of a Java AI :D
Cheers! :)
Re: Java AI Interface for Spring
Posted: 02 Sep 2009, 23:53
by hoijui
disabling all the logging and debugging gave about 20% performance increase (tested by hughperkins). so not nearly enough :/
so there are two possible ways to go:
1. make the java->native calls faster
2. caching
caching is already implemented to some extend, eg in unitDef, but not in unit. the reason is that it is much more complex there, as said, some things can be stored as long as the unit is alive, others only per frame...
all those things have in common that they need input from the engine, eg the events have to be connected to the callback, which adds complexity again, plus we have to manually define for each function how long it┬┤s values can be cached, and then there is dependency on the parameters of the function, and we will have to prevent cache fro mbeeing to big, ...
i see a lot of work, and a lot of bugs in this approach.
making the calls faster could be achieved through the mentioned direct mapping, perhaps. It would need some changes in the interface, as direct mapping can only be done when callign functions, but we are currently directly using the function pointers the engine supplies. so ther would have to be a function to function pointer mapping on the C side of the interface, and then changes on the Java side to do function calls instead of function-pointer calls, and then little changes to do direct mapping. The problem there is, that the interface uses String[] in some places, which is not supported by JNA direct mapping.
Before doing anything, we should be very clear where we loose the most performance.
.. omg. suddenly got very tired, get back tomorow again.
Re: Java AI Interface for Spring
Posted: 03 Sep 2009, 08:57
by hoijui
i never did performance tuning of code, ever, and never did performance messurements either....
cranphin, how did you get that image? it looks Eclipse style to me. I think Netbeans as something for performance messurement too...
anyone having more experience in this area?
i though about the caching again...
The only half way clean way to do it, is to further annotate the functions in the C AI callback, the one defined in
rts/ExternalAI/Interface/SSkirmishAICallback.h. The current "Annotation system" i am using there, looks like this:
Code: Select all
Clb_Economy_0REF1Resource2resourceId0getIncome
meta info included in the function name.
Even doh it is ugly, it has a few tiny pros, and made auto parsing it easier. But if we want a better buffering system, it would get too ugly, and we better change to something separate form the function name. I am thinking of two possible solutions:
1. an additional file for the meta data
2. appending the meta data in a comment next to the function pointer definition
Even doh 1. may be nicer in theory, i tend to 2. as it has some important pros in practice. The main advantage is, that with 2., when soemeone adds a function to the interface, or changes one, it is much mor likely that he will also add or change the meta info accordingly, if it is in the same file. Also, it would make parsing easier.
For the format of the meta data, i am thinking of a properties file format. An example:
old:
Code: Select all
/// Returns the commands currently in the queue of the Unit.
int (CALLING_CONV *Clb_Unit_0MULTI1SIZE1Command0CurrentCommand)(int teamId,
int unitId);
new:
Code: Select all
/// Returns the commands currently in the queue of the Unit.
int (CALLING_CONV *Clb_Unit_CurrentCommand)(int teamId,
int unitId);
/* #ANNOTATION#
* multiFetcherPart = size
* oo.class = Command
* cache.time = frame
* cache.scope = team
*/
This is just meant as a very rough design sketch.
I am open for better suggestions.. but of course it is only ME who decides what is better.. and.. i cant imagine anyone else hten me has better ideas...

no really, influence me pls!
btw, why not XML instead of properties format:
i want to make parsing as simple as possible. i use AWK for generating the Java and the new C++ AI interface, and parsing XML wiht AWK... would not be much fun, plus i dont see a need for it.
Re: Java AI Interface for Spring
Posted: 03 Sep 2009, 10:30
by DJ
What are the specific methods causing the performance problems? Is it just the Unit objects? Just a stab in the dark here but are you fully populating a Unit object for every event call? -if you went back to unit id's which you could then populate a unit object for on demand might that regain some performance?
Re: Java AI Interface for Spring
Posted: 03 Sep 2009, 12:19
by hoijui
i dont know the critical methods (except the already mentioned ones).
no, a unit object is never fully populated. each property is requested from the engine right when you request it from the Unit java Object.
Re: Java AI Interface for Spring
Posted: 03 Sep 2009, 19:19
by cranphin
hoijui wrote:cranphin, how did you get that image? it looks Eclipse style to me. I think Netbeans as something for performance messurement too...
anyone having more experience in this area?
I used JProfiler with a 10 day trial license :D Bit expensive to buy tho, but was the quickest for me to get something with :)
There's other tools that can do the same, I think the netbeans thing you mentioned is one, I'm more of a eclipse user tho
Had to add some properties to the jvm.properties, but otherwise it's not too hard, as long as the profiler supports some way of remote debugging :)
Re: Java AI Interface for Spring
Posted: 03 Sep 2009, 19:30
by cranphin
As for annotating, use whatever you feels is easiest in AWK, since you're the one doing it
Thought more about caching too, I do see/feel some issues.
One is that KAIK cheats for finding enemy positions for example, and I realize that because we have cheating, we may get a different value for a unit position even within one frame:
-cheat on, enemyUnit.getPos() = (10,10,10)
-cheat off, enemyUnit.getPos() = (0,0,0) (actually, I don't know what value we get here XD)
But it's easy to overlook such things that would break caching :)
Mayby we should actually just leave caching to the AI developers, since they can be smart about this, but then, the OOAI interface with Unit class and such is the logical place for caching I think.
So, I don't know... :)
I would love if we could speed up the native calls somehow, I don't care how XD I'll happily rewrite against any new interface for that :)
A funny thing I noticed btw., it seems creating AIFloat3 (just new AIFloat3() ) is also heavy a bit, since it triggers jna code, something I have to be mindfull of (don't create a lot of AIFloat3 just for storage or so XD).
Also, I think the reason unit.getPos and unit.getUnitDef score so high, is cause they get called very often, for example to choose a target from the enemies, you may check the position and type of a lot of enemies.
Anyway, keep hope :D And don't rush a solution, this deserves some time and attention :)