Interesting idea, though I don’t like the annotations syntax for this. I consider the stack allocation as a core feature that shoudn’t be optional as it changes the memory behaviour a lot. This is reason why it throws Error instead of some sort of fallback, users would then accidentally run slower/worse path. Also I like it in this explicit way because it tells something special is occuring and not ordinary allocation, such as the case with constructor with argument (or without), the programmer can be misleaded to think that the constructor is actually run or assume that the values are zeroed whereas it’s not true.
Yes, sorry, I’ve forgot about exact syntax for statement annotations – they are rarely used, as for me.
Well, I agree, your point of view is completely legitime. I just think it’s more about your specific use case. As far, as I understand, stack allocations was a critical feature, letting you to port C code to java without great rewritting it to refactor memory usage strategy. So it’s really “something special” and “core feature” in your case. But if you want your library to be public used (as for me, it worth it – it’s small, easy, and do the work well – that’s more?), just try to look at it from point of view of developer, thinking about incorporate stack allocations in existing code. In current form, it can’t be called non-obtrusive. One should make rather big changes in code, and live with fact, that code won’t be ran without instrumentation. It’s makes a high barrier for such decision. From other side – add annotations to some of statement is not a big deal. Anyone can just do it and be sure, what without special processing such annotations do change nothing in current behavior (and, most probably, even completely removed by obfuscator, if used). As for me, it makes decision “to use or not to use” much easier.
For example. Ive’ just downloaded JBullet and exploring sources. I can’t run it from my IDE without instrumentation – although I just want to debug it to clearify code paths, and it’s ok for me to have code run slow…
As for “changes the memory behaviour a lot” – well, think of it from that point of view: memory behavior may be changed a lot by jvm GC options given at startup. It’s gives you, in some cases, really big changes in memory behavior, and you really do not see nothing about it in code. It can be chaned by JIT – and, again, you’ll se nothing about it in code. It’s java – memory behavior is much less predictable at all, and I think, most java developers already learn to live with it. You even can’t be sure, that new Vector3f() do not actually do the stack allocation by itself – being optimized by JIT (well, may be for now you can – such optimizations usually described in Sun’s jdk’s preview – but for future… we all waiting for it). If jdk1.7 (8,9…) will include such optimization, one can just remove instrumentation step from it’s build process, and letting jit do it’s best. While currently one’s left with some “strange” legacy code in allocations, which can confuse JIT in it’s optimization, and confuse junior developers in understanding “wtf is happens here and why?”
To summarize – I suppose, annotations-based instrumentation can be added as an option. If someone want stack allocation to be explicit – it’ll have such option. If for someone it’ll be easier to add it in non-obtrusive way – the option will also be here. Nobody can escape. Your library will conquer the world! At least, java part of it
Well, I’m not sure if I really want this library to be widely used. I’ve made it for extreme case of allocation of many tiny objects and published here so someone other who will fall into the same situation can use it. Otherwise HotSpot is very good at allocations, so I don’t recommend to use this library in normal situations. I’ve also used it in some other libraries, but I’m considering to remove it from there as the amount of allocation is not that much.
As for JBullet I don’t see much problem here, most users just need precompiled JAR which doesn’t have any runtime or API dependency on JStackAlloc. Ant is standard way for building applications, so I don’t feel bad by requiring it.
Well, yes, JIT and GC becames more and more powerfull each day rise. Years Sun engineers adviced not to use object pools just to improve memory allocation, 'cos it does not give the bonus, but only confuses new GC algorithm (it was time generation GC was introduced). So, after years, I was surprised you was able to gain perfomance bonus from such a method, but it is – and why do not expose it to community? May be it will speed up Sun’s JIT enchancements at least
But if do this, it should be done in the way, which can be easily rolled back if JIT at last become smart enough to do the job by itself. I’m near to sure, what code like this
final Vector3f v = Stack.alloc(Vector3f.class);
will greatly complicate escape analyze job for such “smart” future JIT. So in current version, gaining perfomance bonus for now you’ll likely close the way for you code to gain perfomance boost from future compiler allocation optimization.
By the way, can you summarize the perfomance boost you gaining now? Just to be oriented in then and there to use you library
[quote=“BegemoT,post:24,topic:31983”]
In full fairness to the engineers that made these recommendations (I seem to recall a flurry of them in about 2005), they were only about 10 years early with them - I fully expect that by the time Java 8 rolls around, escape analysis/stack allocation/scalarization will be performing on par with manual object pooling.
:o
The lesson: never trust developers that are mucking with the innards of a system to give you a fair scoop on the best way to use it in its current form; they are far too optimistic as a rule about what is right around the corner, for certain values of “right around the corner.”
jezek2, is there any way to use this library in a form where it can degrade gracefully (i.e. turning all pool pulls into plain old allocations) in the absence of instrumentation, or is that just not a realistic possibility given the way it’s set up?
EDIT: Forget this, this is not needed. Please refer to my next post instead.
This is a patch for JStackAlloc to work with Maven.
I’m building my project with Maven, hence I also build JBullet with Maven (version 2.0.9).
Hence I added an AntRun task to Maven’s POM file to let JStackAlloc instrument JBullet.
For this to work, I had to modify JStackAllock,
because the method FileSet.getDirectoryScanner()
doesn’t exist in the Ant-stuff provided by the Maven AntRun plugin.
Instead, getDirectoryScanner(Project) can be used.
Also a getDir() needs to be replaced by getDir(getProject()).
Without above patch, the Maven AntRun task fails with a NoSuchMethodError:
[ERROR] FATAL ERROR
[INFO] ------------------------------------------------------------------------
[INFO] org.apache.tools.ant.types.FileSet.getDirectoryScanner()Lorg/apache/tools/ant/DirectoryScanner;
[INFO] ------------------------------------------------------------------------
[INFO] Trace
java.lang.NoSuchMethodError: org.apache.tools.ant.types.FileSet.getDirectoryScanner()Lorg/apache/tools/ant/DirectoryScanner;
at cz.advel.stack.instrument.InstrumentationTask.execute(InstrumentationTask.java:110)
at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:275)
at org.apache.tools.ant.Task.perform(Task.java:364)
at org.apache.tools.ant.Target.execute(Target.java:341)
at org.apache.maven.plugin.antrun.AbstractAntMojo.executeTasks(AbstractAntMojo.java:108)
at org.apache.maven.plugin.antrun.AntRunMojo.execute(AntRunMojo.java:83)
at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPluginManager.java:451)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:558)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalWithLifecycle(DefaultLifecycleExecutor.java:499)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoal(DefaultLifecycleExecutor.java:478)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHandleFailures(DefaultLifecycleExecutor.java:330)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegments(DefaultLifecycleExecutor.java:291)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(DefaultLifecycleExecutor.java:142)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:336)
at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:129)
at org.apache.maven.cli.MavenCli.main(MavenCli.java:287)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.classworlds.Launcher.launchEnhanced(Launcher.java:315)
at org.codehaus.classworlds.Launcher.launch(Launcher.java:255)
at org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:430)
at org.codehaus.classworlds.Launcher.main(Launcher.java:375)
Instead I could simply specify that version 1.3 of the Maven AntRun plugin be used.
This AntRun version uses another version of Ant,
in which the above method is present, and so my patch is not needed.
In case anyone wants to build JStackAllock / JBullet with Maven,
below are some POM snippents.
(I hope it’s fine by you, Jezek2, with Jezek2 as group ID?)
I’m just wondering if there is ment to be any errors when i try and use your lirary wth Jbullet-JME.
i get the following error
java.lang.Error: not instrumented
at cz.advel.stack.Stack.alloc(Stack.java:109)
at com.bulletphysics.collision.shapes.BoxShape.calculateLocalInertia(BoxShape.java:165)
at com.jmex.jbullet.collision.shapes.CollisionShape.calculateLocalInertia(CollisionShape.java:59)
at com.jmex.jbullet.nodes.PhysicsNode.preRebuild(PhysicsNode.java:228)
at com.jmex.jbullet.nodes.PhysicsNode.rebuildRigidBody(PhysicsNode.java:216)
at com.jmex.jbullet.nodes.PhysicsNode.createCollisionShape(PhysicsNode.java:747)
at com.jmex.jbullet.nodes.PhysicsNode.<init>(PhysicsNode.java:135)
at com.jmex.jbullet.nodes.PhysicsNode.<init>(PhysicsNode.java:120)
at com.jmex.jbullet.nodes.PhysicsVehicleNode.<init>(PhysicsVehicleNode.java:79)
at jmetest.jbullet.TestSimplePhysicsCar.setupGame(TestSimplePhysicsCar.java:126)
at jmetest.jbullet.TestSimplePhysicsCar$10.call(TestSimplePhysicsCar.java:277)
at jmetest.jbullet.TestSimplePhysicsCar$10.call(TestSimplePhysicsCar.java:274)
at com.jme.util.GameTask.invoke(GameTask.java:140)
at com.jme.util.GameTaskQueue.execute(GameTaskQueue.java:111)
at com.jmex.game.StandardGame.update(StandardGame.java:372)
at com.jmex.game.StandardGame.run(StandardGame.java:244)
at java.lang.Thread.run(Thread.java:619)
There appears to be an issue with the
alloc(Class)
method, it will always throw the error above.
Slightly ???, any help would be appreciated
Finally decided to add support for annotations for stack allocations, yay This will solve compilation problems for JBullet users and make this library (JStackAlloc) more usable on it’s own as the bytecode modification will be optional. My previous stance about not recommending using it unless really necessary still applies though.
The old way will continue to work to anyone who wants it. After a bit of researching, the only option with annotations will be in this form:
@StackAlloc Vector3f vec = new Vector3f();
It will also allow to take any arguments (not just one of the same type like now), in that case the corresponding ‘set’ method will be used (similarly as in the old way). The ability to “directly” allocate output parameters, like this:
isn’t (currently) possible with annotations, so that won’t be supported. In JBullet code base it will probably lead to slightly better utilization of such temporary objects as in some cases these temporary objects could be reused when allocating them explicitly through local variable declarations.
However, the bytecode modification is not sufficient to make this work as local variables annotations aren’t exported to the bytecode. After a bit of researching, it seems it’s doable by using annotation processor (which can be passed as an option to javac). There is no standard way to modify the classes, only by using compiler (javac) specific classes, like the Project Lombok is doing.
FYI: I haven’t looked into it, and it probably isn’t of great interest since it would be eclipse specific, but there is a weaving framework for eclipse for performing these kinds of transforms.