Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
0053b089
Unverified
Commit
0053b089
authored
Aug 28, 2022
by
Jonah Williams
Committed by
GitHub
Aug 28, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[flutter_driver] make empty duration messages more helpful (#110441)
parent
0c6d786e
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
52 additions
and
17 deletions
+52
-17
timeline_summary.dart
packages/flutter_driver/lib/src/driver/timeline_summary.dart
+22
-12
timeline_summary_test.dart
...ter_driver/test/src/real_tests/timeline_summary_test.dart
+30
-5
No files found.
packages/flutter_driver/lib/src/driver/timeline_summary.dart
View file @
0053b089
...
@@ -20,6 +20,16 @@ import 'vsync_frame_lag_summarizer.dart';
...
@@ -20,6 +20,16 @@ import 'vsync_frame_lag_summarizer.dart';
const
JsonEncoder
_prettyEncoder
=
JsonEncoder
.
withIndent
(
' '
);
const
JsonEncoder
_prettyEncoder
=
JsonEncoder
.
withIndent
(
' '
);
const
String
_kEmptyDurationMessage
=
r''
'
The TimelineSummary had no events to summarize.
This can happen if the timeline summarization covered too short of a period
or if the driver script failed to interact with the application to generate
events. For example, if your driver script contained only a "driver.scroll()"
command but the app under test was not scrollable then no events would be
generated by the interaction.
'''
;
/// The maximum amount of time considered safe to spend for a frame's build
/// The maximum amount of time considered safe to spend for a frame's build
/// phase. Anything past that is in the danger of missing the frame as 60FPS.
/// phase. Anything past that is in the danger of missing the frame as 60FPS.
const
Duration
kBuildBudget
=
Duration
(
milliseconds:
16
);
const
Duration
kBuildBudget
=
Duration
(
milliseconds:
16
);
...
@@ -40,21 +50,21 @@ class TimelineSummary {
...
@@ -40,21 +50,21 @@ class TimelineSummary {
/// Average amount of time spent per frame in the framework building widgets,
/// Average amount of time spent per frame in the framework building widgets,
/// updating layout, painting and compositing.
/// updating layout, painting and compositing.
///
///
///
Returns null if no frames were recorded
.
///
Throws a [StateError] if this summary contains no timeline events
.
double
computeAverageFrameBuildTimeMillis
()
{
double
computeAverageFrameBuildTimeMillis
()
{
return
_averageInMillis
(
_extractFrameDurations
());
return
_averageInMillis
(
_extractFrameDurations
());
}
}
/// The [p]-th percentile frame rasterization time in milliseconds.
/// The [p]-th percentile frame rasterization time in milliseconds.
///
///
///
Returns null if no frames were recorded
.
///
Throws a [StateError] if this summary contains no timeline events
.
double
computePercentileFrameBuildTimeMillis
(
double
p
)
{
double
computePercentileFrameBuildTimeMillis
(
double
p
)
{
return
_percentileInMillis
(
_extractFrameDurations
(),
p
);
return
_percentileInMillis
(
_extractFrameDurations
(),
p
);
}
}
/// The longest frame build time in milliseconds.
/// The longest frame build time in milliseconds.
///
///
///
Returns null if no frames were recorded
.
///
Throws a [StateError] if this summary contains no timeline events
.
double
computeWorstFrameBuildTimeMillis
()
{
double
computeWorstFrameBuildTimeMillis
()
{
return
_maxInMillis
(
_extractFrameDurations
());
return
_maxInMillis
(
_extractFrameDurations
());
}
}
...
@@ -67,21 +77,21 @@ class TimelineSummary {
...
@@ -67,21 +77,21 @@ class TimelineSummary {
/// Average amount of time spent per frame in the engine rasterizer.
/// Average amount of time spent per frame in the engine rasterizer.
///
///
///
Returns null if no frames were recorded
.
///
Throws a [StateError] if this summary contains no timeline events
.
double
computeAverageFrameRasterizerTimeMillis
()
{
double
computeAverageFrameRasterizerTimeMillis
()
{
return
_averageInMillis
(
_extractGpuRasterizerDrawDurations
());
return
_averageInMillis
(
_extractGpuRasterizerDrawDurations
());
}
}
/// The longest frame rasterization time in milliseconds.
/// The longest frame rasterization time in milliseconds.
///
///
///
Returns null if no frames were recorded
.
///
Throws a [StateError] if this summary contains no timeline events
.
double
computeWorstFrameRasterizerTimeMillis
()
{
double
computeWorstFrameRasterizerTimeMillis
()
{
return
_maxInMillis
(
_extractGpuRasterizerDrawDurations
());
return
_maxInMillis
(
_extractGpuRasterizerDrawDurations
());
}
}
/// The [p]-th percentile frame rasterization time in milliseconds.
/// The [p]-th percentile frame rasterization time in milliseconds.
///
///
///
Returns null if no frames were recorded
.
///
Throws a [StateError] if this summary contains no timeline events
.
double
computePercentileFrameRasterizerTimeMillis
(
double
p
)
{
double
computePercentileFrameRasterizerTimeMillis
(
double
p
)
{
return
_percentileInMillis
(
_extractGpuRasterizerDrawDurations
(),
p
);
return
_percentileInMillis
(
_extractGpuRasterizerDrawDurations
(),
p
);
}
}
...
@@ -409,26 +419,26 @@ class TimelineSummary {
...
@@ -409,26 +419,26 @@ class TimelineSummary {
return
result
;
return
result
;
}
}
double
_averageInMillis
(
Iterable
<
Duration
>
durations
)
{
double
_averageInMillis
(
List
<
Duration
>
durations
)
{
if
(
durations
.
isEmpty
)
{
if
(
durations
.
isEmpty
)
{
throw
ArgumentError
(
'durations is empty!'
);
throw
StateError
(
_kEmptyDurationMessage
);
}
}
final
double
total
=
durations
.
fold
<
double
>(
0.0
,
(
double
t
,
Duration
duration
)
=>
t
+
duration
.
inMicroseconds
.
toDouble
()
/
1000.0
);
final
double
total
=
durations
.
fold
<
double
>(
0.0
,
(
double
t
,
Duration
duration
)
=>
t
+
duration
.
inMicroseconds
.
toDouble
()
/
1000.0
);
return
total
/
durations
.
length
;
return
total
/
durations
.
length
;
}
}
double
_percentileInMillis
(
Iterable
<
Duration
>
durations
,
double
percentile
)
{
double
_percentileInMillis
(
List
<
Duration
>
durations
,
double
percentile
)
{
if
(
durations
.
isEmpty
)
{
if
(
durations
.
isEmpty
)
{
throw
ArgumentError
(
'durations is empty!'
);
throw
StateError
(
_kEmptyDurationMessage
);
}
}
assert
(
percentile
>=
0.0
&&
percentile
<=
100.0
);
assert
(
percentile
>=
0.0
&&
percentile
<=
100.0
);
final
List
<
double
>
doubles
=
durations
.
map
<
double
>((
Duration
duration
)
=>
duration
.
inMicroseconds
.
toDouble
()
/
1000.0
).
toList
();
final
List
<
double
>
doubles
=
durations
.
map
<
double
>((
Duration
duration
)
=>
duration
.
inMicroseconds
.
toDouble
()
/
1000.0
).
toList
();
return
findPercentile
(
doubles
,
percentile
);
return
findPercentile
(
doubles
,
percentile
);
}
}
double
_maxInMillis
(
Iterable
<
Duration
>
durations
)
{
double
_maxInMillis
(
List
<
Duration
>
durations
)
{
if
(
durations
.
isEmpty
)
{
if
(
durations
.
isEmpty
)
{
throw
ArgumentError
(
'durations is empty!'
);
throw
StateError
(
_kEmptyDurationMessage
);
}
}
return
durations
return
durations
.
map
<
double
>((
Duration
duration
)
=>
duration
.
inMicroseconds
.
toDouble
()
/
1000.0
)
.
map
<
double
>((
Duration
duration
)
=>
duration
.
inMicroseconds
.
toDouble
()
/
1000.0
)
...
...
packages/flutter_driver/test/src/real_tests/timeline_summary_test.dart
View file @
0053b089
...
@@ -159,7 +159,12 @@ void main() {
...
@@ -159,7 +159,12 @@ void main() {
test
(
'throws when there is no data'
,
()
{
test
(
'throws when there is no data'
,
()
{
expect
(
expect
(
()
=>
summarize
(<
Map
<
String
,
dynamic
>>[]).
computeAverageFrameBuildTimeMillis
(),
()
=>
summarize
(<
Map
<
String
,
dynamic
>>[]).
computeAverageFrameBuildTimeMillis
(),
throwsA
(
predicate
<
ArgumentError
>((
ArgumentError
e
)
=>
e
.
message
==
'durations is empty!'
)),
throwsA
(
isA
<
StateError
>()
.
having
((
StateError
e
)
=>
e
.
message
,
'message'
,
contains
(
'The TimelineSummary had no events to summarize.'
),
)),
);
);
});
});
...
@@ -223,7 +228,12 @@ void main() {
...
@@ -223,7 +228,12 @@ void main() {
test
(
'throws when there is no data'
,
()
{
test
(
'throws when there is no data'
,
()
{
expect
(
expect
(
()
=>
summarize
(<
Map
<
String
,
dynamic
>>[]).
computeWorstFrameBuildTimeMillis
(),
()
=>
summarize
(<
Map
<
String
,
dynamic
>>[]).
computeWorstFrameBuildTimeMillis
(),
throwsA
(
predicate
<
ArgumentError
>((
ArgumentError
e
)
=>
e
.
message
==
'durations is empty!'
)),
throwsA
(
isA
<
StateError
>()
.
having
((
StateError
e
)
=>
e
.
message
,
'message'
,
contains
(
'The TimelineSummary had no events to summarize.'
),
)),
);
);
});
});
...
@@ -282,7 +292,12 @@ void main() {
...
@@ -282,7 +292,12 @@ void main() {
test
(
'throws when there is no data'
,
()
{
test
(
'throws when there is no data'
,
()
{
expect
(
expect
(
()
=>
summarize
(<
Map
<
String
,
dynamic
>>[]).
computeAverageFrameRasterizerTimeMillis
(),
()
=>
summarize
(<
Map
<
String
,
dynamic
>>[]).
computeAverageFrameRasterizerTimeMillis
(),
throwsA
(
predicate
<
ArgumentError
>((
ArgumentError
e
)
=>
e
.
message
==
'durations is empty!'
)),
throwsA
(
isA
<
StateError
>()
.
having
((
StateError
e
)
=>
e
.
message
,
'message'
,
contains
(
'The TimelineSummary had no events to summarize.'
),
)),
);
);
});
});
...
@@ -321,7 +336,12 @@ void main() {
...
@@ -321,7 +336,12 @@ void main() {
test
(
'throws when there is no data'
,
()
{
test
(
'throws when there is no data'
,
()
{
expect
(
expect
(
()
=>
summarize
(<
Map
<
String
,
dynamic
>>[]).
computeWorstFrameRasterizerTimeMillis
(),
()
=>
summarize
(<
Map
<
String
,
dynamic
>>[]).
computeWorstFrameRasterizerTimeMillis
(),
throwsA
(
predicate
<
ArgumentError
>((
ArgumentError
e
)
=>
e
.
message
==
'durations is empty!'
)),
throwsA
(
isA
<
StateError
>()
.
having
((
StateError
e
)
=>
e
.
message
,
'message'
,
contains
(
'The TimelineSummary had no events to summarize.'
),
)),
);
);
});
});
...
@@ -368,7 +388,12 @@ void main() {
...
@@ -368,7 +388,12 @@ void main() {
test
(
'throws when there is no data'
,
()
{
test
(
'throws when there is no data'
,
()
{
expect
(
expect
(
()
=>
summarize
(<
Map
<
String
,
dynamic
>>[]).
computePercentileFrameRasterizerTimeMillis
(
90.0
),
()
=>
summarize
(<
Map
<
String
,
dynamic
>>[]).
computePercentileFrameRasterizerTimeMillis
(
90.0
),
throwsA
(
predicate
<
ArgumentError
>((
ArgumentError
e
)
=>
e
.
message
==
'durations is empty!'
)),
throwsA
(
isA
<
StateError
>()
.
having
((
StateError
e
)
=>
e
.
message
,
'message'
,
contains
(
'The TimelineSummary had no events to summarize.'
),
)),
);
);
});
});
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment