commit 43de86ee31532b4c0690bbdd49798300e2eb3313 Author: ninemine <1371605831@qq.com> Date: Wed Nov 26 14:35:58 2025 +0800 Init diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..02d0cd0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps +/.vs +/out diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..2df36a2 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "thirdparty/tracy"] + path = thirdparty/tracy + url = https://github.com/wolfpld/tracy.git diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..25780fb --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.14) +project(TestTracy) + +# 可用的选项:TRACY_ENABLE,TRACY_ON_DEMAND,TRACY_NO_BROADCAST,TRACY_NO_CODE_TRANSFER , ... +# 在add_subdirectory之前设置选项 +option (TRACY_ENABLE "" ON) +option (TRACY_ON_DEMAND "" ON) +add_subdirectory ("thirdparty/tracy") +#链接 `Tracy::TracyClient` 到你想要用Tracy进行性能分析的目标。 +add_executable(MyProject main.cpp) +target_link_libraries (MyProject PUBLIC Tracy::TracyClient) \ No newline at end of file diff --git a/CMakeSettings.json b/CMakeSettings.json new file mode 100644 index 0000000..0c5fbf9 --- /dev/null +++ b/CMakeSettings.json @@ -0,0 +1,27 @@ +{ + "configurations": [ + { + "name": "x64-Debug", + "generator": "Ninja", + "configurationType": "Debug", + "inheritEnvironments": [ "msvc_x64_x64" ], + "buildRoot": "${projectDir}\\out\\build\\${name}", + "installRoot": "${projectDir}\\out\\install\\${name}", + "cmakeCommandArgs": "", + "buildCommandArgs": "", + "ctestCommandArgs": "" + }, + { + "name": "x64-Release", + "generator": "Ninja", + "configurationType": "RelWithDebInfo", + "buildRoot": "${projectDir}\\out\\build\\${name}", + "installRoot": "${projectDir}\\out\\install\\${name}", + "cmakeCommandArgs": "", + "buildCommandArgs": "", + "ctestCommandArgs": "", + "inheritEnvironments": [ "msvc_x64_x64" ], + "variables": [] + } + ] +} \ No newline at end of file diff --git a/README_TEST.md b/README_TEST.md new file mode 100644 index 0000000..3a5c502 --- /dev/null +++ b/README_TEST.md @@ -0,0 +1,112 @@ +# Tracy 性能测试代码说明 + +这个项目包含多个高性能计算测试用例,用于展示 Tracy 性能分析器的功能。 + +## 测试内容 + +### 1. 矩阵乘法 (Matrix Multiplication) +- 200x200 矩阵相乘 +- 展示计算密集型操作的性能 +- 三重循环,复杂度 O(n³) + +### 2. 快速排序 (Quick Sort) +- 对 100,000 个随机整数进行排序 +- 展示递归算法的性能特征 +- 平均复杂度 O(n log n) + +### 3. 质数计算 (Prime Numbers) +- 使用埃拉托斯特尼筛法 +- 计算 0-1,000,000 范围内的所有质数 +- 展示循环嵌套和内存访问模式 + +### 4. 蒙特卡罗π值计算 (Monte Carlo Pi) +- 使用随机采样方法估算π值 +- 10,000,000 次迭代 +- 展示随机数生成和条件判断的性能 + +### 5. 斐波那契数列 (Fibonacci) +- **递归方法**: fibonacci(35) - 展示递归调用的开销 +- **动态规划**: fibonacci(90) - 展示优化算法的性能差异 + +### 6. 向量点积 (Vector Dot Product) +- 10,000,000 维向量点积计算 +- 展示大规模线性代数运算 +- 内存访问密集型操作 + +### 7. 复杂数学运算 (Complex Math) +- sin, cos, tan, sqrt, log 等函数组合 +- 1,000,000 次迭代 +- 展示浮点运算性能 + +### 8. 内存密集型操作 (Memory Intensive) +- 创建 1000x1000 二维数组 +- 填充和遍历大量数据 +- 展示内存分配和访问模式 + +### 9. 多线程测试 (Multi-Threading) +- 8 个线程并行执行 +- 每个线程执行 50,000,000 次计算 +- 展示多线程性能和同步开销 + +## 如何使用 + +### 1. 编译项目 +```bash +# 在 Visual Studio 中打开项目 +# 选择 Release 配置以获得最佳性能测试结果 +# 构建项目 +``` + +### 2. 启动 Tracy Profiler +```bash +# 从 Tracy 仓库的 profiler 目录运行 +# 或使用预编译的 Tracy.exe +``` + +### 3. 运行测试程序 +```bash +# 运行 MyProject.exe +# Tracy Profiler 会自动连接(如果启用了 TRACY_ON_DEMAND) +``` + +### 4. 在 Tracy 中观察 +- 查看每个函数的执行时间 +- 比较递归 vs 动态规划的性能差异 +- 观察多线程的并行执行情况 +- 分析热点函数和瓶颈 + +## Tracy 宏说明 + +- `ZoneScoped`: 自动追踪整个函数的执行时间 +- `ZoneScopedN("名称")`: 追踪代码块并指定自定义名称 +- `FrameMark`: 标记帧边界,便于区分不同的测试轮次 + +## 性能优化建议 + +根据 Tracy 的分析结果,你可以: + +1. **识别热点**: 找出耗时最长的函数 +2. **优化算法**: 比较不同算法实现(如递归 vs 动态规划) +3. **并行化**: 识别可以并行化的计算 +4. **缓存优化**: 观察内存访问模式,优化数据结构 +5. **减少递归**: 递归调用会带来额外开销 + +## 预期结果 + +在 Tracy Profiler 中,你应该能够看到: + +- **矩阵乘法**: 相对较长的执行时间,CPU 密集 +- **递归斐波那契**: 大量重复的函数调用(可视化调用树) +- **动态规划斐波那契**: 单次执行,线性时间 +- **多线程**: 8 个并行执行的线程,清晰的时间线 +- **质数计算**: 循环密集,但相对高效 +- **蒙特卡罗**: 稳定的执行时间,随机数生成开销 + +## 提示 + +- 使用 Release 配置编译可以获得更接近实际应用的性能数据 +- 多次运行测试可以在 Tracy 中观察性能的一致性 +- 尝试修改参数(矩阵大小、迭代次数等)观察性能变化 +- 使用 Tracy 的统计功能分析函数调用次数和平均执行时间 + + diff --git a/Tracy_Macro_CheatSheet.pdf b/Tracy_Macro_CheatSheet.pdf new file mode 100644 index 0000000..d5e2949 --- /dev/null +++ b/Tracy_Macro_CheatSheet.pdf @@ -0,0 +1,143 @@ +%PDF-1.4 +% ReportLab Generated PDF document http://www.reportlab.com +1 0 obj +<< +/F1 2 0 R /F2 3 0 R /F3 4 0 R /F4 5 0 R +>> +endobj +2 0 obj +<< +/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font +>> +endobj +3 0 obj +<< +/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font +>> +endobj +4 0 obj +<< +/BaseFont /ZapfDingbats /Name /F3 /Subtype /Type1 /Type /Font +>> +endobj +5 0 obj +<< +/BaseFont /Helvetica-Oblique /Encoding /WinAnsiEncoding /Name /F4 /Subtype /Type1 /Type /Font +>> +endobj +6 0 obj +<< +/Contents 13 0 R /MediaBox [ 0 0 841.8898 595.2756 ] /Parent 12 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +7 0 obj +<< +/Contents 14 0 R /MediaBox [ 0 0 841.8898 595.2756 ] /Parent 12 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +8 0 obj +<< +/Contents 15 0 R /MediaBox [ 0 0 841.8898 595.2756 ] /Parent 12 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +9 0 obj +<< +/Contents 16 0 R /MediaBox [ 0 0 841.8898 595.2756 ] /Parent 12 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +10 0 obj +<< +/PageMode /UseNone /Pages 12 0 R /Type /Catalog +>> +endobj +11 0 obj +<< +/Author (\(anonymous\)) /CreationDate (D:20251016122249+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20251016122249+00'00') /Producer (ReportLab PDF Library - www.reportlab.com) + /Subject (\(unspecified\)) /Title (Tracy Profiler Macros Cheat Sheet \(Complete\)) /Trapped /False +>> +endobj +12 0 obj +<< +/Count 4 /Kids [ 6 0 R 7 0 R 8 0 R 9 0 R ] /Type /Pages +>> +endobj +13 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1664 +>> +stream +Gat%#gN)%.%"6H'i).V+MF:CP^,^)%kt[^Sm,h`s1HV[3gM/%^.oAmoY@!BcAB>X!'Ak2L`&Rrd!-,ikQ`Im]%,c"([keh*!fJqGe>BJF#k&R27NQ9K@u!NiNru!Y0%`"$grK`TURi-Q:i+Vgf,,#=C.C8LHEbK+Ej&pA',EOL^qWs1'(Nf5JP?3l7j^3(46).,B[[F@#ja9c4[2!5m/U-UDeB4.:pD65EO-DaMtc_;&F1V'"ajd!+\GiLKUH^s1klq1DYnG#"LRR/q;No9SQGV&o%e5k:K;@:TMiOZJf_(h"'BM3X*?Y<5!P_K+>bC9JCtsBGEm<`Kc%<]!cI&98<33TLF-:GGaLdIB8!HJ.W8$u\8-?n"Q=9!P'^Vb]j]m(t3oK&]%A?U;=PmB:Om`DrL#_'&!Cfbr!!f]4EI]/Q'"+KS5WhK7%;Ma.@P#6NP3[n,"/,:O!9DX$6NGNuL'R)NV]-[4:J\G]HiPPK*PD2/(-?`Bc;%*$q3V/(A6\oQGJ^V[7)FT14'ooqZBL-d43ET7C]N:"5f_9bU?KTk,S?,a&=/?TKkV^0HeI,nMdZRc&hfhUCoa>*pA\lgn4CjPFFOlY4@J?W9.Se8Q/pAks2Z?_Zc[MRY;0E00g$le(Ql?ti-d"$YtUbaAH8Ka`Ami#ah$>/;?G>5/n0c2n*HLDVT05'LM:[=HC9SoBSs$kOg1EnGfFfMfrKn4/m)F,W&rp2XkYC@OA^ca<-]tGMZ$)rM6;0Z7E42\B$-t,s(FjO!JKZd4#@0V@3:HWO_S?W]"YiaeN7k8lu;I\YROK1md,qi#p/M1jYlqs\'c*`RC(f&LY`-p&3Y0u%3&endstream +endobj +14 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1259 +>> +stream +Gb!;bgMZ%0&:O:SbbML@)3WQnhn#-g/N,mQ1!g^=Kd'I(G',<(2=#^>LD4;MNj$QJJW4*%)9n[3]Z_6JT_MsX2^na`:#YZ#!TPk.J[r^QkpQ6c*Ed`"b`me39I>>Z"q6;,;&8sm4P-?*#]cU`Qj"#"9-Sc+4I?m_:g!rNP\OjFQ9LYTbn7k9[W1XD+=`tIEO[D#;m([ckhOM2TpaJV>f_Y.[A"5`k6GaA@0T6j+l7$E.JRa1aP[(@9K7gK"$r:(ad_ZONI6o^:MHF`0Qi8.A<[sW7*qAo4u!gnU!)m8p^Yh9+C*j.Z6'8UZ=<=1IV3fXW#W/9_ZZ\,gY^n0W$_/VXXQT32Ap(O]>L5j`Pc0U&KL@SciTBl\8ZG["AQuQ:a041>+P[P']ndJ62U:sQ4D&ZBFI"+T/@Jr3>P4>]jVD:nIqJ>2I*:$V,C>o((b6%&a0+9-ZJI6E.HZ%r]_4Fg2b0?1kAN;XC$W?nC2\FQ#M/*bNT5Jq:6YX'8f,#S$=o'@NG[b7@]d<;g"s]-4oH%?_OiTdCE^;RV<2^RlGNU:dDg3UUc%@X\c\@S*ERa>'/_a#X*bD"Q'LVL]!"Q"'4F$cVYhC*U%Aj?[A$bRhaHqu0&NR"oXT1Q$1<-:g'"Fm%r;ogH)48L%W$/TF4d1f#Gn_meu+ZP)$82$0OsYBr,oS]fbd.fN0gQ(14p(.)U>QnVI,$&XdiWendstream +endobj +15 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1262 +>> +stream +Gb"/&9lJcG&A@sB%!kg/PUd(@H&R]8%sH'T>DkDIlD)R'c+]h]X:'`'$YN5K`K_qp-9[![A)GiKu69Y8lA%Yj.;9#J[Cn[+e<]i2t4EZ'9Nnbp@hIN#8B:FIWp3>N8-Ra/:Pq$3Ca55XNb$0@]>t`8Q,j%Y\!>JPpN!.gZP`:Z^ClcmKCSX_7Z=dS,poSC71Y$%`I5ZY#uGuXOIY/h_(1/"?i9$1Zd(ZbjW^UT34d8=/YlZLRapb#/>oQ_$2npQ68F;?sV\^%7:StU;@C<_>2i^17hW%U6Un0LgD(\;F8Dm.c`'``QM1^L`?Mm)[^212?%["C6(5NJ(J33Z2o'uB@f?[%RUUIeDM/YTr_@)$.Z$qeW]>@W>jLJ\IR!R_=.4YHX?beBAn>:SoE][">:#?<=^cOf_8O9*)57Wc[?T\1:H4S*&]9e^L?lO/iCOd%[9UZ>UknQ6.&`2<_93klUE;M)^X<#J-0d^qD4al\R3lY5:L!-1dOiWiT21-1"7$8Z'2Ab^e&bThl*2l9]Vl(hHS`15C+=Jck557n9[KIFVVlJBZI:]q-/,"#R3)^jlPt&6`*TsELu_gcXL\2a_'DPGP5iW\d9DW9M0582g>i[_qM+KfU\ON]YJDoLp"lIo(&pj:4@H`2#!m^-lBe%oml2^O]Q*q]F69"6H/~>endstream +endobj +16 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 996 +>> +stream +Gatm9?#SFN'Rf.Ggo$!PRVP"1=5RZu.oQU%7&qe;67E%.#GFf=fD4EU6B"@!7N2i36br)F\K&^n$3/]=+s1,c^`^SS.?F5Y5S#QY75W2K9:^Frj&0N!:L*SHAXo%d\Mt&g6+Q$p3Jl,a\#MOhJGI\9s.A,&ENR&C.sMo=H`a@'pA=E]ZJ0*c["q!S(QpU.ZI`ZX(=B8h:GEkZKu'S:+8oj`\t+Tp1)b,&jGJr*S7n$Yp5!Os%c&`O$sLQTEi/79,mN7ehCooh-nqFL.=tO.[8,jk!_&N+e$Z]GZOifQ$KEfSaKL):fBt6lZl6h-a_A#p#TbM'us"[HDendstream +endobj +xref +0 17 +0000000000 65535 f +0000000073 00000 n +0000000134 00000 n +0000000241 00000 n +0000000353 00000 n +0000000436 00000 n +0000000551 00000 n +0000000756 00000 n +0000000961 00000 n +0000001166 00000 n +0000001371 00000 n +0000001441 00000 n +0000001758 00000 n +0000001836 00000 n +0000003592 00000 n +0000004943 00000 n +0000006297 00000 n +trailer +<< +/ID +[<4aefb1af7e31205ddcd23c78d196600e><4aefb1af7e31205ddcd23c78d196600e>] +% ReportLab generated PDF document -- digest (http://www.reportlab.com) + +/Info 11 0 R +/Root 10 0 R +/Size 17 +>> +startxref +7384 +%%EOF diff --git a/UNITY_INTEGRATION_GUIDE.md b/UNITY_INTEGRATION_GUIDE.md new file mode 100644 index 0000000..e9855c5 --- /dev/null +++ b/UNITY_INTEGRATION_GUIDE.md @@ -0,0 +1,802 @@ +# Tracy 集成到 Unity 的完整指南 + +## 概述 + +Tracy 是一个强大的 C++ 性能分析工具,要在 Unity 中使用它,需要通过 **Native Plugin** 的方式集成。本指南将介绍两种主要的集成方法。 + +--- + +## 方法一:通过 Native Plugin 集成(推荐) + +这是最常用和最灵活的方法,适用于所有Unity项目。 + +### 1. 创建 Tracy Native Plugin + +#### 步骤 1:创建 C++ 动态库项目 + +创建一个新的 C++ DLL/Shared Library 项目: + +**目录结构:** +``` +UnityTracyPlugin/ +├── src/ +│ ├── TracyUnityPlugin.cpp +│ └── TracyUnityPlugin.h +├── include/ +│ └── tracy/ # Tracy 源代码 +├── CMakeLists.txt +└── build/ +``` + +#### 步骤 2:编写 Plugin 代码 + +**TracyUnityPlugin.h:** +```cpp +#ifndef TRACY_UNITY_PLUGIN_H +#define TRACY_UNITY_PLUGIN_H + +// Unity Native Plugin 需要使用 C 导出 +#ifdef __cplusplus +extern "C" { +#endif + +// 平台定义 +#if defined(_WIN32) || defined(_WIN64) + #define UNITY_PLUGIN_EXPORT __declspec(dllexport) +#elif defined(__APPLE__) || defined(__linux__) + #define UNITY_PLUGIN_EXPORT __attribute__((visibility("default"))) +#else + #define UNITY_PLUGIN_EXPORT +#endif + +// Tracy API +UNITY_PLUGIN_EXPORT void TracyInit(); +UNITY_PLUGIN_EXPORT void TracyShutdown(); +UNITY_PLUGIN_EXPORT void TracyFrameMark(); +UNITY_PLUGIN_EXPORT void TracyBeginZone(const char* name, const char* function, const char* file, int line); +UNITY_PLUGIN_EXPORT void TracyEndZone(); +UNITY_PLUGIN_EXPORT void TracyPlotValue(const char* name, double value); +UNITY_PLUGIN_EXPORT void TracyMessage(const char* message); +UNITY_PLUGIN_EXPORT void TracySetThreadName(const char* name); + +#ifdef __cplusplus +} +#endif + +#endif // TRACY_UNITY_PLUGIN_H +``` + +**TracyUnityPlugin.cpp:** +```cpp +#include "TracyUnityPlugin.h" +#include "tracy/Tracy.hpp" +#include +#include +#include + +// 用于管理 Zone 的结构 +struct ZoneContext { + tracy::ScopedZone* zone; +}; + +static std::unordered_map g_zones; +static std::mutex g_zonesMutex; +static int g_nextZoneId = 1; + +extern "C" { + +UNITY_PLUGIN_EXPORT void TracyInit() { + // Tracy 会自动初始化,这里可以做一些额外的设置 +} + +UNITY_PLUGIN_EXPORT void TracyShutdown() { + std::lock_guard lock(g_zonesMutex); + g_zones.clear(); +} + +UNITY_PLUGIN_EXPORT void TracyFrameMark() { + FrameMark; +} + +UNITY_PLUGIN_EXPORT int TracyBeginZone(const char* name, const char* function, const char* file, int line) { + std::lock_guard lock(g_zonesMutex); + + int zoneId = g_nextZoneId++; + + // 创建 Zone(注意:这是简化版本,实际使用中需要更复杂的处理) + tracy::SourceLocationData loc; + loc.name = name; + loc.function = function; + loc.file = file; + loc.line = (uint32_t)line; + + // 实际使用中,你可能需要使用 Tracy 的宏来正确创建 Zone + // 这里仅作示例 + + return zoneId; +} + +UNITY_PLUGIN_EXPORT void TracyEndZone(int zoneId) { + std::lock_guard lock(g_zonesMutex); + + auto it = g_zones.find(zoneId); + if (it != g_zones.end()) { + delete it->second.zone; + g_zones.erase(it); + } +} + +UNITY_PLUGIN_EXPORT void TracyPlotValue(const char* name, double value) { + TracyPlot(name, value); +} + +UNITY_PLUGIN_EXPORT void TracyMessage(const char* message) { + TracyMessage(message, strlen(message)); +} + +UNITY_PLUGIN_EXPORT void TracySetThreadName(const char* name) { + tracy::SetThreadName(name); +} + +} // extern "C" +``` + +#### 步骤 3:CMakeLists.txt 配置 + +```cmake +cmake_minimum_required(VERSION 3.10) +project(UnityTracyPlugin) + +set(CMAKE_CXX_STANDARD 17) + +# Tracy 配置 +option(TRACY_ENABLE "Enable Tracy profiling" ON) +option(TRACY_ON_DEMAND "Tracy on-demand profiling" ON) + +add_definitions(-DTRACY_ENABLE) +add_definitions(-DTRACY_ON_DEMAND) + +# Tracy 源文件 +set(TRACY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include/tracy") +set(TRACY_SOURCES + ${TRACY_DIR}/public/TracyClient.cpp +) + +# Plugin 源文件 +set(PLUGIN_SOURCES + src/TracyUnityPlugin.cpp + ${TRACY_SOURCES} +) + +# 包含目录 +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/src + ${TRACY_DIR}/public +) + +# 创建动态库 +add_library(UnityTracyPlugin SHARED ${PLUGIN_SOURCES}) + +# Windows 平台设置 +if(WIN32) + target_link_libraries(UnityTracyPlugin ws2_32 dbghelp) +endif() + +# macOS/iOS 平台设置 +if(APPLE) + set_target_properties(UnityTracyPlugin PROPERTIES + FRAMEWORK FALSE + MACOSX_RPATH TRUE + ) +endif() + +# Linux/Android 平台设置 +if(UNIX AND NOT APPLE) + target_link_libraries(UnityTracyPlugin pthread dl) +endif() +``` + +#### 步骤 4:编译 Plugin + +```bash +# Windows +mkdir build +cd build +cmake .. -G "Visual Studio 17 2022" -A x64 +cmake --build . --config Release + +# macOS +mkdir build +cd build +cmake .. -DCMAKE_BUILD_TYPE=Release +make + +# Linux +mkdir build +cd build +cmake .. -DCMAKE_BUILD_TYPE=Release +make +``` + +### 2. Unity 端集成 + +#### 步骤 1:将编译好的 DLL 放入 Unity 项目 + +``` +UnityProject/ +└── Assets/ + └── Plugins/ + ├── x86_64/ + │ └── UnityTracyPlugin.dll # Windows 64位 + ├── x86/ + │ └── UnityTracyPlugin.dll # Windows 32位 + ├── Android/ + │ ├── arm64-v8a/ + │ │ └── libUnityTracyPlugin.so # Android ARM64 + │ └── armeabi-v7a/ + │ └── libUnityTracyPlugin.so # Android ARM32 + ├── iOS/ + │ └── libUnityTracyPlugin.a # iOS 静态库 + └── macOS/ + └── libUnityTracyPlugin.dylib # macOS +``` + +#### 步骤 2:创建 C# Wrapper + +**Tracy.cs:** +```csharp +using System; +using System.Runtime.InteropServices; +using UnityEngine; + +namespace TracyProfiler +{ + /// + /// Tracy 性能分析器的 Unity 封装 + /// + public static class Tracy + { + private const string DLL_NAME = "UnityTracyPlugin"; + + #region Native Methods + + [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] + private static extern void TracyInit(); + + [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] + private static extern void TracyShutdown(); + + [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] + private static extern void TracyFrameMark(); + + [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] + private static extern int TracyBeginZone(string name, string function, string file, int line); + + [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] + private static extern void TracyEndZone(int zoneId); + + [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] + private static extern void TracyPlotValue(string name, double value); + + [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] + private static extern void TracyMessage(string message); + + [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] + private static extern void TracySetThreadName(string name); + + #endregion + + private static bool s_initialized = false; + + /// + /// 初始化 Tracy + /// + public static void Initialize() + { + if (s_initialized) return; + + try + { + TracyInit(); + s_initialized = true; + Debug.Log("Tracy Profiler 已初始化"); + } + catch (Exception e) + { + Debug.LogError($"Tracy 初始化失败: {e.Message}"); + } + } + + /// + /// 关闭 Tracy + /// + public static void Shutdown() + { + if (!s_initialized) return; + + try + { + TracyShutdown(); + s_initialized = false; + } + catch (Exception e) + { + Debug.LogError($"Tracy 关闭失败: {e.Message}"); + } + } + + /// + /// 标记帧边界(通常在每帧末尾调用) + /// + public static void MarkFrame() + { + if (!s_initialized) return; + TracyFrameMark(); + } + + /// + /// 绘制数值(用于实时监控变量) + /// + public static void Plot(string name, double value) + { + if (!s_initialized) return; + TracyPlotValue(name, value); + } + + /// + /// 发送消息到 Tracy + /// + public static void Message(string message) + { + if (!s_initialized) return; + TracyMessage(message); + } + + /// + /// 设置当前线程名称 + /// + public static void SetThreadName(string name) + { + if (!s_initialized) return; + TracySetThreadName(name); + } + + /// + /// Tracy Zone 的作用域包装器(使用 using 语句自动管理生命周期) + /// + public struct ZoneScope : IDisposable + { + private int zoneId; + private bool isValid; + + public ZoneScope(string name, + [System.Runtime.CompilerServices.CallerMemberName] string function = "", + [System.Runtime.CompilerServices.CallerFilePath] string file = "", + [System.Runtime.CompilerServices.CallerLineNumber] int line = 0) + { + if (s_initialized) + { + zoneId = TracyBeginZone(name, function, file, line); + isValid = true; + } + else + { + zoneId = -1; + isValid = false; + } + } + + public void Dispose() + { + if (isValid && s_initialized) + { + TracyEndZone(zoneId); + } + } + } + + /// + /// 创建一个 Tracy Zone(性能追踪区域) + /// 使用 using 语句确保自动结束 + /// + public static ZoneScope BeginZone(string name) + { + return new ZoneScope(name); + } + } +} +``` + +#### 步骤 3:创建 Tracy Manager + +**TracyManager.cs:** +```csharp +using UnityEngine; + +namespace TracyProfiler +{ + /// + /// Tracy 管理器 - 负责初始化和每帧更新 + /// + public class TracyManager : MonoBehaviour + { + [Header("Tracy Settings")] + [SerializeField] private bool enableOnStart = true; + [SerializeField] private bool markFrames = true; + + private void Awake() + { + // 确保只有一个实例 + if (FindObjectsOfType().Length > 1) + { + Destroy(gameObject); + return; + } + + DontDestroyOnLoad(gameObject); + + if (enableOnStart) + { + Tracy.Initialize(); + } + } + + private void LateUpdate() + { + // 在每帧末尾标记帧边界 + if (markFrames) + { + Tracy.MarkFrame(); + } + + // 示例:绘制一些有用的性能数据 + Tracy.Plot("FPS", 1.0f / Time.deltaTime); + Tracy.Plot("Frame Time (ms)", Time.deltaTime * 1000.0f); + Tracy.Plot("Total Allocated Memory (MB)", GC.GetTotalMemory(false) / (1024.0 * 1024.0)); + } + + private void OnDestroy() + { + Tracy.Shutdown(); + } + + private void OnApplicationQuit() + { + Tracy.Shutdown(); + } + } +} +``` + +#### 步骤 4:使用示例 + +**GameManager.cs:** +```csharp +using UnityEngine; +using TracyProfiler; + +public class GameManager : MonoBehaviour +{ + private void Update() + { + // 追踪整个 Update 方法 + using (Tracy.BeginZone("GameManager.Update")) + { + ProcessInput(); + UpdateGameLogic(); + UpdateAI(); + } + } + + private void ProcessInput() + { + using (Tracy.BeginZone("ProcessInput")) + { + // 输入处理代码 + if (Input.GetKeyDown(KeyCode.Space)) + { + Tracy.Message("玩家按下空格键"); + } + } + } + + private void UpdateGameLogic() + { + using (Tracy.BeginZone("UpdateGameLogic")) + { + // 游戏逻辑代码 + for (int i = 0; i < 1000; i++) + { + // 一些计算 + } + } + } + + private void UpdateAI() + { + using (Tracy.BeginZone("UpdateAI")) + { + // AI 更新代码 + Tracy.Plot("Enemy Count", GameObject.FindGameObjectsWithTag("Enemy").Length); + } + } +} +``` + +**PhysicsController.cs:** +```csharp +using UnityEngine; +using TracyProfiler; + +public class PhysicsController : MonoBehaviour +{ + private void FixedUpdate() + { + using (Tracy.BeginZone("PhysicsController.FixedUpdate")) + { + PerformPhysicsCalculations(); + } + } + + private void PerformPhysicsCalculations() + { + using (Tracy.BeginZone("Physics Calculations")) + { + // 物理计算 + Rigidbody[] rigidbodies = FindObjectsOfType(); + Tracy.Plot("Active Rigidbodies", rigidbodies.Length); + + foreach (var rb in rigidbodies) + { + // 处理刚体 + } + } + } +} +``` + +--- + +## 方法二:IL2CPP 后端集成 + +当 Unity 使用 IL2CPP 作为脚本后端时,可以直接在生成的 C++ 代码中集成 Tracy。 + +### 1. 配置 IL2CPP + +在 Unity 项目中创建 `il2cpp_custom.cpp`: + +```cpp +// 放置在: Assets/Plugins/IL2CPP/il2cpp_custom.cpp + +#include "il2cpp-config.h" + +// 包含 Tracy +#define TRACY_ENABLE +#include "tracy/Tracy.hpp" + +// IL2CPP 钩子函数 +extern "C" void UnityPluginLoad(void* unityInterfaces) +{ + // Tracy 会自动初始化 +} + +extern "C" void UnityPluginUnload() +{ + // Tracy 清理 +} +``` + +### 2. 修改 IL2CPP 构建设置 + +在 Unity 的 Player Settings 中: +1. 切换到 IL2CPP 脚本后端 +2. 添加额外的编译参数:`-DTRACY_ENABLE -DTRACY_ON_DEMAND` +3. 链接 Tracy 库 + +--- + +## 方法三:Unity Profiler 集成(可选) + +可以创建一个桥接层,将 Unity Profiler 的数据转发到 Tracy。 + +**UnityToTracyBridge.cs:** +```csharp +using UnityEngine; +using UnityEngine.Profiling; +using TracyProfiler; + +public class UnityToTracyBridge : MonoBehaviour +{ + private CustomSampler[] samplers; + + private void Start() + { + // 创建自定义采样器 + samplers = new CustomSampler[] + { + CustomSampler.Create("Render"), + CustomSampler.Create("Physics"), + CustomSampler.Create("Scripts"), + CustomSampler.Create("GarbageCollector"), + }; + } + + private void LateUpdate() + { + // 将 Unity Profiler 数据转发到 Tracy + foreach (var sampler in samplers) + { + Tracy.Plot(sampler.name + " (ms)", sampler.GetRecorder().elapsedNanoseconds / 1000000.0); + } + + // 内存统计 + Tracy.Plot("Used Heap Size (MB)", Profiler.usedHeapSizeLong / (1024.0 * 1024.0)); + Tracy.Plot("Total Allocated Memory (MB)", Profiler.GetTotalAllocatedMemoryLong() / (1024.0 * 1024.0)); + Tracy.Plot("Total Reserved Memory (MB)", Profiler.GetTotalReservedMemoryLong() / (1024.0 * 1024.0)); + } +} +``` + +--- + +## 平台特定配置 + +### Windows +- 使用 Visual Studio 编译 DLL +- 确保链接 `ws2_32.lib` 和 `dbghelp.lib` + +### macOS / iOS +- 使用 Xcode 编译动态库或框架 +- 注意代码签名要求 + +### Android +- 为不同的 ABI 编译:armeabi-v7a, arm64-v8a, x86, x86_64 +- 在 `gradle.properties` 中配置 NDK 路径 + +### Linux +- 链接 `pthread` 和 `dl` +- 确保 GLIBC 版本兼容 + +--- + +## 使用 Tracy Profiler 查看数据 + +### 1. 启动 Tracy Profiler + +```bash +# 从 Tracy 仓库构建或下载预编译版本 +# 运行 Tracy.exe (Windows) 或 Tracy (macOS/Linux) +``` + +### 2. 连接到 Unity 应用 + +- Tracy Profiler 会自动发现本地网络中的 Tracy 客户端 +- 点击连接即可开始分析 + +### 3. 查看性能数据 + +- **时间线视图**: 查看各个 Zone 的执行时间 +- **统计视图**: 查看函数调用次数和平均耗时 +- **内存视图**: 查看内存分配情况 +- **图表视图**: 查看 Plot 数据的实时曲线 + +--- + +## 最佳实践 + +### 1. 性能开销 +- Tracy 的开销很小,但仍建议在 Release 构建中禁用细粒度的 Zone +- 使用条件编译:`#if TRACY_ENABLE` + +### 2. Zone 命名 +- 使用清晰、描述性的名称 +- 包含类名和方法名,如 `"PlayerController.Move"` + +### 3. 合理使用 Plot +- 不要在每帧绘制过多数据点 +- 专注于关键性能指标 + +### 4. 多线程支持 +- Unity 的 Job System 需要特殊处理 +- 在每个 Job 中调用 `Tracy.SetThreadName()` + +### 5. 移动平台 +- 注意无线网络连接的延迟 +- 可以使用 Tracy 的文件保存功能,之后再分析 + +--- + +## 故障排除 + +### 问题 1: DLL 加载失败 +**解决方案:** +- 检查 Plugin 导入设置中的平台配置 +- 确保 DLL 与 Unity 架构匹配(x64/x86) +- 检查依赖库是否缺失 + +### 问题 2: Tracy Profiler 无法连接 +**解决方案:** +- 确保防火墙允许 TCP 端口 8086 +- 检查 `TRACY_ON_DEMAND` 是否正确定义 +- 确认 Tracy.Initialize() 已被调用 + +### 问题 3: 性能数据不准确 +**解决方案:** +- 使用 Release 构建测试 +- 禁用 Unity Editor 的 Deep Profiling +- 确保 V-Sync 和帧率限制的设置符合预期 + +### 问题 4: Android 构建失败 +**解决方案:** +- 检查 NDK 版本兼容性 +- 在 `build.gradle` 中添加必要的链接器标志 +- 确保所有 ABI 的库都已编译 + +--- + +## 进阶功能 + +### 1. 自定义内存分配追踪 + +```cpp +// 在 Plugin 中添加 +UNITY_PLUGIN_EXPORT void TracyAllocNamed(void* ptr, size_t size, const char* name) { + TracyAllocN(ptr, size, name); +} + +UNITY_PLUGIN_EXPORT void TracyFreeNamed(void* ptr, const char* name) { + TracyFreeN(ptr, name); +} +``` + +```csharp +// 在 C# 中使用 +public class TrackedMemoryPool +{ + public void Allocate(int size) + { + IntPtr ptr = Marshal.AllocHGlobal(size); + Tracy.AllocNamed(ptr, size, "Memory Pool"); + } + + public void Free(IntPtr ptr) + { + Tracy.FreeNamed(ptr, "Memory Pool"); + Marshal.FreeHGlobal(ptr); + } +} +``` + +### 2. GPU 性能追踪 + +Tracy 支持 OpenGL、Vulkan、DirectX 的 GPU 追踪,但需要在渲染管线中集成。 + +### 3. 锁竞争分析 + +```cpp +// 在 Plugin 中 +#define LockableName(type, varname) TracyLockableN(type, varname, #varname) +``` + +--- + +## 总结 + +将 Tracy 集成到 Unity 中可以提供比 Unity Profiler 更详细的性能分析数据,特别是对于: + +1. **Native Code 性能** - 如果你使用了大量 Native Plugin +2. **多线程分析** - Tracy 的线程视图非常直观 +3. **跨平台分析** - 统一的工具链 +4. **帧级别分析** - 精确到微秒的时间线 + +根据你的项目需求,选择合适的集成方法。对于大多数项目,**方法一(Native Plugin)** 是最推荐的方式。 + +--- + +## 参考资源 + +- [Tracy 官方仓库](https://github.com/wolfpld/tracy) +- [Tracy 手册](https://github.com/wolfpld/tracy/releases/latest/download/tracy.pdf) +- [Unity Native Plugin 文档](https://docs.unity3d.com/Manual/NativePlugins.html) +- [IL2CPP 脚本后端](https://docs.unity3d.com/Manual/IL2CPP.html) + diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..6ed808c --- /dev/null +++ b/main.cpp @@ -0,0 +1,355 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Tracy性能分析器 +#include "tracy/Tracy.hpp" + +using namespace std; + +// 矩阵乘法 - 计算密集型操作 +vector> matrixMultiply(const vector>& A, const vector>& B) { + ZoneScoped; // Tracy追踪这个函数 + + size_t n = A.size(); + size_t m = B[0].size(); + size_t p = B.size(); + + vector> result(n, vector(m, 0.0)); + + for (size_t i = 0; i < n; i++) { + 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]; + } + } + } + + return result; +} + +// 生成随机矩阵 +vector> generateRandomMatrix(size_t rows, size_t cols) { + ZoneScoped; + + random_device rd; + mt19937 gen(rd()); + uniform_real_distribution<> dis(0.0, 100.0); + + vector> matrix(rows, vector(cols)); + for (size_t i = 0; i < rows; i++) { + for (size_t j = 0; j < cols; j++) { + matrix[i][j] = dis(gen); + } + } + + return matrix; +} + +// 快速排序 +void quickSort(vector& arr, int low, int high) { + ZoneScoped; + + if (low < high) { + int pivot = arr[high]; + int i = low - 1; + + for (int j = low; j < high; j++) { + if (arr[j] < pivot) { + i++; + swap(arr[i], arr[j]); + } + } + swap(arr[i + 1], arr[high]); + int pi = i + 1; + + quickSort(arr, low, pi - 1); + quickSort(arr, pi + 1, high); + } +} + +// 计算质数 - 埃拉托斯特尼筛法 +vector sieveOfEratosthenes(int n) { + ZoneScoped; + + vector isPrime(n + 1, true); + vector primes; + + isPrime[0] = isPrime[1] = false; + + for (int i = 2; i <= n; i++) { + if (isPrime[i]) { + primes.push_back(i); + for (int j = i * 2; j <= n; j += i) { + isPrime[j] = false; + } + } + } + + return primes; +} + +// 计算π值 - 蒙特卡罗方法 +double calculatePi(int iterations) { + ZoneScoped; + + random_device rd; + mt19937 gen(rd()); + uniform_real_distribution<> dis(0.0, 1.0); + + int insideCircle = 0; + + for (int i = 0; i < iterations; i++) { + double x = dis(gen); + double y = dis(gen); + + if (x * x + y * y <= 1.0) { + insideCircle++; + } + } + + return 4.0 * insideCircle / iterations; +} + +// 斐波那契数列(递归) +long long fibonacci(int n) { + ZoneScoped; + + if (n <= 1) return n; + return fibonacci(n - 1) + fibonacci(n - 2); +} + +// 斐波那契数列(动态规划) +long long fibonacciDP(int n) { + ZoneScoped; + + if (n <= 1) return n; + + vector dp(n + 1); + dp[0] = 0; + dp[1] = 1; + + for (int i = 2; i <= n; i++) { + dp[i] = dp[i - 1] + dp[i - 2]; + } + + return dp[n]; +} + +// 向量点积 +double dotProduct(const vector& a, const vector& b) { + ZoneScoped; + + double result = 0.0; + for (size_t i = 0; i < a.size(); i++) { + result += a[i] * b[i]; + } + + return result; +} + +// 复杂的数学计算 +void complexMathOperations(int iterations) { + ZoneScoped; + + double sum = 0.0; + for (int i = 1; i <= iterations; i++) { + sum += sin(i) * cos(i) + tan(i / 100.0) + sqrt(i) + log(i); + } + + cout << "复杂数学计算结果: " << sum << endl; +} + +// 内存密集型操作 +void memoryIntensiveOperation(size_t size) { + ZoneScoped; + + vector> bigArray(size, vector(size, 0)); + + // 填充数据 + for (size_t i = 0; i < size; i++) { + for (size_t j = 0; j < size; j++) { + bigArray[i][j] = i * j; + } + } + + // 计算总和 + long long sum = 0; + for (size_t i = 0; i < size; i++) { + for (size_t j = 0; j < size; j++) { + sum += bigArray[i][j]; + } + } + + cout << "内存密集型操作总和: " << sum << endl; +} + +// 多线程测试 +void threadWork(int threadId, int workload) { + ZoneScopedN("ThreadWork"); // 命名追踪区域 + + // 模拟工作负载 + long long sum = 0; + for (int i = 0; i < workload; i++) { + sum += i * threadId; + } + + cout << "线程 " << threadId << " 完成, 结果: " << sum << endl; +} + +void multiThreadTest(int numThreads, int workload) { + ZoneScoped; + + vector threads; + + for (int i = 0; i < numThreads; i++) { + threads.emplace_back(threadWork, i, workload); + } + + for (auto& t : threads) { + t.join(); + } +} + +// 主测试函数 +void runPerformanceTests() { + ZoneScoped; + + cout << "\n========== Tracy 性能测试开始 ==========" << endl; + + // 测试1: 矩阵乘法 + { + ZoneScopedN("Matrix Multiplication Test"); + cout << "\n[测试1] 矩阵乘法..." << endl; + auto A = generateRandomMatrix(200, 200); + auto B = generateRandomMatrix(200, 200); + auto C = matrixMultiply(A, B); + cout << "矩阵乘法完成 (200x200 * 200x200)" << endl; + } + + // 测试2: 快速排序 + { + ZoneScopedN("Quick Sort Test"); + cout << "\n[测试2] 快速排序..." << endl; + vector arr(100000); + random_device rd; + mt19937 gen(rd()); + uniform_int_distribution<> dis(1, 1000000); + + for (int& num : arr) { + num = dis(gen); + } + + quickSort(arr, 0, arr.size() - 1); + cout << "排序完成 (100000个元素)" << endl; + } + + // 测试3: 质数计算 + { + ZoneScopedN("Prime Numbers Test"); + cout << "\n[测试3] 质数计算..." << endl; + auto primes = sieveOfEratosthenes(1000000); + cout << "找到 " << primes.size() << " 个质数 (范围: 0-1000000)" << endl; + } + + // 测试4: 蒙特卡罗π值计算 + { + ZoneScopedN("Monte Carlo Pi Test"); + cout << "\n[测试4] 蒙特卡罗π值计算..." << endl; + double pi = calculatePi(10000000); + cout << "π ≈ " << pi << " (10000000次迭代)" << endl; + } + + // 测试5: 斐波那契(递归 vs 动态规划) + { + ZoneScopedN("Fibonacci Test"); + cout << "\n[测试5] 斐波那契数列..." << endl; + + { + ZoneScopedN("Fibonacci Recursive"); + long long result = fibonacci(35); + cout << "递归方法: fibonacci(35) = " << result << endl; + } + + { + ZoneScopedN("Fibonacci DP"); + long long result = fibonacciDP(90); + cout << "动态规划: fibonacci(90) = " << result << endl; + } + } + + // 测试6: 向量运算 + { + ZoneScopedN("Vector Operations Test"); + cout << "\n[测试6] 向量点积计算..." << endl; + + vector v1(10000000); + vector v2(10000000); + + random_device rd; + mt19937 gen(rd()); + uniform_real_distribution<> dis(0.0, 1.0); + + for (size_t i = 0; i < v1.size(); i++) { + v1[i] = dis(gen); + v2[i] = dis(gen); + } + + double result = dotProduct(v1, v2); + cout << "点积结果: " << result << " (10000000维向量)" << endl; + } + + // 测试7: 复杂数学运算 + { + ZoneScopedN("Complex Math Test"); + cout << "\n[测试7] 复杂数学运算..." << endl; + complexMathOperations(1000000); + } + + // 测试8: 内存密集型操作 + { + ZoneScopedN("Memory Intensive Test"); + cout << "\n[测试8] 内存密集型操作..." << endl; + memoryIntensiveOperation(1000); + } + + // 测试9: 多线程测试 + { + ZoneScopedN("Multi-Threading Test"); + cout << "\n[测试9] 多线程测试..." << endl; + multiThreadTest(8, 50000000); + } + + cout << "\n========== 所有测试完成 ==========" << endl; +} + +int main() +{ + cout << "Tracy性能分析测试程序" << endl; + cout << "请确保Tracy Profiler已经运行并连接" << endl; + cout << "按回车键开始测试..." << endl; + cin.get(); + + // 运行多次测试以便在Tracy中观察 + for (int i = 0; i < 3; i++) { + ZoneScopedN("Main Loop Iteration"); + FrameMark; // Tracy帧标记 + + cout << "\n\n============ 第 " << (i + 1) << " 轮测试 ============" << endl; + runPerformanceTests(); + + // 短暂休息,让Tracy更容易区分不同的测试轮次 + this_thread::sleep_for(chrono::milliseconds(500)); + } + + cout << "\n程序即将退出,按回车键继续..." << endl; + cin.get(); + + return 0; +} \ No newline at end of file diff --git a/thirdparty/tracy b/thirdparty/tracy new file mode 160000 index 0000000..be23d93 --- /dev/null +++ b/thirdparty/tracy @@ -0,0 +1 @@ +Subproject commit be23d9354ad6c0ac3a4e0c210738f76b0572e635 diff --git a/tracy-0.13.0.zip b/tracy-0.13.0.zip new file mode 100644 index 0000000..d54fd4a Binary files /dev/null and b/tracy-0.13.0.zip differ diff --git a/unity_examples/CMakeLists.txt b/unity_examples/CMakeLists.txt new file mode 100644 index 0000000..f882f7a --- /dev/null +++ b/unity_examples/CMakeLists.txt @@ -0,0 +1,298 @@ +# Unity Tracy Plugin - CMakeLists.txt +# 用于编译 Tracy Unity Native Plugin + +cmake_minimum_required(VERSION 3.15) +project(UnityTracyPlugin VERSION 1.0.0) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# ============================================ +# 配置选项 +# ============================================ + +option(TRACY_ENABLE "启用 Tracy 性能分析" ON) +option(TRACY_ON_DEMAND "Tracy 按需分析模式" ON) +option(TRACY_NO_EXIT "Tracy 不在退出时断开连接" OFF) +option(TRACY_NO_BROADCAST "Tracy 不广播发现消息" OFF) +option(TRACY_ONLY_LOCALHOST "Tracy 仅允许本地连接" OFF) + +# ============================================ +# Tracy 配置 +# ============================================ + +if(TRACY_ENABLE) + add_definitions(-DTRACY_ENABLE) + message(STATUS "Tracy 性能分析: 启用") +else() + message(STATUS "Tracy 性能分析: 禁用") +endif() + +if(TRACY_ON_DEMAND) + add_definitions(-DTRACY_ON_DEMAND) + message(STATUS "Tracy 按需模式: 启用") +endif() + +if(TRACY_NO_EXIT) + add_definitions(-DTRACY_NO_EXIT) +endif() + +if(TRACY_NO_BROADCAST) + add_definitions(-DTRACY_NO_BROADCAST) +endif() + +if(TRACY_ONLY_LOCALHOST) + add_definitions(-DTRACY_ONLY_LOCALHOST) +endif() + +# ============================================ +# Tracy 路径配置 +# ============================================ + +# 设置 Tracy 根目录(根据实际情况修改) +set(TRACY_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../thirdparty/tracy" CACHE PATH "Tracy 根目录路径") + +if(NOT EXISTS "${TRACY_ROOT}") + message(FATAL_ERROR "找不到 Tracy 目录: ${TRACY_ROOT}\n请设置正确的 TRACY_ROOT 路径") +endif() + +message(STATUS "Tracy 根目录: ${TRACY_ROOT}") + +# ============================================ +# 源文件 +# ============================================ + +set(TRACY_SOURCES + "${TRACY_ROOT}/public/TracyClient.cpp" +) + +set(PLUGIN_SOURCES + "SimplifiedPlugin.cpp" + ${TRACY_SOURCES} +) + +# ============================================ +# 包含目录 +# ============================================ + +include_directories( + "${CMAKE_CURRENT_SOURCE_DIR}" + "${TRACY_ROOT}/public" +) + +# ============================================ +# 创建动态库 +# ============================================ + +add_library(UnityTracyPlugin SHARED ${PLUGIN_SOURCES}) + +# 设置输出名称 +set_target_properties(UnityTracyPlugin PROPERTIES + OUTPUT_NAME "UnityTracyPlugin" + PREFIX "" # 移除 lib 前缀(Linux/macOS) +) + +# ============================================ +# 平台特定配置 +# ============================================ + +if(WIN32) + # Windows 配置 + message(STATUS "配置 Windows 平台") + + # 链接必要的 Windows 库 + target_link_libraries(UnityTracyPlugin + ws2_32 # Winsock + dbghelp # Debug Help Library + ) + + # 输出到 Windows 平台目录 + set_target_properties(UnityTracyPlugin PROPERTIES + RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/Unity/Plugins/x86_64" + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/Unity/Plugins/x86_64" + ) + + # Windows 导出符号 + target_compile_definitions(UnityTracyPlugin PRIVATE + WIN32_LEAN_AND_MEAN + NOMINMAX + ) + +elseif(APPLE) + # macOS/iOS 配置 + message(STATUS "配置 Apple 平台") + + # 链接 Apple 框架 + target_link_libraries(UnityTracyPlugin + "-framework Foundation" + "-framework CoreFoundation" + ) + + # macOS 特定设置 + if(NOT IOS) + set_target_properties(UnityTracyPlugin PROPERTIES + MACOSX_RPATH TRUE + BUILD_WITH_INSTALL_RPATH TRUE + INSTALL_NAME_DIR "@rpath" + ) + + # 输出到 macOS 平台目录 + set_target_properties(UnityTracyPlugin PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/Unity/Plugins/macOS" + ) + else() + # iOS 配置 - 静态库 + set_target_properties(UnityTracyPlugin PROPERTIES + FRAMEWORK FALSE + ) + + # 输出到 iOS 平台目录 + set_target_properties(UnityTracyPlugin PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/Unity/Plugins/iOS" + ) + endif() + +elseif(UNIX) + # Linux/Android 配置 + message(STATUS "配置 Linux 平台") + + # 链接必要的 Linux 库 + target_link_libraries(UnityTracyPlugin + pthread # POSIX threads + dl # Dynamic linking + ) + + # 符号可见性 + set_target_properties(UnityTracyPlugin PROPERTIES + CXX_VISIBILITY_PRESET hidden + VISIBILITY_INLINES_HIDDEN YES + ) + + # 输出到 Linux 平台目录 + set_target_properties(UnityTracyPlugin PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/Unity/Plugins/Linux/x86_64" + ) + +endif() + +# ============================================ +# 编译选项 +# ============================================ + +if(MSVC) + # Visual Studio 编译器选项 + target_compile_options(UnityTracyPlugin PRIVATE + /W4 # 警告级别 4 + /WX- # 警告不视为错误 + /permissive- # 标准一致性模式 + /MP # 多处理器编译 + ) + + # Release 优化 + target_compile_options(UnityTracyPlugin PRIVATE + $<$:/O2> # 最大优化 + $<$:/Ob2> # 内联展开 + ) +else() + # GCC/Clang 编译器选项 + target_compile_options(UnityTracyPlugin PRIVATE + -Wall + -Wextra + -Wno-unused-parameter + -fPIC # 位置无关代码 + -fvisibility=hidden # 隐藏符号 + ) + + # Release 优化 + target_compile_options(UnityTracyPlugin PRIVATE + $<$:-O3> # 最大优化 + $<$:-DNDEBUG> # 禁用断言 + ) +endif() + +# ============================================ +# Android NDK 配置(如果使用 Android) +# ============================================ + +if(ANDROID) + message(STATUS "配置 Android 平台") + message(STATUS "Android ABI: ${ANDROID_ABI}") + + # 链接 Android 库 + target_link_libraries(UnityTracyPlugin + log # Android 日志 + android # Android API + ) + + # 输出到 Android 平台目录 + set_target_properties(UnityTracyPlugin PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/Unity/Plugins/Android/${ANDROID_ABI}" + ) +endif() + +# ============================================ +# 安装配置 +# ============================================ + +install(TARGETS UnityTracyPlugin + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib +) + +# ============================================ +# 构建信息 +# ============================================ + +message(STATUS "========================================") +message(STATUS "Unity Tracy Plugin 配置完成") +message(STATUS "========================================") +message(STATUS "项目版本: ${PROJECT_VERSION}") +message(STATUS "C++ 标准: ${CMAKE_CXX_STANDARD}") +message(STATUS "构建类型: ${CMAKE_BUILD_TYPE}") +message(STATUS "编译器: ${CMAKE_CXX_COMPILER_ID}") +message(STATUS "Tracy 启用: ${TRACY_ENABLE}") +message(STATUS "Tracy 按需模式: ${TRACY_ON_DEMAND}") +message(STATUS "========================================") + +# ============================================ +# 自定义构建目标 +# ============================================ + +# 清理目标 +add_custom_target(clean-all + COMMAND ${CMAKE_COMMAND} -E remove_directory "${CMAKE_BINARY_DIR}/Unity" + COMMENT "清理所有输出文件" +) + +# 复制到 Unity 项目(需要设置 UNITY_PROJECT_PATH) +if(DEFINED ENV{UNITY_PROJECT_PATH}) + set(UNITY_PROJECT_PATH $ENV{UNITY_PROJECT_PATH}) + message(STATUS "Unity 项目路径: ${UNITY_PROJECT_PATH}") + + add_custom_command(TARGET UnityTracyPlugin POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + "${CMAKE_BINARY_DIR}/Unity/Plugins" + "${UNITY_PROJECT_PATH}/Assets/Plugins" + COMMENT "复制 Plugin 到 Unity 项目" + ) +endif() + +# ============================================ +# 测试(可选) +# ============================================ + +option(BUILD_TESTS "构建测试程序" OFF) + +if(BUILD_TESTS) + enable_testing() + + add_executable(PluginTest + test/plugin_test.cpp + ) + + target_link_libraries(PluginTest UnityTracyPlugin) + + add_test(NAME PluginBasicTest COMMAND PluginTest) +endif() + diff --git a/unity_examples/QUICKSTART.md b/unity_examples/QUICKSTART.md new file mode 100644 index 0000000..739083a --- /dev/null +++ b/unity_examples/QUICKSTART.md @@ -0,0 +1,494 @@ +# Tracy Unity 集成快速开始指南 + +本指南将帮助你快速将 Tracy 性能分析器集成到 Unity 项目中。 + +--- + +## 🚀 快速开始(5 分钟集成) + +### 步骤 1: 准备 Tracy + +1. 克隆或下载 Tracy 仓库: +```bash +git clone https://github.com/wolfpld/tracy.git +``` + +2. (可选)编译 Tracy Profiler 工具: +```bash +cd tracy/profiler +# Windows: 使用 Visual Studio 打开并编译 +# macOS/Linux: +cmake -B build -DCMAKE_BUILD_TYPE=Release +cmake --build build +``` + +### 步骤 2: 编译 Unity Plugin + +#### Windows (使用 CMake + Visual Studio) + +```powershell +# 在 unity_examples 目录下 +mkdir build +cd build + +# 配置(修改 TRACY_ROOT 路径指向你的 tracy 目录) +cmake .. -G "Visual Studio 17 2022" -A x64 ^ + -DTRACY_ROOT="D:/path/to/tracy" ^ + -DTRACY_ENABLE=ON ^ + -DTRACY_ON_DEMAND=ON + +# 编译 +cmake --build . --config Release +``` + +编译完成后,DLL 文件在 `build/Unity/Plugins/x86_64/UnityTracyPlugin.dll` + +#### macOS + +```bash +# 在 unity_examples 目录下 +mkdir build && cd build + +# 配置 +cmake .. \ + -DCMAKE_BUILD_TYPE=Release \ + -DTRACY_ROOT="/path/to/tracy" \ + -DTRACY_ENABLE=ON \ + -DTRACY_ON_DEMAND=ON + +# 编译 +make -j8 +``` + +编译完成后,动态库在 `build/Unity/Plugins/macOS/UnityTracyPlugin.dylib` + +#### Linux + +```bash +# 在 unity_examples 目录下 +mkdir build && cd build + +# 配置 +cmake .. \ + -DCMAKE_BUILD_TYPE=Release \ + -DTRACY_ROOT="/path/to/tracy" \ + -DTRACY_ENABLE=ON \ + -DTRACY_ON_DEMAND=ON + +# 编译 +make -j8 +``` + +编译完成后,动态库在 `build/Unity/Plugins/Linux/x86_64/UnityTracyPlugin.so` + +### 步骤 3: 集成到 Unity 项目 + +1. **复制 Plugin 文件** + +将编译好的 Plugin 复制到 Unity 项目: + +``` +YourUnityProject/ +└── Assets/ + └── Plugins/ + ├── x86_64/ + │ └── UnityTracyPlugin.dll # Windows + ├── macOS/ + │ └── UnityTracyPlugin.dylib # macOS + └── Linux/ + └── x86_64/ + └── UnityTracyPlugin.so # Linux +``` + +2. **复制 C# 脚本** + +将以下文件复制到 Unity 项目: + +``` +YourUnityProject/ +└── Assets/ + └── Scripts/ + └── Tracy/ + ├── TracyWrapper.cs # Tracy C# API + ├── TracyManager.cs # Tracy 管理器 + └── TracyExamples.cs # 使用示例(可选) +``` + +3. **配置 Plugin 导入设置** + +在 Unity Editor 中: +- 选择 `UnityTracyPlugin.dll`(或 .dylib/.so) +- 在 Inspector 中设置平台: + - Windows: 勾选 `x86_64` + - macOS: 勾选 `macOS` + - Linux: 勾选 `Linux x86_64` + +### 步骤 4: 在场景中使用 + +1. **添加 TracyManager** + +在你的主场景中: +- 创建空 GameObject,命名为 "TracyManager" +- 添加 `TracyManager` 组件 +- 在 Inspector 中配置选项 + +2. **在代码中使用 Tracy** + +```csharp +using UnityEngine; +using TracyProfiler; + +public class MyGameScript : MonoBehaviour +{ + void Update() + { + // 方式 1: 使用 using 语句(推荐) + using (Tracy.Zone("MyGameScript.Update")) + { + DoSomething(); + } + + // 方式 2: 手动开始/结束 + Tracy.BeginZone("CustomZone"); + DoSomethingElse(); + Tracy.EndZone(); + + // 绘制数值 + Tracy.Plot("Enemy Count", enemyCount); + + // 发送消息 + if (playerDied) + { + Tracy.Message("Player died"); + } + } + + void DoSomething() + { + using (Tracy.Zone("DoSomething")) + { + // 你的代码 + } + } +} +``` + +### 步骤 5: 启动 Tracy Profiler 并连接 + +1. **启动 Tracy Profiler** + +```bash +# Windows +Tracy.exe + +# macOS/Linux +./Tracy +``` + +2. **运行 Unity 游戏** + +在 Unity Editor 中按 Play,或运行构建的可执行文件。 + +3. **连接到 Tracy** + +Tracy Profiler 会自动发现本地网络中的 Tracy 客户端,点击连接即可开始分析。 + +--- + +## 📊 使用 Tracy 分析性能 + +### 查看性能数据 + +Tracy Profiler 界面主要区域: + +1. **时间线视图** + - 显示所有 Zone 的执行时间 + - 颜色表示不同的调用栈深度 + - 可以缩放和平移 + +2. **统计视图** + - 函数调用次数 + - 总耗时、平均耗时、最小/最大耗时 + - 排序和筛选功能 + +3. **帧视图** + - 查看每帧的性能 + - 识别帧率波动 + - 帧时间分布 + +4. **Plot 视图** + - 查看 `Tracy.Plot()` 绘制的数值曲线 + - 实时监控变量变化 + +### 常用快捷键 + +- `鼠标滚轮`: 缩放时间线 +- `鼠标中键拖拽`: 平移时间线 +- `鼠标左键`: 选择 Zone 查看详情 +- `Ctrl + F`: 搜索函数 +- `Ctrl + Z`: 放大到选中的 Zone + +--- + +## 🔧 常见问题排查 + +### 问题 1: DLL 加载失败 + +**错误信息**: `DllNotFoundException: UnityTracyPlugin` + +**解决方案**: +1. 确认 DLL 文件在正确的目录 +2. 检查 Plugin Import Settings 的平台配置 +3. 确认 DLL 架构与 Unity 项目匹配(x64/x86) +4. Windows: 检查是否缺少 `vcruntime140.dll`(安装 Visual C++ Redistributable) + +### 问题 2: Tracy Profiler 无法连接 + +**症状**: Tracy Profiler 中看不到 Unity 应用 + +**解决方案**: +1. 确认防火墙允许 TCP 端口 8086 +2. 检查 `TRACY_ON_DEMAND` 宏是否正确定义 +3. 确认 `Tracy.Initialize()` 已被调用 +4. 检查 Unity Console 是否有 Tracy 初始化消息 + +```csharp +// 在 Unity Console 应该看到: +// [Tracy] 性能分析器已初始化 +``` + +### 问题 3: 性能数据不显示 + +**症状**: Tracy 已连接,但看不到任何 Zone + +**解决方案**: +1. 确认代码中使用了 `Tracy.Zone()` 或 `ZoneScoped` +2. 确认 `Tracy.MarkFrame()` 在每帧被调用 +3. 检查是否定义了 `TRACY_ENABLE` 编译符号 +4. 在 Unity Editor 中,确认 Tracy Manager 的 "Enable On Start" 已勾选 + +### 问题 4: 编译错误 + +**常见编译错误**: + +1. **找不到 Tracy.hpp** + ``` + fatal error: tracy/Tracy.hpp: No such file or directory + ``` + 解决: 检查 `TRACY_ROOT` 路径是否正确 + +2. **链接错误 (Windows)** + ``` + error LNK2019: unresolved external symbol + ``` + 解决: 确认链接了 `ws2_32.lib` 和 `dbghelp.lib` + +3. **链接错误 (Linux)** + ``` + undefined reference to `pthread_create' + ``` + 解决: 添加 `-lpthread -ldl` 链接选项 + +### 问题 5: Android/iOS 构建问题 + +**Android**: +1. 使用 Android NDK 编译 +2. 确保为所有需要的 ABI 编译(armeabi-v7a, arm64-v8a) +3. 将 `.so` 文件放在 `Assets/Plugins/Android/libs/{ABI}/` + +**iOS**: +1. 编译为静态库(.a) +2. 在 Unity Build Settings 中设置 "Target SDK" 为 "Device SDK" +3. 确保代码签名正确 + +--- + +## 🎯 最佳实践 + +### 1. Zone 命名规范 + +```csharp +// ✅ 好的命名 - 清晰、描述性 +using (Tracy.Zone("PlayerController.Move")) +using (Tracy.Zone("AI.UpdatePathfinding")) +using (Tracy.Zone("Render.DrawTerrain")) + +// ❌ 不好的命名 - 模糊、无意义 +using (Tracy.Zone("Function1")) +using (Tracy.Zone("Update")) +using (Tracy.Zone("Test")) +``` + +### 2. 适度使用 Zone + +```csharp +void Update() +{ + // ✅ 追踪主要的逻辑块 + using (Tracy.Zone("Update")) + { + using (Tracy.Zone("ProcessInput")) + { + ProcessInput(); // 追踪大块逻辑 + } + + UpdateGameLogic(); // 内部有自己的 Zone + } +} + +// ❌ 过度追踪会增加开销 +void BadExample() +{ + for (int i = 0; i < 10000; i++) + { + using (Tracy.Zone($"Iteration {i}")) // 太多 Zone! + { + DoSomething(); + } + } +} +``` + +### 3. 使用条件编译 + +```csharp +// 在生产构建中禁用细粒度追踪 +#if TRACY_ENABLE + using (Tracy.Zone("DetailedAnalysis")) + { + // 详细的性能分析代码 + } +#endif +``` + +### 4. 监控关键指标 + +```csharp +void LateUpdate() +{ + // 监控帧率 + Tracy.Plot("FPS", 1.0f / Time.deltaTime); + + // 监控内存 + Tracy.Plot("Memory (MB)", GC.GetTotalMemory(false) / 1024.0 / 1024.0); + + // 监控对象计数 + Tracy.Plot("Enemy Count", enemies.Count); + Tracy.Plot("Active Particles", particleSystem.particleCount); + + // 监控物理 + Tracy.Plot("Rigidbodies", FindObjectsOfType().Length); +} +``` + +### 5. 多线程命名 + +```csharp +using System.Threading; + +void WorkerThread() +{ + Tracy.SetThreadName("Worker Thread"); + + while (running) + { + using (Tracy.Zone("WorkerThread.Process")) + { + ProcessData(); + } + } +} +``` + +--- + +## 📚 进阶主题 + +### 自定义构建配置 + +在 Unity 项目中创建 `link.xml` 防止代码剥离: + +```xml + + + + + +``` + +### 持久化性能数据 + +Tracy 支持保存性能数据到文件: + +1. 在 Tracy Profiler 中,点击 "Save trace" +2. 选择保存位置(.tracy 文件) +3. 之后可以用 Tracy Profiler 打开查看 + +### 集成到 CI/CD + +可以在自动化测试中使用 Tracy: + +```csharp +public class PerformanceTest +{ + [Test] + public void TestPerformance() + { + Tracy.Initialize(); + + using (Tracy.Zone("PerformanceTest")) + { + // 运行性能测试 + RunGameLoop(100); // 运行 100 帧 + } + + Tracy.Shutdown(); + + // 分析结果... + } +} +``` + +--- + +## 🔗 资源链接 + +- [Tracy 官方仓库](https://github.com/wolfpld/tracy) +- [Tracy 官方手册](https://github.com/wolfpld/tracy/releases/latest/download/tracy.pdf) +- [Unity Native Plugin 文档](https://docs.unity3d.com/Manual/NativePlugins.html) +- 本项目的完整文档: `UNITY_INTEGRATION_GUIDE.md` + +--- + +## 💡 技巧和提示 + +1. **使用 Release 构建进行性能测试** + - Debug 构建会有大量额外开销 + - 在 Unity 中创建专门的 "Profiling" 构建配置 + +2. **关闭 V-Sync 测试真实性能** + - V-Sync 会限制帧率 + - 在 Project Settings > Quality 中关闭 + +3. **使用 Tracy 的统计功能** + - 查看函数调用次数 + - 识别被频繁调用的函数 + +4. **比较不同实现** + - 使用 Tracy 比较算法性能 + - A/B 测试优化效果 + +5. **定期保存 Trace 文件** + - 记录性能基准 + - 跟踪性能变化趋势 + +--- + +## 🎉 完成! + +现在你已经成功将 Tracy 集成到 Unity 项目中了! + +开始使用 Tracy 分析你的游戏性能,找出瓶颈,优化代码吧! + +如有问题,请参考完整文档 `UNITY_INTEGRATION_GUIDE.md` 或访问 Tracy 官方仓库。 + diff --git a/unity_examples/README.md b/unity_examples/README.md new file mode 100644 index 0000000..b1b0101 --- /dev/null +++ b/unity_examples/README.md @@ -0,0 +1,484 @@ +# Tracy Unity 集成示例 + +本目录包含将 Tracy 性能分析器集成到 Unity 项目的完整示例和工具。 + +## 📁 文件结构 + +``` +unity_examples/ +├── README.md # 本文件 - 项目概述 +├── QUICKSTART.md # 5分钟快速开始指南 ⭐ 从这里开始! +├── CMakeLists.txt # CMake 构建配置 +├── SimplifiedPlugin.cpp # Tracy Unity Plugin C++ 实现 +├── TracyWrapper.cs # Tracy C# API 封装 +├── TracyManager.cs # Tracy 管理器组件 +└── TracyExamples.cs # 使用示例和最佳实践 +``` + +## 🚀 快速开始 + +### 新手用户 + +如果你是第一次使用,请按以下顺序阅读: + +1. **[QUICKSTART.md](QUICKSTART.md)** - 5分钟快速集成指南 +2. **[TracyExamples.cs](TracyExamples.cs)** - 查看代码示例 +3. **[../UNITY_INTEGRATION_GUIDE.md](../UNITY_INTEGRATION_GUIDE.md)** - 完整的集成文档 + +### 有经验的用户 + +快速集成步骤: + +```bash +# 1. 编译 Plugin +mkdir build && cd build +cmake .. -DTRACY_ROOT="/path/to/tracy" -DCMAKE_BUILD_TYPE=Release +cmake --build . --config Release + +# 2. 复制文件到 Unity 项目 +cp build/Unity/Plugins/* YourUnityProject/Assets/Plugins/ +cp *.cs YourUnityProject/Assets/Scripts/Tracy/ + +# 3. 在 Unity 场景中添加 TracyManager 组件 + +# 4. 运行 Tracy Profiler 并连接 +``` + +## 📦 文件说明 + +### C++ Plugin 相关 + +#### `SimplifiedPlugin.cpp` +Tracy Unity Native Plugin 的 C++ 实现。 + +**主要功能**: +- 初始化/关闭 Tracy +- 创建性能追踪 Zone +- 绘制实时数值 +- 发送消息和日志 +- 线程命名 + +**导出函数**: +```cpp +TracyInit() // 初始化 +TracyShutdown() // 关闭 +TracyFrameMark() // 标记帧边界 +TracyZoneBegin(name) // 开始 Zone +TracyZoneEnd() // 结束 Zone +TracyPlotValue(name, v) // 绘制数值 +TracyMessage(msg) // 发送消息 +TracySetThreadName(name) // 设置线程名 +``` + +**编译要求**: +- C++17 +- Tracy 源代码 +- Windows: Visual Studio 2019+ +- macOS: Xcode 12+ +- Linux: GCC 9+ 或 Clang 10+ + +#### `CMakeLists.txt` +跨平台 CMake 构建配置。 + +**支持平台**: +- ✅ Windows (x64) +- ✅ macOS (Intel/Apple Silicon) +- ✅ Linux (x64) +- ✅ Android (armeabi-v7a, arm64-v8a) +- ✅ iOS (arm64) + +**配置选项**: +```cmake +-DTRACY_ENABLE=ON # 启用 Tracy +-DTRACY_ON_DEMAND=ON # 按需分析模式 +-DTRACY_ROOT=path # Tracy 根目录 +``` + +### C# 脚本相关 + +#### `TracyWrapper.cs` +Tracy 的 C# API 封装,提供简洁易用的接口。 + +**核心 API**: +```csharp +// 初始化 +Tracy.Initialize() + +// 性能追踪 (推荐使用 using 语句) +using (Tracy.Zone("FunctionName")) +{ + // 要追踪的代码 +} + +// 手动管理 Zone +Tracy.BeginZone("CustomZone") +// ... 代码 ... +Tracy.EndZone() + +// 绘制实时数值 +Tracy.Plot("FPS", fps) +Tracy.Plot("Memory", memoryMB) + +// 发送消息 +Tracy.Message("重要事件发生") + +// 设置线程名 +Tracy.SetThreadName("Worker Thread") + +// 标记帧边界 +Tracy.MarkFrame() +``` + +**特性**: +- 使用 `IDisposable` 自动管理 Zone 生命周期 +- 条件编译支持(`TRACY_ENABLE`) +- 零开销(禁用时) +- 线程安全 + +#### `TracyManager.cs` +Unity 组件,负责 Tracy 的初始化和自动化监控。 + +**功能**: +- 自动初始化 Tracy +- 每帧自动标记帧边界 +- 自动监控系统指标: + - 帧率 (FPS) + - 帧时间 + - 内存使用 + - 渲染统计 + - 物理对象数量 + +**使用方法**: +1. 在场景中创建空 GameObject +2. 添加 `TracyManager` 组件 +3. 配置 Inspector 中的选项 +4. 运行游戏 + +**Inspector 选项**: +- `Enable On Start`: 启动时自动初始化 +- `Mark Frames`: 每帧自动标记 +- `Monitor Frame Rate`: 监控帧率 +- `Monitor Memory`: 监控内存 +- `Monitor Rendering`: 监控渲染 +- `Monitor Physics`: 监控物理 + +#### `TracyExamples.cs` +完整的使用示例和最佳实践。 + +**包含示例**: +1. ✅ 基础 Zone 使用 +2. ✅ 计算密集型操作追踪 +3. ✅ 重度计算测试 +4. ✅ 对象池管理 +5. ✅ 协程性能追踪 +6. ✅ 自定义数据绘制 +7. ✅ 条件性能追踪 + +**交互功能**: +- 按 `Space` 键: 执行重度计算 +- 按 `R` 键: 重置对象池 +- 按 `T` 键: 运行性能测试 + +## 🎯 使用场景 + +### 1. 游戏开发性能优化 + +```csharp +public class GameController : MonoBehaviour +{ + void Update() + { + using (Tracy.Zone("GameController.Update")) + { + using (Tracy.Zone("Update AI")) + { + UpdateAI(); + } + + using (Tracy.Zone("Update Physics")) + { + UpdatePhysics(); + } + + using (Tracy.Zone("Update Rendering")) + { + UpdateRendering(); + } + } + } +} +``` + +### 2. 资源加载分析 + +```csharp +IEnumerator LoadScene() +{ + using (Tracy.Zone("Load Scene")) + { + using (Tracy.Zone("Load Assets")) + { + yield return LoadAssets(); + } + + using (Tracy.Zone("Initialize Scene")) + { + InitializeScene(); + } + + Tracy.Message("Scene loaded successfully"); + } +} +``` + +### 3. AI 系统性能追踪 + +```csharp +public class AIManager : MonoBehaviour +{ + void Update() + { + using (Tracy.Zone("AI Manager")) + { + foreach (var agent in agents) + { + using (Tracy.Zone($"AI Agent {agent.id}")) + { + agent.UpdateBehavior(); + } + } + + Tracy.Plot("Active AI Agents", agents.Count); + } + } +} +``` + +### 4. 网络同步分析 + +```csharp +void OnNetworkUpdate() +{ + using (Tracy.Zone("Network Update")) + { + using (Tracy.Zone("Receive Packets")) + { + ReceivePackets(); + } + + using (Tracy.Zone("Process Messages")) + { + ProcessMessages(); + } + + using (Tracy.Zone("Send Updates")) + { + SendUpdates(); + } + + Tracy.Plot("Network Latency (ms)", latency); + Tracy.Plot("Packet Loss (%)", packetLoss); + } +} +``` + +### 5. 渲染管线优化 + +```csharp +void OnPreRender() +{ + using (Tracy.Zone("Pre-Render")) + { + using (Tracy.Zone("Culling")) + { + PerformCulling(); + } + + using (Tracy.Zone("Sort Render Queue")) + { + SortRenderQueue(); + } + + Tracy.Plot("Visible Objects", visibleCount); + Tracy.Plot("Draw Calls", drawCalls); + } +} +``` + +## 🔧 平台特定说明 + +### Windows + +**依赖**: +- Visual Studio 2019 或更高版本 +- Windows SDK +- vcruntime140.dll (Visual C++ Redistributable) + +**编译**: +```powershell +cmake -B build -G "Visual Studio 17 2022" -A x64 +cmake --build build --config Release +``` + +**输出**: `build/Unity/Plugins/x86_64/UnityTracyPlugin.dll` + +### macOS + +**依赖**: +- Xcode Command Line Tools +- CMake 3.15+ + +**编译**: +```bash +cmake -B build -DCMAKE_BUILD_TYPE=Release +cmake --build build +``` + +**输出**: `build/Unity/Plugins/macOS/UnityTracyPlugin.dylib` + +**注意**: Apple Silicon (M1/M2) 和 Intel 需要分别编译 + +### Linux + +**依赖**: +- GCC 9+ 或 Clang 10+ +- pthread, dl + +**编译**: +```bash +cmake -B build -DCMAKE_BUILD_TYPE=Release +cmake --build build +``` + +**输出**: `build/Unity/Plugins/Linux/x86_64/UnityTracyPlugin.so` + +### Android + +**依赖**: +- Android NDK r21+ +- CMake 3.15+ + +**编译**: +```bash +# ARM64 +cmake -B build-android-arm64 \ + -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \ + -DANDROID_ABI=arm64-v8a \ + -DANDROID_PLATFORM=android-21 + +# ARMv7 +cmake -B build-android-armv7 \ + -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \ + -DANDROID_ABI=armeabi-v7a \ + -DANDROID_PLATFORM=android-21 +``` + +### iOS + +**依赖**: +- Xcode 12+ +- iOS SDK + +**编译**: +```bash +cmake -B build-ios \ + -DCMAKE_SYSTEM_NAME=iOS \ + -DCMAKE_OSX_ARCHITECTURES=arm64 \ + -DCMAKE_OSX_DEPLOYMENT_TARGET=12.0 +``` + +**注意**: iOS 需要静态库(.a)而不是动态库 + +## 📊 性能影响 + +### Tracy 开销 + +| 配置 | 每 Zone 开销 | 内存开销 | 网络带宽 | +|------|-------------|---------|---------| +| 禁用 (Release) | 0 ns | 0 MB | 0 | +| 启用 (On-Demand, 未连接) | ~20 ns | ~1 MB | 0 | +| 启用 (已连接) | ~50 ns | ~10 MB | ~1 Mbps | + +### 建议 + +- ✅ 在 Debug/Development 构建中启用 +- ✅ 追踪主要逻辑块(毫秒级) +- ⚠️ 避免追踪微小操作(微秒级) +- ⚠️ 避免在紧密循环中创建 Zone +- ❌ 不建议在 Release 构建中启用细粒度追踪 + +## 🐛 故障排除 + +### 常见问题 + +详细的故障排除指南请参考 [QUICKSTART.md](QUICKSTART.md#常见问题排查) + +**快速检查清单**: + +- [ ] DLL 文件在正确的 Plugins 目录 +- [ ] Plugin Import Settings 配置正确 +- [ ] Tracy Profiler 正在运行 +- [ ] 防火墙允许端口 8086 +- [ ] `Tracy.Initialize()` 已被调用 +- [ ] Unity Console 显示初始化消息 +- [ ] 代码中使用了 `Tracy.Zone()` 或 `ZoneScoped` +- [ ] `TracyManager` 组件已添加到场景 + +### 获取帮助 + +如果遇到问题: + +1. 查看 [QUICKSTART.md](QUICKSTART.md) 的故障排除章节 +2. 查看 [完整集成指南](../UNITY_INTEGRATION_GUIDE.md) +3. 查看 [Tracy 官方文档](https://github.com/wolfpld/tracy) +4. 检查 Unity Console 的错误消息 + +## 📚 相关资源 + +### 文档 + +- [快速开始指南](QUICKSTART.md) - 5分钟集成 +- [完整集成指南](../UNITY_INTEGRATION_GUIDE.md) - 详细文档 +- [Tracy 官方手册](https://github.com/wolfpld/tracy/releases/latest/download/tracy.pdf) - PDF + +### 链接 + +- [Tracy GitHub](https://github.com/wolfpld/tracy) - 官方仓库 +- [Tracy 演示视频](https://www.youtube.com/watch?v=fB5B46lbapc) - YouTube +- [Unity Native Plugins](https://docs.unity3d.com/Manual/NativePlugins.html) - 官方文档 + +### 示例项目 + +本目录中的示例展示了: +- 基本的 Zone 使用 +- 性能数据绘制 +- 协程追踪 +- 多线程支持 +- 最佳实践 + +## 🤝 贡献 + +欢迎改进和建议! + +如果你有更好的实现方式或发现了问题,请: +1. 修改代码 +2. 测试你的更改 +3. 分享你的改进 + +## 📄 许可证 + +- Tracy: BSD 3-Clause License +- 本示例代码: MIT License + +## 🎉 开始使用 + +现在你已经了解了整体结构,可以开始集成了! + +**下一步**: 打开 [QUICKSTART.md](QUICKSTART.md) 开始 5 分钟快速集成! + +--- + +**祝你使用愉快!** 🚀 + +如有任何问题,欢迎查阅文档或在社区寻求帮助。 + diff --git a/unity_examples/SimplifiedPlugin.cpp b/unity_examples/SimplifiedPlugin.cpp new file mode 100644 index 0000000..107dfee --- /dev/null +++ b/unity_examples/SimplifiedPlugin.cpp @@ -0,0 +1,287 @@ +/* + * Tracy Unity Plugin - 简化版实现 + * + * 这是一个简化的 Tracy Unity Plugin 实现 + * 用于演示如何将 Tracy 集成到 Unity Native Plugin 中 + * + * 编译说明: + * Windows: cl /LD /MD SimplifiedPlugin.cpp /I"path/to/tracy/public" ws2_32.lib dbghelp.lib + * macOS: clang++ -shared -fPIC SimplifiedPlugin.cpp -I"path/to/tracy/public" -o libUnityTracyPlugin.dylib + * Linux: g++ -shared -fPIC SimplifiedPlugin.cpp -I"path/to/tracy/public" -o libUnityTracyPlugin.so -lpthread -ldl + */ + +// 定义 Tracy 启用标志 +#define TRACY_ENABLE +#define TRACY_ON_DEMAND + +#include "tracy/Tracy.hpp" +#include +#include + +// 平台特定的导出定义 +#if defined(_WIN32) || defined(_WIN64) + #define UNITY_PLUGIN_EXPORT __declspec(dllexport) +#elif defined(__APPLE__) || defined(__linux__) + #define UNITY_PLUGIN_EXPORT __attribute__((visibility("default"))) +#else + #define UNITY_PLUGIN_EXPORT +#endif + +// C 导出函数(Unity 需要 C 链接) +extern "C" { + +/** + * 初始化 Tracy + * Unity C# 调用: [DllImport] private static extern void TracyInit(); + */ +UNITY_PLUGIN_EXPORT void TracyInit() +{ + // Tracy 会自动初始化,这里可以添加额外的初始化逻辑 + // 例如:设置采样率、配置选项等 +} + +/** + * 关闭 Tracy + * Unity C# 调用: [DllImport] private static extern void TracyShutdown(); + */ +UNITY_PLUGIN_EXPORT void TracyShutdown() +{ + // Tracy 会在程序退出时自动清理 + // 这里可以添加自定义的清理逻辑 +} + +/** + * 标记帧边界 + * Unity C# 调用: [DllImport] private static extern void TracyFrameMark(); + */ +UNITY_PLUGIN_EXPORT void TracyFrameMark() +{ + FrameMark; +} + +/** + * 绘制数值 + * Unity C# 调用: [DllImport] private static extern void TracyPlotValue(string name, double value); + */ +UNITY_PLUGIN_EXPORT void TracyPlotValue(const char* name, double value) +{ + if (name != nullptr) + { + TracyPlot(name, value); + } +} + +/** + * 发送消息 + * Unity C# 调用: [DllImport] private static extern void TracyMessage(string message); + */ +UNITY_PLUGIN_EXPORT void TracyMessage(const char* message) +{ + if (message != nullptr) + { + TracyMessage(message, std::strlen(message)); + } +} + +/** + * 设置线程名称 + * Unity C# 调用: [DllImport] private static extern void TracySetThreadName(string name); + */ +UNITY_PLUGIN_EXPORT void TracySetThreadName(const char* name) +{ + if (name != nullptr) + { + tracy::SetThreadName(name); + } +} + +/** + * 开始一个命名的 Zone + * Unity C# 调用: [DllImport] private static extern void TracyZoneBegin(string name); + * + * 注意: 这是简化版实现,实际使用中需要更复杂的 Zone 管理 + */ +UNITY_PLUGIN_EXPORT void TracyZoneBegin(const char* name) +{ + if (name != nullptr) + { + // 简化版: 使用动态分配的 Zone + // 实际应用中需要管理 Zone 的生命周期 + + // 方案1: 使用全局 Zone 栈(简单但不支持多线程) + // 方案2: 使用线程局部存储(复杂但支持多线程) + // 方案3: 返回 Zone ID 给 C#,让 C# 管理(推荐) + + // 这里使用宏创建一个 Zone + // 注意:这只是示例,实际使用需要更好的管理方式 + ZoneName(name, std::strlen(name)); + } +} + +/** + * 结束当前 Zone + * Unity C# 调用: [DllImport] private static extern void TracyZoneEnd(); + */ +UNITY_PLUGIN_EXPORT void TracyZoneEnd() +{ + // 简化版: 与 ZoneBegin 配对使用 + // 实际应用中需要管理 Zone 的结束 +} + +/** + * Unity 插件生命周期函数 - 加载时调用 + */ +UNITY_PLUGIN_EXPORT void UnityPluginLoad() +{ + // 可选:在插件加载时执行初始化 +} + +/** + * Unity 插件生命周期函数 - 卸载时调用 + */ +UNITY_PLUGIN_EXPORT void UnityPluginUnload() +{ + // 可选:在插件卸载时执行清理 +} + +} // extern "C" + +/* + * 高级实现示例 - Zone 管理 + * + * 下面是一个更完善的 Zone 管理实现示例 + * 可以根据需要扩展 + */ + +#ifdef ADVANCED_ZONE_MANAGEMENT + +#include +#include +#include + +// Zone 管理器(线程安全) +class ZoneManager +{ +private: + struct ThreadZones + { + 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; + + // 创建源位置信息 + static const tracy::SourceLocationData loc{name, function, file, line, 0}; + + // 创建 Zone(注意:需要在堆上分配) + 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()) + { + auto* zone = it->second.zones.top(); + it->second.zones.pop(); + delete zone; + } + } + + void ClearThread() + { + std::lock_guard lock(mutex); + + auto threadId = std::this_thread::get_id(); + auto it = threadZones.find(threadId); + + if (it != threadZones.end()) + { + // 清理所有未结束的 Zone + while (!it->second.zones.empty()) + { + delete it->second.zones.top(); + it->second.zones.pop(); + } + threadZones.erase(it); + } + } +}; + +// 全局 Zone 管理器实例 +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 + +/* + * 编译和部署说明: + * + * 1. Windows (Visual Studio): + * - 创建 DLL 项目 + * - 添加 Tracy 源文件: tracy/public/TracyClient.cpp + * - 包含目录: tracy/public + * - 链接库: ws2_32.lib dbghelp.lib + * - 输出: UnityTracyPlugin.dll + * + * 2. macOS: + * clang++ -std=c++17 -shared -fPIC \ + * SimplifiedPlugin.cpp \ + * tracy/public/TracyClient.cpp \ + * -I tracy/public \ + * -DTRACY_ENABLE -DTRACY_ON_DEMAND \ + * -o libUnityTracyPlugin.dylib + * + * 3. Linux: + * g++ -std=c++17 -shared -fPIC \ + * SimplifiedPlugin.cpp \ + * tracy/public/TracyClient.cpp \ + * -I tracy/public \ + * -DTRACY_ENABLE -DTRACY_ON_DEMAND \ + * -lpthread -ldl \ + * -o libUnityTracyPlugin.so + * + * 4. Android (NDK): + * 在 Android.mk 或 CMakeLists.txt 中配置 + * + * 5. iOS: + * 使用 Xcode 编译为静态库 (.a) + * + * 部署到 Unity: + * - 将编译好的库文件复制到 Unity 项目的 Assets/Plugins/ 目录 + * - 根据平台放置在相应的子目录中 + * - 配置 Plugin Import Settings 以匹配目标平台 + */ + diff --git a/unity_examples/TracyExamples.cs b/unity_examples/TracyExamples.cs new file mode 100644 index 0000000..02d965f --- /dev/null +++ b/unity_examples/TracyExamples.cs @@ -0,0 +1,396 @@ +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/TracyManager.cs b/unity_examples/TracyManager.cs new file mode 100644 index 0000000..19a5b3d --- /dev/null +++ b/unity_examples/TracyManager.cs @@ -0,0 +1,269 @@ +using UnityEngine; +using UnityEngine.Profiling; + +namespace TracyProfiler +{ + /// + /// Tracy 管理器 - 负责初始化和每帧更新 + /// 在场景中添加此组件以启用 Tracy 性能分析 + /// + [DefaultExecutionOrder(-9999)] // 确保最早执行 + public class TracyManager : MonoBehaviour + { + [Header("Tracy 设置")] + [Tooltip("启动时自动初始化 Tracy")] + [SerializeField] private bool enableOnStart = true; + + [Tooltip("每帧自动标记帧边界")] + [SerializeField] private bool markFrames = true; + + [Header("性能监控")] + [Tooltip("监控帧率和帧时间")] + [SerializeField] private bool monitorFrameRate = true; + + [Tooltip("监控内存使用")] + [SerializeField] private bool monitorMemory = true; + + [Tooltip("监控渲染统计")] + [SerializeField] private bool monitorRendering = true; + + [Tooltip("监控物理系统")] + [SerializeField] private bool monitorPhysics = true; + + [Header("高级选项")] + [Tooltip("在编辑器中也启用 Tracy")] + [SerializeField] private bool enableInEditor = true; + + [Tooltip("显示调试信息")] + [SerializeField] private bool showDebugInfo = false; + + private static TracyManager instance; + + public static TracyManager Instance => instance; + + private void Awake() + { + // 单例模式 + if (instance != null && instance != this) + { + Debug.LogWarning("[Tracy] 检测到多个 TracyManager 实例,销毁多余的实例"); + Destroy(gameObject); + return; + } + + instance = this; + DontDestroyOnLoad(gameObject); + + // 编辑器检查 + if (!Application.isPlaying) + return; + +#if UNITY_EDITOR + if (!enableInEditor) + { + Debug.Log("[Tracy] 编辑器模式下已禁用"); + return; + } +#endif + + // 初始化 Tracy + if (enableOnStart) + { + Tracy.Initialize(); + + if (Tracy.IsInitialized) + { + Tracy.Message("Unity Application Started"); + Tracy.SetThreadName("Main Thread"); + + if (showDebugInfo) + { + LogSystemInfo(); + } + } + } + } + + private void Update() + { + using (Tracy.Zone("TracyManager.Update")) + { + // 监控帧率 + if (monitorFrameRate) + { + MonitorFrameRate(); + } + + // 监控内存 + if (monitorMemory) + { + MonitorMemory(); + } + } + } + + private void LateUpdate() + { + using (Tracy.Zone("TracyManager.LateUpdate")) + { + // 在每帧末尾标记帧边界 + if (markFrames) + { + Tracy.MarkFrame(); + } + + // 监控渲染统计 + if (monitorRendering) + { + MonitorRendering(); + } + } + } + + private void FixedUpdate() + { + using (Tracy.Zone("TracyManager.FixedUpdate")) + { + // 监控物理系统 + if (monitorPhysics) + { + MonitorPhysics(); + } + } + } + + private void OnDestroy() + { + if (instance == this) + { + Tracy.Message("Unity Application Shutting Down"); + Tracy.Shutdown(); + instance = null; + } + } + + private void OnApplicationQuit() + { + Tracy.Message("Unity Application Quit"); + Tracy.Shutdown(); + } + + private void OnApplicationPause(bool pauseStatus) + { + if (pauseStatus) + { + Tracy.Message("Application Paused"); + } + else + { + Tracy.Message("Application Resumed"); + } + } + + #region Performance Monitoring + + private void MonitorFrameRate() + { + float fps = 1.0f / Time.unscaledDeltaTime; + float frameTime = Time.unscaledDeltaTime * 1000.0f; + + Tracy.Plot("FPS", fps); + Tracy.Plot("Frame Time (ms)", frameTime); + Tracy.Plot("Time Scale", Time.timeScale); + } + + private void MonitorMemory() + { + // GC 内存 + long totalMemory = System.GC.GetTotalMemory(false); + Tracy.Plot("GC Memory (MB)", totalMemory / (1024.0 * 1024.0)); + + // Unity Profiler 内存统计 + long usedHeap = Profiler.usedHeapSizeLong; + long totalAllocated = Profiler.GetTotalAllocatedMemoryLong(); + long totalReserved = Profiler.GetTotalReservedMemoryLong(); + + Tracy.Plot("Used Heap (MB)", usedHeap / (1024.0 * 1024.0)); + Tracy.Plot("Total Allocated (MB)", totalAllocated / (1024.0 * 1024.0)); + Tracy.Plot("Total Reserved (MB)", totalReserved / (1024.0 * 1024.0)); + + // 纹理内存 + Tracy.Plot("Texture Memory (MB)", Profiler.GetAllocatedMemoryForGraphicsDriver() / (1024.0 * 1024.0)); + } + + private void MonitorRendering() + { + // 渲染统计 + Tracy.Plot("SetPass Calls", Profiler.GetRuntimeMemorySizeLong(null)); + Tracy.Plot("Draw Calls", UnityEngine.Rendering.FrameTimingManager.GetLatestTimings(1, null)); + Tracy.Plot("Triangles", 0); // 需要通过 Stats 获取 + Tracy.Plot("Vertices", 0); // 需要通过 Stats 获取 + } + + private void MonitorPhysics() + { + // 物理对象计数 + int rigidbodyCount = FindObjectsOfType().Length; + int colliderCount = FindObjectsOfType().Length; + + Tracy.Plot("Rigidbody Count", rigidbodyCount); + Tracy.Plot("Collider Count", colliderCount); + } + + private void LogSystemInfo() + { + Tracy.Message($"Device: {SystemInfo.deviceModel}"); + Tracy.Message($"OS: {SystemInfo.operatingSystem}"); + Tracy.Message($"CPU: {SystemInfo.processorType} ({SystemInfo.processorCount} cores)"); + Tracy.Message($"Memory: {SystemInfo.systemMemorySize} MB"); + Tracy.Message($"GPU: {SystemInfo.graphicsDeviceName}"); + Tracy.Message($"Graphics API: {SystemInfo.graphicsDeviceType}"); + Tracy.Message($"Unity Version: {Application.unityVersion}"); + } + + #endregion + + #region Public API + + /// + /// 手动触发帧标记(如果禁用了自动标记) + /// + public void ManualFrameMark() + { + Tracy.MarkFrame(); + } + + /// + /// 发送自定义消息 + /// + public void SendMessage(string message) + { + Tracy.Message(message); + } + + /// + /// 绘制自定义数值 + /// + public void PlotValue(string name, double value) + { + Tracy.Plot(name, value); + } + + #endregion + +#if UNITY_EDITOR + private void OnValidate() + { + // 在编辑器中修改参数时的验证 + if (!Application.isPlaying) + return; + + if (enableOnStart && !Tracy.IsInitialized) + { + Tracy.Initialize(); + } + } +#endif + } +} + diff --git a/unity_examples/TracyWrapper.cs b/unity_examples/TracyWrapper.cs new file mode 100644 index 0000000..cc88ee2 --- /dev/null +++ b/unity_examples/TracyWrapper.cs @@ -0,0 +1,257 @@ +using System; +using System.Runtime.InteropServices; +using UnityEngine; + +namespace TracyProfiler +{ + /// + /// Tracy 性能分析器的 Unity 封装 + /// 提供简单易用的 C# API 来使用 Tracy 性能分析功能 + /// + public static class Tracy + { +#if UNITY_IOS && !UNITY_EDITOR + private const string DLL_NAME = "__Internal"; +#else + private const string DLL_NAME = "UnityTracyPlugin"; +#endif + + #region Native Methods + + [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] + private static extern void TracyInit(); + + [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] + private static extern void TracyShutdown(); + + [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] + private static extern void TracyFrameMark(); + + [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] + private static extern void TracyPlotValue(string name, double value); + + [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] + private static extern void TracyMessage(string message); + + [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] + private static extern void TracySetThreadName(string name); + + [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] + private static extern void TracyZoneBegin(string name); + + [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] + private static extern void TracyZoneEnd(); + + #endregion + + private static bool s_initialized = false; + private static bool s_enabled = true; + + /// + /// Tracy 是否已启用 + /// + public static bool Enabled + { + get => s_enabled; + set => s_enabled = value; + } + + /// + /// Tracy 是否已初始化 + /// + public static bool IsInitialized => s_initialized; + + /// + /// 初始化 Tracy + /// + public static void Initialize() + { + if (s_initialized) return; + + try + { +#if TRACY_ENABLE || UNITY_EDITOR + TracyInit(); + s_initialized = true; + Debug.Log("[Tracy] 性能分析器已初始化"); +#else + Debug.Log("[Tracy] 性能分析器已禁用(编译时未定义 TRACY_ENABLE)"); +#endif + } + catch (DllNotFoundException e) + { + Debug.LogWarning($"[Tracy] 未找到 Tracy Plugin DLL: {e.Message}"); + s_enabled = false; + } + catch (Exception e) + { + Debug.LogError($"[Tracy] 初始化失败: {e.Message}"); + s_enabled = false; + } + } + + /// + /// 关闭 Tracy + /// + public static void Shutdown() + { + if (!s_initialized) return; + + try + { + TracyShutdown(); + s_initialized = false; + Debug.Log("[Tracy] 性能分析器已关闭"); + } + catch (Exception e) + { + Debug.LogError($"[Tracy] 关闭失败: {e.Message}"); + } + } + + /// + /// 标记帧边界(通常在每帧末尾调用) + /// + [System.Diagnostics.Conditional("TRACY_ENABLE")] + public static void MarkFrame() + { + if (!s_initialized || !s_enabled) return; + TracyFrameMark(); + } + + /// + /// 绘制数值(用于实时监控变量) + /// + [System.Diagnostics.Conditional("TRACY_ENABLE")] + public static void Plot(string name, double value) + { + if (!s_initialized || !s_enabled) return; + TracyPlotValue(name, value); + } + + /// + /// 绘制整数值 + /// + [System.Diagnostics.Conditional("TRACY_ENABLE")] + public static void Plot(string name, int value) + { + Plot(name, (double)value); + } + + /// + /// 绘制浮点数值 + /// + [System.Diagnostics.Conditional("TRACY_ENABLE")] + public static void Plot(string name, float value) + { + Plot(name, (double)value); + } + + /// + /// 发送消息到 Tracy + /// + [System.Diagnostics.Conditional("TRACY_ENABLE")] + public static void Message(string message) + { + if (!s_initialized || !s_enabled) return; + TracyMessage(message); + } + + /// + /// 设置当前线程名称 + /// + [System.Diagnostics.Conditional("TRACY_ENABLE")] + public static void SetThreadName(string name) + { + if (!s_initialized || !s_enabled) return; + TracySetThreadName(name); + } + + /// + /// Tracy Zone 的作用域包装器 + /// 使用 using 语句自动管理生命周期 + /// + public struct ZoneScope : IDisposable + { + private bool isValid; + private string zoneName; + + public ZoneScope(string name) + { + zoneName = name; + isValid = s_initialized && s_enabled; + +#if TRACY_ENABLE + if (isValid) + { + TracyZoneBegin(name); + } +#endif + } + + public void Dispose() + { +#if TRACY_ENABLE + if (isValid && s_initialized && s_enabled) + { + TracyZoneEnd(); + } +#endif + } + } + + /// + /// 创建一个 Tracy Zone(性能追踪区域) + /// 使用 using 语句确保自动结束 + /// + /// + /// using (Tracy.Zone("MyFunction")) + /// { + /// // 要追踪的代码 + /// } + /// + public static ZoneScope Zone(string name) + { + 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(); + } + } + + /// + /// Tracy Zone 的属性标记版本 + /// 可以标记在方法上,自动追踪整个方法 + /// 注意:需要配合 AOP 或代码生成工具使用 + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public class TracyZoneAttribute : Attribute + { + public string Name { get; set; } + + public TracyZoneAttribute(string name = null) + { + Name = name; + } + } +} +