Skip to content
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

Merged
merged 7 commits into from
Oct 29, 2020

Conversation

yjbanov
Copy link
Contributor

@yjbanov yjbanov commented Oct 22, 2020

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

  • Change the Dockerfile to use cirrusci/flutter:stable-web image that includes Chrome dependencies.
  • Use compute credits for Linux builds so that builds are scheduled promptly.
  • Add -x to the build script for better debuggability on CI.

Copy link
Member

@pennzht pennzht left a 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>>());
Copy link
Member

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?

Copy link
Contributor Author

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>.

Comment on lines 37 to 40
List<Map<String, dynamic>> toJson() {
return metrics
.map<Map<String, dynamic>>((BenchmarkMetric e) => e.toJson())
.toList();
Copy link
Member

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?

Copy link
Contributor Author

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.

Copy link
Contributor Author

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.

@yjbanov yjbanov requested a review from pennzht October 23, 2020 22:11
@yjbanov yjbanov marked this pull request as ready for review October 23, 2020 22:23
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
Copy link
Contributor

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/.

Copy link
Contributor Author

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.

Copy link
Contributor

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 :)

Copy link
Contributor Author

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`.
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor Author

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 :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@yjbanov yjbanov requested review from mdebbar and pennzht October 26, 2020 17:21
Copy link
Member

@pennzht pennzht left a 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.

packages/web_benchmarks/testing/web_benchmarks_test.dart Outdated Show resolved Hide resolved
packages/web_benchmarks/testing/web_benchmarks_test.dart Outdated Show resolved Hide resolved
packages/web_benchmarks/testing/web_benchmarks_test.dart Outdated Show resolved Hide resolved
Comment on lines +121 to +129
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);
});
}
Copy link
Contributor

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.

Copy link
Contributor Author

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.

Comment on lines 134 to 136
html.document.body.remove();
html.document.body = html.BodyElement();
html.document.body.appendHtml('<h2>${profile.name}</h2>');
Copy link
Contributor

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>';

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Comment on lines +363 to +364
/// This is the same as calling [html.HttpRequest.request] but it doesn't
/// crash on 404, which we use to detect `flutter run`.
Copy link
Contributor

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 :(

Copy link
Contributor Author

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.

@yjbanov yjbanov merged commit 5297d1d into flutter:master Oct 29, 2020
stuartmorgan pushed a commit to stuartmorgan/packages that referenced this pull request Apr 30, 2021
stuartmorgan pushed a commit that referenced this pull request Oct 31, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants