-
Notifications
You must be signed in to change notification settings - Fork 3k
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
move and clean-up web_benchmarks package to flutter/packages #232
Conversation
88a0c61
to
85d94b5
Compare
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 looks good! I'll test it with the Gallery either later today or Monday.
'"Tracing.dataCollected" returned malformed data. ' | ||
'Expected a List but got: ${value.runtimeType}'); | ||
} | ||
_tracingData.addAll(event.params['value'].cast<Map<String, dynamic>>()); |
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.
event.params['value']
seems to be already of type Map<String, dynamic>
. Why do we need to cast here?
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.
While it's true that the list contains Map<String, dynamic>
the reified type of the list is List<dynamic>
, so we have to cast the element type of the list from dynamic
to Map<String, dynamic>
.
List<Map<String, dynamic>> toJson() { | ||
return metrics | ||
.map<Map<String, dynamic>>((BenchmarkMetric e) => e.toJson()) | ||
.toList(); |
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 output format has changed. The new format is
[
{
"name": "scroll.html.preroll_frame.average",
"value": 78.34693877551021
},
{
"name": "scroll.html.preroll_frame.outlierAverage",
"value": 847.5
},
{
"name": "scroll.html.preroll_frame.outlierRatio",
"value": 10.817270122427715
},
...
]
The old format looks like
{
"success": true,
"data": {
"scroll.html.preroll_frame.average": 93.88659793814433,
"scroll.html.preroll_frame.outlierAverage": 1061.3333333333333,
"scroll.html.preroll_frame.outlierRatio": 11.304417847077339,
...
},
"benchmarkScoreKeys": [
"scroll.html.drawFrameDuration.average",
"scroll.html.drawFrameDuration.outlierRatio",
"scroll.html.totalUiFrame.average"
]
}
- Why is the new format preferred?
- Will it break any existing parts of the toolchain?
- How can we return a benchmark result representing an unsuccessful test? (Similar to the previous
TaskResult.failure
) - How can we specify which parts are benchmarkScoreKeys?
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 intentional. The old format was specific to devicelab. The devicelab expects information, such as whether the run was a success or not, encoded in the JSON message we send to it. The data is separated from benchmarkScoreKeys
because the devicelab runs tests other than benchmarks, and so the results frequently contain data other than benchmark scores.
Since this is purely a benchmark package all we need to encode is benchmark scores, so we don't need to separate data from score keys. A failure is also easily expressible by simply throwing an exception and exiting the process with a non-zero exit code. So I simplified the output format by removing unnecessary features.
When we run this code in the devicelab, we will adapt it to the devicelab protocol (which is an internal implementation detail, and can change any time; it's not a public API). It's better to keep this package protocol-agnostic.
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.
You reminded me about the term "score". I've been struggling what to call the class I ended up calling BenchmarkMetric
. I think a better name is BenchmarkScore
. I'll rename.
33c19ba
to
4261318
Compare
74ff903
to
c700508
Compare
packages/web_benchmarks/README.md
Outdated
app's code and assets. Additionally, the server communicates with the browser to | ||
extract the performance traces. | ||
|
||
[1]: https://github.com/flutter/packages/tree/packages/web_benchmarks/test/web_benchmarks_test.dart |
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 link doesn't work btw. There has to be a branch or sha after /tree/
.
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.
It's because it's pointing at itself. It will work once the PR is submitted.
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.
I know this is a new file so it won't work. But I tried with an existing file, still didn't work. You have to tell it which tree to look at :)
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.
Oh, right. Not sure where I got that "/tree/" from. Must be some copypasta. Done.
/// The number of samples used to extract metrics, such as noise, means, | ||
/// max/min values. | ||
/// | ||
/// Keep this constant in sync with the same constant defined in `dev/benchmarks/macrobenchmarks/lib/src/web/recorder.dart`. |
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.
Github link to the file?
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.
Actually, now that this is the same package, I can move shared constants into a common library.
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, ironically, we didn't keep the two in sync. One was 10, the other 100 lol :)
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.
Done.
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.
Thank you! Looks great to me. I ran the Gallery benchmarks using this package; they were successful.
2fafe39
to
6fb8578
Compare
6fb8578
to
d3aaf61
Compare
for (final String benchmarkName in _benchmarks.keys) { | ||
final html.Element button = html.document.querySelector('#$benchmarkName'); | ||
button.addEventListener('click', (_) { | ||
final html.Element manualPanel = | ||
html.document.querySelector('#manual-panel'); | ||
manualPanel?.remove(); | ||
_runBenchmark(benchmarkName); | ||
}); | ||
} |
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.
Could be done with a single listener on the container, then check the event target to figure out which button was clicked. This would be better for performance, but I don't think it matters much here.
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.
Yeah, this part is not mission-critical.
html.document.body.remove(); | ||
html.document.body = html.BodyElement(); | ||
html.document.body.appendHtml('<h2>${profile.name}</h2>'); |
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.
Suggestion - replace all three lines with:
html.document.body.innerHtml = '<h2>${profile.name}</h2>';
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.
Done.
/// This is the same as calling [html.HttpRequest.request] but it doesn't | ||
/// crash on 404, which we use to detect `flutter run`. |
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.
I was going to suggest something like this:
try {
return html.HttpRequest.request(url, ...);
} on html.ProgressEvent catch(e) {
if (xhr.status! == 404) {
return xhr;
}
rethrow;
}
but then realized inside the catch
there's no way to get the xhr
object :(
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.
I cleaned up this method. It's only used once and a lot of cases it's trying to handle don't exist.
c1cce75
to
309b212
Compare
Move the web benchmark code into a shared package to be used for Flutter benchmarks, Gallery benchmarks, as well as customer benchmarks in the future.
Original sources:
This was adapted from the version staged in https://github.com/pennzht/web_benchmarks
Bonus changes
cirrusci/flutter:stable-web
image that includes Chrome dependencies.-x
to the build script for better debuggability on CI.