JME 2.x slow attachChild

Hi,



For some reason it seems to be quite slow to add TriMeshes to scene graph using attachChild. I have a simple square object (2 triangles). If I try to add about 100-200 square objects to a Node, it takes a couple of seconds. Should it be that slow?



With that said, can I somehow hide an existing Node in a scene graph to toggle if it is rendered or not rendered?



Thanks


sampie wrote:
Should it be that slow?
You're right it should be slower.

When you look at the code, all that method would be doing is adding your object to an ArrayList.

The performance hit is most likely the 100-200 'new' objects you are creating to add to the list.
sampie wrote:
can I somehow hide an existing Node

setCullHint( CullHint.Always );



and to show it again

setCullHint( CullHint.Dynamic );

Hi,



I have created two loops. First loop creates squares and second loop adds squares to scene graph. The first loop runs fast. The second loop which adds squares is slow. I noticed that JME writes a lot of messages to console when I run attachChilds (in second loop). Could writing a lot of messages make things slow? The messages seem to be informative messages, not errors.

paste your code

Hi,



After I see "Attaching tile instances" -message, it takes a long time until display is updated with all new tiles (squares).



What I am actually trying to do is that I have a terrain that consists of tiles and I am trying to paint an area which is selected using mouse. The selected area is shown by creating a square above for each selected terrain tile.



Here is the routine in question:



          private void paintTiles(SparsePlane tileLocations) {

SparsePlaneIterator iter = new SparsePlaneIterator(tileLocations);

iter.begin();

Engine.field3D.clearTilePlates();



System.out.println("Creating Tile Instances");

Vector<TriMesh> v = new Vector<TriMesh>();

for (Location l; (l = iter.next()) != null;) {

TriMesh plane = Engine.instance.createPlane(new Location(l.x,l.y));

v.add(plane);

}



System.out.println("Attaching tile instances");

for (int i = 0; i < v.size(); i++) {

Field3D.instance.tilePlates.attachChild((TriMesh)v.get(i));

}



Engine.field3D.updateTilePlates();

}



Here is some related code:



public TriMesh createPlane(Location l) {



TriMesh m = new TriMesh("CP3D Plane");



Vector3f[] vertexes = {

new Vector3f(-0.5f, 0f, -0.5f),

new Vector3f(0.5f, 0f, -0.5f),

new Vector3f(-0.5f, 0, 0.5f),

new Vector3f(0.5f, 0, 0.5f)

};



Vector3f[] normals = {

new Vector3f(0, 1, 0),

new Vector3f(0, 1, 0),

new Vector3f(0, 1, 0),

new Vector3f(0, 1, 0)

};



ColorRGBA[] colors = {

new ColorRGBA(1f, 1f, 0f, 0.5f),

new ColorRGBA(1f, 1f, 0f, 0.5f),

new ColorRGBA(1f, 1f, 0f, 0.5f),

new ColorRGBA(1f, 1f, 0f, 0.5f)

};



Vector2f[] texCoords = {

new Vector2f(0, 0),

new Vector2f(1, 0),

new Vector2f(0, 1),

new Vector2f(1, 1)

};



int[] indexes = { 0, 2, 1, 1, 2, 3 };



m.reconstruct(BufferUtils.createFloatBuffer(vertexes),

BufferUtils.createFloatBuffer(normals),

BufferUtils.createFloatBuffer(colors),

TexCoords.makeNew(texCoords),

BufferUtils.createIntBuffer(indexes));



m.setLocalScale(blockSize);

m.setLocalTranslation(Field3D.gridPos(l.x, l.y));

m.setModelBound(new BoundingBox());

m.updateModelBound();

return m;

}





public Node tilePlates = new Node(); // this will be connected to rootNode



public void updateTilePlates() {

tilePlates.updateRenderState();

}

sampie wrote:
Could writing a lot of messages make things slow?
Outputting to log does affect performance, which is why you may choose to change the logging level for production code.
sampie wrote:
After I see "Attaching tile instances" -message
Just a minute, you are determining how long each section takes by s.o.p lines, right?

The first loop's time is marked by:

System.out.println("Creating Tile Instances");

try:


           private void paintTiles(SparsePlane tileLocations) {
      SparsePlaneIterator iter = new SparsePlaneIterator(tileLocations);
      iter.begin();
      Engine.field3D.clearTilePlates();

      System.out.println("Creating Tile Instances");
      Vector<TriMesh> v = new Vector<TriMesh>();
      for (Location l; (l = iter.next()) != null;) {
         TriMesh plane = Engine.instance.createPlane(new Location(l.x,l.y));
         plane.updateGeometricState(0.0f, true); // <-
         v.add(plane);
      }

      System.out.println("Attaching tile instances");
      for (int i = 0; i < v.size(); i++) {
         Field3D.instance.tilePlates.attachChild((TriMesh)v.get(i));
      }
     
      Engine.field3D.updateTilePlates();
   }

Hi,



Unfortunately I did not notice any difference when I added: "plane.updateGeometricState(0.0f, true);"



I added also some debug messages and made a test run. What I can see is: STEP 1 and STEP 2 being printed. Then about 250 lines of text is printed on the console. It takes a couple seconds to all those lines being printed. Example of text lines that are printed:

12.5.2010 15:56:10 com.jme.scene.Node attachChild

INFO: Child "CP3D Plane" attached to this node "null"



After the text lines are printed I can see "STEP 3, done" and "STEP 4, done" and the same time, the squares are being updated/displayed on the screen.



How can I set logging level / disable logging?





   System.out.println("STEP 1");
      Vector<TriMesh> v = new Vector<TriMesh>();
      for (Location l; (l = iter.next()) != null;) {
         TriMesh plane = Engine.instance.createPlane(new Location(l.x,l.y));
         plane.updateGeometricState(0.0f, true); // <-
         v.add(plane);
      }

        System.out.println("STEP 2");
      for (int i = 0; i < v.size(); i++) {
         Field3D.instance.tilePlates.attachChild((TriMesh)v.get(i));
      }

        System.out.println("STEP 3, done");
      
      Engine.field3D.updateTilePlates();
      
        System.out.println("STEP 4, done");

sampie wrote:
How can I set logging level / disable logging?
I'm unsure on the the best way to do it, but I use this as a static initialisation block in the class with the entry point (public static void main())

    {
        // The root logger's handlers default to INFO change to ignore all bar SEVERE.
        Handler[] handlers =
                Logger.getLogger("").getHandlers();

        for (int index = 0; index < handlers.length; index++)
        {
            handlers[index].setLevel(Level.SEVERE);
        }
    }

Hi,



I disabled the logging. It made things a little bit faster. Or at least to certain point.



Now comes the strange part. When I tested the application I noticed that it's memory consumption will increase fast as I create squares and does not decrease when squares are removed. Quite soon the application took over 2GB memory and the system begun swapping.



I continued testing and traced the problem to following call:

TriMesh plane = Engine.instance.createPlane(new Location(l.x,l.y));



Even if I don't store the resulting plane (TriMesh) anywhere or add it to schene graph, the memory usage will continue to grow with each call.



I am puzzled, how can createPlane leak memory?

sampie wrote:
Quite soon the application took over 2GB memory
As you're managing to use over 2GB of memory you must be familiar with the JVM settings (as 2GB would be max allocation by default *), have you changed the gc settings?
sampie wrote:
Even if I don't store the resulting plane (TriMesh) anywhere or add it to schene graph, the memory usage will continue to grow with each call.
Well each call you are creating a new TriMesh with all those buffers to boot.
sampie wrote:
I am puzzled, how can createPlane leak memory?
http://www.ibm.com/developerworks/library/j-leaks/


* http://publib.boulder.ibm.com/infocenter/realtime/v2r0/index.jsp?topic=/com.ibm.softrt.doc/diag/appendixes/defaults.html

As far as i see, you add the plane to a Vector, so it cannot be garbage collected.

The Vector is defined in a function, it should be destroyed after function exits. I also made tests, where I don't add the plane to the Vector and it made no difference.

Quote:
As you're managing to use over 2GB of memory you must be familiar with the JVM settings (as 2GB would be max allocation by default *), have you changed the gc settings?

It might be that memory consumption did not exceed 2GB, but became close to it. It's hard to say, because my machine starts to kill processes around that point. Anyway, I have not changed gc-setting or JVM settings.

It seems to me that trying to use large amounts of short-lifespan objects is a bad idea. It leads to performance and memory problems. Perhaps I just try to implement differently what I want.

Big thanks to everybody who helped me to solve and investigate various problems!
sampie wrote:
The Vector is defined in a function, it should be destroyed after function exits.
No, there is no guarantee that the gc will occur after the function exit, so it may be destroyed after exit, or it may not.

On leaving the function all that would have happened is the Vector would be orphaned, awaiting gc -so would still be occupying memory.
sampie wrote:
It leads to performance and memory problems
To be absolutely clear, a memory problem is when you receive an exception like the OutOfMemoryException, and you did not say you were experiencing such problems.

Creating a large number of short life span objects does lead to performance decrement compared to reusing existing objects (pooling / caching), but that's an issue across all languages and a prime reason for various creational design patterns.

(If you want to know more about patterns, google 'GoF patterns')
sampie wrote:
Big thanks to everybody who helped me to solve and investigate various problems!
8)