Jump to content
  • Advertisement
Sign in to follow this  
  • entries
    4
  • comments
    8
  • views
    8831

About this blog

Journal about whatever current project I'm working on.

Entries in this blog

 

Trimming Eclipse's Fat

Hi! In this entry I'll describe how I do my Eclipse installs, with only the stuff I need.

Trimming Eclipse's Fat


So the issue is the following: Eclipse is kinda fat. At least that's the general idea.
.
Now the issue is that it isn't precisely Eclipse which is fat, its mostly the prepackaged distributions Eclipse.org has for downloading, for example:
.
"Eclipse IDE for Java EE Developers"
.
This one has all the crap you could think of. Database tools? Got it. Even for all the databases out there? Yes! For all the damn databases there are! JPA tools? Got it. XML tools? Got it. Support for all those damn JavaEE standards? Every single one of them. Modeling tools, Web tools, I think it even has CSS and JavaScript plugins! Everything. Its pretty much the "All projects under Eclipse Foundation in a single package" install.
.


.
Look at all of that stuff! Each of those has a bunch subitems.
.
Admittedly, the Xtext plugin doesn't comes from the JavaEE distribution, but its for Xtend support. Don't know about Xtend? If you're a Java developer you should, Xtend website, it only works for Eclipse right now but its a pretty seamless experience. You'd think all that transpiling to Java would affect something but it doesn't, works automagically. It even uses Java 8 lambdas automatically if you're targeting JDK 8.
.
I know Kotlin is all the rage these days as far as I know but I'm not fond of the ':' use in the syntax, much like Python's.
.
"Eclipse IDE for Java developers"
.
That one is a bit more trimmed. You got a few things that some might not want though, like XML tools, Mylyn integration, Maven integration (death to Maven!).
.
"Eclipse for Chubu"
.
This is how mine looks:
.


.
Thats all I use for my personal projects. JDT tools and Git/Hg integration.
.
Installation
.
Our journey starts here: Eclipse builds download site. That site tracks the builds of each eclipse version. You can see both the "in development" releases of the coming Eclipse versions, and the builds of the current Eclipse release.
.
To get the current stable release you go to "Latest release" and click on the version you want. In the following screen scroll down a bit, this is the section we want:
.


.
Thats the barebones Eclipse platform.
.
Eclipse is a "platform". You probably know it for JDT, Java Development Tools, but thats just a plugin. Yeah, its the most developed for Eclipse, but for Eclipse, JDT is still a plugin, nothing else.
.
Here we're downloading the platform alone, the "workbench", without anything else. Notice its only the platform, no Java tools, no database tools, no Mylyn, no anything. Just download the one you need depending on the platform you're using.
.
Installing what you need
.
When you launch it you'll see you have absolutely nothing but the basic sections. Hell it doesn't even has the Eclipse Marketplace installed (yes, thats a plugin!). That's a good thing, its an empty canvas on which you can draw the Eclipse of your dreams... or something.
.
All we need to do now is go to Help->Install new software... section, select "All available software sites" from the drop down list, select only the plugins we want. For example, if you're doing Java dev + some ORM stuff, you could only install JDT + Deli Database Tools plugin, without all that extra crap from "Eclipse for JavaEE developers" distribution.
.


.
Install them, restart eclipse, and you're good to go. Eclipse install with only what you need.
.
Extras and suggestions
.
My suggestion is to never have a "catch-all" Eclipse installation. Eclipse is really nice, you can use it for Python, JavaScript, PHP, Java, C, C++, etc. That doesn't means it has to be all done from the same Eclipse install. I have as many separate Eclipse installs as I need. One for plain Java, one for Python, one for doing JPA stuff, one for trying out Xtend, etc.
.
Also, a particular issue with Eclipse on Linux I've had: Eclipse (well technically, SWT) supports both GTK3 and GTK2 on Linux, issue is that with the GTK3 backend I've had issues, plain background colored bands eating part of all the Eclipse's windows on the sides.
.
To force GTK2 I launch it from a bash script like this:
.export SWT_GTK3=0./eclipse
.
That will force GTK2, which works fine (Xfce's dusk standard theme is the one you're seeing in the screenshots).
.
And thats it folks. Hope that helps to better your Eclipse user experience. Cya!

TheChubu

TheChubu

 

Extending Java classes from JavaScript

