Application Profiling

I’ve just committed to trunk some hooks for application profiling. For a long time, I’ve missed in JME the ability to see where the time in a particular frame is going. In a previous discussion (that I can no longer find a link to) on here I mentioned that I intended to do something about this in a more general way… that was probably a year ago or more now. I’ve tried to incorporate all of the ‘desirements’ mentioned in that thread. My notes were thready, though.

This is still a bit experimental but it’s functional and I’ve added a basic profiler visualization. So much more is possible if an application wants to get more detailed information.

The basic entry point is the AppProfiler interface. This has two methods: appStep(AppStep step) and vpStep(VpStep step, ViewPort vp, Bucket bucket).

appStep() is called for the larger application-level parts of a frame. vpStep() is called for viewport/bucket sub-parts of a frame. An AppProfiler implementation can choose to pay attention to or ignore whatever it likes.

By default, the application’s AppProfiler is set to null and effectively amounts to a no-op. When set, each of those methods is called at the appropriate time with the different AppStep or VpStep enum values. In this way, a profiler implementation could even just collect timings for a single ViewPort if it wanted.

Those classes are all in com.jme3.profiler.

In addition to those classes and the necessary hooks in Application, SimpleApplication, and RenderManager, I’ve also added a BasicProfiler and BasicProfilerState to manage it. This profiler implementation tracks application-wide frame timings for ‘update’ and ‘render’ and displays them as a continuously updating bar graph.

Each column represents a single frame. Yellow indicates the portion of the frame that was spent in ‘update’, ie: all non render stuff: enqueued tasks, state updates, control updates, etc… The cyan portion indicates the portion of the frame spent in rendering. The green area represents 16.666… milliseconds, ie: timings that fall outside of that area would drop a frame if 60 FPS is the target. The red area ends at 33.3333… milliseconds though the bar graph is free to draw outside of that range.

To use (if you are building from trunk), simply attach the BasicProfileState to your application. F6 will then toggle on/off the display.

Note: if vsync is on then the synching is part of the cyan area and so pretty much all frames looked maxed out. For meaningful timings it is necessary to leave vsynch off… unless you are just curious where you are dropping frames or spending a lot of ‘update’ time.

17 Likes

For the curious, here you can find the application level and viewport level steps that are reported:

I’ll paste them here, too:

public enum AppStep {
    BeginFrame,
    QueuedTasks,
    ProcessInput,
    ProcessAudio,
    StateManagerUpdate,
    SpatialUpdate,
    StateManagerRender,
    RenderFrame,
    RenderPreviewViewPorts,
    RenderMainViewPorts,
    RenderPostViewPorts,
    EndFrame
} 

public enum VpStep {
    BeginRender,
    RenderScene,
    PostQueue,
    FlushQueue,
    PostFrame,
    RenderBucket,
    EndRender
}

You can see that you could do some really detailed frame timings if you wanted to.

For reference, BasicProfiler ignores everything except AppStep.BeginFrame, AppStep.RenderFrame, and AppStep.EndFrame

2 Likes

This is awesome.
I need to make a profiler for filters so you can know what filter is killing you… :smiley:

1 Like

Nice and pretty cool ! Thank you

Hm just some thoughts, but how easily is this to extend? aka the rendering part, if I can calculate and submit timings myself. Like say red is my luacomputer, i time the updates it needs, and just want to display it in the end?

Well, you can make up your own steps, sure. As to how extensible the built in ‘basic profiler’ display is… you can always replace it with your own because it’s entirely pluggable. So if you just want to add one thing you could cut+paste the code and add it… register yours instead.

See:
com.jme3.profile.*
com.jme3.app.BasicProfiler: tracks the timings between some steps
com.jme3.app.BasicProfilerState: renders the timings