Init
This commit is contained in:
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
13
.gitignore
vendored
Normal file
13
.gitignore
vendored
Normal file
@@ -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
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "thirdparty/tracy"]
|
||||
path = thirdparty/tracy
|
||||
url = https://github.com/wolfpld/tracy.git
|
||||
11
CMakeLists.txt
Normal file
11
CMakeLists.txt
Normal file
@@ -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)
|
||||
27
CMakeSettings.json
Normal file
27
CMakeSettings.json
Normal file
@@ -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": []
|
||||
}
|
||||
]
|
||||
}
|
||||
112
README_TEST.md
Normal file
112
README_TEST.md
Normal file
@@ -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 的统计功能分析函数调用次数和平均执行时间
|
||||
|
||||
|
||||
143
Tracy_Macro_CheatSheet.pdf
Normal file
143
Tracy_Macro_CheatSheet.pdf
Normal file
@@ -0,0 +1,143 @@
|
||||
%PDF-1.4
|
||||
%<25><><EFBFBD><EFBFBD> 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^<P;(m7/iub@iiCC[6sV]A5eiB=8I^_EF0p"'q"mBW42-:gH\e*N)c>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_9<e<QEA6='Im3'9;SXdit8G;YDk(^kE,$44?,2SgIlJp6S9jMQc7oa$4_M4$]`Zd5,Y/0"@SFJ_\](9&^Jf6q,WRb>bU?KTk,S?,a&=/?TKkV^0HeI,nMdZRc&hf<F&r#V-F+5X;#o%DGpB6%P;p)jlUD'C9a\"HCqZ<3#/@oB&Y[6tAh\BCC5fQ):7-e%06!,e)sathZ2:fOu!19S*IB9Wc1Rl]deY:i7)["Y)dY?NYAhlQYO`/>hUCoa>*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;0Z<i,C@r;=45IFDI*Fe6!n5j.$CpXkdVnD%'e9IE^q8n"m!NN=etlI</<.ocX/;B.Pl<W$U2)RWJEE(5_[<f2%D89*-O8V<m0NAPCcU'"HC5QqB<g&TM&%\YJ&,9pX1-hZ6\l0E%>7E42\B$-t,s(FjO!JKZd4#@0V@3:HWO_S?W]"YiaeN7k8lu;I\YROK1md<Ohp):5%ht+G!*/`P5@TYR)h6+*5XEDMO+=(%%DZEmJn@H<n41U&8<[95_j]f'kWH'KfX;M5?%au##4N$kmrK\a9$^@TsJ,eX-Ti-kD4,\\<9Mm)QPLPu,&:?U\07&:_@7mM%JD=U8T&alp@?+i:Zk]XkbZC8/NYQf>,qi#p/M1jYlqs\'c*`RC(f&LY`-p&3Y0u%3&<f%([_-E4Q\EO]4MtK)Wj'DcQ\@t=M^$@XWk2&*==ZG"]'s*;[Za^BH0KUtF5.E6rhQ^0LuYK`lU.UC^91@^s&$+[<N-e%h=:N.'m]jjZIqi@L"MZj]P1$K+K`Je,;`M_eqf!Lo+bW_WC&DkXPa%ife,]k`hRJ,C$U^r3_dF.g%:fkoL6gG$I8O33CbId1TL,dl%2]RaIO&pCo$GiF_@W8f1^tF^+VTHIJe5f=j%`&DXp!52(il1\H]59"1n'ocN~>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<jqf`M!n0(Hi9sP3`-q,;7X3keaM^2+e<!EL+OnHH?ji6OX5P\73"e*]%'.RPaclbFASL^Pqi0Q,`eAs/=FM!j)0#G2T+*GC.>_: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]>L5<q^BdKHe+.?3)6ijX!+:A7[b>j`Pc0U&KL@SciTB<miYuH.#\:jO-O6$\T/D>l\8ZG["AQuQ:a041>+P[P']ndJ62U:sQ4D&ZBFI"+T/<s/1Bd8k+k#m*\Iu!]t;K9!q-BUWZc*C6?Wop:UCZl<,IMiaTb!XP38eM9h[bgs@,2@gk^17RllYr$)]s1FMU/*<BQgWh=3%U-9L6LJK2:1#qdbF8?G;bt52BI$lHF/3p[hJk.b+/ZN/_GM?KE"<Wp1W*V.f%fV/\5hbpa/a41%#4CWu,oMl+g``@%;B@H?*?1M+[J>@Jr3>P4>]jVD:nIqJ>2I*:$V,C>o((b<qQJLYdkKNtVPJ^(Kk%W?ir\',h0tKRBb\1?q'dG-`@T*7M&35f\&d(4#Qak>6%&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_m<ZKHV5>eu+ZP)$82$0OsYBr,oS]fbd.fN0gQ(14p(.)U>QnVI,$&XdiW<CsJ?^#eCQ"d\2e.B<LQ%O"Q[?G3JmNbe=*@th2f:fR]CGfS<4DV0RXAD8bq#OXd?7J[pk*TW5[)IZZ%U=pdOt-cTKhOn6n0R]A]!8;^pSl0dALJJ#Wd5VsUZ`R;(-RWU"0)$d8c~>endstream
|
||||
endobj
|
||||
15 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1262
|
||||
>>
|
||||
stream
|
||||
Gb"/&9lJcG&A@sB%!kg/PU<BuUZ7>d(@H&R]8%sH'T>DkDIlD)R'c+]h]X<!MCVnO';Rmu0c\<1Gr&5Ahil-3ieNs%o/4>:'`'$YN5K`<bTRHia)F60Q1<4S.1+-NZ$jsg)%\0k/G+J&N_@7iZDC$pZ?SVT'&lpR_K66QI0.mD0R]o.I-jp*g]Q/>K_qp-9[![A)GiKu69Y8<GH+P[FLhC,,>lA%Yj.;9#J[Cn[+e<]i2t4EZ'9Nnbp@hIN#8B:FIWp3>N8-Ra/:Pq$3Ca55XNb$0@]>t`8Q,j%Y\!>JP<r?AWMKco`GGBO(H&OMgRW.Q!^T<>pN!.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)<ZRqIqgrr5)b9o)jQLn&g`sYWU:U8<d#F_eQVZ>[^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^q<NVJO*o:JM@MRkMCUYja+(8:]Q?(=s.Smn@;>D4al\R3lY5:L!-1dOiWiT21-1"7$8Z'2Ab^e&bThl*2l9]Vl(hHS`15C+=J<IqS+^Lm.On7=$RbL9Sd>ck557n9[KI<tA2hAkQ.R&?8e=5O0:[4F6]$qfJlOqtqCRa^V2%Q9Wet^bQNcMb!3W3=/%:V65G95cHEG!1!h*oS,7J6n\L7jIA65OkZ+mVI).II\EXNWU3,"ui!cm7eT_=6?CUXs/A=-GNOT?#qPP!rMMaR"iQZAar^1p6^?:s(?E.qRj+Vj&jk]g(ZLm$NbBMR\S=)5kMH]%VbonYlAGP5\I:q)sbSW3[6(7=+hSM.O;+<2a8$V4$47/g'WAYO@.+`ns>FVVlJBZI:]q-/,"#R3)^jlPt&6`*TsELu_gcXL\2a_'DPGP5iW\d9DW9M0582g>i[_qM+KfU\ON]YJDoLp"lIo(&pj:4@H`2#!m^-lBe%oml<FYU-tk:iklrRQ)%,`D"Pq-SCP,&j-uce>2^O]Q<LMHSa!I=^YIu$%C;(2g+tn:hP]Ye@'.BPU9LT>*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=<VuO&FrW1X%7OJuM046-n&`7,#6kl,9RVtg!*:=KF;Q\Ai=qY%!lA/TLCG9u<L=CpLPb+R_IYuc:RUYOZ%Yo#&$hTk0R^H$"n?T!faod0.F'&`L@AFhn>fD4E<g<L&an?_1;OF[!")%:R4<R2iQ+\)O``g%q*:m2IkK<kD6)Akl-31m1JhX"_KcneP8lbPYY*Ah>U6B"@!7<t%6I$.nV-Hu\<asnGf$:8f(V93UHj4PCr_n2T-DSBi!9Zs\:?,bl$7pV%Wso8]2+tN]J:S$-fl<1EuR[`hf?7Zl)_oKdkP\e*IGgENfD.5EZir%^)Au>N2i36br)F\K&^n$3/]=+s1,c^`^SS.?F5Y5S#Q<L1\tfN\[Mbf$46q=M1EWYnG2\9))6Y@Tdi[9QBK5;WM-+%SB+62")*,O_XBJ-nNN&Pkmhr-SSkS`:cs%'oF__Zj7,oia]?l$&SEe(?TbWhM/W1hg`VWCQ!;Or\?;:hi+msa)r@Sf[T%=e`<(cD7WjN)7?!IOEt=$BWf5o2MW&D$A%3psgag53WPNd?H9jCrB;=VF/^"k)+W2@us/ptJL&R[lEBM]\p6nFUdr5>Y75W2K9:^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$sLQ<d7pZcIG5gmGRrU[2pS.F%eD*>TEi/79,mN7ehCooh-nqFL.=tO.[8,jk!_&N+e$Z]GZOifQ$KEfSaKL):fBt6lZl6h-a_A#p#TbM'us"[HD<d@+-,d$^$G[r1#K.jB^OTu-qWAL8LLRJJ$<g))PspceM6[PjI#@P,,IZj.,U\[72a$4'g)&_EOtsI[1Bc3GC7=,U%&q.;.6@~>endstream
|
||||
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
|
||||
802
UNITY_INTEGRATION_GUIDE.md
Normal file
802
UNITY_INTEGRATION_GUIDE.md
Normal file
@@ -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 <string>
|
||||
#include <unordered_map>
|
||||
#include <mutex>
|
||||
|
||||
// 用于管理 Zone 的结构
|
||||
struct ZoneContext {
|
||||
tracy::ScopedZone* zone;
|
||||
};
|
||||
|
||||
static std::unordered_map<int, ZoneContext> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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
|
||||
{
|
||||
/// <summary>
|
||||
/// Tracy 性能分析器的 Unity 封装
|
||||
/// </summary>
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化 Tracy
|
||||
/// </summary>
|
||||
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}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭 Tracy
|
||||
/// </summary>
|
||||
public static void Shutdown()
|
||||
{
|
||||
if (!s_initialized) return;
|
||||
|
||||
try
|
||||
{
|
||||
TracyShutdown();
|
||||
s_initialized = false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"Tracy 关闭失败: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标记帧边界(通常在每帧末尾调用)
|
||||
/// </summary>
|
||||
public static void MarkFrame()
|
||||
{
|
||||
if (!s_initialized) return;
|
||||
TracyFrameMark();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绘制数值(用于实时监控变量)
|
||||
/// </summary>
|
||||
public static void Plot(string name, double value)
|
||||
{
|
||||
if (!s_initialized) return;
|
||||
TracyPlotValue(name, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送消息到 Tracy
|
||||
/// </summary>
|
||||
public static void Message(string message)
|
||||
{
|
||||
if (!s_initialized) return;
|
||||
TracyMessage(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置当前线程名称
|
||||
/// </summary>
|
||||
public static void SetThreadName(string name)
|
||||
{
|
||||
if (!s_initialized) return;
|
||||
TracySetThreadName(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tracy Zone 的作用域包装器(使用 using 语句自动管理生命周期)
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个 Tracy Zone(性能追踪区域)
|
||||
/// 使用 using 语句确保自动结束
|
||||
/// </summary>
|
||||
public static ZoneScope BeginZone(string name)
|
||||
{
|
||||
return new ZoneScope(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 步骤 3:创建 Tracy Manager
|
||||
|
||||
**TracyManager.cs:**
|
||||
```csharp
|
||||
using UnityEngine;
|
||||
|
||||
namespace TracyProfiler
|
||||
{
|
||||
/// <summary>
|
||||
/// Tracy 管理器 - 负责初始化和每帧更新
|
||||
/// </summary>
|
||||
public class TracyManager : MonoBehaviour
|
||||
{
|
||||
[Header("Tracy Settings")]
|
||||
[SerializeField] private bool enableOnStart = true;
|
||||
[SerializeField] private bool markFrames = true;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
// 确保只有一个实例
|
||||
if (FindObjectsOfType<TracyManager>().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<Rigidbody>();
|
||||
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)
|
||||
|
||||
355
main.cpp
Normal file
355
main.cpp
Normal file
@@ -0,0 +1,355 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <random>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <numeric>
|
||||
|
||||
// Tracy性能分析器
|
||||
#include "tracy/Tracy.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// 矩阵乘法 - 计算密集型操作
|
||||
vector<vector<double>> matrixMultiply(const vector<vector<double>>& A, const vector<vector<double>>& B) {
|
||||
ZoneScoped; // Tracy追踪这个函数
|
||||
|
||||
size_t n = A.size();
|
||||
size_t m = B[0].size();
|
||||
size_t p = B.size();
|
||||
|
||||
vector<vector<double>> result(n, vector<double>(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<vector<double>> generateRandomMatrix(size_t rows, size_t cols) {
|
||||
ZoneScoped;
|
||||
|
||||
random_device rd;
|
||||
mt19937 gen(rd());
|
||||
uniform_real_distribution<> dis(0.0, 100.0);
|
||||
|
||||
vector<vector<double>> matrix(rows, vector<double>(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<int>& 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<int> sieveOfEratosthenes(int n) {
|
||||
ZoneScoped;
|
||||
|
||||
vector<bool> isPrime(n + 1, true);
|
||||
vector<int> 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<long long> 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<double>& a, const vector<double>& 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<vector<int>> bigArray(size, vector<int>(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<thread> 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<int> 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<double> v1(10000000);
|
||||
vector<double> 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;
|
||||
}
|
||||
1
thirdparty/tracy
vendored
Submodule
1
thirdparty/tracy
vendored
Submodule
Submodule thirdparty/tracy added at be23d9354a
BIN
tracy-0.13.0.zip
Normal file
BIN
tracy-0.13.0.zip
Normal file
Binary file not shown.
298
unity_examples/CMakeLists.txt
Normal file
298
unity_examples/CMakeLists.txt
Normal file
@@ -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
|
||||
$<$<CONFIG:Release>:/O2> # 最大优化
|
||||
$<$<CONFIG:Release>:/Ob2> # 内联展开
|
||||
)
|
||||
else()
|
||||
# GCC/Clang 编译器选项
|
||||
target_compile_options(UnityTracyPlugin PRIVATE
|
||||
-Wall
|
||||
-Wextra
|
||||
-Wno-unused-parameter
|
||||
-fPIC # 位置无关代码
|
||||
-fvisibility=hidden # 隐藏符号
|
||||
)
|
||||
|
||||
# Release 优化
|
||||
target_compile_options(UnityTracyPlugin PRIVATE
|
||||
$<$<CONFIG:Release>:-O3> # 最大优化
|
||||
$<$<CONFIG:Release>:-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()
|
||||
|
||||
494
unity_examples/QUICKSTART.md
Normal file
494
unity_examples/QUICKSTART.md
Normal file
@@ -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<Rigidbody>().Length);
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 多线程命名
|
||||
|
||||
```csharp
|
||||
using System.Threading;
|
||||
|
||||
void WorkerThread()
|
||||
{
|
||||
Tracy.SetThreadName("Worker Thread");
|
||||
|
||||
while (running)
|
||||
{
|
||||
using (Tracy.Zone("WorkerThread.Process"))
|
||||
{
|
||||
ProcessData();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 进阶主题
|
||||
|
||||
### 自定义构建配置
|
||||
|
||||
在 Unity 项目中创建 `link.xml` 防止代码剥离:
|
||||
|
||||
```xml
|
||||
<linker>
|
||||
<assembly fullname="Assembly-CSharp">
|
||||
<namespace fullname="TracyProfiler" preserve="all"/>
|
||||
</assembly>
|
||||
</linker>
|
||||
```
|
||||
|
||||
### 持久化性能数据
|
||||
|
||||
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 官方仓库。
|
||||
|
||||
484
unity_examples/README.md
Normal file
484
unity_examples/README.md
Normal file
@@ -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 分钟快速集成!
|
||||
|
||||
---
|
||||
|
||||
**祝你使用愉快!** 🚀
|
||||
|
||||
如有任何问题,欢迎查阅文档或在社区寻求帮助。
|
||||
|
||||
287
unity_examples/SimplifiedPlugin.cpp
Normal file
287
unity_examples/SimplifiedPlugin.cpp
Normal file
@@ -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 <string>
|
||||
#include <cstring>
|
||||
|
||||
// 平台特定的导出定义
|
||||
#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 <unordered_map>
|
||||
#include <stack>
|
||||
#include <mutex>
|
||||
|
||||
// Zone 管理器(线程安全)
|
||||
class ZoneManager
|
||||
{
|
||||
private:
|
||||
struct ThreadZones
|
||||
{
|
||||
std::stack<tracy::ScopedZone*> zones;
|
||||
};
|
||||
|
||||
std::unordered_map<std::thread::id, ThreadZones> threadZones;
|
||||
std::mutex mutex;
|
||||
|
||||
public:
|
||||
void BeginZone(const char* name, const char* function, const char* file, uint32_t line)
|
||||
{
|
||||
std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> 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<uint32_t>(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 以匹配目标平台
|
||||
*/
|
||||
|
||||
396
unity_examples/TracyExamples.cs
Normal file
396
unity_examples/TracyExamples.cs
Normal file
@@ -0,0 +1,396 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using TracyProfiler;
|
||||
|
||||
namespace TracyProfiler.Examples
|
||||
{
|
||||
/// <summary>
|
||||
/// Tracy 使用示例
|
||||
/// 展示如何在不同场景下使用 Tracy 性能分析
|
||||
/// </summary>
|
||||
public class TracyExamples : MonoBehaviour
|
||||
{
|
||||
[Header("测试参数")]
|
||||
[SerializeField] private int heavyComputationIterations = 10000;
|
||||
[SerializeField] private int objectPoolSize = 100;
|
||||
[SerializeField] private bool runContinuousTest = false;
|
||||
|
||||
private List<GameObject> objectPool = new List<GameObject>();
|
||||
|
||||
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: 条件性能追踪
|
||||
|
||||
/// <summary>
|
||||
/// 演示如何使用条件编译来控制 Tracy 的开销
|
||||
/// </summary>
|
||||
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
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 演示如何在自定义类中使用 Tracy
|
||||
/// </summary>
|
||||
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"))
|
||||
{
|
||||
// 状态更新
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
269
unity_examples/TracyManager.cs
Normal file
269
unity_examples/TracyManager.cs
Normal file
@@ -0,0 +1,269 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
|
||||
namespace TracyProfiler
|
||||
{
|
||||
/// <summary>
|
||||
/// Tracy 管理器 - 负责初始化和每帧更新
|
||||
/// 在场景中添加此组件以启用 Tracy 性能分析
|
||||
/// </summary>
|
||||
[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<Rigidbody>().Length;
|
||||
int colliderCount = FindObjectsOfType<Collider>().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
|
||||
|
||||
/// <summary>
|
||||
/// 手动触发帧标记(如果禁用了自动标记)
|
||||
/// </summary>
|
||||
public void ManualFrameMark()
|
||||
{
|
||||
Tracy.MarkFrame();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送自定义消息
|
||||
/// </summary>
|
||||
public void SendMessage(string message)
|
||||
{
|
||||
Tracy.Message(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绘制自定义数值
|
||||
/// </summary>
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
257
unity_examples/TracyWrapper.cs
Normal file
257
unity_examples/TracyWrapper.cs
Normal file
@@ -0,0 +1,257 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TracyProfiler
|
||||
{
|
||||
/// <summary>
|
||||
/// Tracy 性能分析器的 Unity 封装
|
||||
/// 提供简单易用的 C# API 来使用 Tracy 性能分析功能
|
||||
/// </summary>
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// Tracy 是否已启用
|
||||
/// </summary>
|
||||
public static bool Enabled
|
||||
{
|
||||
get => s_enabled;
|
||||
set => s_enabled = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tracy 是否已初始化
|
||||
/// </summary>
|
||||
public static bool IsInitialized => s_initialized;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化 Tracy
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭 Tracy
|
||||
/// </summary>
|
||||
public static void Shutdown()
|
||||
{
|
||||
if (!s_initialized) return;
|
||||
|
||||
try
|
||||
{
|
||||
TracyShutdown();
|
||||
s_initialized = false;
|
||||
Debug.Log("[Tracy] 性能分析器已关闭");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"[Tracy] 关闭失败: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标记帧边界(通常在每帧末尾调用)
|
||||
/// </summary>
|
||||
[System.Diagnostics.Conditional("TRACY_ENABLE")]
|
||||
public static void MarkFrame()
|
||||
{
|
||||
if (!s_initialized || !s_enabled) return;
|
||||
TracyFrameMark();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绘制数值(用于实时监控变量)
|
||||
/// </summary>
|
||||
[System.Diagnostics.Conditional("TRACY_ENABLE")]
|
||||
public static void Plot(string name, double value)
|
||||
{
|
||||
if (!s_initialized || !s_enabled) return;
|
||||
TracyPlotValue(name, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绘制整数值
|
||||
/// </summary>
|
||||
[System.Diagnostics.Conditional("TRACY_ENABLE")]
|
||||
public static void Plot(string name, int value)
|
||||
{
|
||||
Plot(name, (double)value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绘制浮点数值
|
||||
/// </summary>
|
||||
[System.Diagnostics.Conditional("TRACY_ENABLE")]
|
||||
public static void Plot(string name, float value)
|
||||
{
|
||||
Plot(name, (double)value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送消息到 Tracy
|
||||
/// </summary>
|
||||
[System.Diagnostics.Conditional("TRACY_ENABLE")]
|
||||
public static void Message(string message)
|
||||
{
|
||||
if (!s_initialized || !s_enabled) return;
|
||||
TracyMessage(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置当前线程名称
|
||||
/// </summary>
|
||||
[System.Diagnostics.Conditional("TRACY_ENABLE")]
|
||||
public static void SetThreadName(string name)
|
||||
{
|
||||
if (!s_initialized || !s_enabled) return;
|
||||
TracySetThreadName(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tracy Zone 的作用域包装器
|
||||
/// 使用 using 语句自动管理生命周期
|
||||
/// </summary>
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个 Tracy Zone(性能追踪区域)
|
||||
/// 使用 using 语句确保自动结束
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// using (Tracy.Zone("MyFunction"))
|
||||
/// {
|
||||
/// // 要追踪的代码
|
||||
/// }
|
||||
/// </example>
|
||||
public static ZoneScope Zone(string name)
|
||||
{
|
||||
return new ZoneScope(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开始一个命名的 Zone
|
||||
/// 注意:必须手动调用 EndZone() 结束,推荐使用 Zone() 方法配合 using 语句
|
||||
/// </summary>
|
||||
[System.Diagnostics.Conditional("TRACY_ENABLE")]
|
||||
public static void BeginZone(string name)
|
||||
{
|
||||
if (!s_initialized || !s_enabled) return;
|
||||
TracyZoneBegin(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 结束当前 Zone
|
||||
/// 注意:必须与 BeginZone() 配对使用
|
||||
/// </summary>
|
||||
[System.Diagnostics.Conditional("TRACY_ENABLE")]
|
||||
public static void EndZone()
|
||||
{
|
||||
if (!s_initialized || !s_enabled) return;
|
||||
TracyZoneEnd();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tracy Zone 的属性标记版本
|
||||
/// 可以标记在方法上,自动追踪整个方法
|
||||
/// 注意:需要配合 AOP 或代码生成工具使用
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
|
||||
public class TracyZoneAttribute : Attribute
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public TracyZoneAttribute(string name = null)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user