com.jme3.app.DetailedProfiler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jme3-core Show documentation
Show all versions of jme3-core Show documentation
jMonkeyEngine is a 3-D game engine for adventurous Java developers
/*
* Copyright (c) 2017-2021 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jme3.app;
import com.jme3.profile.*;
import com.jme3.renderer.Renderer;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.RenderQueue;
import java.util.*;
/**
* Created by Nehon on 25/01/2017.
*/
public class DetailedProfiler implements AppProfiler {
private final static int MAX_FRAMES = 100;
private Map data;
private Map pool;
private long startFrame;
private static int currentFrame = 0;
private String prevPath = null;
private boolean frameEnded = false;
private Renderer renderer;
private boolean ongoingGpuProfiling = false;
private String curAppPath = null;
private String curVpPath = null;
private String curSpPath = null;
private VpStep lastVpStep = null;
final private StringBuilder path = new StringBuilder(256);
final private StringBuilder vpPath = new StringBuilder(256);
final private Deque idsPool = new ArrayDeque<>(100);
StatLine frameTime;
@Override
public void appStep(AppStep step) {
curAppPath = step.name();
if (step == AppStep.BeginFrame) {
if (data == null) {
data = new LinkedHashMap<>();
pool = new HashMap<>();
frameTime = new StatLine(currentFrame);
}
if (frameTime.isActive()) {
frameTime.setValueCpu(System.nanoTime() - frameTime.getValueCpu());
frameTime.closeFrame();
}
frameTime.setNewFrameValueCpu(System.nanoTime());
frameEnded = false;
for (StatLine statLine : data.values()) {
for (Iterator i = statLine.taskIds.iterator(); i.hasNext(); ) {
int id = i.next();
if (renderer.isTaskResultAvailable(id)) {
long val = renderer.getProfilingTime(id);
statLine.setValueGpu(val);
i.remove();
idsPool.push(id);
}
}
}
data.clear();
}
if (data != null) {
String path = getPath(step.name());
if (step == AppStep.EndFrame) {
if (frameEnded) {
return;
}
addStep(path, System.nanoTime());
StatLine end = data.get(path);
end.setValueCpu(System.nanoTime() - startFrame);
frameEnded = true;
} else {
addStep(path, System.nanoTime());
}
}
if (step == AppStep.EndFrame) {
closeFrame();
}
}
@Override
public void appSubStep(String... additionalInfo) {
if (data != null) {
String pathStep = getPath("", additionalInfo);
path.setLength(0);
path.append(curAppPath).append(pathStep);
addStep(path.toString(), System.nanoTime());
}
}
private void closeFrame() {
//close frame
if (data != null) {
if (ongoingGpuProfiling && renderer != null) {
renderer.stopProfiling();
ongoingGpuProfiling = false;
}
prevPath = null;
for (StatLine statLine : data.values()) {
statLine.closeFrame();
}
currentFrame++;
}
}
@Override
public void vpStep(VpStep step, ViewPort vp, RenderQueue.Bucket bucket) {
if (data != null) {
vpPath.setLength(0);
vpPath.append(vp.getName()).append("/").append((bucket == null ? step.name() : bucket.name() + " Bucket"));
path.setLength(0);
if ((lastVpStep == VpStep.PostQueue || lastVpStep == VpStep.PostFrame) && bucket != null) {
path.append(curAppPath).append("/").append(curVpPath).append(curSpPath).append("/").append(vpPath);
curVpPath = vpPath.toString();
} else {
if (bucket != null) {
path.append(curAppPath).append("/").append(curVpPath).append("/").append(bucket.name() + " Bucket");
} else {
path.append(curAppPath).append("/").append(vpPath);
curVpPath = vpPath.toString();
}
}
lastVpStep = step;
addStep(path.toString(), System.nanoTime());
}
}
@Override
public void spStep(SpStep step, String... additionalInfo) {
if (data != null) {
curSpPath = getPath("", additionalInfo);
path.setLength(0);
path.append(curAppPath).append("/").append(curVpPath).append(curSpPath);
addStep(path.toString(), System.nanoTime());
}
}
public Map getStats() {
if (data != null) {
return data;//new LinkedHashMap<>(data);
}
return null;
}
public double getAverageFrameTime() {
return frameTime.getAverageCpu();
}
private void addStep(String path, long value) {
if (ongoingGpuProfiling && renderer != null) {
renderer.stopProfiling();
ongoingGpuProfiling = false;
}
if (prevPath != null) {
StatLine prevLine = data.get(prevPath);
if (prevLine != null) {
prevLine.setValueCpu(value - prevLine.getValueCpu());
}
}
StatLine line = pool.get(path);
if (line == null) {
line = new StatLine(currentFrame);
pool.put(path, line);
}
data.put(path, line);
line.setNewFrameValueCpu(value);
if (renderer != null) {
int id = getUnusedTaskId();
line.taskIds.add(id);
renderer.startProfiling(id);
}
ongoingGpuProfiling = true;
prevPath = path;
}
private String getPath(String step, String... subPath) {
StringBuilder path = new StringBuilder(step);
if (subPath != null) {
for (String s : subPath) {
path.append("/").append(s);
}
}
return path.toString();
}
public void setRenderer(Renderer renderer) {
this.renderer = renderer;
poolTaskIds(renderer);
}
private void poolTaskIds(Renderer renderer) {
int[] ids = renderer.generateProfilingTasks(100);
for (int id : ids) {
idsPool.push(id);
}
}
private int getUnusedTaskId() {
if (idsPool.isEmpty()) {
poolTaskIds(renderer);
}
return idsPool.pop();
}
public static class StatLine {
final private long[] cpuTimes = new long[MAX_FRAMES];
final private long[] gpuTimes = new long[MAX_FRAMES];
private int startCursor = 0;
private int cpuCursor = 0;
private int gpuCursor = 0;
private long cpuSum = 0;
private long gpuSum = 0;
private long lastValue = 0;
private int nbFramesCpu;
private int nbFramesGpu;
List taskIds = new ArrayList<>();
private StatLine(int currentFrame) {
startCursor = currentFrame % MAX_FRAMES;
cpuCursor = startCursor;
gpuCursor = startCursor;
}
private void setNewFrameValueCpu(long value) {
int newCursor = currentFrame % MAX_FRAMES;
if (nbFramesCpu == 0) {
startCursor = newCursor;
}
cpuCursor = newCursor;
lastValue = value;
}
private void setValueCpu(long val) {
lastValue = val;
}
private long getValueCpu() {
return lastValue;
}
private void closeFrame() {
if (isActive()) {
cpuSum -= cpuTimes[cpuCursor];
cpuTimes[cpuCursor] = lastValue;
cpuSum += lastValue;
nbFramesCpu++;
} else {
nbFramesCpu = 0;
}
}
public void setValueGpu(long value) {
gpuSum -= gpuTimes[gpuCursor];
gpuTimes[gpuCursor] = value;
gpuSum += value;
nbFramesGpu++;
gpuCursor = (gpuCursor + 1) % MAX_FRAMES;
}
public boolean isActive() {
return cpuCursor >= currentFrame % MAX_FRAMES - 1;
}
public double getAverageCpu() {
if (nbFramesCpu == 0) {
return 0;
}
return cpuSum / (double) Math.min(nbFramesCpu, MAX_FRAMES);
}
public double getAverageGpu() {
if (nbFramesGpu == 0) {
return 0;
}
return gpuSum / (double) Math.min(nbFramesGpu, MAX_FRAMES);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy