Skip to content

Commit 8cef915

Browse files
authored
Update DetailedProfiler.java
1 parent 9a10591 commit 8cef915

1 file changed

Lines changed: 144 additions & 32 deletions

File tree

jme3-core/src/main/java/com/jme3/app/DetailedProfiler.java

Lines changed: 144 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017-2021 jMonkeyEngine
2+
* Copyright (c) 2017-2025 jMonkeyEngine
33
* All rights reserved.
44
*
55
* Redistribution and use in source and binary forms, with or without
@@ -39,34 +39,93 @@
3939
import java.util.*;
4040

4141
/**
42-
* Created by Nehon on 25/01/2017.
42+
* A detailed profiler implementation that tracks CPU and GPU times for various
43+
* application, viewport, and scene processing steps. It provides per-frame
44+
* statistics and also maintains a history for average calculations.
45+
*
46+
* @author Nehon on 25/01/2017.
4347
*/
4448
public class DetailedProfiler implements AppProfiler {
4549

50+
/**
51+
* The maximum number of frames to keep statistics for average calculations.
52+
*/
4653
private static final int MAX_FRAMES = 100;
54+
/**
55+
* Stores the current frame's profiling data, mapping step paths to StatLine objects.
56+
* This map is cleared at the beginning of each frame.
57+
*/
4758
private Map<String, StatLine> data;
59+
/**
60+
* A pool of StatLine objects, mapping step paths to StatLine objects.
61+
* This pool is used to reuse StatLine instances across frames to reduce garbage collection.
62+
*/
4863
private Map<String, StatLine> pool;
64+
/**
65+
* Not currently used for timing, potentially a leftover from earlier implementation.
66+
*/
4967
private long startFrame;
68+
/**
69+
* The current frame number. Increments with each completed frame.
70+
*/
5071
private static int currentFrame = 0;
72+
/**
73+
* Stores the path of the previously processed profiling step within the current frame.
74+
* Used to calculate the duration of the previous step.
75+
*/
5176
private String prevPath = null;
77+
/**
78+
* Flag indicating if the current frame has officially ended processing.
79+
*/
5280
private boolean frameEnded = false;
81+
/**
82+
* The renderer instance used for GPU profiling.
83+
*/
5384
private Renderer renderer;
85+
/**
86+
* Flag indicating if a GPU profiling task is currently ongoing (i.e., between startProfiling and stopProfiling).
87+
*/
5488
private boolean ongoingGpuProfiling = false;
55-
56-
89+
/**
90+
* The path component for the current application step.
91+
*/
5792
private String curAppPath = null;
93+
/**
94+
* The path component for the current viewport step.
95+
*/
5896
private String curVpPath = null;
97+
/**
98+
* The path component for the current scene processing step.
99+
*/
59100
private String curSpPath = null;
101+
/**
102+
* The last viewport step encountered. Used for path construction logic.
103+
*/
60104
private VpStep lastVpStep = null;
61-
105+
/**
106+
* StringBuilder used for constructing the full profiling path for app steps.
107+
*/
62108
private final StringBuilder path = new StringBuilder(256);
109+
/**
110+
* StringBuilder used for constructing the viewport-specific profiling path.
111+
*/
63112
private final StringBuilder vpPath = new StringBuilder(256);
64-
113+
/**
114+
* A pool of available GPU profiling task IDs.
115+
*/
65116
private final Deque<Integer> idsPool = new ArrayDeque<>(100);
66-
117+
/**
118+
* StatLine object specifically for tracking the total frame time (CPU).
119+
*/
67120
StatLine frameTime;
68121

69122

123+
/**
124+
* Records the time taken for various application-level steps.
125+
* This method is called at predefined points in the application lifecycle.
126+
*
127+
* @param step The application step being profiled.
128+
*/
70129
@Override
71130
public void appStep(AppStep step) {
72131

@@ -115,24 +174,30 @@ public void appStep(AppStep step) {
115174
}
116175
}
117176
if (step == AppStep.EndFrame) {
118-
119177
closeFrame();
120178
}
121179
}
122-
123-
180+
181+
/**
182+
* Records the time taken for application sub-steps, providing additional hierarchical detail.
183+
*
184+
* @param additionalInfo Optional strings to further qualify the sub-step path.
185+
*/
124186
@Override
125187
public void appSubStep(String... additionalInfo) {
126188
if (data != null) {
127-
String pathStep = getPath("", additionalInfo);
128189
path.setLength(0);
129-
path.append(curAppPath).append(pathStep);
190+
path.append(curAppPath);
191+
appendSubPath(path, additionalInfo); // Reusing helper for sub-path append
130192
addStep(path.toString(), System.nanoTime());
131193
}
132194
}
133195

196+
/**
197+
* Completes the profiling for the current frame.
198+
* This involves stopping any ongoing GPU profiling and closing all active StatLine entries.
199+
*/
134200
private void closeFrame() {
135-
//close frame
136201
if (data != null) {
137202
if (ongoingGpuProfiling && renderer != null) {
138203
renderer.stopProfiling();
@@ -147,24 +212,37 @@ private void closeFrame() {
147212
}
148213
}
149214

215+
/**
216+
* Records the time taken for viewport-specific steps, including rendering buckets.
217+
*
218+
* @param step The viewport step being profiled.
219+
* @param vp The ViewPort associated with this step.
220+
* @param bucket The render queue bucket, if applicable (null for non-bucket steps).
221+
*/
150222
@Override
151223
public void vpStep(VpStep step, ViewPort vp, RenderQueue.Bucket bucket) {
152224

153225
if (data != null) {
154226
vpPath.setLength(0);
155-
vpPath.append(vp.getName()).append("/")
156-
.append((bucket == null ? step.name() : bucket.name() + " Bucket"));
227+
vpPath.append(vp.getName()).append("/");
228+
if (bucket == null) {
229+
vpPath.append(step.name());
230+
} else {
231+
vpPath.append(bucket.name()).append(" Bucket");
232+
}
233+
157234
path.setLength(0);
235+
// Optimized path construction
236+
path.append(curAppPath).append("/");
237+
158238
if ((lastVpStep == VpStep.PostQueue || lastVpStep == VpStep.PostFrame) && bucket != null) {
159-
path.append(curAppPath).append("/").append(curVpPath).append(curSpPath).append("/")
160-
.append(vpPath);
239+
path.append(curVpPath).append(curSpPath).append("/").append(vpPath);
161240
curVpPath = vpPath.toString();
162241
} else {
163242
if (bucket != null) {
164-
path.append(curAppPath).append("/").append(curVpPath).append("/")
165-
.append(bucket.name() + " Bucket");
243+
path.append(curVpPath).append("/").append(bucket.name()).append(" Bucket");
166244
} else {
167-
path.append(curAppPath).append("/").append(vpPath);
245+
path.append(vpPath);
168246
curVpPath = vpPath.toString();
169247
}
170248
}
@@ -174,30 +252,49 @@ public void vpStep(VpStep step, ViewPort vp, RenderQueue.Bucket bucket) {
174252
}
175253
}
176254

255+
/**
256+
* Records the time taken for scene processing steps, allowing for additional detail.
257+
*
258+
* @param step The scene processing step being profiled.
259+
* @param additionalInfo Optional strings to further qualify the step path.
260+
*/
177261
@Override
178262
public void spStep(SpStep step, String... additionalInfo) {
179-
180263
if (data != null) {
181264
curSpPath = getPath("", additionalInfo);
182265
path.setLength(0);
183266
path.append(curAppPath).append("/").append(curVpPath).append(curSpPath);
184267
addStep(path.toString(), System.nanoTime());
185268
}
186-
187269
}
188270

271+
/**
272+
* Returns a map of the collected statistics for the current frame.
273+
* The keys are the hierarchical paths of the profiled steps, and the values
274+
* are {@link StatLine} objects containing CPU and GPU time data.
275+
*
276+
* @return A Map of StatLine objects, or null if profiling has not started.
277+
*/
189278
public Map<String, StatLine> getStats() {
190-
if (data != null) {
191-
return data; //new LinkedHashMap<>(data);
192-
}
193-
return null;
279+
return data;
194280
}
195281

282+
/**
283+
* Calculates the average CPU time for the entire frame.
284+
*
285+
* @return The average frame CPU time in nanoseconds.
286+
*/
196287
public double getAverageFrameTime() {
197288
return frameTime.getAverageCpu();
198289
}
199290

200-
291+
/**
292+
* Adds a new profiling step or updates an existing one with its start time.
293+
* Handles stopping the previous GPU profiling task and starting a new one.
294+
*
295+
* @param path The hierarchical path of the profiling step.
296+
* @param value The system nano time when this step began.
297+
*/
201298
private void addStep(String path, long value) {
202299
if (ongoingGpuProfiling && renderer != null) {
203300
renderer.stopProfiling();
@@ -225,26 +322,36 @@ private void addStep(String path, long value) {
225322
}
226323
ongoingGpuProfiling = true;
227324
prevPath = path;
228-
229325
}
230326

231327
private String getPath(String step, String... subPath) {
232-
StringBuilder path = new StringBuilder(step);
328+
StringBuilder sb = new StringBuilder(step);
329+
appendSubPath(sb, subPath);
330+
return sb.toString();
331+
}
332+
333+
private void appendSubPath(StringBuilder pathBuilder, String... subPath) {
233334
if (subPath != null) {
234335
for (String s : subPath) {
235-
path.append("/").append(s);
336+
pathBuilder.append("/").append(s);
236337
}
237338
}
238-
return path.toString();
239339
}
240340

341+
/**
342+
* Sets the {@link Renderer} instance to be used for GPU profiling.
343+
* This method should be called once the renderer is available.
344+
*
345+
* @param renderer The renderer instance.
346+
*/
241347
public void setRenderer(Renderer renderer) {
242348
this.renderer = renderer;
349+
// Initialize the pool of GPU profiling task IDs
243350
poolTaskIds(renderer);
244351
}
245352

246353
private void poolTaskIds(Renderer renderer) {
247-
int[] ids = renderer.generateProfilingTasks(100);
354+
int[] ids = renderer.generateProfilingTasks(MAX_FRAMES);
248355
for (int id : ids) {
249356
idsPool.push(id);
250357
}
@@ -258,7 +365,12 @@ private int getUnusedTaskId() {
258365
return idsPool.pop();
259366
}
260367

368+
/**
369+
* Represents a single line of statistics for a profiled step,
370+
* tracking CPU and GPU times over a set number of frames.
371+
*/
261372
public static class StatLine {
373+
262374
private final long[] cpuTimes = new long[MAX_FRAMES];
263375
private final long[] gpuTimes = new long[MAX_FRAMES];
264376
private int startCursor = 0;

0 commit comments

Comments
 (0)