Commit 33c65264 authored by Yegor's avatar Yegor Committed by GitHub

fix frame info extraction logic; track frames in gallery test (#6505)

parent ed4ca503
...@@ -52,11 +52,22 @@ class GalleryTransitionTest { ...@@ -52,11 +52,22 @@ class GalleryTransitionTest {
Map<String, dynamic> original = JSON.decode(file( Map<String, dynamic> original = JSON.decode(file(
'${galleryDirectory.path}/build/transition_durations.timeline.json') '${galleryDirectory.path}/build/transition_durations.timeline.json')
.readAsStringSync()); .readAsStringSync());
Map<String, dynamic> clean = new Map<String, dynamic>.fromIterable( Map<String, dynamic> transitions = new Map<String, dynamic>.fromIterable(
original.keys, original.keys,
key: (String key) => key.replaceAll('/', ''), key: (String key) => key.replaceAll('/', ''),
value: (String key) => original[key]); value: (String key) => original[key]);
return new TaskResult.success(clean); Map<String, dynamic> summary = JSON.decode(file('${galleryDirectory.path}/build/transitions.timeline_summary.json').readAsStringSync());
Map<String, dynamic> data = <String, dynamic>{
'transitions': transitions,
};
data.addAll(summary);
return new TaskResult.success(data, benchmarkScoreKeys: <String>[
'average_frame_build_time_millis',
'worst_frame_build_time_millis',
'missed_frame_build_budget_count',
]);
} }
} }
...@@ -108,6 +108,14 @@ class PerfTest { ...@@ -108,6 +108,14 @@ class PerfTest {
deviceId, deviceId,
]); ]);
Map<String, dynamic> data = JSON.decode(file('$testDirectory/build/$timelineFileName.timeline_summary.json').readAsStringSync()); Map<String, dynamic> data = JSON.decode(file('$testDirectory/build/$timelineFileName.timeline_summary.json').readAsStringSync());
if (data['frame_count'] < 5) {
return new TaskResult.failure(
'Timeline contains too few frames: ${data['frame_count']}. Possibly '
'trace events are not being captured.',
);
}
return new TaskResult.success(data, benchmarkScoreKeys: <String>[ return new TaskResult.success(data, benchmarkScoreKeys: <String>[
'average_frame_build_time_millis', 'average_frame_build_time_millis',
'worst_frame_build_time_millis', 'worst_frame_build_time_millis',
......
...@@ -138,6 +138,9 @@ void main() { ...@@ -138,6 +138,9 @@ void main() {
// 'Start Transition' event when a demo is launched (see GalleryItem). // 'Start Transition' event when a demo is launched (see GalleryItem).
saveDurationsHistogram(timeline.json['traceEvents']); saveDurationsHistogram(timeline.json['traceEvents']);
TimelineSummary summary = new TimelineSummary.summarize(timeline);
summary.writeSummaryToFile('transitions');
}, timeout: new Timeout(new Duration(minutes: 5))); }, timeout: new Timeout(new Duration(minutes: 5)));
}); });
} }
...@@ -33,7 +33,7 @@ class TimelineSummary { ...@@ -33,7 +33,7 @@ class TimelineSummary {
int totalBuildTimeMicros = 0; int totalBuildTimeMicros = 0;
int frameCount = 0; int frameCount = 0;
for (TimedEvent event in _extractBeginFrameEvents()) { for (TimedEvent event in _extractFrameEvents()) {
frameCount++; frameCount++;
totalBuildTimeMicros += event.duration.inMicroseconds; totalBuildTimeMicros += event.duration.inMicroseconds;
} }
...@@ -51,7 +51,7 @@ class TimelineSummary { ...@@ -51,7 +51,7 @@ class TimelineSummary {
int maxBuildTimeMicros = 0; int maxBuildTimeMicros = 0;
int frameCount = 0; int frameCount = 0;
for (TimedEvent event in _extractBeginFrameEvents()) { for (TimedEvent event in _extractFrameEvents()) {
frameCount++; frameCount++;
maxBuildTimeMicros = math.max(maxBuildTimeMicros, event.duration.inMicroseconds); maxBuildTimeMicros = math.max(maxBuildTimeMicros, event.duration.inMicroseconds);
} }
...@@ -62,13 +62,13 @@ class TimelineSummary { ...@@ -62,13 +62,13 @@ class TimelineSummary {
} }
/// The total number of frames recorded in the timeline. /// The total number of frames recorded in the timeline.
int countFrames() => _extractBeginFrameEvents().length; int countFrames() => _extractFrameEvents().length;
/// The number of frames that missed the [frameBuildBudget] and therefore are /// The number of frames that missed the [frameBuildBudget] and therefore are
/// in the danger of missing frames. /// in the danger of missing frames.
/// ///
/// See [kBuildBudget]. /// See [kBuildBudget].
int computeMissedFrameBuildBudgetCount([Duration frameBuildBudget = kBuildBudget]) => _extractBeginFrameEvents() int computeMissedFrameBuildBudgetCount([Duration frameBuildBudget = kBuildBudget]) => _extractFrameEvents()
.where((TimedEvent event) => event.duration > kBuildBudget) .where((TimedEvent event) => event.duration > kBuildBudget)
.length; .length;
...@@ -79,7 +79,7 @@ class TimelineSummary { ...@@ -79,7 +79,7 @@ class TimelineSummary {
'worst_frame_build_time_millis': computeWorstFrameBuildTimeMillis(), 'worst_frame_build_time_millis': computeWorstFrameBuildTimeMillis(),
'missed_frame_build_budget_count': computeMissedFrameBuildBudgetCount(), 'missed_frame_build_budget_count': computeMissedFrameBuildBudgetCount(),
'frame_count': countFrames(), 'frame_count': countFrames(),
'frame_build_times': _extractBeginFrameEvents() 'frame_build_times': _extractFrameEvents()
.map((TimedEvent event) => event.duration.inMicroseconds) .map((TimedEvent event) => event.duration.inMicroseconds)
.toList() .toList()
}; };
...@@ -113,28 +113,22 @@ class TimelineSummary { ...@@ -113,28 +113,22 @@ class TimelineSummary {
.toList(); .toList();
} }
/// Extracts timed events that are reported as a pair of begin/end events. /// Extracts timed events that are reported as complete ("X") timeline events.
List<TimedEvent> _extractTimedBeginEndEvents(String name) { ///
List<TimedEvent> result = <TimedEvent>[]; /// See: https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU
List<TimedEvent> _extractCompleteEvents(String name) {
// Timeline does not guarantee that the first event is the "begin" event. return _extractNamedEvents(name)
Iterator<TimelineEvent> events = _extractNamedEvents(name) .where((TimelineEvent event) => event.phase == 'X')
.skipWhile((TimelineEvent evt) => evt.phase != 'B').iterator; .map((TimelineEvent event) {
while(events.moveNext()) { return new TimedEvent(
TimelineEvent beginEvent = events.current; event.timestampMicros,
if (events.moveNext()) { event.timestampMicros + event.duration.inMicroseconds,
TimelineEvent endEvent = events.current; );
result.add(new TimedEvent( })
beginEvent.timestampMicros, .toList();
endEvent.timestampMicros
));
}
}
return result;
} }
List<TimedEvent> _extractBeginFrameEvents() => _extractTimedBeginEndEvents('Engine::BeginFrame'); List<TimedEvent> _extractFrameEvents() => _extractCompleteEvents('Frame');
} }
/// Timing information about an event that happened in the event loop. /// Timing information about an event that happened in the event loop.
......
...@@ -17,20 +17,16 @@ void main() { ...@@ -17,20 +17,16 @@ void main() {
})); }));
} }
Map<String, dynamic> begin(int timeStamp) => <String, dynamic>{ Map<String, dynamic> frame(int timeStamp, int duration) => <String, dynamic>{
'name': 'Engine::BeginFrame', 'ph': 'B', 'ts': timeStamp 'name': 'Frame', 'ph': 'X', 'ts': timeStamp, 'dur': duration
};
Map<String, dynamic> end(int timeStamp) => <String, dynamic>{
'name': 'Engine::BeginFrame', 'ph': 'E', 'ts': timeStamp
}; };
group('frame_count', () { group('frame_count', () {
test('counts frames', () { test('counts frames', () {
expect( expect(
summarize(<Map<String, dynamic>>[ summarize(<Map<String, dynamic>>[
begin(1000), end(2000), frame(1000, 1000),
begin(3000), end(5000), frame(3000, 2000),
]).countFrames(), ]).countFrames(),
2 2
); );
...@@ -45,32 +41,12 @@ void main() { ...@@ -45,32 +41,12 @@ void main() {
test('computes average frame build time in milliseconds', () { test('computes average frame build time in milliseconds', () {
expect( expect(
summarize(<Map<String, dynamic>>[ summarize(<Map<String, dynamic>>[
begin(1000), end(2000), frame(1000, 1000),
begin(3000), end(5000), frame(3000, 2000),
]).computeAverageFrameBuildTimeMillis(), ]).computeAverageFrameBuildTimeMillis(),
1.5 1.5
); );
}); });
test('skips leading "end" events', () {
expect(
summarize(<Map<String, dynamic>>[
end(1000),
begin(2000), end(4000),
]).computeAverageFrameBuildTimeMillis(),
2.0
);
});
test('skips trailing "begin" events', () {
expect(
summarize(<Map<String, dynamic>>[
begin(2000), end(4000),
begin(5000),
]).computeAverageFrameBuildTimeMillis(),
2.0
);
});
}); });
group('worst_frame_build_time_millis', () { group('worst_frame_build_time_millis', () {
...@@ -81,35 +57,15 @@ void main() { ...@@ -81,35 +57,15 @@ void main() {
test('computes worst frame build time in milliseconds', () { test('computes worst frame build time in milliseconds', () {
expect( expect(
summarize(<Map<String, dynamic>>[ summarize(<Map<String, dynamic>>[
begin(1000), end(2000), frame(1000, 1000),
begin(3000), end(5000), frame(3000, 2000),
]).computeWorstFrameBuildTimeMillis(),
2.0
);
expect(
summarize(<Map<String, dynamic>>[
begin(3000), end(5000),
begin(1000), end(2000),
]).computeWorstFrameBuildTimeMillis(), ]).computeWorstFrameBuildTimeMillis(),
2.0 2.0
); );
});
test('skips leading "end" events', () {
expect(
summarize(<Map<String, dynamic>>[
end(1000),
begin(2000), end(4000),
]).computeWorstFrameBuildTimeMillis(),
2.0
);
});
test('skips trailing "begin" events', () {
expect( expect(
summarize(<Map<String, dynamic>>[ summarize(<Map<String, dynamic>>[
begin(2000), end(4000), frame(3000, 2000),
begin(5000), frame(1000, 1000),
]).computeWorstFrameBuildTimeMillis(), ]).computeWorstFrameBuildTimeMillis(),
2.0 2.0
); );
...@@ -119,9 +75,9 @@ void main() { ...@@ -119,9 +75,9 @@ void main() {
group('computeMissedFrameBuildBudgetCount', () { group('computeMissedFrameBuildBudgetCount', () {
test('computes the number of missed build budgets', () { test('computes the number of missed build budgets', () {
TimelineSummary summary = summarize(<Map<String, dynamic>>[ TimelineSummary summary = summarize(<Map<String, dynamic>>[
begin(1000), end(10000), frame(1000, 9000),
begin(11000), end(12000), frame(11000, 1000),
begin(13000), end(23000), frame(13000, 10000),
]); ]);
expect(summary.countFrames(), 3); expect(summary.countFrames(), 3);
...@@ -133,9 +89,9 @@ void main() { ...@@ -133,9 +89,9 @@ void main() {
test('computes and returns summary as JSON', () { test('computes and returns summary as JSON', () {
expect( expect(
summarize(<Map<String, dynamic>>[ summarize(<Map<String, dynamic>>[
begin(1000), end(10000), frame(1000, 9000),
begin(11000), end(12000), frame(11000, 1000),
begin(13000), end(24000), frame(13000, 11000),
]).summaryJson, ]).summaryJson,
<String, dynamic>{ <String, dynamic>{
'average_frame_build_time_millis': 7.0, 'average_frame_build_time_millis': 7.0,
...@@ -167,9 +123,9 @@ void main() { ...@@ -167,9 +123,9 @@ void main() {
test('writes summary to JSON file', () async { test('writes summary to JSON file', () async {
await summarize(<Map<String, dynamic>>[ await summarize(<Map<String, dynamic>>[
begin(1000), end(10000), frame(1000, 9000),
begin(11000), end(12000), frame(11000, 1000),
begin(13000), end(24000), frame(13000, 11000),
]).writeSummaryToFile('test', destinationDirectory: '/temp'); ]).writeSummaryToFile('test', destinationDirectory: '/temp');
String written = String written =
await fs.file('/temp/test.timeline_summary.json').readAsString(); await fs.file('/temp/test.timeline_summary.json').readAsString();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment