OLD | NEW |
| (Empty) |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library protoc.benchmark.html_view; | |
6 | |
7 import 'dart:async' show Future; | |
8 import 'dart:html'; | |
9 | |
10 import 'generated/benchmark.pb.dart' as pb; | |
11 import 'report.dart' show createPlatform, createPackages, encodeReport; | |
12 import 'suite.dart' show runSuite; | |
13 | |
14 import '../data/index.dart' as data; | |
15 | |
16 /// Runs a benchmark suite and displays progress and results as HTML. | |
17 /// Returns after rendering the final report. | |
18 Future runSuiteWithView(pb.Suite suite, Element container) async { | |
19 await loadReports(); // TODO: comparison view | |
20 | |
21 var env = await loadBrowserEnv(); | |
22 | |
23 var view = new ReportView(); | |
24 container.children.clear(); | |
25 container.append(view.elt); | |
26 | |
27 for (pb.Report report in runSuite(suite)) { | |
28 report.env = env; | |
29 view.render(report); | |
30 | |
31 // Wait for frame to render and start a new timer task for next benchmark. | |
32 await window.animationFrame; | |
33 await new Future(() => null); | |
34 } | |
35 } | |
36 | |
37 Future<pb.Env> loadBrowserEnv() async { | |
38 const advice = "Run a VM benchmark to create this file."; | |
39 var pubspecYaml = await _loadDataFile(data.pubspecYamlName, advice: advice); | |
40 var pubspecLock = await _loadDataFile(data.pubspecLockName, advice: advice); | |
41 var hostname = await _loadDataFile(data.hostfileName, advice: advice); | |
42 | |
43 var platform = createPlatform() | |
44 ..hostname = hostname | |
45 ..userAgent = window.navigator.userAgent; | |
46 | |
47 return new pb.Env() | |
48 ..page = window.location.pathname | |
49 ..platform = platform | |
50 ..packages = createPackages(pubspecYaml, pubspecLock); | |
51 } | |
52 | |
53 /// Loads all the reports saved to benchmark/data. | |
54 Future<List<pb.Report>> loadReports() async { | |
55 var out = <pb.Report>[]; | |
56 // TODO: maybe parallelize? | |
57 for (var name in data.allReportNames) { | |
58 String json = | |
59 await _loadDataFile(name, optional: (name == data.latestVMReportName)); | |
60 if (json != null) { | |
61 out.add(new pb.Report.fromJson(json)); | |
62 } | |
63 } | |
64 print("loaded ${out.length} reports"); | |
65 return out; | |
66 } | |
67 | |
68 Future<String> _loadDataFile(String name, | |
69 {bool optional: false, String advice}) async { | |
70 try { | |
71 return await HttpRequest.getString("/data/$name"); | |
72 } catch (e) { | |
73 if (optional) return null; | |
74 String error = "File is missing in benchmark/data: $name"; | |
75 if (advice != null) { | |
76 error += ". $advice"; | |
77 } | |
78 throw error; | |
79 } | |
80 } | |
81 | |
82 class ReportView { | |
83 final DivElement elt = new DivElement(); | |
84 final DivElement _statusElt = new DivElement(); | |
85 final PreElement _envElt = new PreElement(); | |
86 final TableElement _responseTable = new TableElement(); | |
87 final _jsonView = new _JsonView(); | |
88 | |
89 String _renderedStatus; | |
90 String _renderedPlatform; | |
91 final rows = <_ResponseView>[]; | |
92 | |
93 ReportView() { | |
94 // Fill in "template" elements that never change. | |
95 elt.children.addAll([ | |
96 _statusElt..style.height = "1em", | |
97 _envElt, | |
98 _responseTable | |
99 ..children.addAll([ | |
100 _headerCell("Benchmark"), | |
101 _headerCell("Params"), | |
102 _headerCell("1000 * int32 reads / second")..colSpan = 3 | |
103 ]), | |
104 _jsonView.elt | |
105 ]); | |
106 } | |
107 | |
108 void render(pb.Report r) { | |
109 _renderStatus(r); | |
110 _renderEnv(r); | |
111 _renderResponses(r); | |
112 _jsonView.render(r); | |
113 } | |
114 | |
115 void _renderStatus(pb.Report r) { | |
116 var newStatus = r.message; | |
117 if (r.status == pb.Status.DONE) newStatus = ""; | |
118 | |
119 if (newStatus == _renderedStatus) return; | |
120 _statusElt.text = newStatus; | |
121 _renderedStatus = newStatus; | |
122 } | |
123 | |
124 void _renderEnv(pb.Report r) { | |
125 String newPlatform = r.env.platform.toString(); | |
126 if (newPlatform == _renderedPlatform) return; | |
127 _envElt.text = newPlatform; | |
128 _renderedPlatform = newPlatform; | |
129 } | |
130 | |
131 void _renderResponses(pb.Report r) { | |
132 var it = r.responses.iterator; | |
133 | |
134 // Update existing rows | |
135 for (var row in rows) { | |
136 var hasNext = it.moveNext(); | |
137 assert(hasNext); // assume that the table only grows | |
138 row.render(it.current); | |
139 } | |
140 | |
141 // Add any new rows | |
142 while (it.moveNext()) { | |
143 var row = new _ResponseView()..render(it.current); | |
144 _responseTable.append(row.elt); | |
145 rows.add(row); | |
146 } | |
147 } | |
148 } | |
149 | |
150 class _ResponseView { | |
151 final TableRowElement elt = new TableRowElement(); | |
152 pb.Response _rendered; | |
153 | |
154 void render(pb.Response response) { | |
155 if (_rendered == response) return; | |
156 | |
157 elt.children.clear(); | |
158 elt.append(_textCell(response.request.id.name)); | |
159 elt.append(_textCell(response.request.params.toString())); | |
160 | |
161 for (var s in response.samples) { | |
162 double kIntsPerSecond = s.counts.int32Reads * 1000 / s.duration; | |
163 var cell = _textCell(kIntsPerSecond.toStringAsFixed(1)) | |
164 ..style.textAlign = "right"; | |
165 elt.append(cell); | |
166 } | |
167 } | |
168 } | |
169 | |
170 class _JsonView { | |
171 final DivElement elt = new DivElement(); | |
172 String _rendered; | |
173 | |
174 void render(pb.Report r) { | |
175 // Don't show JSON while benchmarks are in progress. | |
176 String json = ""; | |
177 if (r.status == pb.Status.DONE) { | |
178 json = encodeReport(r); | |
179 } | |
180 | |
181 if (json == _rendered) return; | |
182 | |
183 elt.children.clear(); | |
184 if (json == "") return; | |
185 elt.children.addAll([ | |
186 new HeadingElement.h2()..text = "Report data as JSON:", | |
187 new PreElement()..text = json | |
188 ]); | |
189 _rendered = json; | |
190 } | |
191 } | |
192 | |
193 _headerCell(String columnName) => new Element.th() | |
194 ..style.textAlign = "left" | |
195 ..text = columnName; | |
196 | |
197 _textCell(String value) => new TableCellElement()..text = value.toString(); | |
OLD | NEW |