on master help sign in
Get todomvc benchmarks running
f232429Evan Czaplicki
bench/elm-package.json+3−2
@@ -9,7 +9,8 @@
9 "exposed-modules": [],
9 "exposed-modules": [],
10 "native-modules": true,
10 "native-modules": true,
11 "dependencies": {
11 "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"
13 },
14 },
14 "elm-version": "0.16.0 <= v < 0.17.0"
15 "elm-version": "0.16.0 <= v < 0.17.0"
15−}
16+}
bench/src/Benchmark.elm+25−25
@@ -1,15 +1,15 @@
1module Benchmark
1module Benchmark
2− ( Suite
2+ ( Benchmark
3− , bench
3+ , test
4 , suite
4 , suite
5 , run
5 , run
6 , Statistics
6 , Statistics
7− , statisticsToString
7+ , view
8 )where
8 )where
9{-| A wrapper around benchmark.js that allows benchmarking of pure functions.
9{-| A wrapper around benchmark.js that allows benchmarking of pure functions.
10
10
11# Creating Benchmarks
11# Creating Benchmarks
12−@docs Benchmark, bench, suite
12+@docs Benchmark, test, suite
13
13
14# Run benchmarks
14# Run benchmarks
15@docs run, Statistics
15@docs run, Statistics
@@ -20,6 +20,8 @@ import Native.Benchmark
20import Native.BenchmarkJS
20import Native.BenchmarkJS
21import String
21import String
22import Task
22import Task
23+import Html exposing (Html, div, ul, li, p, text)
24+import Html.Attributes exposing (style)
23
25
24
26
25
27
@@ -38,8 +40,8 @@ type Thunk = Thunk
38{-| An individual benchmark with a name. It measures how long it takes to
40{-| An individual benchmark with a name. It measures how long it takes to
39evaluate the given function when it is passed a `()` value.
41evaluate the given function when it is passed a `()` value.
40-}
42-}
41−bench : String -> (() -> result) -> Benchmark
43+test : String -> (() -> result) -> Benchmark
42−bench name thunk =
44+test name thunk =
43 Test name (Native.Benchmark.makeThunk thunk)
45 Test name (Native.Benchmark.makeThunk thunk)
44
46
45
47
@@ -59,6 +61,7 @@ type Statistics
59 = StatSuite String (List Statistics)
61 = StatSuite String (List Statistics)
60 | Result String
62 | Result String
61 { mean : Float
63 { mean : Float
64+ , hz : Float
62 }
65 }
63
66
64
67
@@ -70,31 +73,28 @@ run =
70
73
71
74
72
75
73−-- TO STRING
76+-- TO HTML
74
77
75
78
76−statisticsToString : Statistics -> String
79+view : Statistics -> Html
77−statisticsToString statistics =
80+view statistics =
78− List.join "\n" (statisticsToStringHelp statistics)
81+ div [ style [] ]
82+ [ viewHelp statistics
83+ ]
79
84
80
85
81−statisticsToStringHelp : Statistics -> (List String, Float)
86+viewHelp : Statistics -> Html
82−statisticsToStringHelp statistics =
87+viewHelp statistics =
83 case statistics of
88 case statistics of
84− Result name {mean} ->
89+ Result name {hz} ->
85− ( [ name ++ " - " ++ toString mean ]
90+ text (name ++ " - " ++ toString hz ++ " ops/sec")
86− , mean
87− )
88
91
89 StatSuite name subStats ->
92 StatSuite name subStats ->
90 let
93 let
91− (strings, subMeans) =
94+ subResults =
92− List.unzip (List.map statisticsToStringHelp subStats)
95+ List.map viewHelp subStats
93−
94− total =
95− List.sum means
96 in
96 in
97− ( name ++ " - " ++ toString total
97+ p []
98− :: List.map (String.padLeft 4 ' ') (List.concat strings)
98+ [ text name
99− , total
99+ , ul [] (List.map (\html -> li [] [html]) subResults)
100− )
100+ ]
bench/src/Main.elm+9−9
@@ -1,9 +1,8 @@
1module Main where
1module Main where
2
2
3−import Graphics.Element exposing (leftAligned)
3+import Html exposing (Html, text)
4import Signal
4import Signal
5import Task
5import Task
6−import Text
7
6
8import Benchmark
7import Benchmark
9import Realistic.Todo as Todo
8import Realistic.Todo as Todo
@@ -11,24 +10,25 @@ import Realistic.Todo as Todo
11
10
12-- COMPILER BENCHMARK
11-- COMPILER BENCHMARK
13
12
14−compilerBenchmark : List Benchmark.Benchmark
13+compilerBenchmark : Benchmark.Benchmark
15compilerBenchmark =
14compilerBenchmark =
15+ Benchmark.suite "generated code"
16− [ Todo.benchmark
16+ [ Todo.benchmark
17− ]
17+ ]
18
18
19
19
20-- DISPLAY THINGS
20-- DISPLAY THINGS
21
21
22main =
22main =
23− Signal.map (leftAligned << Text.fromString) results.signal
23+ results.signal
24
24
25
25
26−results : Signal.Mailbox String
26+results : Signal.Mailbox Html
27results =
27results =
28− Signal.mailbox "Working..."
28+ Signal.mailbox (text "Working...")
29
29
30
30
31port benchResults : Task.Task x ()
31port benchResults : Task.Task x ()
32port benchResults =
32port benchResults =
33 Benchmark.run compilerBenchmark
33 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
2
2
3+import Benchmark
3import String
4import String
4
5
5−---- MODEL ----
6
6
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+
8type alias Model =
70type alias Model =
9 { tasks : List Task
71 { tasks : List Task
10 , field : String
72 , field : String
@@ -39,11 +101,10 @@ emptyModel =
39 }
101 }
40
102
41
103
42−---- UPDATE ----
43
104
44−-- A description of the kinds of actions that can be performed on the model of
105+-- UPDATE
45−-- our application. See the following post for more info on this pattern and
106+
46−-- some alternatives: http://elm-lang.org/learn/Architecture.elm
107+
47type Action
108type Action
48 = NoOp
109 = NoOp
49 | UpdateField String
110 | UpdateField String
@@ -57,7 +118,6 @@ type Action
57 | ChangeVisibility String
118 | ChangeVisibility String
58
119
59
120
60−-- How we update our Model on a given Action?
61update : Action -> Model -> Model
121update : Action -> Model -> Model
62update action model =
122update action model =
63 case action of
123 case action of
@@ -65,68 +125,43 @@ update action model =
65
125
66 Add ->
126 Add ->
67 { model |
127 { model |
68− uid <- model.uid + 1,
128+ uid = model.uid + 1,
69− field <- "",
129+ field = "",
70− tasks <-
130+ tasks =
71 if String.isEmpty model.field
131 if String.isEmpty model.field
72 then model.tasks
132 then model.tasks
73 else model.tasks ++ [newTask model.field model.uid]
133 else model.tasks ++ [newTask model.field model.uid]
74 }
134 }
75
135
76 UpdateField str ->
136 UpdateField str ->
77− { model | field <- str }
137+ { model | field = str }
78
138
79 EditingTask id isEditing ->
139 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
81 in
141 in
82− { model | tasks <- List.map updateTask model.tasks }
142+ { model | tasks = List.map updateTask model.tasks }
83
143
84 UpdateTask id task ->
144 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
86 in
146 in
87− { model | tasks <- List.map updateTask model.tasks }
147+ { model | tasks = List.map updateTask model.tasks }
88
148
89 Delete id ->
149 Delete id ->
90− { model | tasks <- List.filter (\t -> t.id /= id) model.tasks }
150+ { model | tasks = List.filter (\t -> t.id /= id) model.tasks }
91
151
92 DeleteComplete ->
152 DeleteComplete ->
93− { model | tasks <- List.filter (not << .completed) model.tasks }
153+ { model | tasks = List.filter (not << .completed) model.tasks }
94
154
95 Check id isCompleted ->
155 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
97 in
157 in
98− { model | tasks <- List.map updateTask model.tasks }
158+ { model | tasks = List.map updateTask model.tasks }
99
159
100 CheckAll isCompleted ->
160 CheckAll isCompleted ->
101− let updateTask t = { t | completed <- isCompleted }
161+ let updateTask t = { t | completed = isCompleted }
102 in
162 in
103− { model | tasks <- List.map updateTask model.tasks }
163+ { model | tasks = List.map updateTask model.tasks }
104
164
105 ChangeVisibility visibility ->
165 ChangeVisibility visibility ->
106− { model | visibility <- visibility }
166+ { model | visibility = visibility }
107−
167+
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