on master help sign in
Get todomvc benchmarks running
commitf232429ba90e297a0ea95cc9f5f7f81b27828f8a authorEvan Czaplicki <info@elm-lang.org> dateWed 7 Oct 2015, 18:23 (11 years ago) parent7a6f406
4 files changed+121−85
bench/elm-package.json+3−2 bench/src/Benchmark.elm+25−25 bench/src/Main.elm+9−9 bench/src/Realistic/Todo.elm+84−49
bench/elm-package.json+3−2
@@ -9,7 +9,8 @@
99 "exposed-modules": [],
1010 "native-modules": true,
1111 "dependencies": {
12− "elm-lang/core": "3.0.0 <= v < 4.0.0"
12+ "elm-lang/core": "3.0.0 <= v < 4.0.0",
13+ "evancz/elm-html": "4.0.2 <= v < 5.0.0"
1314 },
1415 "elm-version": "0.16.0 <= v < 0.17.0"
15−}
16+}
bench/src/Benchmark.elm+25−25
@@ -1,15 +1,15 @@
11module Benchmark
2− ( Suite
3− , bench
2+ ( Benchmark
3+ , test
44 , suite
55 , run
66 , Statistics
7− , statisticsToString
7+ , view
88 )where
99{-| A wrapper around benchmark.js that allows benchmarking of pure functions.
1010
1111# Creating Benchmarks
12−@docs Benchmark, bench, suite
12+@docs Benchmark, test, suite
1313
1414# Run benchmarks
1515@docs run, Statistics
@@ -20,6 +20,8 @@ import Native.Benchmark
2020import Native.BenchmarkJS
2121import String
2222import Task
23+import Html exposing (Html, div, ul, li, p, text)
24+import Html.Attributes exposing (style)
2325
2426
2527
@@ -38,8 +40,8 @@ type Thunk = Thunk
3840{-| An individual benchmark with a name. It measures how long it takes to
3941evaluate the given function when it is passed a `()` value.
4042-}
41−bench : String -> (() -> result) -> Benchmark
42−bench name thunk =
43+test : String -> (() -> result) -> Benchmark
44+test name thunk =
4345 Test name (Native.Benchmark.makeThunk thunk)
4446
4547
@@ -59,6 +61,7 @@ type Statistics
5961 = StatSuite String (List Statistics)
6062 | Result String
6163 { mean : Float
64+ , hz : Float
6265 }
6366
6467
@@ -70,31 +73,28 @@ run =
7073
7174
7275
73−-- TO STRING
76+-- TO HTML
7477
7578
76−statisticsToString : Statistics -> String
77−statisticsToString statistics =
78− List.join "\n" (statisticsToStringHelp statistics)
79+view : Statistics -> Html
80+view statistics =
81+ div [ style [] ]
82+ [ viewHelp statistics
83+ ]
7984
8085
81−statisticsToStringHelp : Statistics -> (List String, Float)
82−statisticsToStringHelp statistics =
86+viewHelp : Statistics -> Html
87+viewHelp statistics =
8388 case statistics of
84− Result name {mean} ->
85− ( [ name ++ " - " ++ toString mean ]
86− , mean
87− )
89+ Result name {hz} ->
90+ text (name ++ " - " ++ toString hz ++ " ops/sec")
8891
8992 StatSuite name subStats ->
9093 let
91− (strings, subMeans) =
92− List.unzip (List.map statisticsToStringHelp subStats)
93−
94− total =
95− List.sum means
94+ subResults =
95+ List.map viewHelp subStats
9696 in
97− ( name ++ " - " ++ toString total
98− :: List.map (String.padLeft 4 ' ') (List.concat strings)
99− , total
100− )
97+ p []
98+ [ text name
99+ , ul [] (List.map (\html -> li [] [html]) subResults)
100+ ]
bench/src/Main.elm+9−9
@@ -1,9 +1,8 @@
11module Main where
22
3−import Graphics.Element exposing (leftAligned)
3+import Html exposing (Html, text)
44import Signal
55import Task
6−import Text
76
87import Benchmark
98import Realistic.Todo as Todo
@@ -11,24 +10,25 @@ import Realistic.Todo as Todo
1110
1211-- COMPILER BENCHMARK
1312
14−compilerBenchmark : List Benchmark.Benchmark
13+compilerBenchmark : Benchmark.Benchmark
1514compilerBenchmark =
16− [ Todo.benchmark
17− ]
15+ Benchmark.suite "generated code"
16+ [ Todo.benchmark
17+ ]
1818
1919
2020-- DISPLAY THINGS
2121
2222main =
23− Signal.map (leftAligned << Text.fromString) results.signal
23+ results.signal
2424
2525
26−results : Signal.Mailbox String
26+results : Signal.Mailbox Html
2727results =
28− Signal.mailbox "Working..."
28+ Signal.mailbox (text "Working...")
2929
3030
3131port benchResults : Task.Task x ()
3232port benchResults =
3333 Benchmark.run compilerBenchmark
34− `Task.andThen` (Benchmark.statisticsToString >> Signal.send results.address)
34+ `Task.andThen` (Benchmark.view >> Signal.send results.address)
bench/src/Realistic/Todo.elm+84−49
@@ -1,10 +1,72 @@
1−module TodoBench where
1+module Realistic.Todo (benchmark) where
22
3+import Benchmark
34import String
45
5−---- MODEL ----
66
7−-- The full application state of our todo app.
7+benchmark : Benchmark.Benchmark
8+benchmark =
9+ Benchmark.suite "todomvc business logic"
10+ [ run "type in 5 todos, each 15 characters long" typingActions
11+ , run "do everything" batchActions
12+ ]
13+
14+
15+run : String -> List Action -> Benchmark.Benchmark
16+run description actions =
17+ Benchmark.test
18+ (description ++ " - " ++ toString (List.length actions) ++ " actions")
19+ (\_ -> List.foldl update emptyModel actions)
20+
21+
22+typingActions =
23+ let
24+ enter i =
25+ List.map (\n -> UpdateField (String.repeat n "X")) [1..15]
26+ ++ [ Add ]
27+ in
28+ List.concatMap enter [1..5]
29+
30+
31+batchActions =
32+ let
33+ addTask i =
34+ [ UpdateField ("My task " ++ toString i)
35+ , Add
36+ ]
37+
38+ editTask i =
39+ [ EditingTask i True
40+ , UpdateTask i "New Task text"
41+ , EditingTask i False
42+ ]
43+
44+ check i =
45+ Check i True
46+
47+ uncheck i =
48+ Check i False
49+
50+ isEven i =
51+ i % 2 == 0
52+ in
53+ List.concat
54+ [ List.concatMap addTask [1..50]
55+ , [CheckAll True, CheckAll False]
56+ , List.concatMap editTask (List.filter isEven [1 .. 50])
57+ , List.map check [5, 7, 9, 13, 17, 23, 37]
58+ , List.map uncheck [7, 13, 23, 37]
59+ , [DeleteComplete, Delete 7, Delete 23]
60+ , List.concatMap addTask [51..80]
61+ , List.map check (List.filter isEven [51..80])
62+ , [DeleteComplete, CheckAll True, DeleteComplete]
63+ ]
64+
65+
66+
67+-- MODEL
68+
69+
870type alias Model =
971 { tasks : List Task
1072 , field : String
@@ -39,11 +101,10 @@ emptyModel =
39101 }
40102
41103
42−---- UPDATE ----
43104
44−-- A description of the kinds of actions that can be performed on the model of
45−-- our application. See the following post for more info on this pattern and
46−-- some alternatives: http://elm-lang.org/learn/Architecture.elm
105+-- UPDATE
106+
107+
47108type Action
48109 = NoOp
49110 | UpdateField String
@@ -57,7 +118,6 @@ type Action
57118 | ChangeVisibility String
58119
59120
60−-- How we update our Model on a given Action?
61121update : Action -> Model -> Model
62122update action model =
63123 case action of
@@ -65,68 +125,43 @@ update action model =
65125
66126 Add ->
67127 { model |
68− uid <- model.uid + 1,
69− field <- "",
70− tasks <-
128+ uid = model.uid + 1,
129+ field = "",
130+ tasks =
71131 if String.isEmpty model.field
72132 then model.tasks
73133 else model.tasks ++ [newTask model.field model.uid]
74134 }
75135
76136 UpdateField str ->
77− { model | field <- str }
137+ { model | field = str }
78138
79139 EditingTask id isEditing ->
80− let updateTask t = if t.id == id then { t | editing <- isEditing } else t
140+ let updateTask t = if t.id == id then { t | editing = isEditing } else t
81141 in
82− { model | tasks <- List.map updateTask model.tasks }
142+ { model | tasks = List.map updateTask model.tasks }
83143
84144 UpdateTask id task ->
85− let updateTask t = if t.id == id then { t | description <- task } else t
145+ let updateTask t = if t.id == id then { t | description = task } else t
86146 in
87− { model | tasks <- List.map updateTask model.tasks }
147+ { model | tasks = List.map updateTask model.tasks }
88148
89149 Delete id ->
90− { model | tasks <- List.filter (\t -> t.id /= id) model.tasks }
150+ { model | tasks = List.filter (\t -> t.id /= id) model.tasks }
91151
92152 DeleteComplete ->
93− { model | tasks <- List.filter (not << .completed) model.tasks }
153+ { model | tasks = List.filter (not << .completed) model.tasks }
94154
95155 Check id isCompleted ->
96− let updateTask t = if t.id == id then { t | completed <- isCompleted } else t
156+ let updateTask t = if t.id == id then { t | completed = isCompleted } else t
97157 in
98− { model | tasks <- List.map updateTask model.tasks }
158+ { model | tasks = List.map updateTask model.tasks }
99159
100160 CheckAll isCompleted ->
101− let updateTask t = { t | completed <- isCompleted }
161+ let updateTask t = { t | completed = isCompleted }
102162 in
103− { model | tasks <- List.map updateTask model.tasks }
163+ { model | tasks = List.map updateTask model.tasks }
104164
105165 ChangeVisibility visibility ->
106− { model | visibility <- visibility }
107−
108−testActions =
109− List.concat
110− [ List.concatMap --Add 50 tasks
111− (\i -> [UpdateField <| "My task " ++ toString i, Add]) [1 .. 50]
112− , [CheckAll True] --Check them all
113− , [CheckAll False] --Uncheck them all
114− , List.concatMap --Alter the text of even numbered tasks
115− (\i -> [EditingTask i True, UpdateTask i "New Task text", Add] ) <| List.filter (\x -> x % 2 == 0 ) [1 .. 50]
116− --Check and uncheck some more tasks
117− , [Check 5 True, Check 7 True, Check 9 True, Check 13 True, Check 17 True, Check 23 True, Check 37 True]
118− , [Check 7 False, Check 13 False, Check 23 False, Check 37 False]
119− , [DeleteComplete] --Delete our checked tasks
120− , [Delete 7, Delete 23] --Delete a few more tasks
121− , List.concatMap --Add a few more tasks
122− (\i -> [UpdateField <| "Second batch task " ++ toString i, Add]) [51 .. 80]
123− , List.map --Check off and delete every other task
124− (\i -> Check i True ) <| List.filter (\x -> x % 2 == 0 ) [1 .. 80]
125− , [DeleteComplete]
126− , [CheckAll True, DeleteComplete] --Check and delete the remaining tasks
127− ]
128−
129−
130−evalActions : List Action -> Model
131−evalActions actions =
132− List.foldr update emptyModel actions
166+ { model | visibility = visibility }
167+