git.iko.soy/typeable/elm-ui
on master help sign in
improve benchmarking suite
cc9b2acMatthew Griffith
benchmarks/runtime/benchPage.js+52−3
@@ -1,23 +1,44 @@
1const path = require('path');
1const path = require('path');
2
2
3−async function benchPage(page) {
3+async function benchPage(page, file) {
4 const client = await page.target().createCDPSession();
4 const client = await page.target().createCDPSession();
5 await client.send('Performance.enable');
5 await client.send('Performance.enable');
6 // await page.tracing.start({ path: 'trace.json' });
6 // await page.tracing.start({ path: 'trace.json' });
7− await page.goto('file://' + path.resolve('./tmp/run.html'))
7+ await page.goto('file://' + path.resolve(file))
8
8
9 await page.waitFor(5000);
9 await page.waitFor(5000);
10 // await page.tracing.stop();
10 // await page.tracing.stop();
11 const metrics = await client.send('Performance.getMetrics');
11 const metrics = await client.send('Performance.getMetrics');
12+
13+ const startMetrics = await page.metrics()
14+ await page.evaluate(() => { window.elmRefresh() })
15+ await page.waitFor(1500);
16+ const endMetrics = await page.metrics()
17+
12 await page.evaluate(() => { window.elmStartAnim() })
18 await page.evaluate(() => { window.elmStartAnim() })
13 await sleep(5000)
19 await sleep(5000)
14 await page.evaluate(() => { window.elmStopAnim() })
20 await page.evaluate(() => { window.elmStopAnim() })
21+ await page.waitFor(2000);
22+ const finalMetrics = await page.metrics()
15 const frames = await page.evaluate(x => {
23 const frames = await page.evaluate(x => {
16 return Promise.resolve(window.metrics);
24 return Promise.resolve(window.metrics);
17 }, {});
25 }, {});
18 return {
26 return {
19 name: frames.name,
27 name: frames.name,
28+ link: 'file://' + path.resolve(file),
20 perf: extract(metrics),
29 perf: extract(metrics),
30+ afterRefresh: {
31+ RecalcStyleDuration: endMetrics.RecalcStyleDuration - startMetrics.RecalcStyleDuration,
32+ LayoutDuration: endMetrics.LayoutDuration - startMetrics.LayoutDuration,
33+ ScriptDuration: endMetrics.ScriptDuration - startMetrics.ScriptDuration,
34+ JSHeapUsedSize: endMetrics.JSHeapUsedSize - startMetrics.JSHeapUsedSize
35+ },
36+ afterAnimation: {
37+ RecalcStyleDuration: finalMetrics.RecalcStyleDuration - endMetrics.RecalcStyleDuration,
38+ LayoutDuration: finalMetrics.LayoutDuration - endMetrics.LayoutDuration,
39+ ScriptDuration: finalMetrics.ScriptDuration - endMetrics.ScriptDuration,
40+ JSHeapUsedSize: finalMetrics.JSHeapUsedSize - endMetrics.JSHeapUsedSize
41+ },
21 frames: summarize(frames.frames),
42 frames: summarize(frames.frames),
22 }
43 }
23}
44}
@@ -28,7 +49,9 @@ function summarize(frames) {
28 median: median(frames),
49 median: median(frames),
29 mode: mode(frames),
50 mode: mode(frames),
30 avg: average(frames),
51 avg: average(frames),
31− fps: 1000 / average(frames)
52+ fps: 1000 / median(frames),
53+ min: minimum(frames),
54+ max: maximum(frames)
32 }
55 }
33}
56}
34
57
@@ -65,6 +88,32 @@ function mode(array) {
65 return maxEl;
88 return maxEl;
66}
89}
67
90
91+function minimum(values) {
92+ var m = null
93+ for (var i = 0; i < values.length; i++) {
94+ if (m == null) {
95+ m = values[i]
96+ } else if (values[i] < m) {
97+ m = values[i]
98+ }
99+ }
100+ return m
101+}
102+
103+
104+function maximum(values) {
105+ var m = null
106+ for (var i = 0; i < values.length; i++) {
107+ if (m == null) {
108+ m = values[i]
109+ } else if (values[i] > m) {
110+ m = values[i]
111+ }
112+ }
113+ return m
114+}
115+
116+
68function average(values) {
117function average(values) {
69 var total = 0;
118 var total = 0;
70 for (var i = 0; i < values.length; i++) {
119 for (var i = 0; i < values.length; i++) {
benchmarks/runtime/index.js+52−26
@@ -35,13 +35,31 @@ function regroupResults(results) {
35 if (results[i].group) {
35 if (results[i].group) {
36
36
37 var reorged = {
37 var reorged = {
38+ name: results[i].name
39+ , link: results[i].link
38− count: results[i].count
40+ , count: results[i].count
39 , fps: results[i].frames.fps
41 , fps: results[i].frames.fps
40 , timeToFirstPaintMS: results[i].perf.TimeToFirstPaintMS
42 , timeToFirstPaintMS: results[i].perf.TimeToFirstPaintMS
41 , nodes: results[i].perf.Nodes
43 , nodes: results[i].perf.Nodes
44+ , coldRender: {
42− , layoutSeconds: results[i].perf.LayoutDuration
45+ layoutSeconds: results[i].perf.LayoutDuration
43− , recalcStyleSeconds: results[i].perf.RecalcStyleDuration
46+ , recalcStyleSeconds: results[i].perf.RecalcStyleDuration
44− , scriptDurationSeconds: results[i].perf.ScriptDuration
47+ , scriptDurationSeconds: results[i].perf.ScriptDuration
48+
49+ }
50+ , warmRender: {
51+ layoutSeconds: results[i].afterRefresh.LayoutDuration
52+ , recalcStyleSeconds: results[i].afterRefresh.RecalcStyleDuration
53+ , scriptDurationSeconds: results[i].afterRefresh.ScriptDuration
54+
55+ }
56+ , extendedRender: {
57+ layoutSeconds: results[i].afterAnimation.LayoutDuration
58+ , recalcStyleSeconds: results[i].afterAnimation.RecalcStyleDuration
59+ , scriptDurationSeconds: results[i].afterAnimation.ScriptDuration
60+
61+ }
62+
45 }
63 }
46 if (results[i].group in regrouped) {
64 if (results[i].group in regrouped) {
47 regrouped[results[i].group].results.push(reorged)
65 regrouped[results[i].group].results.push(reorged)
@@ -58,8 +76,8 @@ var contain = [{ module: "Contain", group: "html", count: 1024, value: "viewHtml
58 , { module: "Contain", group: "contain", count: 128, value: "viewHtmlContain8192" }]
76 , { module: "Contain", group: "contain", count: 128, value: "viewHtmlContain8192" }]
59
77
60
78
61−async function write_results(allResults) {
79+async function writeResults(allResults, resultsDir, name) {
62− var resultsDir = "benchmarks/results"
80+
63 if (!fs.existsSync(resultsDir)) {
81 if (!fs.existsSync(resultsDir)) {
64 fs.mkdirSync(resultsDir);
82 fs.mkdirSync(resultsDir);
65 }
83 }
@@ -68,7 +86,7 @@ async function write_results(allResults) {
68 // we embed the compiled js to avoid having to start a server to read the app.
86 // we embed the compiled js to avoid having to start a server to read the app.
69 await compileToString(["./src/View/Results.elm"], { optimize: true, cwd: "./benchmarks" }).then(function (compiled_elm_code) {
87 await compileToString(["./src/View/Results.elm"], { optimize: true, cwd: "./benchmarks" }).then(function (compiled_elm_code) {
70 const compiled = eval(`\`${template}\``)
88 const compiled = eval(`\`${template}\``)
71− fs.writeFileSync(`./${resultsDir}/1.1.1-cand.html`, compiled)
89+ fs.writeFileSync(`./${resultsDir}/${name}/index.html`, compiled)
72 });
90 });
73
91
74 // fs.writeFileSync(`./${resultsDir}/1.1.1-candidate-optimized.json`, results)
92 // fs.writeFileSync(`./${resultsDir}/1.1.1-candidate-optimized.json`, results)
@@ -82,40 +100,40 @@ async function write_results(allResults) {
82 var instances = [
100 var instances = [
83 { module: "Baseline", group: null, value: "bench" }
101 { module: "Baseline", group: null, value: "bench" }
84 , { module: "ManyElements", group: "elmUI", count: 1024, value: "elmUI1024" }
102 , { module: "ManyElements", group: "elmUI", count: 1024, value: "elmUI1024" }
85− , { module: "ManyElements", group: "elmUI", count: 128, value: "elmUI128" }
103+ // , { module: "ManyElements", group: "elmUI", count: 128, value: "elmUI128" }
86 , { module: "ManyElements", group: "elmUI", count: 2048, value: "elmUI2048" }
104 , { module: "ManyElements", group: "elmUI", count: 2048, value: "elmUI2048" }
87 , { module: "ManyElements", group: "elmUI", count: 24, value: "elmUI24" }
105 , { module: "ManyElements", group: "elmUI", count: 24, value: "elmUI24" }
88− , { module: "ManyElements", group: "elmUI", count: 256, value: "elmUI256" }
106+ // , { module: "ManyElements", group: "elmUI", count: 256, value: "elmUI256" }
89 , { module: "ManyElements", group: "elmUI", count: 4096, value: "elmUI4096" }
107 , { module: "ManyElements", group: "elmUI", count: 4096, value: "elmUI4096" }
90− , { module: "ManyElements", group: "elmUI", count: 512, value: "elmUI512" }
108+ // , { module: "ManyElements", group: "elmUI", count: 512, value: "elmUI512" }
91− , { module: "ManyElements", group: "elmUI", count: 64, value: "elmUI64" }
109+ // , { module: "ManyElements", group: "elmUI", count: 64, value: "elmUI64" }
92 , { module: "ManyElements", group: "elmUI", count: 8192, value: "elmUI8192" }
110 , { module: "ManyElements", group: "elmUI", count: 8192, value: "elmUI8192" }
93 , { module: "ManyElements", group: "elmUIVCSS", count: 1024, value: "elmUIVCSS1024" }
111 , { module: "ManyElements", group: "elmUIVCSS", count: 1024, value: "elmUIVCSS1024" }
94− , { module: "ManyElements", group: "elmUIVCSS", count: 128, value: "elmUIVCSS128" }
112+ // , { module: "ManyElements", group: "elmUIVCSS", count: 128, value: "elmUIVCSS128" }
95 , { module: "ManyElements", group: "elmUIVCSS", count: 2048, value: "elmUIVCSS2048" }
113 , { module: "ManyElements", group: "elmUIVCSS", count: 2048, value: "elmUIVCSS2048" }
96 , { module: "ManyElements", group: "elmUIVCSS", count: 24, value: "elmUIVCSS24" }
114 , { module: "ManyElements", group: "elmUIVCSS", count: 24, value: "elmUIVCSS24" }
97− , { module: "ManyElements", group: "elmUIVCSS", count: 256, value: "elmUIVCSS256" }
115+ // , { module: "ManyElements", group: "elmUIVCSS", count: 256, value: "elmUIVCSS256" }
98 , { module: "ManyElements", group: "elmUIVCSS", count: 4096, value: "elmUIVCSS4096" }
116 , { module: "ManyElements", group: "elmUIVCSS", count: 4096, value: "elmUIVCSS4096" }
99− , { module: "ManyElements", group: "elmUIVCSS", count: 512, value: "elmUIVCSS512" }
117+ // , { module: "ManyElements", group: "elmUIVCSS", count: 512, value: "elmUIVCSS512" }
100− , { module: "ManyElements", group: "elmUIVCSS", count: 64, value: "elmUIVCSS64" }
118+ // , { module: "ManyElements", group: "elmUIVCSS", count: 64, value: "elmUIVCSS64" }
101 , { module: "ManyElements", group: "elmUIVCSS", count: 8192, value: "elmUIVCSS8192" }
119 , { module: "ManyElements", group: "elmUIVCSS", count: 8192, value: "elmUIVCSS8192" }
102 , { module: "ManyElements", group: "viewHtml", count: 1024, value: "viewHtml1024" }
120 , { module: "ManyElements", group: "viewHtml", count: 1024, value: "viewHtml1024" }
103− , { module: "ManyElements", group: "viewHtml", count: 128, value: "viewHtml128" }
121+ // , { module: "ManyElements", group: "viewHtml", count: 128, value: "viewHtml128" }
104 , { module: "ManyElements", group: "viewHtml", count: 2048, value: "viewHtml2048" }
122 , { module: "ManyElements", group: "viewHtml", count: 2048, value: "viewHtml2048" }
105 , { module: "ManyElements", group: "viewHtml", count: 24, value: "viewHtml24" }
123 , { module: "ManyElements", group: "viewHtml", count: 24, value: "viewHtml24" }
106− , { module: "ManyElements", group: "viewHtml", count: 256, value: "viewHtml256" }
124+ // , { module: "ManyElements", group: "viewHtml", count: 256, value: "viewHtml256" }
107 , { module: "ManyElements", group: "viewHtml", count: 4096, value: "viewHtml4096" }
125 , { module: "ManyElements", group: "viewHtml", count: 4096, value: "viewHtml4096" }
108− , { module: "ManyElements", group: "viewHtml", count: 512, value: "viewHtml512" }
126+ // , { module: "ManyElements", group: "viewHtml", count: 512, value: "viewHtml512" }
109− , { module: "ManyElements", group: "viewHtml", count: 64, value: "viewHtml64" }
127+ // , { module: "ManyElements", group: "viewHtml", count: 64, value: "viewHtml64" }
110 , { module: "ManyElements", group: "viewHtml", count: 8192, value: "viewHtml8192" }
128 , { module: "ManyElements", group: "viewHtml", count: 8192, value: "viewHtml8192" }
111 , { module: "ManyElements", group: "viewInline", count: 1024, value: "viewInline1024" }
129 , { module: "ManyElements", group: "viewInline", count: 1024, value: "viewInline1024" }
112− , { module: "ManyElements", group: "viewInline", count: 128, value: "viewInline128" }
130+ // , { module: "ManyElements", group: "viewInline", count: 128, value: "viewInline128" }
113 , { module: "ManyElements", group: "viewInline", count: 2048, value: "viewInline2048" }
131 , { module: "ManyElements", group: "viewInline", count: 2048, value: "viewInline2048" }
114 , { module: "ManyElements", group: "viewInline", count: 24, value: "viewInline24" }
132 , { module: "ManyElements", group: "viewInline", count: 24, value: "viewInline24" }
115− , { module: "ManyElements", group: "viewInline", count: 256, value: "viewInline256" }
133+ // , { module: "ManyElements", group: "viewInline", count: 256, value: "viewInline256" }
116 , { module: "ManyElements", group: "viewInline", count: 4096, value: "viewInline4096" }
134 , { module: "ManyElements", group: "viewInline", count: 4096, value: "viewInline4096" }
117− , { module: "ManyElements", group: "viewInline", count: 512, value: "viewInline512" }
135+ // , { module: "ManyElements", group: "viewInline", count: 512, value: "viewInline512" }
118− , { module: "ManyElements", group: "viewInline", count: 64, value: "viewInline64" }
136+ // , { module: "ManyElements", group: "viewInline", count: 64, value: "viewInline64" }
119 , { module: "ManyElements", group: "viewInline", count: 8192, value: "viewInline8192" }
137 , { module: "ManyElements", group: "viewInline", count: 8192, value: "viewInline8192" }
120 ]
138 ]
121
139
@@ -131,20 +149,28 @@ async function write_results(allResults) {
131 }
149 }
132
150
133 var allResults = []
151 var allResults = []
152+ const resultsDir = "benchmarks/results"
153+ const resultName = "1.2-cand"
154+
155+ if (!fs.existsSync(`./${resultsDir}/${resultName}/instances/`)) {
156+ fs.mkdirSync(`./${resultsDir}/${resultName}/instances/`, { recursive: true });
157+ }
158+
134
159
135 for (var i = 0; i < instances.length; i++) {
160 for (var i = 0; i < instances.length; i++) {
136 var item = instances[i]
161 var item = instances[i]
137 write_entrypoint(item)
162 write_entrypoint(item)
163+ const test_file = `${resultsDir}/${resultName}/instances/${item.value}.html`
138 var template = fs.readFileSync("./benchmarks/runtime/template/run.html")
164 var template = fs.readFileSync("./benchmarks/runtime/template/run.html")
139 var cssom = fs.readFileSync("./experiments/virtual-css/cssom.js")
165 var cssom = fs.readFileSync("./experiments/virtual-css/cssom.js")
140 // we embed the compiled js to avoid having to start a server to read the app.
166 // we embed the compiled js to avoid having to start a server to read the app.
141 await compileToString(["tmp/Main.elm"], { optimize: true, cwd: "./benchmarks" }).then(function (compiled_elm_code) {
167 await compileToString(["tmp/Main.elm"], { optimize: true, cwd: "./benchmarks" }).then(function (compiled_elm_code) {
142 const compiled = eval(`\`${template}\``)
168 const compiled = eval(`\`${template}\``)
143− fs.writeFileSync("./tmp/run.html", compiled)
169+ fs.writeFileSync(test_file, compiled)
144 });
170 });
145
171
146 const page = await browser.newPage();
172 const page = await browser.newPage();
147− const results = await benchPage(page);
173+ const results = await benchPage(page, test_file);
148 results.group = item.group
174 results.group = item.group
149 results.count = item.count
175 results.count = item.count
150 await page.close()
176 await page.close()
@@ -155,6 +181,6 @@ async function write_results(allResults) {
155
181
156 allResults = regroupResults(allResults)
182 allResults = regroupResults(allResults)
157
183
158− write_results(allResults)
184+ writeResults(allResults, resultsDir, resultName)
159
185
160})();
186})();
benchmarks/src/Benchmark/Render.elm+13−1
@@ -6,6 +6,8 @@ port module Benchmark.Render exposing (Benchmark, toProgram)
6import Browser
6import Browser
7import Browser.Events
7import Browser.Events
8import Html exposing (Html)
8import Html exposing (Html)
9+import Html.Attributes as Attr
10+import Html.Events as Events
9import Json.Decode as Decode
11import Json.Decode as Decode
10import Json.Encode as Encode
12import Json.Encode as Encode
11import Time
13import Time
@@ -50,7 +52,17 @@ toProgram render =
50 , view =
52 , view =
51 \model ->
53 \model ->
52 { title = render.name
54 { title = render.name
55+ , body =
56+ [ Html.div
57+ [ Attr.style "display" "flex"
58+ , Attr.style "flex-direction" "row"
59+ ]
60+ [ Html.button [ Events.onClick Refresh ] [ Html.text "Refresh" ]
61+ , Html.button [ Events.onClick StartAnim ] [ Html.text "StartAnim" ]
62+ , Html.button [ Events.onClick StopAnim ] [ Html.text "StopAnim" ]
63+ ]
53− , body = [ render.view model.model ]
64+ , render.view model.model
65+ ]
54 }
66 }
55 , update =
67 , update =
56 update render
68 update render
benchmarks/src/ManyElements.elm+29−4
@@ -343,14 +343,14 @@ viewEl selectedIndex index =
343 el
343 el
344 [ Background.color
344 [ Background.color
345 (if selectedIndex == index then
345 (if selectedIndex == index then
346− pink
346+ pinkish index
347
347
348 else
348 else
349 white
349 white
350 )
350 )
351 , Font.color
351 , Font.color
352 (if selectedIndex /= index then
352 (if selectedIndex /= index then
353− pink
353+ pinkish index
354
354
355 else
355 else
356 white
356 white
@@ -375,6 +375,21 @@ pink =
375 rgb255 240 0 245
375 rgb255 240 0 245
376
376
377
377
378+pinkish i =
379+ rgb255 (wrap255 (i + 240)) 0 245
380+
381+
382+wrap255 i =
383+ if i > 255 then
384+ 0
385+
386+ else if i < 0 then
387+ 0
388+
389+ else
390+ i
391+
392+
378{-| -}
393{-| -}
379viewHtml : String -> Int -> Benchmark.Render.Benchmark Model Msg
394viewHtml : String -> Int -> Benchmark.Render.Benchmark Model Msg
380viewHtml name count =
395viewHtml name count =
@@ -470,14 +485,14 @@ viewInline name count =
470viewInlineHtmlElement selectedIndex index =
485viewInlineHtmlElement selectedIndex index =
471 Html.div
486 Html.div
472 (if selectedIndex == index then
487 (if selectedIndex == index then
473− [ Html.Attributes.style "background-color" "rgb(240, 0, 245)"
488+ [ Html.Attributes.style "background-color" (renderColor (wrap255 (index + 240)) 0 245)
474 , Html.Attributes.style "color" "white"
489 , Html.Attributes.style "color" "white"
475 , Html.Attributes.style "padding" "24"
490 , Html.Attributes.style "padding" "24"
476 ]
491 ]
477
492
478 else
493 else
479 [ Html.Attributes.style "background-color" "white"
494 [ Html.Attributes.style "background-color" "white"
480− , Html.Attributes.style "color" "rgb(240, 0, 245)"
495+ , Html.Attributes.style "color" (renderColor (wrap255 (index + 240)) 0 245)
481 , Html.Attributes.style "padding" "24"
496 , Html.Attributes.style "padding" "24"
482 ]
497 ]
483 )
498 )
@@ -489,3 +504,13 @@ viewInlineHtmlElement selectedIndex index =
489 Html.text "Hello!"
504 Html.text "Hello!"
490 ]
505 ]
491 ]
506 ]
507+
508+
509+renderColor r g b =
510+ "rgb("
511+ ++ String.fromInt r
512+ ++ ","
513+ ++ String.fromInt g
514+ ++ ","
515+ ++ String.fromInt b
516+ ++ ")"
benchmarks/src/View/Results.elm+196−72
@@ -3,11 +3,15 @@ port module View.Results exposing (main)
3import Browser
3import Browser
4import Color
4import Color
5import Html
5import Html
6−import Html.Attributes exposing (class)
6+import Html.Attributes as Attr exposing (class)
7import LineChart as LineChart
7import LineChart as LineChart
8import LineChart.Area as Area
8import LineChart.Area as Area
9import LineChart.Axis as Axis
9import LineChart.Axis as Axis
10import LineChart.Axis.Intersection as Intersection
10import LineChart.Axis.Intersection as Intersection
11+import LineChart.Axis.Line as AxisLine
12+import LineChart.Axis.Range as Range
13+import LineChart.Axis.Ticks as Ticks
14+import LineChart.Axis.Title as Title
11import LineChart.Colors as Colors
15import LineChart.Colors as Colors
12import LineChart.Container as Container
16import LineChart.Container as Container
13import LineChart.Dots as Dots
17import LineChart.Dots as Dots
@@ -19,6 +23,22 @@ import LineChart.Legends as Legends
19import LineChart.Line as Line
23import LineChart.Line as Line
20
24
21
25
26+row children =
27+ Html.div
28+ [ Attr.style "display" "flex"
29+ , Attr.style "flex-direction" "row"
30+ ]
31+ children
32+
33+
34+column children =
35+ Html.div
36+ [ Attr.style "display" "flex"
37+ , Attr.style "flex-direction" "column"
38+ ]
39+ children
40+
41+
22main =
42main =
23 Browser.document
43 Browser.document
24 { init =
44 { init =
@@ -32,12 +52,58 @@ main =
32 , body =
52 , body =
33 [ Html.div
53 [ Html.div
34 [ class "container" ]
54 [ class "container" ]
55+ [ row
56+ (List.map viewLinks model.data)
57+ , row
35− ([ viewNodes model.data
58+ [ viewNodes model.data
36− , viewFps model.data
59+ , viewFps model.data
37− , viewTimeToPaint model.data
60+ , viewTimeToPaint model.data
38− ]
61+ ]
62+ , row
63+ [ column
64+ (List.map
65+ (\data ->
66+ viewRenderBreakdown
67+ { get = .coldRender
68+ , getCount = .count
69+ , name = data.name
70+ , flavor = "Cold render"
71+ , range = (0, 1.2)
72+ }
73+ (List.sortBy .count data.results)
74+ )
75+ model.data
76+ )
77+ , column
78+ (List.map
79+ (\data ->
80+ viewRenderBreakdown
81+ { get = .warmRender
82+ , getCount = .count
83+ , name = data.name
84+ , flavor = "Warm render"
85+ , range = (0, 1.2)
86+ }
87+ (List.sortBy .count data.results)
88+ )
89+ model.data
90+ )
91+ , column
92+ (List.map
93+ (\data ->
94+ viewRenderBreakdown
95+ { get = .extendedRender
96+ , getCount = .count
97+ , name = data.name
98+ , flavor = "Long Animation"
99+ , range = (0, 5)
100+ }
101+ (List.sortBy .count data.results)
102+ )
39− ++ List.map viewTimeDistribution model.data
103+ model.data
40− )
104+ )
105+ ]
106+ ]
41 ]
107 ]
42 }
108 }
43 , update =
109 , update =
@@ -61,6 +127,20 @@ update msg model =
61 ( { data = data }, Cmd.none )
127 ( { data = data }, Cmd.none )
62
128
63
129
130+viewLinks data =
131+ column
132+ (Html.h2 [] [ Html.text data.name ]
133+ :: (data.results
134+ |> List.sortBy .link
135+ |> List.map viewSingleLink
136+ )
137+ )
138+
139+
140+viewSingleLink result =
141+ Html.a [ Attr.href result.link ] [ Html.text result.name ]
142+
143+
64
144
65-- DATA
145-- DATA
66
146
@@ -79,11 +159,23 @@ type alias Data =
79
159
80
160
81type alias Render =
161type alias Render =
162+ { name : String
82− { count : Float
163+ , count : Float
83 , fps : Float
164 , fps : Float
84 , timeToFirstPaintMS : Float
165 , timeToFirstPaintMS : Float
85 , nodes : Float
166 , nodes : Float
167+ , link : String
168+ , coldRender :
169+ Breakdown
170+ , warmRender :
171+ Breakdown
172+ , extendedRender :
173+ Breakdown
174+ }
175+
176+
177+type alias Breakdown =
86− , layoutSeconds : Float
178+ { layoutSeconds : Float
87 , recalcStyleSeconds : Float
179 , recalcStyleSeconds : Float
88 , scriptDurationSeconds : Float
180 , scriptDurationSeconds : Float
89 }
181 }
@@ -112,12 +204,27 @@ getShape i =
112 Dots.triangle
204 Dots.triangle
113
205
114
206
207+graphWidth =
208+ 800
209+
210+
211+graphHeight =
212+ 500
213+
214+
215+container =
216+ Container.styled "line-chart-1"
217+ [ ( "font-family", "monospace" )
218+ , ( "flex-shrink", "0" )
219+ ]
220+
221+
115viewFps : List Data -> Html.Html msg
222viewFps : List Data -> Html.Html msg
116viewFps datums =
223viewFps datums =
117 LineChart.viewCustom
224 LineChart.viewCustom
118− { y = Axis.default 800 "FPS" .fps
225+ { y = Axis.default graphHeight "FPS" .fps
119− , x = Axis.default 1400 "Base Count" .count
226+ , x = Axis.default graphWidth "Base Count" .count
120− , container = Container.styled "line-chart-1" [ ( "font-family", "monospace" ) ]
227+ , container = container
121 , interpolation =
228 , interpolation =
122 -- Try out these different configs!
229 -- Try out these different configs!
123 -- Interpolation.linear
230 -- Interpolation.linear
@@ -143,9 +250,9 @@ viewResult i data =
143viewTimeToPaint : List Data -> Html.Html msg
250viewTimeToPaint : List Data -> Html.Html msg
144viewTimeToPaint datums =
251viewTimeToPaint datums =
145 LineChart.viewCustom
252 LineChart.viewCustom
146− { y = Axis.default 800 "First Paint" (max 0 << .timeToFirstPaintMS)
253+ { y = Axis.default graphHeight "First Paint" (max 0 << .timeToFirstPaintMS)
147− , x = Axis.default 1400 "Base Count" .count
254+ , x = Axis.default graphWidth "Base Count" .count
148− , container = Container.styled "line-chart-1" [ ( "font-family", "monospace" ) ]
255+ , container = container
149 , interpolation =
256 , interpolation =
150 -- Try out these different configs!
257 -- Try out these different configs!
151 -- Interpolation.linear
258 -- Interpolation.linear
@@ -167,9 +274,9 @@ viewTimeToPaint datums =
167viewNodes : List Data -> Html.Html msg
274viewNodes : List Data -> Html.Html msg
168viewNodes datums =
275viewNodes datums =
169 LineChart.viewCustom
276 LineChart.viewCustom
170− { y = Axis.default 800 "Nodes" .nodes
277+ { y = Axis.default graphHeight "Nodes" .nodes
171− , x = Axis.default 1400 "Base Count" .count
278+ , x = Axis.default graphWidth "Base Count" .count
172− , container = Container.styled "line-chart-1" [ ( "font-family", "monospace" ) ]
279+ , container = container
173 , interpolation =
280 , interpolation =
174 -- Try out these different configs!
281 -- Try out these different configs!
175 -- Interpolation.linear
282 -- Interpolation.linear
@@ -188,62 +295,79 @@ viewNodes datums =
188 (List.indexedMap viewResult datums)
295 (List.indexedMap viewResult datums)
189
296
190
297
298+viewRenderBreakdown :
299+ { get : Render -> Breakdown
300+ , getCount : Render -> Float
301+ , name : String
302+ , flavor : String
303+ , range : (Float, Float)
304+ }
305+ -> List Render
191−viewTimeDistribution : Data -> Html.Html msg
306+ -> Html.Html msg
192−viewTimeDistribution data =
307+viewRenderBreakdown { get, getCount, name, flavor, range } results =
193− let
308+ Html.div []
194− sorted =
309+ [ Html.h2 [] [ Html.text (name ++ ", " ++ flavor) ]
195− List.sortBy .count data.results
196− in
197− LineChart.viewCustom
310+ , LineChart.viewCustom
198− { y = Axis.default 800 (data.name ++ "(s)") .seconds
311+ { y =
199− , x = Axis.default 1400 "Base Count" .count
312+ Axis.custom
200− , container = Container.styled "line-chart-1" [ ( "font-family", "monospace" ) ]
313+ { title = Title.default (name ++ "(s)")
201− , interpolation =
314+ , variable = Just << .seconds
202− -- Try out these different configs!
315+ , pixels = graphHeight
203− -- Interpolation.linear
316+ , range = Range.window (Tuple.first range) (Tuple.second range)
204− Interpolation.monotone
317+ , axisLine = AxisLine.full Colors.black
205−
318+ , ticks = Ticks.default
206− -- Interpolation.stepped
207− , intersection = Intersection.default
208− , legends = Legends.default
209− , events = Events.default
210− , junk = Junk.default
211− , grid = Grid.default
212− , area = Area.stacked 0.5
213− , line = Line.default
214− , dots = Dots.default
215− }
216− [ LineChart.line (getColor 0)
217− (getShape 0)
218− "Layout"
219− (List.map
220− (\x ->
221− { seconds = x.layoutSeconds
222− , count = x.count
223 }
319 }
320+ , x = Axis.default graphWidth "Base Count" .count
321+ , container = container
322+ , interpolation =
323+ -- Try out these different configs!
324+ -- Interpolation.linear
325+ Interpolation.monotone
326+
327+ -- Interpolation.stepped
328+ , intersection = Intersection.default
329+ , legends = Legends.default
330+ , events = Events.default
331+ , junk = Junk.default
332+ , grid = Grid.default
333+ , area = Area.stacked 0.5
334+ , line = Line.default
335+ , dots = Dots.default
336+ }
337+ [ LineChart.line (getColor 0)
338+ (getShape 0)
339+ "Layout"
340+ (List.map
341+ (\x ->
342+ { seconds = .layoutSeconds (get x)
343+ , count = getCount x
344+ }
345+ )
346+ results
224 )
347 )
225− sorted
226− )
227− , LineChart.line (getColor 1)
348+ , LineChart.line (getColor 1)
228− (getShape 1)
349+ (getShape 1)
229− "RecalcStyle"
350+ "RecalcStyle"
230− (List.map
351+ (List.map
231− (\x ->
352+ (\x ->
353+ { seconds =
232− { seconds = x.recalcStyleSeconds
354+ .recalcStyleSeconds (get x)
233− , count = x.count
355+ , count = getCount x
234− }
356+ }
357+ )
358+ results
235 )
359 )
236− sorted
237− )
238− , LineChart.line (getColor 2)
360+ , LineChart.line (getColor 2)
239− (getShape 2)
361+ (getShape 2)
240− "Script"
362+ "Script"
241− (List.map
363+ (List.map
242− (\x ->
364+ (\x ->
365+ { seconds =
243− { seconds = x.scriptDurationSeconds
366+ .scriptDurationSeconds (get x)
244− , count = x.count
367+ , count = getCount x
245− }
368+ }
369+ )
370+ results
246 )
371 )
247− sorted
372+ ]
248− )
249 ]
373 ]
src/Internal/Model.elm+1
@@ -16,6 +16,7 @@ module Internal.Model exposing
16 , LayoutContext(..)
16 , LayoutContext(..)
17 , Length(..)
17 , Length(..)
18 , Location(..)
18 , Location(..)
19+ , NearbyChildren(..)
19 , NodeName(..)
20 , NodeName(..)
20 , Option(..)
21 , Option(..)
21 , OptionRecord
22 , OptionRecord