Once again! fast MappedObjects implementation

Structs! What I don’t get is why there is so little interest in an official array of structs language addition.

All RFEs in that direction have been either closed or ignored, so it’s obvious at least Sun couldn’t care less. Maybe Oracle will, but it would be a major rewrite of the language, would require new bytecodes. So it’d probably require Java 2.0, which would be tough for the marketing department, as we’re on 6.0 already :slight_smile:

Easiest solution is to hack it in…

It’s not that Sun doesn’t care about Struts. Struts shouldn’t be needed language wise because what Riven proposed here is an optimization that should be done at the JVM level. Sun/Oracle chose this way to not break backwards compatibility and provide the performance benefit. Although slowly, they are working on it, e.g. escape analysis.

You absolutely positively cannot let the JVM figure this out.

Escape analysis has nothing to do with it either. There is a fundamental difference between stack-allocation and structs, eventhough structs can be allocated on the stack. Structs can be used for giving an existing memory region new meaning, while escape analysis only prevents the creation of new instances.

IMHO the idea of mapped objects is/was the very best solution provided the bytecode executed fast enough, and lo and behold, here we have what looks like a working implementation.

Cas :slight_smile:

Hi!

Can it be used to improve the performances of 3D scenegraphs, for example those using javax.vecmath or something similar?

Is the CCPL GPL-compatible?

Do you have a typical test case in which we would like to “transfer” a set of values from the CPU to the GPU and vice versa by using your API and any OpenCL binding?

Thank you very much for sharing your source code.

Riven, the library needs to ignore static fields on mapped classes. Adding this:

if ( (field.getModifiers() & Modifier.STATIC) != 0 )
      continue;

in MappedObjectTransformer.java, line 52, should do it.

I’ll try to explain the benefits that this library provides:

  • Reduced memory consumption. Every Java object has some memory overhead; the reference to the object takes 4-8 bytes and then there’s whatever padding/alignment the JVM applies to the class fields. Arrays can be tricky as well (compare the memory usage of int[256] and int[128][2]). This overhead becomes significant when the objects are small and you have lots of them. In the context of game development the usual classes that create problems are vectors, matrices, sprite data, etc. By using the mapping this library provides, the object overhead is gone, you only have the data itself.

  • Since there are no objects, the GC has much less work to do. In a way, we get explicit memory management, which is something Java game developers have always wanted. You may argue that this is a bad idea and that Java requires no such thing, in which case I will simply point you to Terracotta’s BigMemory. Enterprise developers often face very similar problems to game developers, only at a much greater scale. A full GC on a multi-gigabyte heap is catastrophic when you require millisecond responses to thousands of users. Kinda like a game, you can’t afford to drop a frame due to GC. And even though modern JVMs have super-efficient collectors, it’s still a problem game developers face frequently. Obviously Terracotta chose to implement BigMemory with serialization, which makes sense for that environment and requires minimum code changes. With Riven’s library there’s no serialization, the data is the object. Also, memory management is “half-explicit”, that is, you do have to allocate the buffer to map, but you never have to “free” it, it still works like normal Java, make it null and it’s gone. This is actually beneficial for game development, since you often need to allocate/deallocate objects in batches anyway (e.g. on level start/end).

  • Continuous allocations stay that way. This may not be obvious to many Java programmers, but if you consider code like:

Vector4f[] vectors = new Vector4f[256];
for ( int i = 0; i < vectors.length; i++ )
    vectors[i] = new Vector4f();

you might expect that these vectors you just allocated are in continuous blocks in memory. Well, they may be for a while, but what happens when the objects get promoted from eden to tenured, while going through the survivor stages? Exactly, data locality is gone. You may get lucky, but really, it’s not deterministic and you don’t know what you will end-up with. This may sound like a GC implementation detail and the truth is that JVM engineers are currently working on a solution, but don’t expect it before Java 8. Anyway, having continuous data is very important for getting the most out of the CPU caches, so that’s a nice performance benefit.

  • This should be really obvious to anyone who has written OpenGL/CL code using a Java binding, any time you need interaction between Java data structures and OpenGL/CL buffers, it’s a mess. Not only do you have to copy data to and from buffers, the code is ugly as hell. Even C looks elegant in comparison. No point analyzing this further, you get better performance (no copies necessary) and super-sweet code (POJOs + managing the mapped buffer view offset). For me this justifies the library even if you ignore the other benefits.

@Riven: I wouldn’t even care too much about low level support. I’d be happy with sugar. Implementing array of structures would be easier than some of the stuff that currently on the table IHMO. I think the real problem is that it’s not very OO and thus must be bad or something. (Even though Java is a pretty weak OO language…not that this is bad or anything.)

In addition to stuff mentioned by Spasi, it’s difficult to impossible to implement efficient cache obvious methods in Java the high level language ATM…AoS would go a long way to fixing that.

What exactly isn’t OO about it?

Cas :slight_smile:

Is the question structs or Java?

Has anyone tested it with ridiculous big models like the stanford bunny or dragon in high res? I wonder how big the gain would be. :slight_smile:

Well, either.

Cas :slight_smile:

Absolutely none at all, unless you’re updating the vertex data in the bunny every frame… setup code might certainly look prettier though.

Cas :slight_smile:

That was my intention. Not primarily for the bunny or dragon, but for my character models I’m working on. As the animation requires a lot of updates. =(

The main argument against that I’ve seen is the structs aren’t the OO way, since structs aren’t objects. I find this silly, esp since Java isn’t a pure OO language and worst (from a pure OO standpoint) it’s strongly typed! From a pure standpoint languages like Java & C++ look like C-structures with a hidden header and a little sytax sugar. (Again, I’m not saying this is a bad thing) So pushing this argument I’d claim that Java isn’t the OO way.

So I don’t see that it’s a big deal to allow user defined types which aren’t objects and that arrays of structs would have type constraints.

I admit I never understood the “it’s not OOP” camp either. OOP has its uses but… sheesh.

Cas :slight_smile:

I think the argument usually goes that Java is not fully OOP because it has primitive types.

jabber jabber jabber ;D

Due to the awesome folks at LWJGL, it will soon be integrated in the nightlies of said project. License dropped. :point:

Changes:

  • migrated packages from ‘eden.mapped’ to ‘org.lwjgl.util.mapped’
  • added more inline comments
  • added basic javadoc comments with instructions

Bugfixes:

  • ignore static fields when calculating the field offsets.
  • hilarious off-by-one error in foreach(…).

Riven you are a star. Why don’t you come and work for me?

Cas :slight_smile: