Frame rate loss with upgrade from alpha 3 to latest nightly

So, the bottom line up front: after upgrading my stock JME alpha 3 to the latest nightly build as of yesterday afternoon, I discover that my application runs around 10+ FPS slower than before (77-80 down to 65-67 or so).



I have experienced this with no other changes to the application code and can even run the same application jar against both different versions to see the difference.



Obviously, there have been a lot of changes since alpha 3 and I’m slowly trying to weed through them and will post anything I find here. However, if anyone has any other ideas of things that might narrow my search, that would be excellent. This is very tedious.



It’s not so much the frame loss I mind, though that’s pretty significant. It’s the not knowing where it went. If I’m getting extra goodness somewhere for those lost frames then I’d like to take proper advantage… and if it’s something I can turn off if I don’t want… well, you get the picture.



Right now, I’m in a unique position to try some things, at least from application code. I have a setup where I can build my app and run it under both different JME versions to see what’s up. As hinted above, I’ll collect any coincidences I find out here just in case it sparks a memory somewhere.



I’m open to ideas.

First thing I would check would be the shaders?

Another thing might be the sorting by material, but I am not sure if it was actually added after alpha3

I played with sorting by material since it at least changed right around then… however, sorting by material was definitely an improvement in the newer code.



I’m trying to replicate the slow-down with an SVN build and then I’m going to go back in time and march forward until I see the issue. I’m on a mission now.

I noticed that in the old version I had like 500 textures switches, but in the new one I have like 50 which is much better. Its strange there’s an FPS loss

I may have guessed wrong at when base-alpha 3 was cut, svn revision-wise.

I’ve built against raw jme3 branch and see the slow down. I build against what looks to be the tagged alpha 3 (r6220) and do not see the slow down. Now I just need to work out which of the 500+ interceding revisions causes slow-down.



Oh, and for fun throw in the fact that occasionally (once in 20 runs?) I get an amazing speed-up of nearly 20 FPS. Wish I could figure out why those happen. :wink:

I’ve narrowed it down to a block of 100 revisions. :wink:

Don’t forget to use binary search to find which revision caused the change :wink:

Should only take log 2 (500) ~= 9 tries

I went forward by 100 until I saw slow down… binary search seemed a little too random, especially since I’ve already seen a handful of things I plan to go back and look into.



In the 6420-6520 block, I’m going through a few revisions at a time.

1 Like

Well, I see my first big drop at r6462… following a more minor one at r6460.



The r6462 one is bizarre because I can’t see anything that would cause a per-frame slow-down… just lots of m_Foo → Foo type of changes. In this version, the check for falling back is expensive but it should only be done once per set and not once per frame… besides, it will kick out a warning to the log.



But between r6459 and r6462, I go from ~76 FPS to ~64 FPS… the biggest drop is from r6461 (at 72/73 FPS) to r6462 (63-65 FPS)



I think I need sleep and fresher eyes.

mhhhh

it’s the m_ thing

I’m gonna look into it

mhh wait

do you set params into the material on a frame basis, with the m_ prefix?

Nope. I already commented that out before I even started this testing because you get warnings every time that way.

ok so even with no “m_” you get these slowdowns?

I’m trying not to change too much of my code until I can identify the hot spot… but that is one of my next steps.

Keeping track of what I’m finding for posterity.



The handful frame loss between 6459 and 6460 comes from these lines in Material:

[java]

if (techDef.getRenderState() != null) {

r.applyRenderState(techDef.getRenderState().cloneMerged(additionalState));

// if (additionalState != null) {

// r.applyRenderState(additionalState);

// }

} else {

r.applyRenderState(RenderState.DEFAULT.cloneMerged(additionalState));

// if (additionalState != null) {

// r.applyRenderState(additionalState);

// } else {

// r.applyRenderState(RenderState.DEFAULT);

// }

}

if (rm.getForcedRenderState() != null) {

r.applyRenderState(rm.getForcedRenderState());

}

[/java]



I’ll assume for the moment that the clone is a necessary evil but from a layman’s perspective, it is odd that an “apply” method would mutate its parameters… unless it’s the merging part that is why the clone is needed.

You guess right :stuck_out_tongue:

This thing is a bit messed up yeah…but there not a lot of way to make this efficient

I’m on it

One issue is in Technique and it still exists in the latest code…



See this:

http://code.google.com/p/jmonkeyengine/source/diff?path=/branches/jme3/src/core/com/jme3/material/Technique.java&format=side&r=6567



That has been put back and added a few times.



Real fix is like this:

[java]

public void notifyClearParam(String paramName) {

String defineName = def.getShaderParamDefine(paramName);

if (defineName != null) {

defines.remove(defineName);

needReload = true;

}

if (shader != null) {

if( !paramName.startsWith( "m_" ) )

paramName="m_"+paramName;

shader.removeUniform(paramName);//"m_"+paramName);

}

}



void updateUniformParam(String paramName, VarType type, Object value, boolean ifNotOwner) {

if( !paramName.startsWith( "m_" ) )

paramName="m_"+paramName;

Uniform u = shader.getUniform(paramName);

[/java]

Commited in last svn



and btw about that :

pspeed said:
[java]
if (techDef.getRenderState() != null) {
r.applyRenderState(techDef.getRenderState().cloneMerged(additionalState));
// if (additionalState != null) {
// r.applyRenderState(additionalState);
// }
} else {
r.applyRenderState(RenderState.DEFAULT.cloneMerged(additionalState));
// if (additionalState != null) {
// r.applyRenderState(additionalState);
// } else {
// r.applyRenderState(RenderState.DEFAULT);
// }
}
if (rm.getForcedRenderState() != null) {
r.applyRenderState(rm.getForcedRenderState());
}
[/java]
I'll assume for the moment that the clone is a necessary evil but from a layman's perspective, it is odd that an "apply" method would mutate its parameters... unless it's the merging part that is why the clone is needed.

The clone has been removed in revision r6597 now values are copied in a temp variable to avoid frame basis instantiation