diff --git a/test.cpp b/test.cpp index cedd23b..960089f 100644 --- a/test.cpp +++ b/test.cpp @@ -27,6 +27,7 @@ vector> matrixMultiply(const vector>& A, const vec for (size_t j = 0; j < m; j++) { for (size_t k = 0; k < p; k++) { result[i][j] += A[i][k] * B[k][j]; + TracyPlot("matrixMultiply", result[i][j]); } } } @@ -46,6 +47,7 @@ vector> generateRandomMatrix(size_t rows, size_t cols) { for (size_t i = 0; i < rows; i++) { for (size_t j = 0; j < cols; j++) { matrix[i][j] = dis(gen); + TracyPlot("generateRandomMatrix", matrix[i][j]); } } @@ -68,7 +70,9 @@ void quickSort(vector& arr, int low, int high) { } swap(arr[i + 1], arr[high]); int pi = i + 1; - + + TracyPlot("quickSort.low", (int64_t)low); + TracyPlot("quickSort.high", (int64_t)high); quickSort(arr, low, pi - 1); quickSort(arr, pi + 1, high); } @@ -88,6 +92,7 @@ vector sieveOfEratosthenes(int n) { primes.push_back(i); for (int j = i * 2; j <= n; j += i) { isPrime[j] = false; + TracyPlot("sieveOfEratosthenes", (isPrime[j] ? 1.0 : 0.0)); } } } @@ -108,7 +113,8 @@ double calculatePi(int iterations) { for (int i = 0; i < iterations; i++) { double x = dis(gen); double y = dis(gen); - + + TracyPlot("calculatePi", (x * x + y * y)); if (x * x + y * y <= 1.0) { insideCircle++; } @@ -120,6 +126,7 @@ double calculatePi(int iterations) { // 斐波那契数列(递归) long long fibonacci(int n) { ZoneScoped; + TracyPlot("fibonacci", (int64_t)n); if (n <= 1) return n; return fibonacci(n - 1) + fibonacci(n - 2); @@ -149,6 +156,7 @@ double dotProduct(const vector& a, const vector& b) { double result = 0.0; for (size_t i = 0; i < a.size(); i++) { result += a[i] * b[i]; + TracyPlot("dotProduct", result); } return result; @@ -161,6 +169,7 @@ void complexMathOperations(int iterations) { double sum = 0.0; for (int i = 1; i <= iterations; i++) { sum += sin(i) * cos(i) + tan(i / 100.0) + sqrt(i) + log(i); + TracyPlot("complexMathOperations", sum); } cout << "复杂数学计算结果: " << sum << endl; diff --git a/unity_examples/CMakeLists.txt b/unity_examples/CMakeLists.txt index 1b24188..7c318f4 100644 --- a/unity_examples/CMakeLists.txt +++ b/unity_examples/CMakeLists.txt @@ -16,7 +16,6 @@ option(IS_TRACY_ON_DEMAND "Tracy 按需分析模式" ON) option(IS_TRACY_NO_EXIT "Tracy 不在退出时断开连接" OFF) option(IS_TRACY_NO_BROADCAST "Tracy 不广播发现消息" OFF) option(IS_TRACY_ONLY_LOCALHOST "Tracy 仅允许本地连接" OFF) -option(IS_ADVANCED_ZONE_MANAGEMENT "启用Tracy管理器类" ON) # ============================================ # Tracy 配置 @@ -46,10 +45,6 @@ if(IS_TRACY_ONLY_LOCALHOST) add_definitions(-DTRACY_ONLY_LOCALHOST) endif() -if(IS_ADVANCED_ZONE_MANAGEMENT) - add_definitions(-DADVANCED_ZONE_MANAGEMENT) -endif() - # ============================================ # Tracy 路径配置 # ============================================ diff --git a/unity_examples/SimplifiedPlugin.cpp b/unity_examples/SimplifiedPlugin.cpp index a02cc13..10744a7 100644 --- a/unity_examples/SimplifiedPlugin.cpp +++ b/unity_examples/SimplifiedPlugin.cpp @@ -15,13 +15,8 @@ #include "tracy/Tracy.hpp" #include #include - -#ifdef ADVANCED_ZONE_MANAGEMENT -#include +#include #include -#include -#include -#endif // Platform specific export definition #if defined(_WIN32) || defined(_WIN64) @@ -32,22 +27,10 @@ #define UNITY_PLUGIN_EXPORT #endif -// Simple Zone Manager for basic Zone tracking -#ifndef ADVANCED_ZONE_MANAGEMENT -namespace { - struct SimpleZone { - const char* name; - int64_t startTime; - }; - - struct ThreadZones { - std::stack zones; - }; - - std::unordered_map g_threadZones; - std::mutex g_zonesMutex; -} -#endif +std::map sourceLocationCache; +std::map zoneFunctionNameCache; +std::map zoneFilePathCache; +std::map> zoneStackCache; // C export functions (Unity requires C linkage) extern "C" @@ -67,10 +50,7 @@ extern "C" */ UNITY_PLUGIN_EXPORT void TracyShutdown() { -#ifndef ADVANCED_ZONE_MANAGEMENT - std::lock_guard lock(g_zonesMutex); - g_threadZones.clear(); -#endif + } /** @@ -118,51 +98,6 @@ extern "C" } } - /** - * Begin a named Zone - * Unity C# call: [DllImport] private static extern void TracyZoneBegin(string name); - * - * Note: This is a simplified implementation. For production use, consider using - * ADVANCED_ZONE_MANAGEMENT or a different Zone management approach. - */ - UNITY_PLUGIN_EXPORT void TracyZoneBegin(const char* name) - { -#ifndef ADVANCED_ZONE_MANAGEMENT - if (name != nullptr) - { - std::lock_guard lock(g_zonesMutex); - auto threadId = std::this_thread::get_id(); - - SimpleZone zone; - zone.name = name; - zone.startTime = tracy::GetTime(); - - g_threadZones[threadId].zones.push(zone); - - // Send zone begin event to Tracy - TracyMessageL(name); - } -#endif - } - - /** - * End current Zone - * Unity C# call: [DllImport] private static extern void TracyZoneEnd(); - */ - UNITY_PLUGIN_EXPORT void TracyZoneEnd() - { -#ifndef ADVANCED_ZONE_MANAGEMENT - std::lock_guard lock(g_zonesMutex); - auto threadId = std::this_thread::get_id(); - auto it = g_threadZones.find(threadId); - - if (it != g_threadZones.end() && !it->second.zones.empty()) - { - it->second.zones.pop(); - } -#endif - } - /** * Unity plugin lifecycle function - called on load */ @@ -180,117 +115,33 @@ extern "C" TracyShutdown(); } -} // extern "C" - -/* - * Advanced Implementation Example - Zone Management - * - * Below is a more complete Zone management implementation example - * Can be extended as needed - */ - -#ifdef ADVANCED_ZONE_MANAGEMENT - -// Zone Manager (Thread-safe) -class ZoneManager -{ -private: - struct ThreadZones + UNITY_PLUGIN_EXPORT void TracyZoneScopedBegin( + const char* name, + const char* functionName, + const char* filePath, + int lineNumber + ) { - std::stack zones; - }; - - std::unordered_map threadZones; - std::mutex mutex; - -public: - void BeginZone(const char* name, const char* function, const char* file, uint32_t line) - { - std::lock_guard lock(mutex); - - auto threadId = std::this_thread::get_id(); - auto& zones = threadZones[threadId].zones; - - // Create source location info - static const tracy::SourceLocationData loc{name, function, file, line, 0}; - - // Create Zone (note: must be heap allocated) - auto* zone = new tracy::ScopedZone(&loc, true); - zones.push(zone); - } - - void EndZone() - { - std::lock_guard lock(mutex); - - auto threadId = std::this_thread::get_id(); - auto it = threadZones.find(threadId); - - if (it != threadZones.end() && !it->second.zones.empty()) + std::string nameStr(name); + auto iter = sourceLocationCache.find(nameStr); + if (iter == sourceLocationCache.end()) { - auto* zone = it->second.zones.top(); - it->second.zones.pop(); - delete zone; + zoneFunctionNameCache[nameStr] = functionName; + zoneFilePathCache[nameStr] = filePath; + iter = sourceLocationCache.insert(sourceLocationCache.end(), std::make_pair(nameStr, tracy::SourceLocationData{})); + iter->second.name = iter->first.c_str(); + iter->second.function = zoneFunctionNameCache[nameStr].c_str(); + iter->second.file = zoneFilePathCache[nameStr].c_str(); + iter->second.line = static_cast(lineNumber); + iter->second.color = 0; } + zoneStackCache[nameStr].push(new tracy::ScopedZone(&iter->second, 0, true)); } - void ClearThread() + UNITY_PLUGIN_EXPORT void TracyZoneScopedEnd(const char* name) { - std::lock_guard lock(mutex); - - auto threadId = std::this_thread::get_id(); - auto it = threadZones.find(threadId); - - if (it != threadZones.end()) - { - // Clean up all unfinished Zones - while (!it->second.zones.empty()) - { - delete it->second.zones.top(); - it->second.zones.pop(); - } - threadZones.erase(it); - } + delete zoneStackCache[name].top(); + zoneStackCache[name].pop(); } -}; - -// Global Zone Manager instance -static ZoneManager g_zoneManager; - -extern "C" { - -UNITY_PLUGIN_EXPORT void TracyZoneBeginAdvanced(const char* name, const char* function, const char* file, int line) -{ - g_zoneManager.BeginZone(name, function, file, static_cast(line)); -} - -UNITY_PLUGIN_EXPORT void TracyZoneEndAdvanced() -{ - g_zoneManager.EndZone(); -} - -UNITY_PLUGIN_EXPORT void TracyClearThreadZones() -{ - g_zoneManager.ClearThread(); -} } // extern "C" - -#endif // ADVANCED_ZONE_MANAGEMENT - -/* - * Build and Deployment Instructions: - * - * Use CMake for all platforms (see CMakeLists.txt) - * - * Quick build: - * 1. mkdir build && cd build - * 2. cmake .. -DTRACY_ROOT="/path/to/tracy" - * 3. cmake --build . --config Release - * - * Deploy to Unity: - * - Copy compiled library to Unity project Assets/Plugins/ directory - * - Place in appropriate subdirectory based on platform - * - Configure Plugin Import Settings to match target platform - */ - diff --git a/unity_examples/TracyExamples.cs b/unity_examples/TracyExamples.cs deleted file mode 100644 index 02d965f..0000000 --- a/unity_examples/TracyExamples.cs +++ /dev/null @@ -1,396 +0,0 @@ -using UnityEngine; -using System.Collections; -using System.Collections.Generic; -using TracyProfiler; - -namespace TracyProfiler.Examples -{ - /// - /// Tracy 使用示例 - /// 展示如何在不同场景下使用 Tracy 性能分析 - /// - public class TracyExamples : MonoBehaviour - { - [Header("测试参数")] - [SerializeField] private int heavyComputationIterations = 10000; - [SerializeField] private int objectPoolSize = 100; - [SerializeField] private bool runContinuousTest = false; - - private List objectPool = new List(); - - private void Start() - { - Tracy.Message("TracyExamples - 示例场景启动"); - InitializeObjectPool(); - } - - private void Update() - { - // 示例 1: 追踪整个 Update 方法 - using (Tracy.Zone("TracyExamples.Update")) - { - // 示例 2: 追踪输入处理 - HandleInput(); - - // 示例 3: 追踪游戏逻辑 - if (runContinuousTest) - { - UpdateGameLogic(); - } - - // 示例 4: 绘制自定义数据 - PlotCustomData(); - } - } - - #region 示例 1: 基础 Zone 使用 - - private void HandleInput() - { - using (Tracy.Zone("Handle Input")) - { - if (Input.GetKeyDown(KeyCode.Space)) - { - Tracy.Message("用户按下空格键"); - PerformHeavyComputation(); - } - - if (Input.GetKeyDown(KeyCode.R)) - { - Tracy.Message("用户按下 R 键 - 重置对象池"); - ResetObjectPool(); - } - - if (Input.GetKeyDown(KeyCode.T)) - { - Tracy.Message("用户按下 T 键 - 运行测试"); - StartCoroutine(RunPerformanceTest()); - } - } - } - - #endregion - - #region 示例 2: 计算密集型操作追踪 - - private void UpdateGameLogic() - { - using (Tracy.Zone("Update Game Logic")) - { - // 模拟一些游戏逻辑 - ProcessAI(); - UpdatePhysics(); - CheckCollisions(); - } - } - - private void ProcessAI() - { - using (Tracy.Zone("Process AI")) - { - // 模拟 AI 计算 - float sum = 0; - for (int i = 0; i < 1000; i++) - { - sum += Mathf.Sin(i) * Mathf.Cos(i); - } - - Tracy.Plot("AI Computation Result", sum); - } - } - - private void UpdatePhysics() - { - using (Tracy.Zone("Update Physics")) - { - // 模拟物理更新 - foreach (var obj in objectPool) - { - if (obj.activeInHierarchy) - { - // 简单的物理模拟 - obj.transform.position += Vector3.down * Time.deltaTime; - } - } - } - } - - private void CheckCollisions() - { - using (Tracy.Zone("Check Collisions")) - { - // 模拟碰撞检测 - int activeObjects = 0; - foreach (var obj in objectPool) - { - if (obj.activeInHierarchy) - { - activeObjects++; - } - } - - Tracy.Plot("Active Objects", activeObjects); - } - } - - #endregion - - #region 示例 3: 重度计算测试 - - [ContextMenu("执行重度计算")] - public void PerformHeavyComputation() - { - using (Tracy.Zone("Heavy Computation")) - { - Tracy.Message($"开始重度计算 ({heavyComputationIterations} 次迭代)"); - - // 矩阵运算 - using (Tracy.Zone("Matrix Operations")) - { - Matrix4x4 result = Matrix4x4.identity; - for (int i = 0; i < heavyComputationIterations; i++) - { - Matrix4x4 temp = Matrix4x4.TRS( - Random.insideUnitSphere, - Random.rotation, - Vector3.one - ); - result = result * temp; - } - } - - // 数学运算 - using (Tracy.Zone("Math Operations")) - { - double sum = 0; - for (int i = 0; i < heavyComputationIterations; i++) - { - sum += System.Math.Sqrt(i) * System.Math.Sin(i) * System.Math.Cos(i); - } - Tracy.Plot("Math Result", sum); - } - - Tracy.Message("重度计算完成"); - } - } - - #endregion - - #region 示例 4: 对象池管理 - - private void InitializeObjectPool() - { - using (Tracy.Zone("Initialize Object Pool")) - { - Tracy.Message($"初始化对象池 (大小: {objectPoolSize})"); - - for (int i = 0; i < objectPoolSize; i++) - { - GameObject obj = GameObject.CreatePrimitive(PrimitiveType.Cube); - obj.name = $"PoolObject_{i}"; - obj.transform.position = Random.insideUnitSphere * 10f; - obj.SetActive(false); - objectPool.Add(obj); - } - - Tracy.Plot("Object Pool Size", objectPoolSize); - } - } - - [ContextMenu("重置对象池")] - public void ResetObjectPool() - { - using (Tracy.Zone("Reset Object Pool")) - { - foreach (var obj in objectPool) - { - obj.transform.position = Random.insideUnitSphere * 10f; - obj.SetActive(Random.value > 0.5f); - } - - Tracy.Message("对象池已重置"); - } - } - - #endregion - - #region 示例 5: 协程性能追踪 - - [ContextMenu("运行性能测试")] - public void StartPerformanceTest() - { - StartCoroutine(RunPerformanceTest()); - } - - private IEnumerator RunPerformanceTest() - { - Tracy.Message("=== 性能测试开始 ==="); - - // 测试 1: 快速操作 - using (Tracy.Zone("Test: Fast Operations")) - { - for (int i = 0; i < 100; i++) - { - float temp = Mathf.Sin(i); - } - } - - yield return null; - - // 测试 2: 中等操作 - using (Tracy.Zone("Test: Medium Operations")) - { - for (int i = 0; i < 1000; i++) - { - Vector3 temp = Random.insideUnitSphere; - } - } - - yield return new WaitForSeconds(0.1f); - - // 测试 3: 慢速操作 - using (Tracy.Zone("Test: Slow Operations")) - { - for (int i = 0; i < objectPoolSize; i++) - { - objectPool[i].SetActive(true); - objectPool[i].transform.position = Random.insideUnitSphere * 20f; - } - } - - yield return null; - - Tracy.Message("=== 性能测试完成 ==="); - } - - #endregion - - #region 示例 6: 自定义数据绘制 - - private void PlotCustomData() - { - using (Tracy.Zone("Plot Custom Data")) - { - // 绘制内存使用 - long memoryUsed = System.GC.GetTotalMemory(false); - Tracy.Plot("Custom Memory (MB)", memoryUsed / (1024.0 * 1024.0)); - - // 绘制对象计数 - int activeCount = 0; - foreach (var obj in objectPool) - { - if (obj.activeInHierarchy) activeCount++; - } - Tracy.Plot("Active Pool Objects", activeCount); - - // 绘制帧时间 - Tracy.Plot("Custom Frame Time (ms)", Time.deltaTime * 1000f); - - // 绘制时间戳 - Tracy.Plot("Time Since Startup", Time.realtimeSinceStartup); - } - } - - #endregion - - #region 示例 7: 条件性能追踪 - - /// - /// 演示如何使用条件编译来控制 Tracy 的开销 - /// - private void ConditionalProfiling() - { -#if TRACY_ENABLE - // 只有在定义了 TRACY_ENABLE 时才执行的代码 - using (Tracy.Zone("Conditional Profiling")) - { - // 详细的性能追踪 - DetailedPerformanceTracking(); - } -#endif - } - - private void DetailedPerformanceTracking() - { - // 非常细粒度的性能追踪 - for (int i = 0; i < 10; i++) - { - using (Tracy.Zone($"Iteration {i}")) - { - // 每次迭代的详细追踪 - System.Threading.Thread.Sleep(1); - } - } - } - - #endregion - - private void OnDestroy() - { - // 清理对象池 - using (Tracy.Zone("Cleanup Object Pool")) - { - foreach (var obj in objectPool) - { - if (obj != null) - { - Destroy(obj); - } - } - objectPool.Clear(); - - Tracy.Message("TracyExamples - 场景清理完成"); - } - } - -#if UNITY_EDITOR - [ContextMenu("切换连续测试")] - private void ToggleContinuousTest() - { - runContinuousTest = !runContinuousTest; - Tracy.Message($"连续测试: {(runContinuousTest ? "启用" : "禁用")}"); - } -#endif - } - - /// - /// 演示如何在自定义类中使用 Tracy - /// - public class CustomSystem - { - private string systemName; - - public CustomSystem(string name) - { - systemName = name; - Tracy.Message($"{systemName} - 系统创建"); - } - - public void Update() - { - using (Tracy.Zone($"{systemName}.Update")) - { - // 系统更新逻辑 - ProcessData(); - UpdateState(); - } - } - - private void ProcessData() - { - using (Tracy.Zone($"{systemName}.ProcessData")) - { - // 数据处理 - } - } - - private void UpdateState() - { - using (Tracy.Zone($"{systemName}.UpdateState")) - { - // 状态更新 - } - } - } -} - diff --git a/unity_examples/TracyWrapper.cs b/unity_examples/TracyWrapper.cs index cb77e64..e297235 100644 --- a/unity_examples/TracyWrapper.cs +++ b/unity_examples/TracyWrapper.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; using UnityEngine; namespace TracyProfiler @@ -37,10 +38,11 @@ namespace TracyProfiler private static extern void TracySetThreadName(string name); [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] - private static extern void TracyZoneBegin(string name); + private static extern void TracyZoneScopedBegin(string name, string function = "", string file = "", + int line = 0); [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] - private static extern void TracyZoneEnd(); + private static extern void TracyZoneScopedEnd(string name); #endregion @@ -70,7 +72,7 @@ namespace TracyProfiler try { -#if TRACY_ENABLE || UNITY_EDITOR +#if TRACY_ENABLE TracyInit(); s_initialized = true; Debug.Log("[Tracy] 性能分析器已初始化"); @@ -176,15 +178,14 @@ namespace TracyProfiler private bool isValid; private string zoneName; - public ZoneScope(string name) + public ZoneScope(string name, string function = "", string file = "", int line = 0) { zoneName = name; isValid = s_initialized && s_enabled; - #if TRACY_ENABLE if (isValid) { - TracyZoneBegin(name); + TracyZoneScopedBegin(name, function, file, line); } #endif } @@ -194,7 +195,7 @@ namespace TracyProfiler #if TRACY_ENABLE if (isValid && s_initialized && s_enabled) { - TracyZoneEnd(); + TracyZoneScopedEnd(zoneName); } #endif } @@ -210,31 +211,12 @@ namespace TracyProfiler /// // 要追踪的代码 /// } /// - public static ZoneScope Zone(string name) + public static ZoneScope Zone(string name, + [CallerMemberName] string function = "", + [CallerFilePath] string file = "", + [CallerLineNumber] int line = 0) { - return new ZoneScope(name); - } - - /// - /// 开始一个命名的 Zone - /// 注意:必须手动调用 EndZone() 结束,推荐使用 Zone() 方法配合 using 语句 - /// - [System.Diagnostics.Conditional("TRACY_ENABLE")] - public static void BeginZone(string name) - { - if (!s_initialized || !s_enabled) return; - TracyZoneBegin(name); - } - - /// - /// 结束当前 Zone - /// 注意:必须与 BeginZone() 配对使用 - /// - [System.Diagnostics.Conditional("TRACY_ENABLE")] - public static void EndZone() - { - if (!s_initialized || !s_enabled) return; - TracyZoneEnd(); + return new ZoneScope(name, function, file, line); } }