Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
sxychenjing
engine
提交
94af181a
E
engine
项目概览
sxychenjing
/
engine
与 Fork 源项目一致
从无法访问的项目Fork
通知
3
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
E
engine
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
94af181a
编写于
10月 02, 2020
作者:
Y
Yegor
提交者:
GitHub
10月 02, 2020
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
web: implement frame timings (#21552)
* web: implement frame timings
上级
a24c7c13
变更
7
隐藏空白更改
内联
并排
Showing
7 changed file
with
242 addition
and
2 deletion
+242
-2
lib/web_ui/lib/src/engine.dart
lib/web_ui/lib/src/engine.dart
+9
-2
lib/web_ui/lib/src/engine/html/scene_builder.dart
lib/web_ui/lib/src/engine/html/scene_builder.dart
+9
-0
lib/web_ui/lib/src/engine/profiler.dart
lib/web_ui/lib/src/engine/profiler.dart
+111
-0
lib/web_ui/lib/src/engine/window.dart
lib/web_ui/lib/src/engine/window.dart
+11
-0
lib/web_ui/test/canvaskit/frame_timings_test.dart
lib/web_ui/test/canvaskit/frame_timings_test.dart
+32
-0
lib/web_ui/test/engine/surface/frame_timings_test.dart
lib/web_ui/test/engine/surface/frame_timings_test.dart
+24
-0
lib/web_ui/test/frame_timings_common.dart
lib/web_ui/test/frame_timings_common.dart
+46
-0
未找到文件。
lib/web_ui/lib/src/engine.dart
浏览文件 @
94af181a
...
...
@@ -164,8 +164,6 @@ void registerHotRestartListener(ui.VoidCallback listener) {
///
/// This is only available on the Web, as native Flutter configures the
/// environment in the native embedder.
// TODO(yjbanov): we should refactor the code such that the framework does not
// call this method directly.
void
initializeEngine
(
)
{
if
(
_engineInitialized
)
{
return
;
...
...
@@ -205,6 +203,8 @@ void initializeEngine() {
if
(!
waitingForAnimation
)
{
waitingForAnimation
=
true
;
html
.
window
.
requestAnimationFrame
((
num
highResTime
)
{
_frameTimingsOnVsync
();
// Reset immediately, because `frameHandler` can schedule more frames.
waitingForAnimation
=
false
;
...
...
@@ -215,6 +215,13 @@ void initializeEngine() {
// microsecond precision, and only then convert to `int`.
final
int
highResTimeMicroseconds
=
(
1000
*
highResTime
).
toInt
();
// In Flutter terminology "building a frame" consists of "beginning
// frame" and "drawing frame".
//
// We do not call `_frameTimingsOnBuildFinish` from here because
// part of the rasterization process, particularly in the HTML
// renderer, takes place in the `SceneBuilder.build()`.
_frameTimingsOnBuildStart
();
if
(
window
.
_onBeginFrame
!=
null
)
{
window
.
invokeOnBeginFrame
(
Duration
(
microseconds:
highResTimeMicroseconds
));
...
...
lib/web_ui/lib/src/engine/html/scene_builder.dart
浏览文件 @
94af181a
...
...
@@ -528,6 +528,15 @@ class SurfaceSceneBuilder implements ui.SceneBuilder {
/// cannot be used further.
@override
SurfaceScene
build
()
{
// "Build finish" and "raster start" happen back-to-back because we
// render on the same thread, so there's no overhead from hopping to
// another thread.
//
// In the HTML renderer we time the beginning of the rasterization phase
// (counter-intuitively) in SceneBuilder.build because DOM updates happen
// here. This is different from CanvasKit.
_frameTimingsOnBuildFinish
();
_frameTimingsOnRasterStart
();
timeAction
<
void
>(
kProfilePrerollFrame
,
()
{
while
(
_surfaceStack
.
length
>
1
)
{
// Auto-pop layers that were pushed without a corresponding pop.
...
...
lib/web_ui/lib/src/engine/profiler.dart
浏览文件 @
94af181a
...
...
@@ -107,3 +107,114 @@ class Profiler {
}
}
}
/// Whether we are collecting [ui.FrameTiming]s.
bool
get
_frameTimingsEnabled
{
return
window
.
_onReportTimings
!=
null
;
}
/// Collects frame timings from frames.
///
/// This list is periodically reported to the framework (see
/// [_kFrameTimingsSubmitInterval]).
List
<
ui
.
FrameTiming
>
_frameTimings
=
<
ui
.
FrameTiming
>[];
/// The amount of time in microseconds we wait between submitting
/// frame timings.
const
int
_kFrameTimingsSubmitInterval
=
100000
;
// 100 milliseconds
/// The last time (in microseconds) we submitted frame timings.
int
_frameTimingsLastSubmitTime
=
_nowMicros
();
// These variables store individual [ui.FrameTiming] properties.
int
_vsyncStartMicros
=
-
1
;
int
_buildStartMicros
=
-
1
;
int
_buildFinishMicros
=
-
1
;
int
_rasterStartMicros
=
-
1
;
int
_rasterFinishMicros
=
-
1
;
/// Records the vsync timestamp for this frame.
void
_frameTimingsOnVsync
(
)
{
if
(!
_frameTimingsEnabled
)
{
return
;
}
_vsyncStartMicros
=
_nowMicros
();
}
/// Records the time when the framework started building the frame.
void
_frameTimingsOnBuildStart
(
)
{
if
(!
_frameTimingsEnabled
)
{
return
;
}
_buildStartMicros
=
_nowMicros
();
}
/// Records the time when the framework finished building the frame.
void
_frameTimingsOnBuildFinish
(
)
{
if
(!
_frameTimingsEnabled
)
{
return
;
}
_buildFinishMicros
=
_nowMicros
();
}
/// Records the time when the framework started rasterizing the frame.
///
/// On the web, this value is almost always the same as [_buildFinishMicros]
/// because it's single-threaded so there's no delay between building
/// and rasterization.
///
/// This also means different things between HTML and CanvasKit renderers.
///
/// In HTML "rasterization" only captures DOM updates, but not the work that
/// the browser performs after the DOM updates are committed. The browser
/// does not report that information.
///
/// CanvasKit captures everything because we control the rasterization
/// process, so we know exactly when rasterization starts and ends.
void
_frameTimingsOnRasterStart
(
)
{
if
(!
_frameTimingsEnabled
)
{
return
;
}
_rasterStartMicros
=
_nowMicros
();
}
/// Records the time when the framework started rasterizing the frame.
///
/// See [_frameTimingsOnRasterStart] for more details on what rasterization
/// timings mean on the web.
void
_frameTimingsOnRasterFinish
(
)
{
if
(!
_frameTimingsEnabled
)
{
return
;
}
final
int
now
=
_nowMicros
();
_rasterFinishMicros
=
now
;
_frameTimings
.
add
(
ui
.
FrameTiming
(
vsyncStart:
_vsyncStartMicros
,
buildStart:
_buildStartMicros
,
buildFinish:
_buildFinishMicros
,
rasterStart:
_rasterStartMicros
,
rasterFinish:
_rasterFinishMicros
,
));
_vsyncStartMicros
=
-
1
;
_buildStartMicros
=
-
1
;
_buildFinishMicros
=
-
1
;
_rasterStartMicros
=
-
1
;
_rasterFinishMicros
=
-
1
;
if
(
now
-
_frameTimingsLastSubmitTime
>
_kFrameTimingsSubmitInterval
)
{
_frameTimingsLastSubmitTime
=
now
;
window
.
invokeOnReportTimings
(
_frameTimings
);
_frameTimings
=
<
ui
.
FrameTiming
>[];
}
}
/// Current timestamp in microseconds taken from the high-precision
/// monotonically increasing timer.
///
/// See also:
///
/// * https://developer.mozilla.org/en-US/docs/Web/API/Performance/now,
/// particularly notes about Firefox rounding to 1ms for security reasons,
/// which can be bypassed in tests by setting certain browser options.
int
_nowMicros
(
)
{
return
(
html
.
window
.
performance
.
now
()
*
1000
).
toInt
();
}
lib/web_ui/lib/src/engine/window.dart
浏览文件 @
94af181a
...
...
@@ -765,12 +765,23 @@ class EngineWindow extends ui.Window {
@override
void
render
(
ui
.
Scene
scene
)
{
if
(
experimentalUseSkia
)
{
// "Build finish" and "raster start" happen back-to-back because we
// render on the same thread, so there's no overhead from hopping to
// another thread.
//
// CanvasKit works differently from the HTML renderer in that in HTML
// we update the DOM in SceneBuilder.build, which is these function calls
// here are CanvasKit-only.
_frameTimingsOnBuildFinish
();
_frameTimingsOnRasterStart
();
final
LayerScene
layerScene
=
scene
as
LayerScene
;
rasterizer
!.
draw
(
layerScene
.
layerTree
);
}
else
{
final
SurfaceScene
surfaceScene
=
scene
as
SurfaceScene
;
domRenderer
.
renderScene
(
surfaceScene
.
webOnlyRootElement
);
}
_frameTimingsOnRasterFinish
();
}
@visibleForTesting
...
...
lib/web_ui/test/canvaskit/frame_timings_test.dart
0 → 100644
浏览文件 @
94af181a
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.6
import
'package:test/bootstrap/browser.dart'
;
import
'package:test/test.dart'
;
import
'package:ui/src/engine.dart'
;
import
'package:ui/ui.dart'
as
ui
;
import
'common.dart'
;
import
'../frame_timings_common.dart'
;
void
main
(
)
{
internalBootstrapBrowserTest
(()
=>
testMain
);
}
void
testMain
(
)
{
group
(
'frame timings'
,
()
{
setUpAll
(()
async
{
await
ui
.
webOnlyInitializePlatform
();
});
test
(
'Using CanvasKit'
,
()
{
expect
(
experimentalUseSkia
,
true
);
});
test
(
'collects frame timings'
,
()
async
{
await
runFrameTimingsTest
();
});
},
skip:
isIosSafari
);
// TODO: https://github.com/flutter/flutter/issues/60040
}
lib/web_ui/test/engine/surface/frame_timings_test.dart
0 → 100644
浏览文件 @
94af181a
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.6
import
'package:test/bootstrap/browser.dart'
;
import
'package:test/test.dart'
;
import
'package:ui/src/engine.dart'
;
import
'../../frame_timings_common.dart'
;
void
main
(
)
{
internalBootstrapBrowserTest
(()
=>
testMain
);
}
void
testMain
(
)
{
setUp
(()
async
{
await
initializeEngine
();
});
test
(
'collects frame timings'
,
()
async
{
await
runFrameTimingsTest
();
});
}
lib/web_ui/test/frame_timings_common.dart
0 → 100644
浏览文件 @
94af181a
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.6
import
'dart:async'
;
import
'package:test/test.dart'
;
import
'package:ui/ui.dart'
as
ui
;
/// Tests frame timings in a renderer-agnostic way.
///
/// See CanvasKit-specific and HTML-specific test files `frame_timings_test.dart`.
Future
<
void
>
runFrameTimingsTest
()
async
{
List
<
ui
.
FrameTiming
>
timings
;
ui
.
window
.
onReportTimings
=
(
List
<
ui
.
FrameTiming
>
data
)
{
timings
=
data
;
};
Completer
<
void
>
frameDone
=
Completer
<
void
>();
ui
.
window
.
onDrawFrame
=
()
{
final
ui
.
SceneBuilder
sceneBuilder
=
ui
.
SceneBuilder
();
sceneBuilder
..
pushOffset
(
0
,
0
)
..
pop
();
ui
.
window
.
render
(
sceneBuilder
.
build
());
frameDone
.
complete
();
};
// Frame 1.
ui
.
window
.
scheduleFrame
();
await
frameDone
.
future
;
expect
(
timings
,
isNull
,
reason:
'100 ms hasn
\'
t passed yet'
);
await
Future
<
void
>.
delayed
(
const
Duration
(
milliseconds:
150
));
// Frame 2.
frameDone
=
Completer
<
void
>();
ui
.
window
.
scheduleFrame
();
await
frameDone
.
future
;
expect
(
timings
,
hasLength
(
2
),
reason:
'100 ms passed. 2 frames pumped.'
);
for
(
final
ui
.
FrameTiming
timing
in
timings
)
{
expect
(
timing
.
vsyncOverhead
,
greaterThanOrEqualTo
(
Duration
.
zero
));
expect
(
timing
.
buildDuration
,
greaterThanOrEqualTo
(
Duration
.
zero
));
expect
(
timing
.
rasterDuration
,
greaterThanOrEqualTo
(
Duration
.
zero
));
expect
(
timing
.
totalSpan
,
greaterThanOrEqualTo
(
Duration
.
zero
));
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录