Skip to content

Commit f8534a4

Browse files
committed
docs: 最佳实践检测文档
1 parent 1e1afae commit f8534a4

File tree

6 files changed

+315
-3
lines changed

6 files changed

+315
-3
lines changed

Design/PerformanceMonitor.md

Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
# 最佳实践检测工具
2+
- [最佳实践检测工具](#最佳实践检测工具)
3+
- [作用](#作用)
4+
- [如何使用](#如何使用)
5+
- [检测示意](#检测示意)
6+
- [检测指标解释](#检测指标解释)
7+
- [启动检测](#启动检测)
8+
- [监控指标](#监控指标)
9+
- [优化建议概览](#优化建议概览)
10+
- [预下载检测](#预下载检测)
11+
- [监控指标](#监控指标-1)
12+
- [优化建议概览](#优化建议概览-1)
13+
- [wasm分包检测](#wasm分包检测)
14+
- [监控指标](#监控指标-2)
15+
- [优化建议概览](#优化建议概览-2)
16+
- [网络信息检测](#网络信息检测)
17+
- [监控指标](#监控指标-3)
18+
- [优化建议概览](#优化建议概览-3)
19+
- [帧率检测](#帧率检测)
20+
- [监控指标](#监控指标-4)
21+
- [优化建议概览](#优化建议概览-4)
22+
23+
24+
## 作用
25+
为了使游戏达到比较好的性能表现,仍需要开发者结合游戏实际情况进行优化。平台针对启动和运行输出了大量优化手段,使用最佳实践检测,可帮助开发者在**开发阶段**针对问题进行优化
26+
27+
## 如何使用
28+
版本要求:`转换插件版本 > 202305230000`
29+
30+
导出小游戏默认在**开发版和体验版**开启检测,可通过`minigame/unity-namespace.js`修改
31+
32+
```js
33+
// 最佳实践检测配置
34+
unityNamespace.monitorConfig = {
35+
enableMonitor: true, // 是否开启检测(只影响开发版/体验版,线上版本不会检测)
36+
fps: 10, // 帧率低于此值的帧会被记录,用于分析长耗时帧,做了限帧的游戏应该适当调低
37+
showResultAfterLaunch: true, // 是否一直检测到游戏可交互完成
38+
monitorDuration: 30000, // 仅当showResultAfterLaunch=false时有效, 在引擎初始化完成(即callmain)后多长时间停止检测
39+
}
40+
```
41+
42+
默认检测条件如上。插件并不知道什么时候检测截止,可选择可交互上报后或在引擎初始化完成(`callmain`)后多少ms截止,根据游戏实际情况修改。
43+
44+
1. 有上报游戏可交互[`WX.ReportGameStart()`](ReportStartupStat.md#三上报自定义阶段)的游戏
45+
应该设置`showResultAfterLaunch=true`,同时会忽略`monitorDuration`的值
46+
47+
1. 未上报游戏可交互上报的游戏
48+
应设置`showResultAfterLaunch=false`,此时根据`monitorDuration`的值截止检测
49+
50+
## 检测示意
51+
52+
优化建议通过弹框提示,详细内容通过vconsole打印
53+
54+
1. 弹框提醒优化建议
55+
56+
<img src="../image/monitor/monitor-dialog.png" width="500"/>
57+
58+
2. console打印详细信息
59+
60+
<img src="../image/monitor/monitor-console.png" width="500"/>
61+
62+
## 检测指标解释
63+
64+
### 启动检测
65+
检查框架启动阶段的耗时和资源大小
66+
67+
#### 监控指标
68+
```
69+
{
70+
assetLoadCost: number; // 首资源包下载耗时,单位ms
71+
assetContentLength: number; // 首资源包大小(未压缩原始大小),单位bytes
72+
useContentEncoding: boolean; // 首资源包是否开启服务器压缩
73+
wasmLoadCost: number; // wasm包下载耗时,ms
74+
wasmContentLength: number; // 启动下载的wasm包大小,单位bytes
75+
useCodeSplit: boolean; // 是否使用了wasm代码分包
76+
callmainCost: number; // 引擎初始化耗时,ms
77+
}
78+
```
79+
80+
#### 优化建议概览
81+
当提示优化建议时,可采用对应的优化手段
82+
1. `未使用wasm代码分包`
83+
- 条件: `useCodeSplit``false`,未使用wasm代码分包
84+
- 优化手段: [使用代码分包工具](WasmSplit.md)
85+
86+
2. `首资源包较大`
87+
- 条件: `assetContentLength`超过15 * 1024 * 1024,即未压缩的首资源包超过15MB
88+
- 优化手段: [首资源包下载与体积](StartupOptimization.md#221-首资源包下载与体积)
89+
90+
3. `首资源包未开启服务器压缩`
91+
- 条件: `useContentEncoding`值为`false`,服务器未开启br或gzip
92+
- 优化手段: [首资源包下载与体积](StartupOptimization.md#221-首资源包下载与体积)
93+
94+
4. `callmain耗时较长,请用安卓cpuprofile分析热点函数`
95+
- 条件: iOS平台`callmainCost>1500`或安卓平台`callmainCost>3000`
96+
- 优化手段: [引擎初始化与开发者首帧逻辑](StartupOptimization.md#223-引擎初始化与开发者首帧逻辑)
97+
98+
### 预下载检测
99+
检查预下载列表使用情况,分为引擎初始化完成(`callmain`)和检测完成时两个结果
100+
101+
> vconsole输出如下:`预下载基本信息: xxx , callmain完成时预下载信息: xxx`。其中xxx为js对象
102+
103+
#### 监控指标
104+
```
105+
{
106+
loadedCount: number; // 已预下载完成数量
107+
loadingCount: number; // 正在预下载数量
108+
loadedSizeStr: string; // 已预下载完成大小字符串表示, eg: 10.1MB
109+
loadedSize: number; // 已预下载完成大小,bytes
110+
hitCacheCount: number; // 命中CDN缓存的数量
111+
useH2: boolean; // 是否启用HTTP2
112+
useContentEncoding: boolean; // 是否开启了服务器压缩
113+
preloadListLength: number; // 预下载资源个数
114+
}
115+
```
116+
117+
#### 优化建议概览
118+
1. `未使用预下载能力`
119+
- 条件: `preloadListLength=0`; 即导出时未配置预下载列表
120+
- 优化手段: [使用预下载功能](UsingPreload.md)
121+
122+
2. `已发起预下载,但未完成,请检查预下载资源是否过大,或是否下载过慢`
123+
- 条件: 引擎初始化完成时,`loadingCount != 0``loadedCount = 0`; 表示预下载已发起但未完成
124+
- 优化手段: [使用预下载功能-注意事项第五点](UsingPreload.md#注意事项),预下载文件体积不应过大,将优先需要使用的资源放到列表头部
125+
126+
3. `预下载资源较小,请将大资源调整到预下载列表顶部`
127+
- 条件: 引擎初始化完成时 `loadedSize < 1 * 1024 * 1024 (1MB)` 或停止检测时 `loadedSize < 5 * 1024 * 1024 (5MB)`
128+
- 优化手段: 适当增加预下载资源大小
129+
130+
4. `预下载资源个数较多`
131+
- 条件: `preloadListLength > 15`;即预下载列表数大于15
132+
- 优化手段: 减小预下载个数
133+
134+
5. `预下载资源量较大`
135+
- 条件: `loadedSize > 20 * 1024 * 1024 (20MB)`;即总预下载大小超过20MB
136+
- 优化手段: 减小预下载资源量,过大的资源下载会造成带宽抢占,推荐由游戏自行控制加载时机
137+
138+
### wasm分包检测
139+
使用wasm代码分包后,检查wasm分包代码的加载时机,加载分包造成的卡顿时长,用来分析分包收集是否合理。若加载时机过早、阻塞时间过长,则需要优化。
140+
141+
> tips: 在新包做wasm分包期间可能会频繁提示优化建议
142+
143+
#### 监控指标
144+
```
145+
{
146+
loadSubWasmPackageStartTime: number; // 开始下载wasm子包的时间,ms
147+
loadSubWasmPackageCostTime: number; // (仅安卓)加载子包耗时,ms
148+
loadDurationCallmain: boolean; // 是否在引擎初始化期间加载子包
149+
maxFetchPendingTime: number; // (仅iOS高性能)最大阻塞时间,ms。iOS高性能加载子包代码时会卡顿
150+
costTimeAfterCallmain: number; // 引擎初始化完成后多长时间开始加载子包,ms
151+
}
152+
```
153+
154+
#### 优化建议概览
155+
1. `wasm子包在callmain期间加载,请使用分包工具继续收集`
156+
- 条件: `loadDurationCallmain=true`
157+
- 优化手段: 分包收集不足,使用分包工具[继续迭代](WasmSplit.md#迭代流程)
158+
159+
2. `wasm子包加载时机过早,请使用分包工具继续收集`
160+
- 条件: `costTimeAfterCallmain < 30000 (30s)`
161+
- 优化手段: 游戏前期不应加载子包,当前期出现子包加载,则需要[继续迭代](WasmSplit.md#迭代流程)
162+
163+
3. `缺失函数过多,请使用分包工具继续收集`
164+
- 条件: `maxFetchPendingTime > 2000`
165+
- 优化手段: [iOS高性能模式收集](WasmSplit.md#ios-高性能模式收集很卡) [继续迭代](WasmSplit.md#迭代流程)
166+
167+
168+
### 网络信息检测
169+
检查可缓存资源配置、CDN配置、并发数数、请求量、资源量
170+
171+
#### 监控指标
172+
```
173+
{
174+
useH2: boolean, // 是否开启HTTP2.0
175+
useContentEncoding: boolean, // 是否开启服务器压缩
176+
cacheSettings: boolean, // settings.json是否自动缓存
177+
cacheCatalog: boolean, // catalog.json是否自动缓存
178+
appendHashToCatalog: boolean, // catalog.json是否带上了hash或其他用于区分版本的信息
179+
requestCataHash: boolean, // 是否请求了catalog.hash文件用于资源热更新
180+
requestBundleSettings: boolean, // 是否请求了settings.json
181+
requestBundleCatalog: boolean, // 是否请求了catalog.json
182+
loadCount: number, // 已发起请求数
183+
loadedCount: number, // 已完成请求数
184+
loadedSizeStr: string, // 请求回包总大小的字符串表示,eg: 10.1MB
185+
loadedSize: number, // 请求回包总大小,bytes
186+
hitCacheCount: number, // 命中CDN缓存个数
187+
cacheableCount: number, // 可自动缓存个数
188+
loadFromCacheCount: number, // 使用本地缓存的个数
189+
startTime: number, // 首个请求开始时间
190+
duration: number, // 监控时长
191+
networkTime: number, // 有网络请求的总时长
192+
maxLoadingCount: number, // 最大并发数,基于业务侧统计,会大于10个,表示有请求会排队
193+
avgLoadingCount: number, // 平均并发数
194+
loadedTasks: IBaseRequestInfo[], // 已下载完成请求详细信息
195+
}
196+
197+
// 请求详细信息如下
198+
interface IBaseRequestInfo {
199+
url: string; // 请求URL
200+
startTime: number; // 请求开始时间
201+
statusCode?: number; // 服务器状态码
202+
enableContentEncoding?: boolean; // 是否开启了服务器压缩
203+
endTime?: number; // 请求介绍时间
204+
duration?: number; // 请求耗时
205+
protocol?: string; // 网络协议,h2或http1.1
206+
receivedBytedCount?: number; // 回包大小,bytes
207+
hitCache?: boolean; // 是否命中CDN缓存
208+
isReadFromCache?: boolean; // 是否使用本地缓存
209+
cacheable?: boolean; // 是否自动缓存的资源
210+
}
211+
212+
```
213+
214+
#### 优化建议概览
215+
1. `未开启http2`
216+
- 条件: `useH2=false`
217+
- 优化手段: 服务器开启HTTP2.0,通过多路复用和头部压缩的特性,能提升细碎文件的下载效率
218+
219+
2. `未命中CDN缓存`
220+
- 条件: `hitCacheCount=0`
221+
- 优化手段: 发布新版本时,建议进行CDN预热,避免直接从源站拉取资源
222+
223+
3. `请勿缓存settings.json`
224+
- 条件: `requestBundleSettings=true``cacheSettings=true`
225+
- 优化手段: Addressables的`settings.json`文件用来记录打包配置,不应该缓存到本地。取消此文件的自动缓存,[哪些资源会自动缓存](FileCache.md#二哪些资源会自动缓存)
226+
227+
4. `可将catalog.json配置为可缓存文件`
228+
- 条件: `requestBundleCatalog=true``cacheCatalog=false`
229+
- 优化手段: Addressables的`catalog.json`记录了所有资源文件的描述信息和依赖关系,一般大小较大,推荐缓存到本地,[哪些资源会自动缓存](FileCache.md#二哪些资源会自动缓存)
230+
231+
5. `catalog.json被缓存且无hash/版本信息, 会导致无法更新`
232+
- 条件: `requestBundleCatalog=true``cacheCatalog=true``appendHashToCatalog=false`
233+
- 优化手段: `catalog.json`缓存到本地若无版本标识,会导致无法更新到最新版本, [缓存规则](FileCache.md#三缓存规则)
234+
235+
6. `请勿请求catalog.hash来做资源热更新,小游戏平台不支持`
236+
- 条件: `requestCataHash=true`
237+
- 优化手段: `catalog.hash`记录了`catalog.json`的hash,用来热更新资源,但小游戏平台不支持,推荐使用`catalog.json`文件名带hash的方式来管理catalog版本,参见建议第五点
238+
239+
7. `可缓存文件过少,检查缓存配置`
240+
- 条件: `cacheableCount < loadCount / 2`,可缓存资源小于总请求数的一半
241+
- 优化手段: 检查[缓存配置](FileCache.md#二哪些资源会自动缓存),是否资源文件大部分未缓存。提高可缓存数量
242+
243+
8. `网络并发数过少`
244+
- 条件: `avgLoadingCount < 5`,平均并发数小于5
245+
- 优化手段: 并发数较少可能导致细碎文件较多时网络利用率不高,业务侧提高请求并发数
246+
247+
9. `网络未充分利用`
248+
- 条件: `networkTime / duration < 0.7`, 网络时间占监控时长占比不足70%
249+
- 优化建议: 可能由于游戏业务初始化逻辑较重,cpu繁忙,在cpu繁忙时未充分利用网络空闲;建议:在开始长耗时逻辑前,发起资源下载任务,充分利用网络
250+
251+
252+
### 帧率检测
253+
检查是否有大长帧,标记大长帧出现的位置,辅助定位是cpu耗时还是网络耗时导致启动慢
254+
255+
#### 监控指标
256+
```
257+
{
258+
frames: string[]; // 长耗时的帧
259+
frameCount: number; // 长耗时帧的个数
260+
longestFrame: { // 最长帧信息
261+
frame: string; // 帧数
262+
frameCost: number; // 单帧耗时, ms
263+
runtime: number; // 游戏运行时长, ms
264+
};
265+
frameInfo: IWrongFrame; // 长耗时帧信息
266+
totalJankTime: number; // 总卡帧时长, ms
267+
currentRuntime: number; // 当前游戏运行时长, ms
268+
jankRate: number; // 卡顿率
269+
}
270+
```
271+
272+
#### 优化建议概览
273+
卡帧问题,均需要使用cpuprofile定位。[使用Android CPU Profiler性能调优](AndroidProfile.md)[使用Unity Profiler性能调优](UnityProfiler.md)
274+
275+
276+
1. `存在长耗时帧cost=xxxms,runtime=xxxms`
277+
- 条件: `longestFrame.frameCost > 1000 (1s)`
278+
279+
2. `总卡顿时长xxxms`
280+
- 条件: `totalJankTime > 5000 (5s)`
281+
282+
3. `卡顿时长占比xx%`
283+
- 条件: `jankRate > 0.3`

Design/UsingLoader.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ Unity Loader是在微信小游戏环境加载Unity WebGL游戏的加载与适配
3434
CDN: cdn地址
3535
dataFileSubPrefix: 首包资源相对cdn地址的存放目录,默认首包资源放在cdn一级目录
3636
```
37+
38+
#### 通过接口修改
39+
游戏存在备用CDN地址,可通过C#接口 `WX.SetDataCDN` 或js接口 `GameGlobal.manager.setDataCDN` 修改DATA_CDN配置
40+
3741
### 3.2 启动界面
3842
由于Unity WebGL启动加载需要一定时间,因此需要使用视频或图片等内容作为过渡以留住玩家。Unity Loader默认使用视频+进度信息呈现,开发者可以自定义封面/视频,可参考[启动Loader视频规范](video.md)进行配置。
3943

@@ -68,6 +72,9 @@ hideAfterCallmain: $HIDE_AFTER_CALLMAIN, // 是否callmain完成立即隐藏封
6872
> backgroundImage需要注意图片宽高不可超过2048,否则无法显示
6973
> 使用coverview需要基础库版本>=2.16.1,插件已做兼容,若不支持,降级为使用离屏canvas渲染进度的方式
7074
> hideAfterCallmain: 游戏业务Awake逻辑耗时较高时可能导致出现短暂黑屏,改为false可盖住黑屏,等游戏第一帧渲染时隐藏
75+
76+
更多信息请参考[定制启动封面](CustomLoading.md)
77+
7178
### 3.3 首包资源加载方式
7279
**加载方式在转换工具导出时就确定好了,开发者一般不需要修改**
7380
**游戏资源量比较少**时,可选择将首包资源作为小游戏分包加载,了解[小游戏分包](https://developers.weixin.qq.com/minigame/dev/guide/base-ability/sub-packages.html)
@@ -95,3 +102,8 @@ let managerConfig = {
95102
### 3.5 资源缓存与淘汰策略
96103
loader会自动按一定规则做文件缓存,加快二次启动速度
97104
详情参考[资源缓存](FileCache.md)
105+
106+
### 3.6 插件调试信息
107+
通过修改`minigame/unity-namespace.js``enableDebugLog=true`,可查看插件详细日志,例如预下载发起和命中、文件缓存等。
108+
109+
> 真机需通过右上角菜单-调试-打开调试,查看小游戏日志

Design/UsingPreload.md

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
## 概述
33
通过 [启动流程与时序](Startup.md)我们知道,在UnityLoader加载过程中存在**网络空闲**的情况。特别是“引擎初始化和首场景准备”,影响该步骤包括:引擎自身模块与数据初始化,游戏首个场景加载以及Awake流程。这个过程是CPU处理密集,但网络空闲的期间,根据机型性能不同,通常**平均耗时会在3~6s**左右,我们可以在此阶段提前下载资源。
44

5-
## 导出预下载列表
5+
在引擎初始化期间,最多**并发10个**预下载。已发起但未完成的下载任务,以及列表中尚未发起的任务,会在引擎初始完成后继续进行,但**并发数为1个**。可通过`WX.SetConcurrent`修改引擎初始化后的预下载并发数,若想修改引擎初始化期间的并发数,需要使用js接口`GameGlobal.manager.setConcurrent`
6+
7+
## 配置方式
8+
### 导出预下载列表
69
<img src='../image/usingpreload1.png' width="500"/>
710

811
#### MiniGameConfig.asset相关配置
@@ -13,7 +16,7 @@ preloadFiles: -- $PRELOAD_LIST
1316
在Unity转换导出插件填写文件列表,生成时工具会自动从**webgl/StreamAssets目录**找资源并填充到game.js。
1417
运行时UnityLoader将根据列表内容在网络空闲期下载。
1518

16-
## 手动配置
19+
### 手动配置
1720
除了在Unity转换导出插件填写文件列表外,也可以在生成的game.js手动配置:
1821
``` js
1922
let managerConfig = {
@@ -31,12 +34,25 @@ let managerConfig = {
3134
}
3235
```
3336

37+
### 运行时配置「推荐」
38+
可能存在资源热更,导致配置在预下载列表中的资源是旧版本的资源。支持通过接口在运行时动态修改预下载列表
39+
40+
#### 在插件启动前修改
41+
在插件启动前,拉取游戏后台获取最新的预下载列表,修改 `managerConfig.preloadDataList` 或通过js接口 `GameGlobal.manager.setPreloadList` 修改
42+
43+
#### 引擎初始化完成后修改
44+
同样的,拉取游戏后台接口获取最新的预下载列表后,通过C#接口 `WX.SetPreloadList` 修改
45+
3446
## 路径规范
3547
- 若填写完成路径,如`$STREAM_CDN/StreamingAssets/WebGL/textures_8d265a9dfd6cb7669cdb8b726f0afb1e`;实际发起预载请求的URL采用填写的地址
3648
- 若填写相对路径,如`/WebGL/sounds_97cd953f8494c3375312e75a29c34fc2`;实际发起请求的URL为`DATA_CDN/StreamingAssets/WebGL/sounds_97cd953f8494c3375312e75a29c34fc2`
3749

50+
## 如何验证
51+
[查看插件调试信息](UsingLoader.md#36-插件调试信息), 当存在 `PreloadManager:` 字样日志,即为预下载。
52+
3853
## 注意事项
3954
1. 预下载所有文件总体积应控制在合理范围内,通常可以3~5MB左右的内容。
4055
2. 文件数量应控制在10个以内,在此阶段最多只能允许10个并发,超过将会排队。
4156
3. UnityLoader插件已经考虑到业务会重复请求预下载的文件,游戏逻辑依然按未使用预下载的异步加载逻辑,无需做其他处理。如果预下载完成UnityLoader会立即构造网络数据返回,业务无感知。
42-
4. 添加到预下载列表中的文件,需是插件会自动缓存的文件,否则会导致下载浪费,预下载无效,详见[资源缓存](FileCache.md)
57+
4. 添加到预下载列表中的文件,需是插件会自动缓存的文件,否则会导致下载浪费,预下载无效,详见[资源缓存](FileCache.md)
58+
5. 会按照列表顺序发起预下载,请将优先需要的资源放到列表前面。

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
- [首场景启动优化](Design/FirstSceneOptimization.md)
5757
- [使用代码分包工具](Design/WasmSplit.md)
5858
- [启动留存数据上报统计](Design/ReportStartupStat.md)
59+
- [最佳实践检测工具](Design/PerformanceMonitor.md)
5960

6061

6162
- 运行性能

image/monitor/monitor-console.png

791 KB
Loading

image/monitor/monitor-dialog.png

1.53 MB
Loading

0 commit comments

Comments
 (0)