| // Copyright 2014 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. |
| |
| import 'timeline.dart'; |
| |
| /// GC related timeline events. |
| /// |
| /// All these events occur only on the UI thread and are non overlapping. |
| const Set<String> kGCRootEvents = <String>{ |
| 'CollectNewGeneration', |
| 'CollectOldGeneration', |
| 'EvacuateNewGeneration', |
| 'StartConcurrentMark', |
| }; |
| |
| /// Summarizes [TimelineEvents]s corresponding to [kGCRootEvents] category. |
| /// |
| /// A sample event (some fields have been omitted for brevity): |
| /// ``` |
| /// { |
| /// "name": "StartConcurrentMarking", |
| /// "cat": "GC", |
| /// "ts": 3240710599608, |
| /// } |
| /// ``` |
| /// This class provides methods to compute the total time spend in GC on |
| /// the UI thread. |
| class GCSummarizer { |
| GCSummarizer._(this.totalGCTimeMillis); |
| |
| /// Creates a [GCSummarizer] given the timeline events. |
| static GCSummarizer fromEvents(List<TimelineEvent> gcEvents) { |
| double totalGCTimeMillis = 0; |
| TimelineEvent? lastGCBeginEvent; |
| |
| for (final TimelineEvent event in gcEvents) { |
| if (!kGCRootEvents.contains(event.name)) { |
| continue; |
| } |
| if (event.phase == 'B') { |
| lastGCBeginEvent = event; |
| } else if (lastGCBeginEvent != null) { |
| // These events must not overlap. |
| assert(event.name == lastGCBeginEvent.name, |
| 'Expected "${lastGCBeginEvent.name}" got "${event.name}"'); |
| final double st = lastGCBeginEvent.timestampMicros!.toDouble(); |
| final double end = event.timestampMicros!.toDouble(); |
| lastGCBeginEvent = null; |
| totalGCTimeMillis += (end - st) / 1000; |
| } |
| } |
| |
| return GCSummarizer._(totalGCTimeMillis); |
| } |
| |
| /// Total time spent doing GC on the UI thread. |
| final double totalGCTimeMillis; |
| } |