diff --git a/build.gradle.kts b/build.gradle.kts index faa105ee9fa..9b10f1fdb58 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -100,6 +100,8 @@ dependencies { // Natives for JNBullet natives(group = "org.terasology.jnbullet", name = "JNBullet", version = "1.0.4", ext = "zip") + // Natives for Tracy bindings (embedded in JAR) + natives("io.github.benjaminamos.TracyJavaBindings:TracyJavaBindings:1.0.0-SNAPSHOT") } tasks.register("extractWindowsNatives") { @@ -135,6 +137,13 @@ tasks.register("extractNativeBulletNatives") { into("$dirNatives") } +tasks.register("extractTracyJNINatives") { + description = "Extracts the Tracy JNI natives from the module jar" + from(configurations["natives"].filter { it.name.contains("TracyJavaBindings") }.map { zipTree(it) }) + into(dirNatives) + exclude("io/**", "META-INF/**") +} + tasks.register("extractNatives") { description = "Extracts all the native lwjgl libraries from the downloaded zip" dependsOn( @@ -142,7 +151,8 @@ tasks.register("extractNatives") { "extractLinuxNatives", "extractMacOSXNatives", "extractJNLuaNatives", - "extractNativeBulletNatives" + "extractNativeBulletNatives", + "extractTracyJNINatives" ) // specifying the outputs directory lets gradle have an up-to-date check, and automatic clean task outputs.dir("$dirNatives") diff --git a/engine/build.gradle.kts b/engine/build.gradle.kts index 6891217379c..e46ac5bd734 100644 --- a/engine/build.gradle.kts +++ b/engine/build.gradle.kts @@ -142,6 +142,8 @@ dependencies { implementation("org.terasology.crashreporter:cr-terasology:5.0.0") api(project(":subsystems:TypeHandlerLibrary")) + + implementation("io.github.benjaminamos.TracyJavaBindings:TracyJavaBindings:1.0.0-SNAPSHOT") } protobuf { diff --git a/engine/src/main/java/org/terasology/engine/core/TerasologyEngine.java b/engine/src/main/java/org/terasology/engine/core/TerasologyEngine.java index d3852f083ce..3ce433dab8e 100644 --- a/engine/src/main/java/org/terasology/engine/core/TerasologyEngine.java +++ b/engine/src/main/java/org/terasology/engine/core/TerasologyEngine.java @@ -468,12 +468,10 @@ public synchronized void runMain() { */ @SuppressWarnings("checkstyle:EmptyBlock") private void mainLoop() { - PerformanceMonitor.startActivity("Other"); // MAIN GAME LOOP while (tick()) { /* do nothing */ } - PerformanceMonitor.endActivity(); } /** @@ -482,6 +480,7 @@ private void mainLoop() { * @return true if the loop requesting a tick should continue running */ public boolean tick() { + PerformanceMonitor.startActivity("Tick"); if (shutdownRequested) { return false; } @@ -524,8 +523,8 @@ public boolean tick() { } assetTypeManager.disposedUnusedAssets(); + PerformanceMonitor.endActivity(); PerformanceMonitor.rollCycle(); - PerformanceMonitor.startActivity("Other"); return true; } diff --git a/engine/src/main/java/org/terasology/engine/monitoring/impl/PerformanceMonitorImpl.java b/engine/src/main/java/org/terasology/engine/monitoring/impl/PerformanceMonitorImpl.java index 842ead3ac5f..b20e652ce51 100644 --- a/engine/src/main/java/org/terasology/engine/monitoring/impl/PerformanceMonitorImpl.java +++ b/engine/src/main/java/org/terasology/engine/monitoring/impl/PerformanceMonitorImpl.java @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 package org.terasology.engine.monitoring.impl; +import io.github.benjaminamos.tracy.Tracy; import com.google.common.collect.Lists; import com.google.common.collect.Queues; import gnu.trove.map.TObjectDoubleMap; @@ -78,6 +79,8 @@ public PerformanceMonitorImpl() { timer = (EngineTime) CoreRegistry.get(Time.class); mainThread = Thread.currentThread(); + + Tracy.startupProfiler(); } @Override @@ -101,6 +104,10 @@ public void rollCycle() { currentExecutionData = new TObjectLongHashMap<>(); currentAllocationData = new TObjectLongHashMap<>(); + + activityStack.clear(); + + Tracy.markFrame(); } @Override @@ -111,6 +118,11 @@ public Activity startActivity(String activityName) { ActivityInfo newActivity = new ActivityInfo(activityName).initialize(); + StackWalker.StackFrame caller = java.security.AccessController.doPrivileged((java.security.PrivilegedAction) () -> + StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).walk(s -> s.skip(4).findFirst()).get()); + long sourceLocation = Tracy.allocSourceLocation(caller.getLineNumber(), caller.getFileName(), caller.getClassName() + "#" + caller.getMethodName(), activityName, 0); + newActivity.zoneContext = Tracy.zoneBegin(sourceLocation, 1); + if (!activityStack.isEmpty()) { ActivityInfo currentActivity = activityStack.peek(); currentActivity.ownTime += newActivity.startTime - ((currentActivity.resumeTime > 0) @@ -133,6 +145,8 @@ public void endActivity() { ActivityInfo oldActivity = activityStack.pop(); + Tracy.zoneEnd(oldActivity.zoneContext); + long endTime = timer.getRealTimeInMs(); long totalTime = (oldActivity.resumeTime > 0) ? oldActivity.ownTime + endTime - oldActivity.resumeTime @@ -152,6 +166,7 @@ public void endActivity() { } } + @Override public TObjectDoubleMap getRunningMean() { TObjectDoubleMap activityToMeanMap = new TObjectDoubleHashMap<>(); @@ -186,6 +201,8 @@ private class ActivityInfo { public long ownTime; public long startMem; public long ownMem; + public StackWalker.StackFrame caller; + public Tracy.ZoneContext zoneContext; ActivityInfo(String activityName) { this.name = activityName;