Hi! So this entry will be dealing with the Nashorn JavaScript engine found in Java 8+, specifically, how to extend a Java class from JavaScript and use the resulting JavaScript object in the Java side.

Extending Java classes from JavaScript

First this what I want to do:
Extend a Java class from JavaScript implementing a specific method.
Fetch the resulting object from Java and call that method.

So lets start by initializing the script engine:
String[] options = new String[] { "--language=es6" }; NashornScriptEngineFactory factory = new NashornScriptEngineFactory();NashornScriptEngine engine = (NashornScriptEngine) factory.getScriptEngine(options);
That will get us a Nashorn JS engine instance supporting some ECMAScript 6 features (the ones I want specifically are 'let' and 'const'). I spent hours Googling for a way to pass the "--language=es6" argument to the engine initialization since I was creating it with Java's "standard" script engine API instead of using the Nashorn factory object directly.

Now we need to load the script file, for that I'll use my ResourceManager and TxtFileLoader classes:// Create a manager at top level folder at 'res'.ResourceManager rm = new ResourceManager( "res" );// Now register the text file loader at sub folder 'script'.rm.registerResource( StringBuilder.class, new TxtFileLoader(), "script" );// Now load the script named 'testEntitySystem.js'.String scriptSource = rm.get( StringBuilder.class, "testEntitySystem.js" ).toString();
The long term goal is allowing me to have some EntitySystems implemented in JavaScript, so what we'll do on the JS side is to extend an EntitySystem and give it some implementation of 'processEntities(entities)' method, here is the script file:function main(){ // We need this one for initializing the EntitySystem. const Aspect = Java.type("com.artemis.Aspect") // Now fetch the type. const EntitySystem = Java.type("com.artemis.EntitySystem") // Prepare for extension. const JSEntitySystem = Java.extend(EntitySystem) // Now return an instance that implements the abstract 'processEntities' method. return new JSEntitySystem(Aspect.EMPTY_ASPECT) { processEntities: function(entities) print("Extended from JavaScript!") }}// Calling the function so it will return the EntitySystem instance to Java after execution. main()
Now all we need to do is to eval the script (or compile then execute) with the Nashorn engine instance and call the method:Object jsSystem = null;try{ jsSystem = engine.eval( scriptSource );}catch ( ScriptException e ){ e.printStackTrace();}// Lets see what kind of class it is...System.out.println(jsSystem.getClass());// Is it really a subclass of EntitySystem?System.out.println(jsSystem instanceof EntitySystem);// Now lets try to run the JS implementation!((EntitySystem)jsSystem).process();
And this outputs:[quote]
class com.artemis.EntitySystem$$NashornJavaAdapter
true
Extended from JavaScript![/quote]

We see that it really is an instance of EntitySystem, it executes the JS implementation just fine, and it seems the Nashorn engine is creating an adhoc adapter class for extension purposes, cool!

The fun thing here is that I can do "gameWorld.addObserver(jsSystem)" just fine and it will get iterated over like any other EntitySystem in the engine, so I can have systems both implemented in Java and in JavaScript working side to side.

Given how easy is the integration I'm pretty sure I'll be using this a lot in the future for scripting all sort of things. Thats all, cya later!

TheChubu

TheChubu

 

From YAML to renderer in 50ms

[font=arial]The idea of these couple entries will be to describe how I load my renderer's pipeline from a YAML file. In this particular entry I'll be describing the renderer architecture as it is right now.[/font]


[font=arial] From YAML to renderer in 50ms[/font]
[font=arial] Part 1[/font]


[font=arial]Hi! I'm going to take a different approach with this series. I'm going to upload a PDF with the entry, or I risk getting myself killed by the stupidity of the journal entry editor. I hope you download it and read it! See you later [/font]

PDF linky
[font=arial][/font]

[font=arial]Obligatory shiny image[/font]
[font=arial][/font]

[font=arial]EDIT: Tiny update in the PDF. Had one paragraph that was out of place, also using a more readable .mesh(mesh) method for setting up a RenderTask.

EDIT2: Another tiny update, shiny image.[/font]

TheChubu

TheChubu

 

Megamorphic calls

[font=verdana]I'll be having this journal to post random stuff probably! So...

Megamorphic calls

JVM distinguish regular calls from megamorphic calls (actually it distinguishes bimorphic calls too but whatever).

Regular calls can be optimized for, they can be inlined, or at least you can have the vtable round trip avoided. Whats a "regular call" ? Well its not necessarily a 'final' method.

HotSpot evaluates each call site of a method, and gathers statistics on what implementations of those methods were called. In most of the code, its very rare to find sections where say, 5 implementations of the same method are called, which is the case where vtable pointer chasing is actually needed.

HotSpot knows this, it can determine if a particular call site is only receiving objects of a certain type by profiling the code while its running, in the best of cases, it can inline the call, regardless of how many other implementations of said method there are running around, if a call site only ever sees one, it can be inlined.

This has a cost though. It can't inline the call blindly, what happens if you send 10k objects of one type, but that very last one is from another type? You'd be making the wrong call! This is called an "speculative optimization" for a reason, HotSpot can never be 100% sure you wont send another subclass down the same path eventually.

The best thing it can do is to inline the call for now and add an "uncommon trap" just in case, this is a type check before continuing the execution of the call. If the type is the expected, run the inlined code, otherwise, let HotSpot know what happened and fetch the correct function pointer to execute.

Example

This is a bit of code I was looking at today:[/font]public final void batchUpdate ( final T[] items, final int offset, final int limit ){ final ByteBuffer buff = tmpBuffer; // Reset position. buff.clear(); for ( int i = offset; i , buff ); } // Upload data in buffer to UBO. updateUBO();} // accept signature being:void accept(T t, ByteCode u)
[font=verdana]Thats the snippet of a batch updater for UBOs, that 'updateFunc' is a functional interface, BiConsumer specifically. We delegate the actual update operation implementation to that function since it depends on the kind of renderable we're trying to fetch data from. Thus its often implemented as a consumer of a specific renderable type (say, a Spatial, or a SpotLight).

Function implementation usually looks like this lambda:[/font]updateFunc = ( item, buff ) -> { float radius = item.pointLight.radius; item.viewPosition.putIn( buff ); item.pointLight.color.putIn( buff ); buff.putFloat( (1.0f / radius) );} );
[font=verdana]The 'item' in this case is a point light renderable. Put the view space position, color and inverse radius in the buffer. Alignment is done here if necessary, not the case though since viewPosition is a Vec4f, color is a Vec3f and a float is put in the last position. 32 bytes in total, perfect for std140 layout.

For all the different UBOs we have (transforms, spot lights, point lights, animation data, materials and whatever comes next), we'll have one specific updateFunc implementation. And each call to updateFunc.accept is a megamorphic call since by the time they're inside the RenderPasses, we're uploading
all the different kinds of data.

What does this means? Well, have in mind if we're rendering a couple thousand meshes, we're probably calling one to four of these updateFunc.apply calls per mesh, we could go anywhere from 10k to 100k updateFunc.apply calls.

Its dangerous to do virtual calls alone, take this!

This has a very tiny and simple fix though, we just need to move the for loop inside the function. For that we only need to add two parameters to the 'accept' signature, 'offset' and 'limit', and replace the single 'item' parameter with an array 'items'.[/font]
// New interface to use.@FunctionalInterfacepublic interface UpdateFunc{ public void accept ( T[] items, ByteBuffer buff, int start, int end );} // New point light update function implementation:updateFunc = ( items, buff, start, end ) -> { // This is the easiest kind of lambda to resolve for HotSpot btw, it gets the same treatment as static methods, // since it doesn't needs to capture any state, it just works with the passed parameters. for ( int i = start; i ; float radius = item.pointLight.radius; item.viewPosition.putIn( buff ); item.pointLight.color.putIn( buff ); buff.putFloat( (1.0f / radius) ); }} ); // And new update call inside the UBO updater:public final void batchUpdate ( final T[] items, final int offset, final int limit ){ final ByteBuffer buff = tmpBuffer; // Reset buffer. buff.clear(); // Update all the batched renderables. updateFunc.accept(items, buff, offset, limit ); // Upload data in buffer to UBO. updateUBO();}
[font=verdana]Now we haven't eliminated the megamorphic call, its still there, but we have reduced the amount of calls we make considerably. [/font]

[font=verdana]If we batch 500 instance updates, and we're rendering say, 10k meshes (disregarding instancing, or other batching methods for now), now we will be making just 20 calls in total for that particular updater, tops around 100 calls once we upload the data for the other kinds of UBOs.

In conclusion

Much better! Cya.[/font]

TheChubu

TheChubu

Sign in to follow this  
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!