-
Notifications
You must be signed in to change notification settings - Fork 29.7k
fire service protocol extension events for frames #10966
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fire service protocol extension events for frames #10966
Conversation
| Duration _currentFrameTimeStamp; | ||
|
|
||
| int _debugFrameNumber = 0; | ||
| Stopwatch _frameStopwatch; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if this is debug-only, please name it _debugFrameStopwatch
|
Seems a bit dubious to be recording this information in debug mode, since we don't make particular efforts to get good performance in debug builds. Ideally this would be profile-mode-only. |
Ah, yeah, we would want the events when in profile mode. Is there a way to recognize that in the framework? (I realize that the asserts will all be stripped out at that point) |
|
I think that's a Dart-level problem. Ideally I'd like a way to have profile-mode-only code stripped out of the binary in release builds. |
|
We have a way today to recognize debug mode (via |
|
I suggest we create a function in the foundation layer called |
|
sgtm; I'm in the process of re-working this given the |
|
@Hixie, re-worked, but I could use some guidance about where |
|
(I added |
| /// When running in profile mode (or debug mode), invoke the given function. | ||
| /// | ||
| /// In release mode, the function is not invoked. In the future, we'd want the | ||
| /// given closure - and the call to [profile] - to be tree-shaken out. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "In the future" sentence should probably just be a TODO() rather than part of the documentation.
|
This looks fine but needs a test for the Flutter.Frame logic (verifying that the data is being sent in the expected format, for example, so that nobody accidentally breaks the protocol during a global search-and-replace of the string "startTime" or some such). |
👍, will add a test |
|
cc @DanTup for ideas for VS Code :) @devoncarew this looks great, thanks! |
|
@Hixie, I did refactor this a bit for better testability; we now have an event stream for the frame information, and that gets copied into service protocol events. It's not exactly the test you mentioned above, but does test that we're creating frame info events w/ the expected info. |
| return true; | ||
| } | ||
|
|
||
| /// Performance information for a Flutter frame. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we need much more information here, such as, how to get an instance of such a class, what information it stores, what modes it would be available in, the protocol by which it's sent over to IDEs or pointers to documentation on that protocol, etc.
|
|
||
| /// The frame number. | ||
| final int number; | ||
| /// The start time in microseconds. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
blank lines between members
| class FrameInfo { | ||
| FrameInfo(this.number, this.startTime, this.elapsed); | ||
|
|
||
| /// The frame number. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this documentation doesn't comply to our style guide.
|
|
||
| /// The frame number. | ||
| final int number; | ||
| /// The start time in microseconds. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"start time in microseconds" only raises more questions! relative to what? is it monotonic? is it affected by timeDilation? etc etc etc
| final int elapsed; | ||
|
|
||
| @override | ||
| String toString() => 'frame $number, elapsed time: $elapsed micros'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rather than "micros" let's just say "µs".
| int _debugFrameNumber = 0; | ||
| int _profileFrameNumber = 0; | ||
| Stopwatch _profileFrameStopwatch = new Stopwatch(); | ||
| StreamController<FrameInfo> _frameInfoController = new StreamController<FrameInfo>.broadcast(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's not initialise this in release mode...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also presumably it should be final?
| /// These events are created after a frame is rendered and contain performance related | ||
| /// information. Events are only fired when the app is running in debug or profile mode; | ||
| /// no frame information events are fired in release mode. | ||
| Stream<FrameInfo> get onFrameInfo => _frameInfoController.stream; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this member doesn't comply with our style guide's naming convention.
|
i'm not entirely convinced that exposing this stream to the app makes much sense... what's the use case other than tests? |
I don't have any other use case in mind than for tests. It looks like we do expose some other timing related information in |
|
I'm just dubious about instantiating a whole Stream object and so forth in applications, just for testing purposes. That's a very high cost for something that happens very rarely. |
|
Maybe you could collect the data then pass it to a protected method that calls developer.whatever, and in the test just subclass the binding and override that method? The real thing that needs testing though is the VM service protocol and none of these tests are going to do that... |
I'll do some noodling, and either rework for visibility, or move to another type of test (a devicelab test) which tests at a different level.
I agree it would be good to test at that level - not sure that we currently are for our other service extension work. |
Someone has to be the first. :-) For example, until yesterday, we didn't have any test of |
|
@sethladd I don't believe Code has any way for us to render arbitrary content like this :( Also; we don't currently support profiling mode (I don't really know much about this) which I figure is where this makes sense. I've raised Dart-Code/Dart-Code#373 to have this in the list though :-) |
|
@Hixie - circling back to this one - I updated it to add a devicelab test, and removed the public API around listening for frame events (we're back to only firing them on the service protocol). |
| expect(event.data['startTime'] is int); | ||
| expect(event.data['startTime'] >= 0); | ||
| expect(event.data['elapsed'] is int); | ||
| expect(event.data['elapsed'] >= 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is fantastic. thank you!
|
bombs away |
|
Looks like this is turning the devicelab bots red (https://flutter-dashboard.appspot.com/api/get-log?ownerKey=ahNzfmZsdXR0ZXItZGFzaGJvYXJkclgLEglDaGVja2xpc3QiOGZsdXR0ZXIvZmx1dHRlci80YjRjYWJiNzYxZWMxY2I3ZmI1ZjJlOGVjNmU4NTBkZTI5YTAzMDU2DAsSBFRhc2sYgICAgICAyAsM). I'm not sure why, so may revert in the meantime, |
)" This reverts commit 4b4cabb.

We're currently recording frame info to the VM timeline; this PR also fires service protocol extension events for flutter frames. The event includes the
frameNumber, thestartTime(in micros, from app start), andelapsedtime, in micros. Debugger clients can opt-into this event viastreamListen('Extension').This info will allow clients to show a bit more awareness of real-time frame times.
@Hixie