on master help sign in
Merge pull request #1023 from JoeyEremondi/bench
440c663Evan Czaplicki
bench/CompilerBenchmarks.elmnew file+165
@@ -0,0 +1,165 @@
1+import Graphics.Element exposing (show)
2+import Signal
3+import Benchmark
4+import Task exposing (Task, andThen)
5+import Text
6+import Array
7+import Random
8+import Dict
9+import Time
10+
11+import LargeDictionary
12+import ArrayBench
13+import ListBench
14+
15+import RecordBench
16+import SmallRecordBench
17+import TupleBench
18+import SmallTupleBench
19+import CtorBench
20+import SmallCtorBench
21+import PatternMatchBench
22+import IfBench
23+import DictBench
24+
25+import AnimateBench
26+import TodoBench
27+
28+{-| Compile this with --output=Benchmarks.html to generate
29+ a webpage, which runs the benchmarks and shows the results.
30+-}
31+
32+
33+mySuite =
34+ Benchmark.Suite "My Suite"
35+ [ Benchmark.bench1 "Access 20-field record 200 times: " RecordBench.sumRandomElems indices200
36+ , Benchmark.bench1 "Access 9-field record 200 times: " SmallRecordBench.sumRandomElems indices200
37+
38+ , Benchmark.bench1 "Access 9-field tuple 200 times: " TupleBench.sumRandomElems indices200
39+ , Benchmark.bench1 "Access 3-field tuple 200 times: " SmallTupleBench.sumRandomElems indices200
40+
41+ , Benchmark.bench1 "Access 20-constructor Type 200 times: " CtorBench.sumFieldsList ctorData200
42+ , Benchmark.bench1 "Access 10-constructor Type 200 times: " SmallCtorBench.sumFieldsList smallCtorData200
43+
44+ , Benchmark.bench1 "Tail-recursive if function, called 200 times: " IfBench.tailRecSum indices200
45+ , Benchmark.bench1 "If expression with 20 branches, called 200 times: " IfBench.manyConditionalSum indices200
46+ , Benchmark.bench1 "If expression with 4 branches, called 200 times: " IfBench.fewConditionalSum indices200
47+
48+ , Benchmark.bench1 "Pattern match 18-levels deep, use all values, 200 times " PatternMatchBench.deepMatchSum nestedData200
49+ , Benchmark.bench1 "Pattern match 18-levels deep, 16 wildcards, 200 times " PatternMatchBench.wildcardMatchSum nestedData200
50+ , Benchmark.bench1 "Pattern match 4-levels deep, use all values, 200 times " PatternMatchBench.shallowMatchSum nestedData200
51+
52+ , Benchmark.bench1 "Make and sum dict, 10000 elems: " LargeDictionary.addNToDictAndSum 10000
53+ , Benchmark.bench1 "Make and sum dict, 50 elems: " LargeDictionary.addNToDictAndSum 50
54+
55+ , Benchmark.bench1 "Array native foldr, 500 elems: " ArrayBench.foldrMeanStddev array500
56+ , Benchmark.bench1 "Array native foldl, 500 elems: " ArrayBench.foldlMeanStddev array500
57+ , Benchmark.bench1 "Array custom foldr, 500 elems: " ArrayBench.customFoldrMeanStddev array500
58+ , Benchmark.bench1 "Array custom foldl, 500 elems: " ArrayBench.customFoldrMeanStddev array500
59+ , Benchmark.bench3 "Array square nth elem, 500 elems: " ArrayBench.updateNRandomIndices (\x -> x*x) indices200 array500
60+
61+ , Benchmark.bench1 "Dict native foldr, 500 elems: " DictBench.foldrMeanStddev dict500
62+ , Benchmark.bench1 "Dict native foldl, 500 elems: " DictBench.foldlMeanStddev dict500
63+ , Benchmark.bench3 "Dict square nth elem, 500 elems: " DictBench.updateNRandomIndices (\x -> x*x) indices200 dict500
64+
65+ , Benchmark.bench1 "List native foldr, 500 elems: " ListBench.foldrMeanStddev list500
66+ , Benchmark.bench1 "List native foldl, 500 elems: " ListBench.foldlMeanStddev list500
67+ , Benchmark.bench1 "List custom foldr, 500 elems: " ListBench.customFoldrMeanStddev list500
68+ , Benchmark.bench1 "List custom foldl, 500 elems: " ListBench.customFoldrMeanStddev list500
69+ , Benchmark.bench3 "List square nth elem, 500 elems: " ListBench.updateNRandomIndices (\x -> x*x) indices200 list500
70+
71+ , Benchmark.bench2 "200 lookups in array of 500 elems: " ArrayBench.randomLookups indices200 (Array.fromList [1 .. 500] )
72+ , Benchmark.bench2 "200 lookups in list of 500 elems: " ListBench.randomLookups indices200 ([1 .. 500] )
73+ , Benchmark.bench2 "200 lookups in dict of 500 elems: " DictBench.randomLookups indices200 (Dict.fromList (List.map2 (,) [1 .. 500] [1 .. 500]) )
74+
75+ , Benchmark.bench1 "30s simulated animation @ 30fps: " AnimateBench.runAnimation timeSteps30s
76+ , Benchmark.bench1 "TodoMVC: approx. 330 simulated actions " TodoBench.evalActions TodoBench.testActions
77+ ]
78+
79+
80+--Display of results:
81+
82+--Mailbox updated with benchmark run progress
83+results : Signal.Mailbox String
84+results =
85+ Signal.mailbox "Benchmark loading"
86+
87+
88+--The actual task which runs the benchmarks
89+port benchResults : (Task Benchmark.Never ())
90+port benchResults =
91+ Benchmark.runWithProgress (Just results) mySuite
92+ `andThen` \_ -> Task.sleep 0
93+
94+
95+--Our main page:
96+main =
97+ Signal.map (Graphics.Element.leftAligned << Text.fromString) results.signal
98+
99+
100+
101+-- Random generation and structures
102+
103+--Maximum size for random numbers
104+maxSize = 1000000
105+
106+
107+--Random generator for floating point numbers
108+floatGen =
109+ Random.float (-1 * maxSize) (maxSize)
110+
111+
112+--Generate random indices for lists out of 500 elements
113+indexGen =
114+ Random.int (0) (499)
115+
116+
117+--Random seeds: they're fixed, so it's not truly random
118+--But we get seemingly random data, that we can compare fairly
119+--across multiple runs of the benchmark
120+
121+--seed for our index generation
122+indexSeed =
123+ Random.initialSeed 56
124+
125+
126+--Seed for our float generation
127+seed =
128+ Random.initialSeed 23
129+
130+
131+--Pseudo-random array of 500 floating point numbers
132+array500 =
133+ (ArrayBench.randomArray floatGen 500 seed)
134+
135+
136+--Pseudo-random dictionary, indexed 0 .. 500, of 500 floating point numbers
137+dict500 =
138+ (DictBench.randomDict floatGen 500 seed)
139+
140+
141+
142+--Same contents as array500, but in list form
143+list500 =
144+ (ListBench.randomList floatGen 500 seed)
145+
146+
147+--Pseudo random list of 200 indices between 0 and 499
148+indices200 =
149+ (ListBench.randomList indexGen 200 indexSeed)
150+
151+
152+--List of timesteps simulating 30 seconds of animation at 30fps
153+timeSteps30s =
154+ List.map (\x -> (1.0 / 30.0) * (toFloat x * Time.second) ) [1 .. 900]
155+
156+ctorData200 =
157+ List.map CtorBench.makeRandomData indices200
158+
159+
160+smallCtorData200 =
161+ List.map SmallCtorBench.makeRandomData indices200
162+
163+
164+nestedData200 =
165+ List.map PatternMatchBench.intToNest indices200
bench/elm-package.jsonnew file+15
@@ -0,0 +1,15 @@
1+{
2+ "version": "1.0.0",
3+ "summary": "Benchmarking based on benchmark.js",
4+ "repository": "https://github.com/JoeyEremondi/elm-benchmark.git",
5+ "license": "BSD3",
6+ "source-directories": [
7+ "src"
8+ ],
9+ "exposed-modules": [],
10+ "native-modules": true,
11+ "dependencies": {
12+ "elm-lang/core": "2.1.0 <= v < 3.0.0"
13+ },
14+ "elm-version": "0.15.1 <= v < 0.16.0"
15+}
bench/src/AnimateBench.elmnew file+58
@@ -0,0 +1,58 @@
1+module AnimateBench where
2+
3+import Time exposing (Time)
4+
5+
6+{-| Main Spring Type.
7+A spring's behavior is defined by its stiffness and damping parameters.
8+-}
9+type alias Spring a =
10+ { stiffness : Float
11+ , damping : Float
12+ , position : a
13+ , velocity : a
14+ , destination : a
15+ }
16+
17+
18+defaultSpring =
19+ Spring 1.0 0.5 0.0 1.0 100.0
20+
21+
22+epsilon = 0.0001
23+
24+
25+{-| Animate a spring given a framerate.
26+
27+ animate framerate spring
28+-}
29+animate : Time -> Spring Float -> Spring Float
30+animate fpms spring =
31+ let
32+ frameRate = fpms / 1000
33+
34+ fspring = -spring.stiffness * (spring.position - spring.destination)
35+
36+ fdamper = -spring.damping * spring.velocity
37+
38+ a = fspring + fdamper
39+
40+ newV = spring.velocity + a * frameRate
41+ newX = spring.position + newV * frameRate
42+ in
43+ if
44+ abs (newV - spring.velocity) < epsilon && abs (newX - spring.position) < epsilon
45+ then
46+ { spring | position <- spring.destination
47+ , velocity <- 0
48+ }
49+ else
50+ { spring | position <- newX
51+ , velocity <- newV
52+ }
53+
54+
55+
56+runAnimation : List Float -> Spring Float
57+runAnimation timeSteps =
58+ List.foldr animate defaultSpring timeSteps
bench/src/ArrayBench.elmnew file+94
@@ -0,0 +1,94 @@
1+module ArrayBench where
2+
3+import Array
4+import Random
5+import Debug exposing (crash)
6+
7+
8+
9+randomArray
10+ : Random.Generator a
11+ -> Int
12+ -> Random.Seed
13+ -> Array.Array a
14+randomArray gen n initSeed =
15+ let
16+ f n (seed, accum) =
17+ let
18+ (nextToAdd, newSeed) = Random.generate gen seed
19+ newAccum = Array.push nextToAdd accum
20+ in (newSeed, newAccum)
21+ in
22+ snd <| List.foldl f (initSeed, Array.empty) [1 .. n]
23+
24+meanAndStddev
25+ : ((Float -> (Float, Float) -> (Float, Float)) -> (Float, Float) -> Array.Array Float -> (Float, Float))
26+ -> Array.Array Float
27+ -> (Float, Float)
28+meanAndStddev foldFn ourArray =
29+ let
30+ --ourArray = randomArray n (Random.initialSeed 23)
31+ (theSum, sumSq) = foldFn (\x (sum, sumSq) -> (x + sum, (x^2) + sumSq) ) (0,0) ourArray
32+ in
33+ (theSum, sqrt(theSum*theSum - sumSq))
34+
35+
36+foldrMeanStddev = meanAndStddev Array.foldr
37+
38+
39+foldlMeanStddev = meanAndStddev Array.foldl
40+
41+
42+customFoldrMeanStddev = meanAndStddev myFoldr
43+
44+
45+customFoldlMeanStddev = meanAndStddev myFoldl
46+
47+
48+updateNRandomIndices
49+ : (Float -> Float)
50+ -> List Int
51+ -> Array.Array Float
52+ -> Array.Array Float
53+updateNRandomIndices f indexList startList =
54+ List.foldr
55+ (\ i oldList -> updateN i f oldList)
56+ startList indexList
57+
58+
59+randomLookups : List Int -> Array.Array Float -> List (Maybe Float)
60+randomLookups indices arr =
61+ List.map (\i -> Array.get i arr) indices
62+
63+
64+myFoldl : (a -> b -> b) -> b -> Array.Array a -> b
65+myFoldl f init arr =
66+ let
67+ len = Array.length arr
68+ fromJust (Just x) = x
69+ helper init i =
70+ if (i >= len)
71+ then init
72+ else
73+ helper (f (fromJust <| Array.get i arr) init) (i+1)
74+ in helper init 0
75+
76+
77+myFoldr : (a -> b -> b) -> b -> Array.Array a -> b
78+myFoldr f init arr =
79+ let
80+ len = Array.length arr
81+ fromJust (Just x) = x
82+ helper init i =
83+ if (i <= 0)
84+ then init
85+ else
86+ helper (f (fromJust <| Array.get i arr) init) (i-1)
87+ in helper init (len-1)
88+
89+
90+updateN : Int -> (a -> a) -> Array.Array a -> Array.Array a
91+updateN n f arr =
92+ case Array.get n arr of
93+ Just x -> Array.set n (f x) arr
94+ _ -> crash "Array out of bounds"
bench/src/Benchmark.elmnew file+212
@@ -0,0 +1,212 @@
1+module Benchmark
2+ ( Never
3+ , Benchmark
4+ , Suite (..)
5+ , BenchStats
6+ , run
7+ , runWithProgress
8+ , bench
9+ , bench1
10+ , bench2
11+ , bench3
12+ , bench4
13+ , bench5
14+ , bench6
15+ , bench7
16+ , bench8
17+ , bench9
18+ )where
19+{-| A wrapper around benchmark.js that allows benchmarking
20+of pure functions to be evaluated.
21+
22+# Error and Benchmark types
23+@docs Never, Benchmark, Suite, BenchStats
24+
25+# Running benchmarks
26+@docs run, runWithProgress
27+
28+# Creating benchmarks
29+@docs bench, bench1, bench2, bench3, bench4, bench5, bench6, bench7, bench8, bench9
30+-}
31+
32+
33+import Task
34+import String
35+import Native.Benchmark
36+import Native.BenchmarkJS
37+import Signal
38+import Time
39+
40+
41+{-|
42+Our error return type: can never be instantiated
43+because running benchmarks should not fail
44+|-}
45+type Never =
46+ Never Never
47+
48+
49+{-|
50+Opaque type representing a function to be timed
51+|-}
52+type Benchmark =
53+ Benchmark
54+
55+
56+{-|
57+The results of running a benchmark
58+|-}
59+type BenchStats =
60+ BenchStats
61+ { name : String
62+ , hz : Float
63+ , marginOfError : Float
64+ , moePercent : Float
65+-- , numRunsSampled : Int
66+ }
67+
68+
69+{-|
70+A single or collection of benchmarks
71+that can be run, generating output
72+|-}
73+type Suite =
74+ SingleBenchmark Benchmark
75+ | Suite String (List Benchmark)
76+
77+
78+{-|
79+Run a benchmark, generating a list of results for each benchmark.
80+Results contain a pretty-printed string summary, and a list
81+of detailed data for each benchmark.
82+|-}
83+run
84+ : Suite
85+ -> Task.Task Never (String, List BenchStats)
86+run = runWithProgress Nothing
87+
88+
89+{-|
90+Run a benchmark, generating a list of results for each benchmark
91+and updating a String signal with progress as the benchmarks run
92+|-}
93+runWithProgress
94+ : Maybe (Signal.Mailbox String)
95+ -> Suite
96+ -> Task.Task Never (String, List BenchStats)
97+runWithProgress maybeMailbox suite =
98+ let
99+ ourTask =
100+ case maybeMailbox of
101+ Nothing -> \_ -> Task.sleep 0
102+ Just mailbox ->
103+ \s ->
104+ (Signal.send mailbox.address s
105+ `Task.andThen` \_ -> Task.sleep (5*Time.second))
106+ -- `Task.andThen` \_ -> Task.keepGoing
107+ in
108+ Native.Benchmark.runWithProgress ourTask suite
109+
110+{-|
111+Create a benchmark with the given name
112+running an arbitrary thunk
113+|-}
114+bench : String -> (() -> result) -> Benchmark
115+bench = Native.Benchmark.makeBenchmark
116+
117+
118+{-|
119+Functions for creating named benchmarks with 1 to 9 arguments
120+|-}
121+bench1 : String -> (a -> result) -> a -> Benchmark
122+bench1 name f a =
123+ Native.Benchmark.makeBenchmark name (\_ -> f a)
124+
125+
126+{-||-}
127+bench2 : String -> (a -> b -> result) -> a -> b -> Benchmark
128+bench2 name f a b =
129+ Native.Benchmark.makeBenchmark name (\_ -> f a b)
130+
131+
132+{-||-}
133+bench3 : String -> (a -> b -> c -> result) -> a -> b -> c -> Benchmark
134+bench3 name f a b c =
135+ Native.Benchmark.makeBenchmark name (\_ -> f a b c)
136+
137+
138+{-||-}
139+bench4 : String -> (a -> b -> c -> d -> result) -> a -> b -> c -> d -> Benchmark
140+bench4 name f a b c d =
141+ Native.Benchmark.makeBenchmark name (\_ -> f a b c d)
142+
143+
144+{-||-}
145+bench5 : String -> (a -> b -> c -> d -> e -> result) -> a -> b -> c -> d -> e -> Benchmark
146+bench5 name f a b c d e =
147+ Native.Benchmark.makeBenchmark name (\_ -> f a b c d e)
148+
149+
150+{-||-}
151+bench6 :
152+ String
153+ -> (a -> b -> c -> d -> e -> f -> result)
154+ -> a
155+ -> b
156+ -> c
157+ -> d
158+ -> e
159+ -> f
160+ -> Benchmark
161+bench6 name fn a b c d e f =
162+ Native.Benchmark.makeBenchmark name (\_ -> fn a b c d e f)
163+
164+
165+{-||-}
166+bench7 :
167+ String
168+ -> (a -> b -> c -> d -> e -> f -> g -> result)
169+ -> a
170+ -> b
171+ -> c
172+ -> d
173+ -> e
174+ -> f
175+ -> g
176+ -> Benchmark
177+bench7 name fn a b c d e f g =
178+ Native.Benchmark.makeBenchmark name (\_ -> fn a b c d e f g)
179+
180+
181+{-||-}
182+bench8 :
183+ String
184+ -> (a -> b -> c -> d -> e -> f -> g -> h -> result)
185+ -> a
186+ -> b
187+ -> c
188+ -> d
189+ -> e
190+ -> f
191+ -> g
192+ -> h
193+ -> Benchmark
194+bench8 name fn a b c d e f g h =
195+ Native.Benchmark.makeBenchmark name (\_ -> fn a b c d e f g h)
196+
197+{-||-}
198+bench9 :
199+ String
200+ -> (a -> b -> c -> d -> e -> f -> g -> h -> i -> result)
201+ -> a
202+ -> b
203+ -> c
204+ -> d
205+ -> e
206+ -> f
207+ -> g
208+ -> h
209+ -> i
210+ -> Benchmark
211+bench9 name fn a b c d e f g h i =
212+ Native.Benchmark.makeBenchmark name (\_ -> fn a b c d e f g h i)
bench/src/CtorBench.elmnew file+135
@@ -0,0 +1,135 @@
1+module CtorBench where
2+
3+type ManyCtors =
4+ MyLongNamedCtor1 Float Float Float
5+ | MyLongNamedCtor2 Float Float
6+ | MyLongNamedCtor3 Float Float Float
7+ | MyLongNamedCtor4 Float Float
8+ | MyLongNamedCtor5 Float Float Float
9+ | MyLongNamedCtor6 Float Float
10+ | MyLongNamedCtor7 Float Float Float
11+ | MyLongNamedCtor8 Float Float
12+ | MyLongNamedCtor9 Float Float Float
13+ | MyLongNamedCtor10 Float Float
14+ | MyLongNamedCtor11 Float Float Float
15+ | MyLongNamedCtor12 Float Float
16+ | MyLongNamedCtor13 Float Float Float
17+ | MyLongNamedCtor14 Float Float
18+ | MyLongNamedCtor15 Float Float Float
19+ | MyLongNamedCtor16 Float Float
20+ | MyLongNamedCtor17 Float Float Float
21+ | MyLongNamedCtor18 Float Float
22+ | MyLongNamedCtor19 Float Float Float
23+ | MyLongNamedCtor20 Float Float
24+
25+
26+getFieldSum someData =
27+ case someData of
28+ MyLongNamedCtor1 x y z ->
29+ x + y + z
30+
31+ MyLongNamedCtor3 x y z ->
32+ x + y + z
33+
34+ MyLongNamedCtor5 x y z ->
35+ x + y + z
36+
37+ MyLongNamedCtor7 x y z ->
38+ x + y + z
39+
40+ MyLongNamedCtor9 x y z ->
41+ x + y + z
42+
43+ MyLongNamedCtor11 x y z ->
44+ x + y + z
45+
46+ MyLongNamedCtor13 x y z ->
47+ x + y + z
48+
49+ MyLongNamedCtor15 x y z ->
50+ x + y + z
51+
52+ MyLongNamedCtor17 x y z ->
53+ x + y + z
54+
55+ MyLongNamedCtor19 x y z ->
56+ x + y + z
57+
58+ MyLongNamedCtor20 x y ->
59+ x + y
60+
61+ MyLongNamedCtor18 x y ->
62+ x + y
63+
64+ MyLongNamedCtor16 x y ->
65+ x + y
66+
67+ MyLongNamedCtor14 x y ->
68+ x + y
69+
70+ MyLongNamedCtor12 x y ->
71+ x + y
72+
73+ MyLongNamedCtor10 x y ->
74+ x + y
75+
76+ MyLongNamedCtor8 x y ->
77+ x + y
78+
79+ MyLongNamedCtor6 x y ->
80+ x + y
81+
82+ MyLongNamedCtor4 x y ->
83+ x + y
84+
85+ MyLongNamedCtor2 x y ->
86+ x + y
87+
88+
89+makeRandomData i =
90+ case (i % 20) of
91+ 0 ->
92+ MyLongNamedCtor20 (toFloat i) (toFloat <| i*i)
93+ 1 ->
94+ MyLongNamedCtor1 (toFloat i) (toFloat <| i*i) (toFloat <| i*i*i)
95+ 2 ->
96+ MyLongNamedCtor2 (toFloat i) (toFloat <| i*i)
97+ 3 ->
98+ MyLongNamedCtor3 (toFloat i) (toFloat <| i*i) (toFloat <| i*i*i)
99+ 4 ->
100+ MyLongNamedCtor4 (toFloat i) (toFloat <| i*i)
101+ 5 ->
102+ MyLongNamedCtor5 (toFloat i) (toFloat <| i*i) (toFloat <| i*i*i)
103+ 6 ->
104+ MyLongNamedCtor6 (toFloat i) (toFloat <| i*i)
105+ 7 ->
106+ MyLongNamedCtor7 (toFloat i) (toFloat <| i*i) (toFloat <| i*i*i)
107+ 8 ->
108+ MyLongNamedCtor8 (toFloat i) (toFloat <| i*i)
109+ 9 ->
110+ MyLongNamedCtor9 (toFloat i) (toFloat <| i*i) (toFloat <| i*i*i)
111+ 10 ->
112+ MyLongNamedCtor10 (toFloat i) (toFloat <| i*i)
113+ 11 ->
114+ MyLongNamedCtor11 (toFloat i) (toFloat <| i*i) (toFloat <| i*i*i)
115+ 12 ->
116+ MyLongNamedCtor12 (toFloat i) (toFloat <| i*i)
117+ 13 ->
118+ MyLongNamedCtor13 (toFloat i) (toFloat <| i*i) (toFloat <| i*i*i)
119+ 14 ->
120+ MyLongNamedCtor14 (toFloat i) (toFloat <| i*i)
121+ 15 ->
122+ MyLongNamedCtor15 (toFloat i) (toFloat <| i*i) (toFloat <| i*i*i)
123+ 16 ->
124+ MyLongNamedCtor16 (toFloat i) (toFloat <| i*i)
125+ 17 ->
126+ MyLongNamedCtor17 (toFloat i) (toFloat <| i*i) (toFloat <| i*i*i)
127+ 18 ->
128+ MyLongNamedCtor18 (toFloat i) (toFloat <| i*i)
129+ 19 ->
130+ MyLongNamedCtor19 (toFloat i) (toFloat <| i*i) (toFloat <| i*i*i)
131+
132+
133+sumFieldsList : List ManyCtors -> Float
134+sumFieldsList dataList =
135+ List.foldr (\val sumSoFar -> (getFieldSum val) + sumSoFar ) 0.0 dataList
bench/src/DictBench.elmnew file+63
@@ -0,0 +1,63 @@
1+module DictBench where
2+
3+import Dict
4+import Random
5+import Debug exposing (crash)
6+
7+
8+
9+randomDict
10+ : Random.Generator a
11+ -> Int
12+ -> Random.Seed
13+ -> Dict.Dict Int a
14+randomDict gen n initSeed =
15+ let
16+ f n (seed, accum) =
17+ let
18+ (nextToAdd, newSeed) = Random.generate gen seed
19+ newAccum = Dict.insert n nextToAdd accum
20+ in (newSeed, newAccum)
21+ in
22+ snd <| List.foldl f (initSeed, Dict.empty) [1 .. n]
23+
24+meanAndStddev
25+ : ((Int -> Float -> (Float, Float) -> (Float, Float)) -> (Float, Float) -> Dict.Dict Int Float -> (Float, Float))
26+ -> Dict.Dict Int Float
27+ -> (Float, Float)
28+meanAndStddev foldFn ourDict =
29+ let
30+ --ourDict = randomDict n (Random.initialSeed 23)
31+ (theSum, sumSq) = foldFn (\_ x (sum, sumSq) -> (x + sum, (x^2) + sumSq) ) (0,0) ourDict
32+ in
33+ (theSum, sqrt(theSum*theSum - sumSq))
34+
35+
36+foldrMeanStddev = meanAndStddev Dict.foldr
37+
38+
39+foldlMeanStddev = meanAndStddev Dict.foldl
40+
41+
42+updateNRandomIndices
43+ : (Float -> Float)
44+ -> List Int
45+ -> Dict.Dict Int Float
46+ -> Dict.Dict Int Float
47+updateNRandomIndices f indexList startList =
48+ List.foldr
49+ (\ i oldList -> updateN i f oldList)
50+ startList indexList
51+
52+
53+randomLookups : List Int -> Dict.Dict Int Float -> List (Maybe Float)
54+randomLookups indices arr =
55+ List.map (\i -> Dict.get i arr) indices
56+
57+
58+
59+updateN : Int -> (a -> a) -> Dict.Dict Int a -> Dict.Dict Int a
60+updateN n f arr =
61+ case Dict.get n arr of
62+ Just x -> Dict.insert n (f x) arr
63+ _ -> crash "Dict out of bounds"
bench/src/IfBench.elmnew file+81
@@ -0,0 +1,81 @@
1+module IfBench where
2+
3+tailRecursiveIfFn : Int -> Float
4+tailRecursiveIfFn i =
5+ if
6+ | i < 0 ->
7+ 10.0
8+ | i == 0 ->
9+ 20.0
10+ | i > 0 && i < 10 ->
11+ 30.0
12+ | otherwise ->
13+ tailRecursiveIfFn (i - (1 + (i % 5 ) ) )
14+
15+
16+manyConditionFunction i =
17+ if
18+ | i <= 0 ->
19+ 30.0 + (toFloat i)
20+ | i > 100 && (i * i) % 20 == 7 ->
21+ 24.3 + (toFloat i)
22+ | i > 100 && (i % 3 == 1) ->
23+ 3.33 + (toFloat i)
24+ | (i == 152) ->
25+ 29.0 + (toFloat i)
26+ | (i + (i*i) > 200 && (i + (i*i) < 300)) ->
27+ 32.9 + (toFloat i)
28+ | i == 99 ->
29+ 93.0 + (toFloat i)
30+ | (i*i % 17 == 13 ) ->
31+ 9.0 + (toFloat i)
32+ | (i == 101) ->
33+ 39.0 + (toFloat i)
34+ | (i == 102) ->
35+ 38.0 + (toFloat i)
36+ | (i == 103) ->
37+ 49.0 + (toFloat i)
38+ | (i == 104) ->
39+ 59.0 + (toFloat i)
40+ | (i == 105) ->
41+ 69.0 + (toFloat i)
42+ | (i == 106) ->
43+ 39.0 + (toFloat i)
44+ | (i == 107) ->
45+ 38.0 + (toFloat i)
46+ | (i == 108) ->
47+ 49.0 + (toFloat i)
48+ | (i == 109) ->
49+ 59.0 + (toFloat i)
50+ | (i == 110) ->
51+ 69.0 + (toFloat i)
52+ | (i == 111) ->
53+ 39.0 + (toFloat i)
54+ | (i == 115) ->
55+ 69.0 + (toFloat i)
56+ | otherwise ->
57+ toFloat i
58+
59+
60+fewConditionFunction i =
61+ if
62+ | i <= 0 ->
63+ 30.0 + (toFloat i)
64+ | (i == 104) ->
65+ 59.0 + (toFloat i)
66+ | (i == 105) ->
67+ 69.0 + (toFloat i)
68+ | otherwise ->
69+ toFloat i
70+
71+
72+tailRecSum intList =
73+ List.foldr (\i sumSoFar -> sumSoFar + tailRecursiveIfFn i ) 0.0 intList
74+
75+manyConditionalSum intList =
76+ List.foldr (\i sumSoFar -> sumSoFar + manyConditionFunction i ) 0.0 intList
77+
78+
79+fewConditionalSum intList =
80+ List.foldr (\i sumSoFar -> sumSoFar + fewConditionFunction i ) 0.0 intList
81+
bench/src/LargeDictionary.elmnew file+34
@@ -0,0 +1,34 @@
1+module LargeDictionary where
2+
3+
4+import Dict
5+import Random
6+import Signal
7+import Time
8+import Graphics.Element
9+
10+
11+maxSize = 10000000
12+
13+
14+randomGen =
15+ Random.int (-1 * maxSize) (maxSize)
16+
17+
18+addNToDictWithSeed
19+ : Int
20+ -> Random.Seed
21+ -> Dict.Dict Int Int
22+ -> Dict.Dict Int Int
23+addNToDictWithSeed n seed accum =
24+ case n of
25+ 0 -> accum
26+ _ ->
27+ let
28+ (nextToAdd, newSeed) = Random.generate randomGen seed
29+ newAccum = Dict.insert nextToAdd nextToAdd accum
30+ in addNToDictWithSeed (n-1) newSeed newAccum
31+
32+
33+addNToDictAndSum numToInsert =
34+ addNToDictWithSeed numToInsert (Random.initialSeed 23) Dict.empty
bench/src/ListBench.elmnew file+85
@@ -0,0 +1,85 @@
1+module ListBench where
2+
3+import Random
4+
5+
6+
7+randomList
8+ : Random.Generator a
9+ -> Int
10+ -> Random.Seed
11+ -> List a
12+randomList gen n initSeed =
13+ let
14+ f n (seed, accum) =
15+ let
16+ (nextToAdd, newSeed) = Random.generate gen seed
17+ newAccum = nextToAdd :: accum
18+ in (newSeed, newAccum)
19+ in
20+ snd <| List.foldl f (initSeed, []) [1 .. n]
21+
22+meanAndStddev
23+ : ((Float -> (Float, Float) -> (Float, Float)) -> (Float, Float) -> List Float -> (Float, Float))
24+ -> List Float
25+ -> (Float, Float)
26+meanAndStddev foldFn ourList =
27+ let
28+ --ourList = addNToListWithSeed n (Random.initialSeed 23)
29+ (theSum, sumSq) = foldFn (\x (sum, sumSq) -> (x + sum, (x^2) + sumSq) ) (0,0) ourList
30+ in
31+ (theSum, sqrt(theSum*theSum - sumSq))
32+
33+
34+foldrMeanStddev = meanAndStddev List.foldr
35+
36+
37+foldlMeanStddev = meanAndStddev List.foldl
38+
39+
40+customFoldrMeanStddev = meanAndStddev myFoldr
41+
42+
43+customFoldlMeanStddev = meanAndStddev myFoldl
44+
45+
46+updateNRandomIndices
47+ : (Float -> Float)
48+ -> List Int
49+ -> List Float
50+ -> List Float
51+updateNRandomIndices f indexList startList =
52+ List.foldr
53+ (\ i oldList -> updateN i f oldList)
54+ startList indexList
55+
56+
57+
58+randomLookups : List Int -> List Float -> List (Maybe Float)
59+randomLookups indices ourList =
60+ let
61+ getNth i l =
62+ case (i, l) of
63+ (_, []) -> Nothing
64+ (0, x :: _) -> Just x
65+ (i, _ :: xs ) -> getNth i xs
66+ in List.map (\i -> getNth i ourList) indices
67+
68+
69+myFoldl : (a -> b -> b) -> b -> List a -> b
70+myFoldl f init l =
71+ case l of
72+ [] -> init
73+ (x :: xs) -> myFoldl f (f x init) xs
74+
75+
76+myFoldr : (a -> b -> b) -> b -> List a -> b
77+myFoldr f init l =
78+ case l of
79+ [] -> init
80+ (x :: xs) -> f x (myFoldr f init xs)
81+
82+
83+updateN : Int -> (a -> a) -> List a -> List a
84+updateN n f list =
85+ List.indexedMap (\index value -> if index == n then f value else value) list
bench/src/Native/Benchmark.jsnew file+102
@@ -0,0 +1,102 @@
1+Elm.Native.Benchmark = {};
2+Elm.Native.Benchmark.make = function(localRuntime) {
3+
4+ localRuntime.Native = localRuntime.Native || {};
5+ localRuntime.Native.Benchmark = localRuntime.Native.Benchmark || {};
6+ if (localRuntime.Native.Benchmark.values)
7+ {
8+ return localRuntime.Native.Benchmark.values;
9+ }
10+
11+ var List = Elm.Native.List.make(localRuntime);
12+ var Task = Elm.Native.Task.make(localRuntime);
13+ var Signal = Elm.Signal.make(localRuntime);
14+ var Utils = Elm.Native.Utils.make(localRuntime);
15+
16+ //Nothing special happens here, but we need to use it as a Native function
17+ //So that we can accept thunks of any type
18+ function makeBenchmark(name, thunk)
19+ {
20+ return {name : name, thunk : thunk};
21+ }
22+
23+ //Generate the task for running a benchmark suite
24+ //Possibly updating a given mailbox with a string describing
25+ //Our progress of running the benchmarks so far
26+ function runWithProgress(maybeTaskFn, inSuite)
27+ {
28+
29+ return Task.asyncFunction(function(callback) {
30+ var bjsSuite = new Benchmark.Suite;
31+ var benchArray;
32+ var retData = [];
33+ var finalString = "";
34+ var numCompleted = 0;
35+ var numToRun;
36+
37+ switch (inSuite.ctor)
38+ {
39+ case "Suite":
40+ benchArray = List.toArray(inSuite._1);
41+ break;
42+ case "SingleBenchmark":
43+ benchArray = [inSuite._0 ];
44+ break;
45+ }
46+
47+ numToRun = benchArray.length;
48+ Task.perform(maybeTaskFn("Running benchmark 1 of " + numToRun));
49+
50+ //Initialize each benchmark in the suite
51+ for (i = 0; i < benchArray.length; i++)
52+ {
53+ var ourThunk = function (){
54+ //Run the thing we're timing, then mark the asynch benchmark as done
55+ benchArray[i].thunk();
56+ deferred.resolve();
57+ }
58+ bjsSuite.add(benchArray[i].name, benchArray[i].thunk );
59+ }
60+
61+ //Every time a benchmark finishes, we store its results
62+ //and update our progress string
63+ bjsSuite.on('cycle', function(event) {
64+ numCompleted += 1;
65+ retData.push(
66+ { name : event.target.options.name
67+ , hz : event.target.hz
68+ , marginOfError : event.target.stats.moe
69+ , moePercent : event.target.stats.rme
70+ }
71+ );
72+ finalString += String(event.target) + "\n";
73+ var intermedString =
74+ "Running benchmark "
75+ + (numCompleted + 1)
76+ + " of " + numToRun
77+ + "\nLast result: " + String(event.target);
78+ Task.perform(maybeTaskFn(intermedString));
79+ //retString += String(event.target) + "\n";
80+ });
81+
82+ //When the last benchmark finishes, we show all results collected
83+ bjsSuite.on('complete', function(event) {
84+ Task.perform(maybeTaskFn("Final results:\n\n" + finalString) );
85+ return callback(Task.succeed(Utils.Tuple2(finalString, List.fromArray(retData))));
86+ });
87+
88+ //Finally: actually run the suite
89+ Task.perform(
90+ Task.asyncFunction(function(otherCallback){
91+ bjsSuite.run({ 'async': true });
92+ }));
93+ });
94+ }
95+
96+ return localRuntime.Native.Benchmark.values = {
97+ makeBenchmark: F2(makeBenchmark),
98+ runWithProgress: F2(runWithProgress)
99+ };
100+
101+
102+};
bench/src/Native/BenchmarkJS.jsnew file+3919
@@ -0,0 +1,3919 @@
1+/*!
2+ * Benchmark.js v1.0.0 <http://benchmarkjs.com/>
3+ * Copyright 2010-2012 Mathias Bynens <http://mths.be/>
4+ * Based on JSLitmus.js, copyright Robert Kieffer <http://broofa.com/>
5+ * Modified by John-David Dalton <http://allyoucanleet.com/>
6+ * Available under MIT license <http://mths.be/mit>
7+ */
8+;(function(window, undefined) {
9+ 'use strict';
10+
11+ /** Used to assign each benchmark an incrimented id */
12+ var counter = 0;
13+
14+ /** Detect DOM document object */
15+ var doc = isHostType(window, 'document') && document;
16+
17+ /** Detect free variable `define` */
18+ var freeDefine = typeof define == 'function' &&
19+ typeof define.amd == 'object' && define.amd && define;
20+
21+ /** Detect free variable `exports` */
22+ var freeExports = typeof exports == 'object' && exports &&
23+ (typeof global == 'object' && global && global == global.global && (window = global), exports);
24+
25+ /** Detect free variable `require` */
26+ var freeRequire = typeof require == 'function' && require;
27+
28+ /** Used to crawl all properties regardless of enumerability */
29+ var getAllKeys = Object.getOwnPropertyNames;
30+
31+ /** Used to get property descriptors */
32+ var getDescriptor = Object.getOwnPropertyDescriptor;
33+
34+ /** Used in case an object doesn't have its own method */
35+ var hasOwnProperty = {}.hasOwnProperty;
36+
37+ /** Used to check if an object is extensible */
38+ var isExtensible = Object.isExtensible || function() { return true; };
39+
40+ /** Used to access Wade Simmons' Node microtime module */
41+ var microtimeObject = req('microtime');
42+
43+ /** Used to access the browser's high resolution timer */
44+ var perfObject = isHostType(window, 'performance') && performance;
45+
46+ /** Used to call the browser's high resolution timer */
47+ var perfName = perfObject && (
48+ perfObject.now && 'now' ||
49+ perfObject.webkitNow && 'webkitNow'
50+ );
51+
52+ /** Used to access Node's high resolution timer */
53+ var processObject = isHostType(window, 'process') && process;
54+
55+ /** Used to check if an own property is enumerable */
56+ var propertyIsEnumerable = {}.propertyIsEnumerable;
57+
58+ /** Used to set property descriptors */
59+ var setDescriptor = Object.defineProperty;
60+
61+ /** Used to resolve a value's internal [[Class]] */
62+ var toString = {}.toString;
63+
64+ /** Used to prevent a `removeChild` memory leak in IE < 9 */
65+ var trash = doc && doc.createElement('div');
66+
67+ /** Used to integrity check compiled tests */
68+ var uid = 'uid' + (+new Date);
69+
70+ /** Used to avoid infinite recursion when methods call each other */
71+ var calledBy = {};
72+
73+ /** Used to avoid hz of Infinity */
74+ var divisors = {
75+ '1': 4096,
76+ '2': 512,
77+ '3': 64,
78+ '4': 8,
79+ '5': 0
80+ };
81+
82+ /**
83+ * T-Distribution two-tailed critical values for 95% confidence
84+ * http://www.itl.nist.gov/div898/handbook/eda/section3/eda3672.htm
85+ */
86+ var tTable = {
87+ '1': 12.706,'2': 4.303, '3': 3.182, '4': 2.776, '5': 2.571, '6': 2.447,
88+ '7': 2.365, '8': 2.306, '9': 2.262, '10': 2.228, '11': 2.201, '12': 2.179,
89+ '13': 2.16, '14': 2.145, '15': 2.131, '16': 2.12, '17': 2.11, '18': 2.101,
90+ '19': 2.093, '20': 2.086, '21': 2.08, '22': 2.074, '23': 2.069, '24': 2.064,
91+ '25': 2.06, '26': 2.056, '27': 2.052, '28': 2.048, '29': 2.045, '30': 2.042,
92+ 'infinity': 1.96
93+ };
94+
95+ /**
96+ * Critical Mann-Whitney U-values for 95% confidence
97+ * http://www.saburchill.com/IBbiology/stats/003.html
98+ */
99+ var uTable = {
100+ '5': [0, 1, 2],
101+ '6': [1, 2, 3, 5],
102+ '7': [1, 3, 5, 6, 8],
103+ '8': [2, 4, 6, 8, 10, 13],
104+ '9': [2, 4, 7, 10, 12, 15, 17],
105+ '10': [3, 5, 8, 11, 14, 17, 20, 23],
106+ '11': [3, 6, 9, 13, 16, 19, 23, 26, 30],
107+ '12': [4, 7, 11, 14, 18, 22, 26, 29, 33, 37],
108+ '13': [4, 8, 12, 16, 20, 24, 28, 33, 37, 41, 45],
109+ '14': [5, 9, 13, 17, 22, 26, 31, 36, 40, 45, 50, 55],
110+ '15': [5, 10, 14, 19, 24, 29, 34, 39, 44, 49, 54, 59, 64],
111+ '16': [6, 11, 15, 21, 26, 31, 37, 42, 47, 53, 59, 64, 70, 75],
112+ '17': [6, 11, 17, 22, 28, 34, 39, 45, 51, 57, 63, 67, 75, 81, 87],
113+ '18': [7, 12, 18, 24, 30, 36, 42, 48, 55, 61, 67, 74, 80, 86, 93, 99],
114+ '19': [7, 13, 19, 25, 32, 38, 45, 52, 58, 65, 72, 78, 85, 92, 99, 106, 113],
115+ '20': [8, 14, 20, 27, 34, 41, 48, 55, 62, 69, 76, 83, 90, 98, 105, 112, 119, 127],
116+ '21': [8, 15, 22, 29, 36, 43, 50, 58, 65, 73, 80, 88, 96, 103, 111, 119, 126, 134, 142],
117+ '22': [9, 16, 23, 30, 38, 45, 53, 61, 69, 77, 85, 93, 101, 109, 117, 125, 133, 141, 150, 158],
118+ '23': [9, 17, 24, 32, 40, 48, 56, 64, 73, 81, 89, 98, 106, 115, 123, 132, 140, 149, 157, 166, 175],
119+ '24': [10, 17, 25, 33, 42, 50, 59, 67, 76, 85, 94, 102, 111, 120, 129, 138, 147, 156, 165, 174, 183, 192],
120+ '25': [10, 18, 27, 35, 44, 53, 62, 71, 80, 89, 98, 107, 117, 126, 135, 145, 154, 163, 173, 182, 192, 201, 211],
121+ '26': [11, 19, 28, 37, 46, 55, 64, 74, 83, 93, 102, 112, 122, 132, 141, 151, 161, 171, 181, 191, 200, 210, 220, 230],
122+ '27': [11, 20, 29, 38, 48, 57, 67, 77, 87, 97, 107, 118, 125, 138, 147, 158, 168, 178, 188, 199, 209, 219, 230, 240, 250],
123+ '28': [12, 21, 30, 40, 50, 60, 70, 80, 90, 101, 111, 122, 132, 143, 154, 164, 175, 186, 196, 207, 218, 228, 239, 250, 261, 272],
124+ '29': [13, 22, 32, 42, 52, 62, 73, 83, 94, 105, 116, 127, 138, 149, 160, 171, 182, 193, 204, 215, 226, 238, 249, 260, 271, 282, 294],
125+ '30': [13, 23, 33, 43, 54, 65, 76, 87, 98, 109, 120, 131, 143, 154, 166, 177, 189, 200, 212, 223, 235, 247, 258, 270, 282, 293, 305, 317]
126+ };
127+
128+ /**
129+ * An object used to flag environments/features.
130+ *
131+ * @static
132+ * @memberOf Benchmark
133+ * @type Object
134+ */
135+ var support = {};
136+
137+ (function() {
138+
139+ /**
140+ * Detect Adobe AIR.
141+ *
142+ * @memberOf Benchmark.support
143+ * @type Boolean
144+ */
145+ support.air = isClassOf(window.runtime, 'ScriptBridgingProxyObject');
146+
147+ /**
148+ * Detect if `arguments` objects have the correct internal [[Class]] value.
149+ *
150+ * @memberOf Benchmark.support
151+ * @type Boolean
152+ */
153+ support.argumentsClass = isClassOf(arguments, 'Arguments');
154+
155+ /**
156+ * Detect if in a browser environment.
157+ *
158+ * @memberOf Benchmark.support
159+ * @type Boolean
160+ */
161+ support.browser = doc && isHostType(window, 'navigator');
162+
163+ /**
164+ * Detect if strings support accessing characters by index.
165+ *
166+ * @memberOf Benchmark.support
167+ * @type Boolean
168+ */
169+ support.charByIndex =
170+ // IE 8 supports indexes on string literals but not string objects
171+ ('x'[0] + Object('x')[0]) == 'xx';
172+
173+ /**
174+ * Detect if strings have indexes as own properties.
175+ *
176+ * @memberOf Benchmark.support
177+ * @type Boolean
178+ */
179+ support.charByOwnIndex =
180+ // Narwhal, Rhino, RingoJS, IE 8, and Opera < 10.52 support indexes on
181+ // strings but don't detect them as own properties
182+ support.charByIndex && hasKey('x', '0');
183+
184+ /**
185+ * Detect if Java is enabled/exposed.
186+ *
187+ * @memberOf Benchmark.support
188+ * @type Boolean
189+ */
190+ support.java = isClassOf(window.java, 'JavaPackage');
191+
192+ /**
193+ * Detect if the Timers API exists.
194+ *
195+ * @memberOf Benchmark.support
196+ * @type Boolean
197+ */
198+ support.timeout = isHostType(window, 'setTimeout') && isHostType(window, 'clearTimeout');
199+
200+ /**
201+ * Detect if functions support decompilation.
202+ *
203+ * @name decompilation
204+ * @memberOf Benchmark.support
205+ * @type Boolean
206+ */
207+ try {
208+ // Safari 2.x removes commas in object literals
209+ // from Function#toString results
210+ // http://webk.it/11609
211+ // Firefox 3.6 and Opera 9.25 strip grouping
212+ // parentheses from Function#toString results
213+ // http://bugzil.la/559438
214+ support.decompilation = Function(
215+ 'return (' + (function(x) { return { 'x': '' + (1 + x) + '', 'y': 0 }; }) + ')'
216+ )()(0).x === '1';
217+ } catch(e) {
218+ support.decompilation = false;
219+ }
220+
221+ /**
222+ * Detect ES5+ property descriptor API.
223+ *
224+ * @name descriptors
225+ * @memberOf Benchmark.support
226+ * @type Boolean
227+ */
228+ try {
229+ var o = {};
230+ support.descriptors = (setDescriptor(o, o, o), 'value' in getDescriptor(o, o));
231+ } catch(e) {
232+ support.descriptors = false;
233+ }
234+
235+ /**
236+ * Detect ES5+ Object.getOwnPropertyNames().
237+ *
238+ * @name getAllKeys
239+ * @memberOf Benchmark.support
240+ * @type Boolean
241+ */
242+ try {
243+ support.getAllKeys = /\bvalueOf\b/.test(getAllKeys(Object.prototype));
244+ } catch(e) {
245+ support.getAllKeys = false;
246+ }
247+
248+ /**
249+ * Detect if own properties are iterated before inherited properties (all but IE < 9).
250+ *
251+ * @name iteratesOwnLast
252+ * @memberOf Benchmark.support
253+ * @type Boolean
254+ */
255+ support.iteratesOwnFirst = (function() {
256+ var props = [];
257+ function ctor() { this.x = 1; }
258+ ctor.prototype = { 'y': 1 };
259+ for (var prop in new ctor) { props.push(prop); }
260+ return props[0] == 'x';
261+ }());
262+
263+ /**
264+ * Detect if a node's [[Class]] is resolvable (all but IE < 9)
265+ * and that the JS engine errors when attempting to coerce an object to a
266+ * string without a `toString` property value of `typeof` "function".
267+ *
268+ * @name nodeClass
269+ * @memberOf Benchmark.support
270+ * @type Boolean
271+ */
272+ try {
273+ support.nodeClass = ({ 'toString': 0 } + '', toString.call(doc || 0) != '[object Object]');
274+ } catch(e) {
275+ support.nodeClass = true;
276+ }
277+ }());
278+
279+ /**
280+ * Timer object used by `clock()` and `Deferred#resolve`.
281+ *
282+ * @private
283+ * @type Object
284+ */
285+ var timer = {
286+
287+ /**
288+ * The timer namespace object or constructor.
289+ *
290+ * @private
291+ * @memberOf timer
292+ * @type Function|Object
293+ */
294+ 'ns': Date,
295+
296+ /**
297+ * Starts the deferred timer.
298+ *
299+ * @private
300+ * @memberOf timer
301+ * @param {Object} deferred The deferred instance.
302+ */
303+ 'start': null, // lazy defined in `clock()`
304+
305+ /**
306+ * Stops the deferred timer.
307+ *
308+ * @private
309+ * @memberOf timer
310+ * @param {Object} deferred The deferred instance.
311+ */
312+ 'stop': null // lazy defined in `clock()`
313+ };
314+
315+ /** Shortcut for inverse results */
316+ var noArgumentsClass = !support.argumentsClass,
317+ noCharByIndex = !support.charByIndex,
318+ noCharByOwnIndex = !support.charByOwnIndex;
319+
320+ /** Math shortcuts */
321+ var abs = Math.abs,
322+ floor = Math.floor,
323+ max = Math.max,
324+ min = Math.min,
325+ pow = Math.pow,
326+ sqrt = Math.sqrt;
327+
328+ /*--------------------------------------------------------------------------*/
329+
330+ /**
331+ * The Benchmark constructor.
332+ *
333+ * @constructor
334+ * @param {String} name A name to identify the benchmark.
335+ * @param {Function|String} fn The test to benchmark.
336+ * @param {Object} [options={}] Options object.
337+ * @example
338+ *
339+ * // basic usage (the `new` operator is optional)
340+ * var bench = new Benchmark(fn);
341+ *
342+ * // or using a name first
343+ * var bench = new Benchmark('foo', fn);
344+ *
345+ * // or with options
346+ * var bench = new Benchmark('foo', fn, {
347+ *
348+ * // displayed by Benchmark#toString if `name` is not available
349+ * 'id': 'xyz',
350+ *
351+ * // called when the benchmark starts running
352+ * 'onStart': onStart,
353+ *
354+ * // called after each run cycle
355+ * 'onCycle': onCycle,
356+ *
357+ * // called when aborted
358+ * 'onAbort': onAbort,
359+ *
360+ * // called when a test errors
361+ * 'onError': onError,
362+ *
363+ * // called when reset
364+ * 'onReset': onReset,
365+ *
366+ * // called when the benchmark completes running
367+ * 'onComplete': onComplete,
368+ *
369+ * // compiled/called before the test loop
370+ * 'setup': setup,
371+ *
372+ * // compiled/called after the test loop
373+ * 'teardown': teardown
374+ * });
375+ *
376+ * // or name and options
377+ * var bench = new Benchmark('foo', {
378+ *
379+ * // a flag to indicate the benchmark is deferred
380+ * 'defer': true,
381+ *
382+ * // benchmark test function
383+ * 'fn': function(deferred) {
384+ * // call resolve() when the deferred test is finished
385+ * deferred.resolve();
386+ * }
387+ * });
388+ *
389+ * // or options only
390+ * var bench = new Benchmark({
391+ *
392+ * // benchmark name
393+ * 'name': 'foo',
394+ *
395+ * // benchmark test as a string
396+ * 'fn': '[1,2,3,4].sort()'
397+ * });
398+ *
399+ * // a test's `this` binding is set to the benchmark instance
400+ * var bench = new Benchmark('foo', function() {
401+ * 'My name is '.concat(this.name); // My name is foo
402+ * });
403+ */
404+ function Benchmark(name, fn, options) {
405+ var me = this;
406+
407+ // allow instance creation without the `new` operator
408+ if (me == null || me.constructor != Benchmark) {
409+ return new Benchmark(name, fn, options);
410+ }
411+ // juggle arguments
412+ if (isClassOf(name, 'Object')) {
413+ // 1 argument (options)
414+ options = name;
415+ }
416+ else if (isClassOf(name, 'Function')) {
417+ // 2 arguments (fn, options)
418+ options = fn;
419+ fn = name;
420+ }
421+ else if (isClassOf(fn, 'Object')) {
422+ // 2 arguments (name, options)
423+ options = fn;
424+ fn = null;
425+ me.name = name;
426+ }
427+ else {
428+ // 3 arguments (name, fn [, options])
429+ me.name = name;
430+ }
431+ setOptions(me, options);
432+ me.id || (me.id = ++counter);
433+ me.fn == null && (me.fn = fn);
434+ me.stats = deepClone(me.stats);
435+ me.times = deepClone(me.times);
436+ }
437+
438+ /**
439+ * The Deferred constructor.
440+ *
441+ * @constructor
442+ * @memberOf Benchmark
443+ * @param {Object} clone The cloned benchmark instance.
444+ */
445+ function Deferred(clone) {
446+ var me = this;
447+ if (me == null || me.constructor != Deferred) {
448+ return new Deferred(clone);
449+ }
450+ me.benchmark = clone;
451+ clock(me);
452+ }
453+
454+ /**
455+ * The Event constructor.
456+ *
457+ * @constructor
458+ * @memberOf Benchmark
459+ * @param {String|Object} type The event type.
460+ */
461+ function Event(type) {
462+ var me = this;
463+ return (me == null || me.constructor != Event)
464+ ? new Event(type)
465+ : (type instanceof Event)
466+ ? type
467+ : extend(me, { 'timeStamp': +new Date }, typeof type == 'string' ? { 'type': type } : type);
468+ }
469+
470+ /**
471+ * The Suite constructor.
472+ *
473+ * @constructor
474+ * @memberOf Benchmark
475+ * @param {String} name A name to identify the suite.
476+ * @param {Object} [options={}] Options object.
477+ * @example
478+ *
479+ * // basic usage (the `new` operator is optional)
480+ * var suite = new Benchmark.Suite;
481+ *
482+ * // or using a name first
483+ * var suite = new Benchmark.Suite('foo');
484+ *
485+ * // or with options
486+ * var suite = new Benchmark.Suite('foo', {
487+ *
488+ * // called when the suite starts running
489+ * 'onStart': onStart,
490+ *
491+ * // called between running benchmarks
492+ * 'onCycle': onCycle,
493+ *
494+ * // called when aborted
495+ * 'onAbort': onAbort,
496+ *
497+ * // called when a test errors
498+ * 'onError': onError,
499+ *
500+ * // called when reset
501+ * 'onReset': onReset,
502+ *
503+ * // called when the suite completes running
504+ * 'onComplete': onComplete
505+ * });
506+ */
507+ function Suite(name, options) {
508+ var me = this;
509+
510+ // allow instance creation without the `new` operator
511+ if (me == null || me.constructor != Suite) {
512+ return new Suite(name, options);
513+ }
514+ // juggle arguments
515+ if (isClassOf(name, 'Object')) {
516+ // 1 argument (options)
517+ options = name;
518+ } else {
519+ // 2 arguments (name [, options])
520+ me.name = name;
521+ }
522+ setOptions(me, options);
523+ }
524+
525+ /*--------------------------------------------------------------------------*/
526+
527+ /**
528+ * Note: Some array methods have been implemented in plain JavaScript to avoid
529+ * bugs in IE, Opera, Rhino, and Mobile Safari.
530+ *
531+ * IE compatibility mode and IE < 9 have buggy Array `shift()` and `splice()`
532+ * functions that fail to remove the last element, `object[0]`, of
533+ * array-like-objects even though the `length` property is set to `0`.
534+ * The `shift()` method is buggy in IE 8 compatibility mode, while `splice()`
535+ * is buggy regardless of mode in IE < 9 and buggy in compatibility mode in IE 9.
536+ *
537+ * In Opera < 9.50 and some older/beta Mobile Safari versions using `unshift()`
538+ * generically to augment the `arguments` object will pave the value at index 0
539+ * without incrimenting the other values's indexes.
540+ * https://github.com/documentcloud/underscore/issues/9
541+ *
542+ * Rhino and environments it powers, like Narwhal and RingoJS, may have
543+ * buggy Array `concat()`, `reverse()`, `shift()`, `slice()`, `splice()` and
544+ * `unshift()` functions that make sparse arrays non-sparse by assigning the
545+ * undefined indexes a value of undefined.
546+ * https://github.com/mozilla/rhino/commit/702abfed3f8ca043b2636efd31c14ba7552603dd
547+ */
548+
549+ /**
550+ * Creates an array containing the elements of the host array followed by the
551+ * elements of each argument in order.
552+ *
553+ * @memberOf Benchmark.Suite
554+ * @returns {Array} The new array.
555+ */
556+ function concat() {
557+ var value,
558+ j = -1,
559+ length = arguments.length,
560+ result = slice.call(this),
561+ index = result.length;
562+
563+ while (++j < length) {
564+ value = arguments[j];
565+ if (isClassOf(value, 'Array')) {
566+ for (var k = 0, l = value.length; k < l; k++, index++) {
567+ if (k in value) {
568+ result[index] = value[k];
569+ }
570+ }
571+ } else {
572+ result[index++] = value;
573+ }
574+ }
575+ return result;
576+ }
577+
578+ /**
579+ * Utility function used by `shift()`, `splice()`, and `unshift()`.
580+ *
581+ * @private
582+ * @param {Number} start The index to start inserting elements.
583+ * @param {Number} deleteCount The number of elements to delete from the insert point.
584+ * @param {Array} elements The elements to insert.
585+ * @returns {Array} An array of deleted elements.
586+ */
587+ function insert(start, deleteCount, elements) {
588+ // `result` should have its length set to the `deleteCount`
589+ // see https://bugs.ecmascript.org/show_bug.cgi?id=332
590+ var deleteEnd = start + deleteCount,
591+ elementCount = elements ? elements.length : 0,
592+ index = start - 1,
593+ length = start + elementCount,
594+ object = this,
595+ result = Array(deleteCount),
596+ tail = slice.call(object, deleteEnd);
597+
598+ // delete elements from the array
599+ while (++index < deleteEnd) {
600+ if (index in object) {
601+ result[index - start] = object[index];
602+ delete object[index];
603+ }
604+ }
605+ // insert elements
606+ index = start - 1;
607+ while (++index < length) {
608+ object[index] = elements[index - start];
609+ }
610+ // append tail elements
611+ start = index--;
612+ length = max(0, (object.length >>> 0) - deleteCount + elementCount);
613+ while (++index < length) {
614+ if ((index - start) in tail) {
615+ object[index] = tail[index - start];
616+ } else if (index in object) {
617+ delete object[index];
618+ }
619+ }
620+ // delete excess elements
621+ deleteCount = deleteCount > elementCount ? deleteCount - elementCount : 0;
622+ while (deleteCount--) {
623+ index = length + deleteCount;
624+ if (index in object) {
625+ delete object[index];
626+ }
627+ }
628+ object.length = length;
629+ return result;
630+ }
631+
632+ /**
633+ * Rearrange the host array's elements in reverse order.
634+ *
635+ * @memberOf Benchmark.Suite
636+ * @returns {Array} The reversed array.
637+ */
638+ function reverse() {
639+ var upperIndex,
640+ value,
641+ index = -1,
642+ object = Object(this),
643+ length = object.length >>> 0,
644+ middle = floor(length / 2);
645+
646+ if (length > 1) {
647+ while (++index < middle) {
648+ upperIndex = length - index - 1;
649+ value = upperIndex in object ? object[upperIndex] : uid;
650+ if (index in object) {
651+ object[upperIndex] = object[index];
652+ } else {
653+ delete object[upperIndex];
654+ }
655+ if (value != uid) {
656+ object[index] = value;
657+ } else {
658+ delete object[index];
659+ }
660+ }
661+ }
662+ return object;
663+ }
664+
665+ /**
666+ * Removes the first element of the host array and returns it.
667+ *
668+ * @memberOf Benchmark.Suite
669+ * @returns {Mixed} The first element of the array.
670+ */
671+ function shift() {
672+ return insert.call(this, 0, 1)[0];
673+ }
674+
675+ /**
676+ * Creates an array of the host array's elements from the start index up to,
677+ * but not including, the end index.
678+ *
679+ * @memberOf Benchmark.Suite
680+ * @param {Number} start The starting index.
681+ * @param {Number} end The end index.
682+ * @returns {Array} The new array.
683+ */
684+ function slice(start, end) {
685+ var index = -1,
686+ object = Object(this),
687+ length = object.length >>> 0,
688+ result = [];
689+
690+ start = toInteger(start);
691+ start = start < 0 ? max(length + start, 0) : min(start, length);
692+ start--;
693+ end = end == null ? length : toInteger(end);
694+ end = end < 0 ? max(length + end, 0) : min(end, length);
695+
696+ while ((++index, ++start) < end) {
697+ if (start in object) {
698+ result[index] = object[start];
699+ }
700+ }
701+ return result;
702+ }
703+
704+ /**
705+ * Allows removing a range of elements and/or inserting elements into the
706+ * host array.
707+ *
708+ * @memberOf Benchmark.Suite
709+ * @param {Number} start The start index.
710+ * @param {Number} deleteCount The number of elements to delete.
711+ * @param {Mixed} [val1, val2, ...] values to insert at the `start` index.
712+ * @returns {Array} An array of removed elements.
713+ */
714+ function splice(start, deleteCount) {
715+ var object = Object(this),
716+ length = object.length >>> 0;
717+
718+ start = toInteger(start);
719+ start = start < 0 ? max(length + start, 0) : min(start, length);
720+
721+ // support the de-facto SpiderMonkey extension
722+ // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice#Parameters
723+ // https://bugs.ecmascript.org/show_bug.cgi?id=429
724+ deleteCount = arguments.length == 1
725+ ? length - start
726+ : min(max(toInteger(deleteCount), 0), length - start);
727+
728+ return insert.call(object, start, deleteCount, slice.call(arguments, 2));
729+ }
730+
731+ /**
732+ * Converts the specified `value` to an integer.
733+ *
734+ * @private
735+ * @param {Mixed} value The value to convert.
736+ * @returns {Number} The resulting integer.
737+ */
738+ function toInteger(value) {
739+ value = +value;
740+ return value === 0 || !isFinite(value) ? value || 0 : value - (value % 1);
741+ }
742+
743+ /**
744+ * Appends arguments to the host array.
745+ *
746+ * @memberOf Benchmark.Suite
747+ * @returns {Number} The new length.
748+ */
749+ function unshift() {
750+ var object = Object(this);
751+ insert.call(object, 0, 0, arguments);
752+ return object.length;
753+ }
754+
755+ /*--------------------------------------------------------------------------*/
756+
757+ /**
758+ * A generic `Function#bind` like method.
759+ *
760+ * @private
761+ * @param {Function} fn The function to be bound to `thisArg`.
762+ * @param {Mixed} thisArg The `this` binding for the given function.
763+ * @returns {Function} The bound function.
764+ */
765+ function bind(fn, thisArg) {
766+ return function() { fn.apply(thisArg, arguments); };
767+ }
768+
769+ /**
770+ * Creates a function from the given arguments string and body.
771+ *
772+ * @private
773+ * @param {String} args The comma separated function arguments.
774+ * @param {String} body The function body.
775+ * @returns {Function} The new function.
776+ */
777+ function createFunction() {
778+ // lazy define
779+ createFunction = function(args, body) {
780+ var result,
781+ anchor = freeDefine ? define.amd : Benchmark,
782+ prop = uid + 'createFunction';
783+
784+ runScript((freeDefine ? 'define.amd.' : 'Benchmark.') + prop + '=function(' + args + '){' + body + '}');
785+ result = anchor[prop];
786+ delete anchor[prop];
787+ return result;
788+ };
789+ // fix JaegerMonkey bug
790+ // http://bugzil.la/639720
791+ createFunction = support.browser && (createFunction('', 'return"' + uid + '"') || noop)() == uid ? createFunction : Function;
792+ return createFunction.apply(null, arguments);
793+ }
794+
795+ /**
796+ * Delay the execution of a function based on the benchmark's `delay` property.
797+ *
798+ * @private
799+ * @param {Object} bench The benchmark instance.
800+ * @param {Object} fn The function to execute.
801+ */
802+ function delay(bench, fn) {
803+ bench._timerId = setTimeout(fn, bench.delay * 1e3);
804+ }
805+
806+ /**
807+ * Destroys the given element.
808+ *
809+ * @private
810+ * @param {Element} element The element to destroy.
811+ */
812+ function destroyElement(element) {
813+ trash.appendChild(element);
814+ trash.innerHTML = '';
815+ }
816+
817+ /**
818+ * Iterates over an object's properties, executing the `callback` for each.
819+ * Callbacks may terminate the loop by explicitly returning `false`.
820+ *
821+ * @private
822+ * @param {Object} object The object to iterate over.
823+ * @param {Function} callback The function executed per own property.
824+ * @param {Object} options The options object.
825+ * @returns {Object} Returns the object iterated over.
826+ */
827+ function forProps() {
828+ var forShadowed,
829+ skipSeen,
830+ forArgs = true,
831+ shadowed = ['constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf'];
832+
833+ (function(enumFlag, key) {
834+ // must use a non-native constructor to catch the Safari 2 issue
835+ function Klass() { this.valueOf = 0; };
836+ Klass.prototype.valueOf = 0;
837+ // check various for-in bugs
838+ for (key in new Klass) {
839+ enumFlag += key == 'valueOf' ? 1 : 0;
840+ }
841+ // check if `arguments` objects have non-enumerable indexes
842+ for (key in arguments) {
843+ key == '0' && (forArgs = false);
844+ }
845+ // Safari 2 iterates over shadowed properties twice
846+ // http://replay.waybackmachine.org/20090428222941/http://tobielangel.com/2007/1/29/for-in-loop-broken-in-safari/
847+ skipSeen = enumFlag == 2;
848+ // IE < 9 incorrectly makes an object's properties non-enumerable if they have
849+ // the same name as other non-enumerable properties in its prototype chain.
850+ forShadowed = !enumFlag;
851+ }(0));
852+
853+ // lazy define
854+ forProps = function(object, callback, options) {
855+ options || (options = {});
856+
857+ var result = object;
858+ object = Object(object);
859+
860+ var ctor,
861+ key,
862+ keys,
863+ skipCtor,
864+ done = !result,
865+ which = options.which,
866+ allFlag = which == 'all',
867+ index = -1,
868+ iteratee = object,
869+ length = object.length,
870+ ownFlag = allFlag || which == 'own',
871+ seen = {},
872+ skipProto = isClassOf(object, 'Function'),
873+ thisArg = options.bind;
874+
875+ if (thisArg !== undefined) {
876+ callback = bind(callback, thisArg);
877+ }
878+ // iterate all properties
879+ if (allFlag && support.getAllKeys) {
880+ for (index = 0, keys = getAllKeys(object), length = keys.length; index < length; index++) {
881+ key = keys[index];
882+ if (callback(object[key], key, object) === false) {
883+ break;
884+ }
885+ }
886+ }
887+ // else iterate only enumerable properties
888+ else {
889+ for (key in object) {
890+ // Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1
891+ // (if the prototype or a property on the prototype has been set)
892+ // incorrectly set a function's `prototype` property [[Enumerable]] value
893+ // to `true`. Because of this we standardize on skipping the `prototype`
894+ // property of functions regardless of their [[Enumerable]] value.
895+ if ((done =
896+ !(skipProto && key == 'prototype') &&
897+ !(skipSeen && (hasKey(seen, key) || !(seen[key] = true))) &&
898+ (!ownFlag || ownFlag && hasKey(object, key)) &&
899+ callback(object[key], key, object) === false)) {
900+ break;
901+ }
902+ }
903+ // in IE < 9 strings don't support accessing characters by index
904+ if (!done && (forArgs && isArguments(object) ||
905+ ((noCharByIndex || noCharByOwnIndex) && isClassOf(object, 'String') &&
906+ (iteratee = noCharByIndex ? object.split('') : object)))) {
907+ while (++index < length) {
908+ if ((done =
909+ callback(iteratee[index], String(index), object) === false)) {
910+ break;
911+ }
912+ }
913+ }
914+ if (!done && forShadowed) {
915+ // Because IE < 9 can't set the `[[Enumerable]]` attribute of an existing
916+ // property and the `constructor` property of a prototype defaults to
917+ // non-enumerable, we manually skip the `constructor` property when we
918+ // think we are iterating over a `prototype` object.
919+ ctor = object.constructor;
920+ skipCtor = ctor && ctor.prototype && ctor.prototype.constructor === ctor;
921+ for (index = 0; index < 7; index++) {
922+ key = shadowed[index];
923+ if (!(skipCtor && key == 'constructor') &&
924+ hasKey(object, key) &&
925+ callback(object[key], key, object) === false) {
926+ break;
927+ }
928+ }
929+ }
930+ }
931+ return result;
932+ };
933+ return forProps.apply(null, arguments);
934+ }
935+
936+ /**
937+ * Gets the name of the first argument from a function's source.
938+ *
939+ * @private
940+ * @param {Function} fn The function.
941+ * @returns {String} The argument name.
942+ */
943+ function getFirstArgument(fn) {
944+ return (!hasKey(fn, 'toString') &&
945+ (/^[\s(]*function[^(]*\(([^\s,)]+)/.exec(fn) || 0)[1]) || '';
946+ }
947+
948+ /**
949+ * Computes the arithmetic mean of a sample.
950+ *
951+ * @private
952+ * @param {Array} sample The sample.
953+ * @returns {Number} The mean.
954+ */
955+ function getMean(sample) {
956+ return reduce(sample, function(sum, x) {
957+ return sum + x;
958+ }) / sample.length || 0;
959+ }
960+
961+ /**
962+ * Gets the source code of a function.
963+ *
964+ * @private
965+ * @param {Function} fn The function.
966+ * @param {String} altSource A string used when a function's source code is unretrievable.
967+ * @returns {String} The function's source code.
968+ */
969+ function getSource(fn, altSource) {
970+ var result = altSource;
971+ if (isStringable(fn)) {
972+ result = String(fn);
973+ } else if (support.decompilation) {
974+ // escape the `{` for Firefox 1
975+ result = (/^[^{]+\{([\s\S]*)}\s*$/.exec(fn) || 0)[1];
976+ }
977+ // trim string
978+ result = (result || '').replace(/^\s+|\s+$/g, '');
979+
980+ // detect strings containing only the "use strict" directive
981+ return /^(?:\/\*+[\w|\W]*?\*\/|\/\/.*?[\n\r\u2028\u2029]|\s)*(["'])use strict\1;?$/.test(result)
982+ ? ''
983+ : result;
984+ }
985+
986+ /**
987+ * Checks if a value is an `arguments` object.
988+ *
989+ * @private
990+ * @param {Mixed} value The value to check.
991+ * @returns {Boolean} Returns `true` if the value is an `arguments` object, else `false`.
992+ */
993+ function isArguments() {
994+ // lazy define
995+ isArguments = function(value) {
996+ return toString.call(value) == '[object Arguments]';
997+ };
998+ if (noArgumentsClass) {
999+ isArguments = function(value) {
1000+ return hasKey(value, 'callee') &&
1001+ !(propertyIsEnumerable && propertyIsEnumerable.call(value, 'callee'));
1002+ };
1003+ }
1004+ return isArguments(arguments[0]);
1005+ }
1006+
1007+ /**
1008+ * Checks if an object is of the specified class.
1009+ *
1010+ * @private
1011+ * @param {Mixed} value The value to check.
1012+ * @param {String} name The name of the class.
1013+ * @returns {Boolean} Returns `true` if the value is of the specified class, else `false`.
1014+ */
1015+ function isClassOf(value, name) {
1016+ return value != null && toString.call(value) == '[object ' + name + ']';
1017+ }
1018+
1019+ /**
1020+ * Host objects can return type values that are different from their actual
1021+ * data type. The objects we are concerned with usually return non-primitive
1022+ * types of object, function, or unknown.
1023+ *
1024+ * @private
1025+ * @param {Mixed} object The owner of the property.
1026+ * @param {String} property The property to check.
1027+ * @returns {Boolean} Returns `true` if the property value is a non-primitive, else `false`.
1028+ */
1029+ function isHostType(object, property) {
1030+ var type = object != null ? typeof object[property] : 'number';
1031+ return !/^(?:boolean|number|string|undefined)$/.test(type) &&
1032+ (type == 'object' ? !!object[property] : true);
1033+ }
1034+
1035+ /**
1036+ * Checks if a given `value` is an object created by the `Object` constructor
1037+ * assuming objects created by the `Object` constructor have no inherited
1038+ * enumerable properties and that there are no `Object.prototype` extensions.
1039+ *
1040+ * @private
1041+ * @param {Mixed} value The value to check.
1042+ * @returns {Boolean} Returns `true` if the `value` is a plain `Object` object, else `false`.
1043+ */
1044+ function isPlainObject(value) {
1045+ // avoid non-objects and false positives for `arguments` objects in IE < 9
1046+ var result = false;
1047+ if (!(value && typeof value == 'object') || isArguments(value)) {
1048+ return result;
1049+ }
1050+ // IE < 9 presents DOM nodes as `Object` objects except they have `toString`
1051+ // methods that are `typeof` "string" and still can coerce nodes to strings.
1052+ // Also check that the constructor is `Object` (i.e. `Object instanceof Object`)
1053+ var ctor = value.constructor;
1054+ if ((support.nodeClass || !(typeof value.toString != 'function' && typeof (value + '') == 'string')) &&
1055+ (!isClassOf(ctor, 'Function') || ctor instanceof ctor)) {
1056+ // In most environments an object's own properties are iterated before
1057+ // its inherited properties. If the last iterated property is an object's
1058+ // own property then there are no inherited enumerable properties.
1059+ if (support.iteratesOwnFirst) {
1060+ forProps(value, function(subValue, subKey) {
1061+ result = subKey;
1062+ });
1063+ return result === false || hasKey(value, result);
1064+ }
1065+ // IE < 9 iterates inherited properties before own properties. If the first
1066+ // iterated property is an object's own property then there are no inherited
1067+ // enumerable properties.
1068+ forProps(value, function(subValue, subKey) {
1069+ result = !hasKey(value, subKey);
1070+ return false;
1071+ });
1072+ return result === false;
1073+ }
1074+ return result;
1075+ }
1076+
1077+ /**
1078+ * Checks if a value can be safely coerced to a string.
1079+ *
1080+ * @private
1081+ * @param {Mixed} value The value to check.
1082+ * @returns {Boolean} Returns `true` if the value can be coerced, else `false`.
1083+ */
1084+ function isStringable(value) {
1085+ return hasKey(value, 'toString') || isClassOf(value, 'String');
1086+ }
1087+
1088+ /**
1089+ * Wraps a function and passes `this` to the original function as the
1090+ * first argument.
1091+ *
1092+ * @private
1093+ * @param {Function} fn The function to be wrapped.
1094+ * @returns {Function} The new function.
1095+ */
1096+ function methodize(fn) {
1097+ return function() {
1098+ var args = [this];
1099+ args.push.apply(args, arguments);
1100+ return fn.apply(null, args);
1101+ };
1102+ }
1103+
1104+ /**
1105+ * A no-operation function.
1106+ *
1107+ * @private
1108+ */
1109+ function noop() {
1110+ // no operation performed
1111+ }
1112+
1113+ /**
1114+ * A wrapper around require() to suppress `module missing` errors.
1115+ *
1116+ * @private
1117+ * @param {String} id The module id.
1118+ * @returns {Mixed} The exported module or `null`.
1119+ */
1120+ function req(id) {
1121+ try {
1122+ var result = freeExports && freeRequire(id);
1123+ } catch(e) { }
1124+ return result || null;
1125+ }
1126+
1127+ /**
1128+ * Runs a snippet of JavaScript via script injection.
1129+ *
1130+ * @private
1131+ * @param {String} code The code to run.
1132+ */
1133+ function runScript(code) {
1134+ var anchor = freeDefine ? define.amd : Benchmark,
1135+ script = doc.createElement('script'),
1136+ sibling = doc.getElementsByTagName('script')[0],
1137+ parent = sibling.parentNode,
1138+ prop = uid + 'runScript',
1139+ prefix = '(' + (freeDefine ? 'define.amd.' : 'Benchmark.') + prop + '||function(){})();';
1140+
1141+ // Firefox 2.0.0.2 cannot use script injection as intended because it executes
1142+ // asynchronously, but that's OK because script injection is only used to avoid
1143+ // the previously commented JaegerMonkey bug.
1144+ try {
1145+ // remove the inserted script *before* running the code to avoid differences
1146+ // in the expected script element count/order of the document.
1147+ script.appendChild(doc.createTextNode(prefix + code));
1148+ anchor[prop] = function() { destroyElement(script); };
1149+ } catch(e) {
1150+ parent = parent.cloneNode(false);
1151+ sibling = null;
1152+ script.text = code;
1153+ }
1154+ parent.insertBefore(script, sibling);
1155+ delete anchor[prop];
1156+ }
1157+
1158+ /**
1159+ * A helper function for setting options/event handlers.
1160+ *
1161+ * @private
1162+ * @param {Object} bench The benchmark instance.
1163+ * @param {Object} [options={}] Options object.
1164+ */
1165+ function setOptions(bench, options) {
1166+ options = extend({}, bench.constructor.options, options);
1167+ bench.options = forOwn(options, function(value, key) {
1168+ if (value != null) {
1169+ // add event listeners
1170+ if (/^on[A-Z]/.test(key)) {
1171+ forEach(key.split(' '), function(key) {
1172+ bench.on(key.slice(2).toLowerCase(), value);
1173+ });
1174+ } else if (!hasKey(bench, key)) {
1175+ bench[key] = deepClone(value);
1176+ }
1177+ }
1178+ });
1179+ }
1180+
1181+ /*--------------------------------------------------------------------------*/
1182+
1183+ /**
1184+ * Handles cycling/completing the deferred benchmark.
1185+ *
1186+ * @memberOf Benchmark.Deferred
1187+ */
1188+ function resolve() {
1189+ var me = this,
1190+ clone = me.benchmark,
1191+ bench = clone._original;
1192+
1193+ if (bench.aborted) {
1194+ // cycle() -> clone cycle/complete event -> compute()'s invoked bench.run() cycle/complete
1195+ me.teardown();
1196+ clone.running = false;
1197+ cycle(me);
1198+ }
1199+ else if (++me.cycles < clone.count) {
1200+ // continue the test loop
1201+ if (support.timeout) {
1202+ // use setTimeout to avoid a call stack overflow if called recursively
1203+ setTimeout(function() { clone.compiled.call(me, timer); }, 0);
1204+ } else {
1205+ clone.compiled.call(me, timer);
1206+ }
1207+ }
1208+ else {
1209+ timer.stop(me);
1210+ me.teardown();
1211+ delay(clone, function() { cycle(me); });
1212+ }
1213+ }
1214+
1215+ /*--------------------------------------------------------------------------*/
1216+
1217+ /**
1218+ * A deep clone utility.
1219+ *
1220+ * @static
1221+ * @memberOf Benchmark
1222+ * @param {Mixed} value The value to clone.
1223+ * @returns {Mixed} The cloned value.
1224+ */
1225+ function deepClone(value) {
1226+ var accessor,
1227+ circular,
1228+ clone,
1229+ ctor,
1230+ descriptor,
1231+ extensible,
1232+ key,
1233+ length,
1234+ markerKey,
1235+ parent,
1236+ result,
1237+ source,
1238+ subIndex,
1239+ data = { 'value': value },
1240+ index = 0,
1241+ marked = [],
1242+ queue = { 'length': 0 },
1243+ unmarked = [];
1244+
1245+ /**
1246+ * An easily detectable decorator for cloned values.
1247+ */
1248+ function Marker(object) {
1249+ this.raw = object;
1250+ }
1251+
1252+ /**
1253+ * The callback used by `forProps()`.
1254+ */
1255+ function forPropsCallback(subValue, subKey) {
1256+ // exit early to avoid cloning the marker
1257+ if (subValue && subValue.constructor == Marker) {
1258+ return;
1259+ }
1260+ // add objects to the queue
1261+ if (subValue === Object(subValue)) {
1262+ queue[queue.length++] = { 'key': subKey, 'parent': clone, 'source': value };
1263+ }
1264+ // assign non-objects
1265+ else {
1266+ try {
1267+ // will throw an error in strict mode if the property is read-only
1268+ clone[subKey] = subValue;
1269+ } catch(e) { }
1270+ }
1271+ }
1272+
1273+ /**
1274+ * Gets an available marker key for the given object.
1275+ */
1276+ function getMarkerKey(object) {
1277+ // avoid collisions with existing keys
1278+ var result = uid;
1279+ while (object[result] && object[result].constructor != Marker) {
1280+ result += 1;
1281+ }
1282+ return result;
1283+ }
1284+
1285+ do {
1286+ key = data.key;
1287+ parent = data.parent;
1288+ source = data.source;
1289+ clone = value = source ? source[key] : data.value;
1290+ accessor = circular = descriptor = false;
1291+
1292+ // create a basic clone to filter out functions, DOM elements, and
1293+ // other non `Object` objects
1294+ if (value === Object(value)) {
1295+ // use custom deep clone function if available
1296+ if (isClassOf(value.deepClone, 'Function')) {
1297+ clone = value.deepClone();
1298+ } else {
1299+ ctor = value.constructor;
1300+ switch (toString.call(value)) {
1301+ case '[object Array]':
1302+ clone = new ctor(value.length);
1303+ break;
1304+
1305+ case '[object Boolean]':
1306+ clone = new ctor(value == true);
1307+ break;
1308+
1309+ case '[object Date]':
1310+ clone = new ctor(+value);
1311+ break;
1312+
1313+ case '[object Object]':
1314+ isPlainObject(value) && (clone = {});
1315+ break;
1316+
1317+ case '[object Number]':
1318+ case '[object String]':
1319+ clone = new ctor(value);
1320+ break;
1321+
1322+ case '[object RegExp]':
1323+ clone = ctor(value.source,
1324+ (value.global ? 'g' : '') +
1325+ (value.ignoreCase ? 'i' : '') +
1326+ (value.multiline ? 'm' : ''));
1327+ }
1328+ }
1329+ // continue clone if `value` doesn't have an accessor descriptor
1330+ // http://es5.github.com/#x8.10.1
1331+ if (clone && clone != value &&
1332+ !(descriptor = source && support.descriptors && getDescriptor(source, key),
1333+ accessor = descriptor && (descriptor.get || descriptor.set))) {
1334+ // use an existing clone (circular reference)
1335+ if ((extensible = isExtensible(value))) {
1336+ markerKey = getMarkerKey(value);
1337+ if (value[markerKey]) {
1338+ circular = clone = value[markerKey].raw;
1339+ }
1340+ } else {
1341+ // for frozen/sealed objects
1342+ for (subIndex = 0, length = unmarked.length; subIndex < length; subIndex++) {
1343+ data = unmarked[subIndex];
1344+ if (data.object === value) {
1345+ circular = clone = data.clone;
1346+ break;
1347+ }
1348+ }
1349+ }
1350+ if (!circular) {
1351+ // mark object to allow quickly detecting circular references and tie it to its clone
1352+ if (extensible) {
1353+ value[markerKey] = new Marker(clone);
1354+ marked.push({ 'key': markerKey, 'object': value });
1355+ } else {
1356+ // for frozen/sealed objects
1357+ unmarked.push({ 'clone': clone, 'object': value });
1358+ }
1359+ // iterate over object properties
1360+ forProps(value, forPropsCallback, { 'which': 'all' });
1361+ }
1362+ }
1363+ }
1364+ if (parent) {
1365+ // for custom property descriptors
1366+ if (accessor || (descriptor && !(descriptor.configurable && descriptor.enumerable && descriptor.writable))) {
1367+ if ('value' in descriptor) {
1368+ descriptor.value = clone;
1369+ }
1370+ setDescriptor(parent, key, descriptor);
1371+ }
1372+ // for default property descriptors
1373+ else {
1374+ parent[key] = clone;
1375+ }
1376+ } else {
1377+ result = clone;
1378+ }
1379+ } while ((data = queue[index++]));
1380+
1381+ // remove markers
1382+ for (index = 0, length = marked.length; index < length; index++) {
1383+ data = marked[index];
1384+ delete data.object[data.key];
1385+ }
1386+ return result;
1387+ }
1388+
1389+ /**
1390+ * An iteration utility for arrays and objects.
1391+ * Callbacks may terminate the loop by explicitly returning `false`.
1392+ *
1393+ * @static
1394+ * @memberOf Benchmark
1395+ * @param {Array|Object} object The object to iterate over.
1396+ * @param {Function} callback The function called per iteration.
1397+ * @param {Mixed} thisArg The `this` binding for the callback.
1398+ * @returns {Array|Object} Returns the object iterated over.
1399+ */
1400+ function each(object, callback, thisArg) {
1401+ var result = object;
1402+ object = Object(object);
1403+
1404+ var fn = callback,
1405+ index = -1,
1406+ length = object.length,
1407+ isSnapshot = !!(object.snapshotItem && (length = object.snapshotLength)),
1408+ isSplittable = (noCharByIndex || noCharByOwnIndex) && isClassOf(object, 'String'),
1409+ isConvertable = isSnapshot || isSplittable || 'item' in object,
1410+ origObject = object;
1411+
1412+ // in Opera < 10.5 `hasKey(object, 'length')` returns `false` for NodeLists
1413+ if (length === length >>> 0) {
1414+ if (isConvertable) {
1415+ // the third argument of the callback is the original non-array object
1416+ callback = function(value, index) {
1417+ return fn.call(this, value, index, origObject);
1418+ };
1419+ // in IE < 9 strings don't support accessing characters by index
1420+ if (isSplittable) {
1421+ object = object.split('');
1422+ } else {
1423+ object = [];
1424+ while (++index < length) {
1425+ // in Safari 2 `index in object` is always `false` for NodeLists
1426+ object[index] = isSnapshot ? result.snapshotItem(index) : result[index];
1427+ }
1428+ }
1429+ }
1430+ forEach(object, callback, thisArg);
1431+ } else {
1432+ forOwn(object, callback, thisArg);
1433+ }
1434+ return result;
1435+ }
1436+
1437+ /**
1438+ * Copies enumerable properties from the source(s) object to the destination object.
1439+ *
1440+ * @static
1441+ * @memberOf Benchmark
1442+ * @param {Object} destination The destination object.
1443+ * @param {Object} [source={}] The source object.
1444+ * @returns {Object} The destination object.
1445+ */
1446+ function extend(destination, source) {
1447+ // Chrome < 14 incorrectly sets `destination` to `undefined` when we `delete arguments[0]`
1448+ // http://code.google.com/p/v8/issues/detail?id=839
1449+ var result = destination;
1450+ delete arguments[0];
1451+
1452+ forEach(arguments, function(source) {
1453+ forProps(source, function(value, key) {
1454+ result[key] = value;
1455+ });
1456+ });
1457+ return result;
1458+ }
1459+
1460+ /**
1461+ * A generic `Array#filter` like method.
1462+ *
1463+ * @static
1464+ * @memberOf Benchmark
1465+ * @param {Array} array The array to iterate over.
1466+ * @param {Function|String} callback The function/alias called per iteration.
1467+ * @param {Mixed} thisArg The `this` binding for the callback.
1468+ * @returns {Array} A new array of values that passed callback filter.
1469+ * @example
1470+ *
1471+ * // get odd numbers
1472+ * Benchmark.filter([1, 2, 3, 4, 5], function(n) {
1473+ * return n % 2;
1474+ * }); // -> [1, 3, 5];
1475+ *
1476+ * // get fastest benchmarks
1477+ * Benchmark.filter(benches, 'fastest');
1478+ *
1479+ * // get slowest benchmarks
1480+ * Benchmark.filter(benches, 'slowest');
1481+ *
1482+ * // get benchmarks that completed without erroring
1483+ * Benchmark.filter(benches, 'successful');
1484+ */
1485+ function filter(array, callback, thisArg) {
1486+ var result;
1487+
1488+ if (callback == 'successful') {
1489+ // callback to exclude those that are errored, unrun, or have hz of Infinity
1490+ callback = function(bench) { return bench.cycles && isFinite(bench.hz); };
1491+ }
1492+ else if (callback == 'fastest' || callback == 'slowest') {
1493+ // get successful, sort by period + margin of error, and filter fastest/slowest
1494+ result = filter(array, 'successful').sort(function(a, b) {
1495+ a = a.stats; b = b.stats;
1496+ return (a.mean + a.moe > b.mean + b.moe ? 1 : -1) * (callback == 'fastest' ? 1 : -1);
1497+ });
1498+ result = filter(result, function(bench) {
1499+ return result[0].compare(bench) == 0;
1500+ });
1501+ }
1502+ return result || reduce(array, function(result, value, index) {
1503+ return callback.call(thisArg, value, index, array) ? (result.push(value), result) : result;
1504+ }, []);
1505+ }
1506+
1507+ /**
1508+ * A generic `Array#forEach` like method.
1509+ * Callbacks may terminate the loop by explicitly returning `false`.
1510+ *
1511+ * @static
1512+ * @memberOf Benchmark
1513+ * @param {Array} array The array to iterate over.
1514+ * @param {Function} callback The function called per iteration.
1515+ * @param {Mixed} thisArg The `this` binding for the callback.
1516+ * @returns {Array} Returns the array iterated over.
1517+ */
1518+ function forEach(array, callback, thisArg) {
1519+ var index = -1,
1520+ length = (array = Object(array)).length >>> 0;
1521+
1522+ if (thisArg !== undefined) {
1523+ callback = bind(callback, thisArg);
1524+ }
1525+ while (++index < length) {
1526+ if (index in array &&
1527+ callback(array[index], index, array) === false) {
1528+ break;
1529+ }
1530+ }
1531+ return array;
1532+ }
1533+
1534+ /**
1535+ * Iterates over an object's own properties, executing the `callback` for each.
1536+ * Callbacks may terminate the loop by explicitly returning `false`.
1537+ *
1538+ * @static
1539+ * @memberOf Benchmark
1540+ * @param {Object} object The object to iterate over.
1541+ * @param {Function} callback The function executed per own property.
1542+ * @param {Mixed} thisArg The `this` binding for the callback.
1543+ * @returns {Object} Returns the object iterated over.
1544+ */
1545+ function forOwn(object, callback, thisArg) {
1546+ return forProps(object, callback, { 'bind': thisArg, 'which': 'own' });
1547+ }
1548+
1549+ /**
1550+ * Converts a number to a more readable comma-separated string representation.
1551+ *
1552+ * @static
1553+ * @memberOf Benchmark
1554+ * @param {Number} number The number to convert.
1555+ * @returns {String} The more readable string representation.
1556+ */
1557+ function formatNumber(number) {
1558+ number = String(number).split('.');
1559+ return number[0].replace(/(?=(?:\d{3})+$)(?!\b)/g, ',') +
1560+ (number[1] ? '.' + number[1] : '');
1561+ }
1562+
1563+ /**
1564+ * Checks if an object has the specified key as a direct property.
1565+ *
1566+ * @static
1567+ * @memberOf Benchmark
1568+ * @param {Object} object The object to check.
1569+ * @param {String} key The key to check for.
1570+ * @returns {Boolean} Returns `true` if key is a direct property, else `false`.
1571+ */
1572+ function hasKey() {
1573+ // lazy define for worst case fallback (not as accurate)
1574+ hasKey = function(object, key) {
1575+ var parent = object != null && (object.constructor || Object).prototype;
1576+ return !!parent && key in Object(object) && !(key in parent && object[key] === parent[key]);
1577+ };
1578+ // for modern browsers
1579+ if (isClassOf(hasOwnProperty, 'Function')) {
1580+ hasKey = function(object, key) {
1581+ return object != null && hasOwnProperty.call(object, key);
1582+ };
1583+ }
1584+ // for Safari 2
1585+ else if ({}.__proto__ == Object.prototype) {
1586+ hasKey = function(object, key) {
1587+ var result = false;
1588+ if (object != null) {
1589+ object = Object(object);
1590+ object.__proto__ = [object.__proto__, object.__proto__ = null, result = key in object][0];
1591+ }
1592+ return result;
1593+ };
1594+ }
1595+ return hasKey.apply(this, arguments);
1596+ }
1597+
1598+ /**
1599+ * A generic `Array#indexOf` like method.
1600+ *
1601+ * @static
1602+ * @memberOf Benchmark
1603+ * @param {Array} array The array to iterate over.
1604+ * @param {Mixed} value The value to search for.
1605+ * @param {Number} [fromIndex=0] The index to start searching from.
1606+ * @returns {Number} The index of the matched value or `-1`.
1607+ */
1608+ function indexOf(array, value, fromIndex) {
1609+ var index = toInteger(fromIndex),
1610+ length = (array = Object(array)).length >>> 0;
1611+
1612+ index = (index < 0 ? max(0, length + index) : index) - 1;
1613+ while (++index < length) {
1614+ if (index in array && value === array[index]) {
1615+ return index;
1616+ }
1617+ }
1618+ return -1;
1619+ }
1620+
1621+ /**
1622+ * Modify a string by replacing named tokens with matching object property values.
1623+ *
1624+ * @static
1625+ * @memberOf Benchmark
1626+ * @param {String} string The string to modify.
1627+ * @param {Object} object The template object.
1628+ * @returns {String} The modified string.
1629+ */
1630+ function interpolate(string, object) {
1631+ forOwn(object, function(value, key) {
1632+ // escape regexp special characters in `key`
1633+ string = string.replace(RegExp('#\\{' + key.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1') + '\\}', 'g'), value);
1634+ });
1635+ return string;
1636+ }
1637+
1638+ /**
1639+ * Invokes a method on all items in an array.
1640+ *
1641+ * @static
1642+ * @memberOf Benchmark
1643+ * @param {Array} benches Array of benchmarks to iterate over.
1644+ * @param {String|Object} name The name of the method to invoke OR options object.
1645+ * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the method with.
1646+ * @returns {Array} A new array of values returned from each method invoked.
1647+ * @example
1648+ *
1649+ * // invoke `reset` on all benchmarks
1650+ * Benchmark.invoke(benches, 'reset');
1651+ *
1652+ * // invoke `emit` with arguments
1653+ * Benchmark.invoke(benches, 'emit', 'complete', listener);
1654+ *
1655+ * // invoke `run(true)`, treat benchmarks as a queue, and register invoke callbacks
1656+ * Benchmark.invoke(benches, {
1657+ *
1658+ * // invoke the `run` method
1659+ * 'name': 'run',
1660+ *
1661+ * // pass a single argument
1662+ * 'args': true,
1663+ *
1664+ * // treat as queue, removing benchmarks from front of `benches` until empty
1665+ * 'queued': true,
1666+ *
1667+ * // called before any benchmarks have been invoked.
1668+ * 'onStart': onStart,
1669+ *
1670+ * // called between invoking benchmarks
1671+ * 'onCycle': onCycle,
1672+ *
1673+ * // called after all benchmarks have been invoked.
1674+ * 'onComplete': onComplete
1675+ * });
1676+ */
1677+ function invoke(benches, name) {
1678+ var args,
1679+ bench,
1680+ queued,
1681+ index = -1,
1682+ eventProps = { 'currentTarget': benches },
1683+ options = { 'onStart': noop, 'onCycle': noop, 'onComplete': noop },
1684+ result = map(benches, function(bench) { return bench; });
1685+
1686+ /**
1687+ * Invokes the method of the current object and if synchronous, fetches the next.
1688+ */
1689+ function execute() {
1690+ var listeners,
1691+ async = isAsync(bench);
1692+
1693+ if (async) {
1694+ // use `getNext` as the first listener
1695+ bench.on('complete', getNext);
1696+ listeners = bench.events.complete;
1697+ listeners.splice(0, 0, listeners.pop());
1698+ }
1699+ // execute method
1700+ result[index] = isClassOf(bench && bench[name], 'Function') ? bench[name].apply(bench, args) : undefined;
1701+ // if synchronous return true until finished
1702+ return !async && getNext();
1703+ }
1704+
1705+ /**
1706+ * Fetches the next bench or executes `onComplete` callback.
1707+ */
1708+ function getNext(event) {
1709+ var cycleEvent,
1710+ last = bench,
1711+ async = isAsync(last);
1712+
1713+ if (async) {
1714+ last.off('complete', getNext);
1715+ last.emit('complete');
1716+ }
1717+ // emit "cycle" event
1718+ eventProps.type = 'cycle';
1719+ eventProps.target = last;
1720+ cycleEvent = Event(eventProps);
1721+ options.onCycle.call(benches, cycleEvent);
1722+
1723+ // choose next benchmark if not exiting early
1724+ if (!cycleEvent.aborted && raiseIndex() !== false) {
1725+ bench = queued ? benches[0] : result[index];
1726+ if (isAsync(bench)) {
1727+ delay(bench, execute);
1728+ }
1729+ else if (async) {
1730+ // resume execution if previously asynchronous but now synchronous
1731+ while (execute()) { }
1732+ }
1733+ else {
1734+ // continue synchronous execution
1735+ return true;
1736+ }
1737+ } else {
1738+ // emit "complete" event
1739+ eventProps.type = 'complete';
1740+ options.onComplete.call(benches, Event(eventProps));
1741+ }
1742+ // When used as a listener `event.aborted = true` will cancel the rest of
1743+ // the "complete" listeners because they were already called above and when
1744+ // used as part of `getNext` the `return false` will exit the execution while-loop.
1745+ if (event) {
1746+ event.aborted = true;
1747+ } else {
1748+ return false;
1749+ }
1750+ }
1751+
1752+ /**
1753+ * Checks if invoking `Benchmark#run` with asynchronous cycles.
1754+ */
1755+ function isAsync(object) {
1756+ // avoid using `instanceof` here because of IE memory leak issues with host objects
1757+ var async = args[0] && args[0].async;
1758+ return Object(object).constructor == Benchmark && name == 'run' &&
1759+ ((async == null ? object.options.async : async) && support.timeout || object.defer);
1760+ }
1761+
1762+ /**
1763+ * Raises `index` to the next defined index or returns `false`.
1764+ */
1765+ function raiseIndex() {
1766+ var length = result.length;
1767+ if (queued) {
1768+ // if queued remove the previous bench and subsequent skipped non-entries
1769+ do {
1770+ ++index > 0 && shift.call(benches);
1771+ } while ((length = benches.length) && !('0' in benches));
1772+ }
1773+ else {
1774+ while (++index < length && !(index in result)) { }
1775+ }
1776+ // if we reached the last index then return `false`
1777+ return (queued ? length : index < length) ? index : (index = false);
1778+ }
1779+
1780+ // juggle arguments
1781+ if (isClassOf(name, 'String')) {
1782+ // 2 arguments (array, name)
1783+ args = slice.call(arguments, 2);
1784+ } else {
1785+ // 2 arguments (array, options)
1786+ options = extend(options, name);
1787+ name = options.name;
1788+ args = isClassOf(args = 'args' in options ? options.args : [], 'Array') ? args : [args];
1789+ queued = options.queued;
1790+ }
1791+
1792+ // start iterating over the array
1793+ if (raiseIndex() !== false) {
1794+ // emit "start" event
1795+ bench = result[index];
1796+ eventProps.type = 'start';
1797+ eventProps.target = bench;
1798+ options.onStart.call(benches, Event(eventProps));
1799+
1800+ // end early if the suite was aborted in an "onStart" listener
1801+ if (benches.aborted && benches.constructor == Suite && name == 'run') {
1802+ // emit "cycle" event
1803+ eventProps.type = 'cycle';
1804+ options.onCycle.call(benches, Event(eventProps));
1805+ // emit "complete" event
1806+ eventProps.type = 'complete';
1807+ options.onComplete.call(benches, Event(eventProps));
1808+ }
1809+ // else start
1810+ else {
1811+ if (isAsync(bench)) {
1812+ delay(bench, execute);
1813+ } else {
1814+ while (execute()) { }
1815+ }
1816+ }
1817+ }
1818+ return result;
1819+ }
1820+
1821+ /**
1822+ * Creates a string of joined array values or object key-value pairs.
1823+ *
1824+ * @static
1825+ * @memberOf Benchmark
1826+ * @param {Array|Object} object The object to operate on.
1827+ * @param {String} [separator1=','] The separator used between key-value pairs.
1828+ * @param {String} [separator2=': '] The separator used between keys and values.
1829+ * @returns {String} The joined result.
1830+ */
1831+ function join(object, separator1, separator2) {
1832+ var result = [],
1833+ length = (object = Object(object)).length,
1834+ arrayLike = length === length >>> 0;
1835+
1836+ separator2 || (separator2 = ': ');
1837+ each(object, function(value, key) {
1838+ result.push(arrayLike ? value : key + separator2 + value);
1839+ });
1840+ return result.join(separator1 || ',');
1841+ }
1842+
1843+ /**
1844+ * A generic `Array#map` like method.
1845+ *
1846+ * @static
1847+ * @memberOf Benchmark
1848+ * @param {Array} array The array to iterate over.
1849+ * @param {Function} callback The function called per iteration.
1850+ * @param {Mixed} thisArg The `this` binding for the callback.
1851+ * @returns {Array} A new array of values returned by the callback.
1852+ */
1853+ function map(array, callback, thisArg) {
1854+ return reduce(array, function(result, value, index) {
1855+ result[index] = callback.call(thisArg, value, index, array);
1856+ return result;
1857+ }, Array(Object(array).length >>> 0));
1858+ }
1859+
1860+ /**
1861+ * Retrieves the value of a specified property from all items in an array.
1862+ *
1863+ * @static
1864+ * @memberOf Benchmark
1865+ * @param {Array} array The array to iterate over.
1866+ * @param {String} property The property to pluck.
1867+ * @returns {Array} A new array of property values.
1868+ */
1869+ function pluck(array, property) {
1870+ return map(array, function(object) {
1871+ return object == null ? undefined : object[property];
1872+ });
1873+ }
1874+
1875+ /**
1876+ * A generic `Array#reduce` like method.
1877+ *
1878+ * @static
1879+ * @memberOf Benchmark
1880+ * @param {Array} array The array to iterate over.
1881+ * @param {Function} callback The function called per iteration.
1882+ * @param {Mixed} accumulator Initial value of the accumulator.
1883+ * @returns {Mixed} The accumulator.
1884+ */
1885+ function reduce(array, callback, accumulator) {
1886+ var noaccum = arguments.length < 3;
1887+ forEach(array, function(value, index) {
1888+ accumulator = noaccum ? (noaccum = false, value) : callback(accumulator, value, index, array);
1889+ });
1890+ return accumulator;
1891+ }
1892+
1893+ /*--------------------------------------------------------------------------*/
1894+
1895+ /**
1896+ * Aborts all benchmarks in the suite.
1897+ *
1898+ * @name abort
1899+ * @memberOf Benchmark.Suite
1900+ * @returns {Object} The suite instance.
1901+ */
1902+ function abortSuite() {
1903+ var event,
1904+ me = this,
1905+ resetting = calledBy.resetSuite;
1906+
1907+ if (me.running) {
1908+ event = Event('abort');
1909+ me.emit(event);
1910+ if (!event.cancelled || resetting) {
1911+ // avoid infinite recursion
1912+ calledBy.abortSuite = true;
1913+ me.reset();
1914+ delete calledBy.abortSuite;
1915+
1916+ if (!resetting) {
1917+ me.aborted = true;
1918+ invoke(me, 'abort');
1919+ }
1920+ }
1921+ }
1922+ return me;
1923+ }
1924+
1925+ /**
1926+ * Adds a test to the benchmark suite.
1927+ *
1928+ * @memberOf Benchmark.Suite
1929+ * @param {String} name A name to identify the benchmark.
1930+ * @param {Function|String} fn The test to benchmark.
1931+ * @param {Object} [options={}] Options object.
1932+ * @returns {Object} The benchmark instance.
1933+ * @example
1934+ *
1935+ * // basic usage
1936+ * suite.add(fn);
1937+ *
1938+ * // or using a name first
1939+ * suite.add('foo', fn);
1940+ *
1941+ * // or with options
1942+ * suite.add('foo', fn, {
1943+ * 'onCycle': onCycle,
1944+ * 'onComplete': onComplete
1945+ * });
1946+ *
1947+ * // or name and options
1948+ * suite.add('foo', {
1949+ * 'fn': fn,
1950+ * 'onCycle': onCycle,
1951+ * 'onComplete': onComplete
1952+ * });
1953+ *
1954+ * // or options only
1955+ * suite.add({
1956+ * 'name': 'foo',
1957+ * 'fn': fn,
1958+ * 'onCycle': onCycle,
1959+ * 'onComplete': onComplete
1960+ * });
1961+ */
1962+ function add(name, fn, options) {
1963+ var me = this,
1964+ bench = Benchmark(name, fn, options),
1965+ event = Event({ 'type': 'add', 'target': bench });
1966+
1967+ if (me.emit(event), !event.cancelled) {
1968+ me.push(bench);
1969+ }
1970+ return me;
1971+ }
1972+
1973+ /**
1974+ * Creates a new suite with cloned benchmarks.
1975+ *
1976+ * @name clone
1977+ * @memberOf Benchmark.Suite
1978+ * @param {Object} options Options object to overwrite cloned options.
1979+ * @returns {Object} The new suite instance.
1980+ */
1981+ function cloneSuite(options) {
1982+ var me = this,
1983+ result = new me.constructor(extend({}, me.options, options));
1984+
1985+ // copy own properties
1986+ forOwn(me, function(value, key) {
1987+ if (!hasKey(result, key)) {
1988+ result[key] = value && isClassOf(value.clone, 'Function')
1989+ ? value.clone()
1990+ : deepClone(value);
1991+ }
1992+ });
1993+ return result;
1994+ }
1995+
1996+ /**
1997+ * An `Array#filter` like method.
1998+ *
1999+ * @name filter
2000+ * @memberOf Benchmark.Suite
2001+ * @param {Function|String} callback The function/alias called per iteration.
2002+ * @returns {Object} A new suite of benchmarks that passed callback filter.
2003+ */
2004+ function filterSuite(callback) {
2005+ var me = this,
2006+ result = new me.constructor;
2007+
2008+ result.push.apply(result, filter(me, callback));
2009+ return result;
2010+ }
2011+
2012+ /**
2013+ * Resets all benchmarks in the suite.
2014+ *
2015+ * @name reset
2016+ * @memberOf Benchmark.Suite
2017+ * @returns {Object} The suite instance.
2018+ */
2019+ function resetSuite() {
2020+ var event,
2021+ me = this,
2022+ aborting = calledBy.abortSuite;
2023+
2024+ if (me.running && !aborting) {
2025+ // no worries, `resetSuite()` is called within `abortSuite()`
2026+ calledBy.resetSuite = true;
2027+ me.abort();
2028+ delete calledBy.resetSuite;
2029+ }
2030+ // reset if the state has changed
2031+ else if ((me.aborted || me.running) &&
2032+ (me.emit(event = Event('reset')), !event.cancelled)) {
2033+ me.running = false;
2034+ if (!aborting) {
2035+ invoke(me, 'reset');
2036+ }
2037+ }
2038+ return me;
2039+ }
2040+
2041+ /**
2042+ * Runs the suite.
2043+ *
2044+ * @name run
2045+ * @memberOf Benchmark.Suite
2046+ * @param {Object} [options={}] Options object.
2047+ * @returns {Object} The suite instance.
2048+ * @example
2049+ *
2050+ * // basic usage
2051+ * suite.run();
2052+ *
2053+ * // or with options
2054+ * suite.run({ 'async': true, 'queued': true });
2055+ */
2056+ function runSuite(options) {
2057+ var me = this;
2058+
2059+ me.reset();
2060+ me.running = true;
2061+ options || (options = {});
2062+
2063+ invoke(me, {
2064+ 'name': 'run',
2065+ 'args': options,
2066+ 'queued': options.queued,
2067+ 'onStart': function(event) {
2068+ me.emit(event);
2069+ },
2070+ 'onCycle': function(event) {
2071+ var bench = event.target;
2072+ if (bench.error) {
2073+ me.emit({ 'type': 'error', 'target': bench });
2074+ }
2075+ me.emit(event);
2076+ event.aborted = me.aborted;
2077+ },
2078+ 'onComplete': function(event) {
2079+ me.running = false;
2080+ me.emit(event);
2081+ }
2082+ });
2083+ return me;
2084+ }
2085+
2086+ /*--------------------------------------------------------------------------*/
2087+
2088+ /**
2089+ * Executes all registered listeners of the specified event type.
2090+ *
2091+ * @memberOf Benchmark, Benchmark.Suite
2092+ * @param {String|Object} type The event type or object.
2093+ * @returns {Mixed} Returns the return value of the last listener executed.
2094+ */
2095+ function emit(type) {
2096+ var listeners,
2097+ me = this,
2098+ event = Event(type),
2099+ events = me.events,
2100+ args = (arguments[0] = event, arguments);
2101+
2102+ event.currentTarget || (event.currentTarget = me);
2103+ event.target || (event.target = me);
2104+ delete event.result;
2105+
2106+ if (events && (listeners = hasKey(events, event.type) && events[event.type])) {
2107+ forEach(listeners.slice(), function(listener) {
2108+ if ((event.result = listener.apply(me, args)) === false) {
2109+ event.cancelled = true;
2110+ }
2111+ return !event.aborted;
2112+ });
2113+ }
2114+ return event.result;
2115+ }
2116+
2117+ /**
2118+ * Returns an array of event listeners for a given type that can be manipulated
2119+ * to add or remove listeners.
2120+ *
2121+ * @memberOf Benchmark, Benchmark.Suite
2122+ * @param {String} type The event type.
2123+ * @returns {Array} The listeners array.
2124+ */
2125+ function listeners(type) {
2126+ var me = this,
2127+ events = me.events || (me.events = {});
2128+
2129+ return hasKey(events, type) ? events[type] : (events[type] = []);
2130+ }
2131+
2132+ /**
2133+ * Unregisters a listener for the specified event type(s),
2134+ * or unregisters all listeners for the specified event type(s),
2135+ * or unregisters all listeners for all event types.
2136+ *
2137+ * @memberOf Benchmark, Benchmark.Suite
2138+ * @param {String} [type] The event type.
2139+ * @param {Function} [listener] The function to unregister.
2140+ * @returns {Object} The benchmark instance.
2141+ * @example
2142+ *
2143+ * // unregister a listener for an event type
2144+ * bench.off('cycle', listener);
2145+ *
2146+ * // unregister a listener for multiple event types
2147+ * bench.off('start cycle', listener);
2148+ *
2149+ * // unregister all listeners for an event type
2150+ * bench.off('cycle');
2151+ *
2152+ * // unregister all listeners for multiple event types
2153+ * bench.off('start cycle complete');
2154+ *
2155+ * // unregister all listeners for all event types
2156+ * bench.off();
2157+ */
2158+ function off(type, listener) {
2159+ var me = this,
2160+ events = me.events;
2161+
2162+ events && each(type ? type.split(' ') : events, function(listeners, type) {
2163+ var index;
2164+ if (typeof listeners == 'string') {
2165+ type = listeners;
2166+ listeners = hasKey(events, type) && events[type];
2167+ }
2168+ if (listeners) {
2169+ if (listener) {
2170+ index = indexOf(listeners, listener);
2171+ if (index > -1) {
2172+ listeners.splice(index, 1);
2173+ }
2174+ } else {
2175+ listeners.length = 0;
2176+ }
2177+ }
2178+ });
2179+ return me;
2180+ }
2181+
2182+ /**
2183+ * Registers a listener for the specified event type(s).
2184+ *
2185+ * @memberOf Benchmark, Benchmark.Suite
2186+ * @param {String} type The event type.
2187+ * @param {Function} listener The function to register.
2188+ * @returns {Object} The benchmark instance.
2189+ * @example
2190+ *
2191+ * // register a listener for an event type
2192+ * bench.on('cycle', listener);
2193+ *
2194+ * // register a listener for multiple event types
2195+ * bench.on('start cycle', listener);
2196+ */
2197+ function on(type, listener) {
2198+ var me = this,
2199+ events = me.events || (me.events = {});
2200+
2201+ forEach(type.split(' '), function(type) {
2202+ (hasKey(events, type)
2203+ ? events[type]
2204+ : (events[type] = [])
2205+ ).push(listener);
2206+ });
2207+ return me;
2208+ }
2209+
2210+ /*--------------------------------------------------------------------------*/
2211+
2212+ /**
2213+ * Aborts the benchmark without recording times.
2214+ *
2215+ * @memberOf Benchmark
2216+ * @returns {Object} The benchmark instance.
2217+ */
2218+ function abort() {
2219+ var event,
2220+ me = this,
2221+ resetting = calledBy.reset;
2222+
2223+ if (me.running) {
2224+ event = Event('abort');
2225+ me.emit(event);
2226+ if (!event.cancelled || resetting) {
2227+ // avoid infinite recursion
2228+ calledBy.abort = true;
2229+ me.reset();
2230+ delete calledBy.abort;
2231+
2232+ if (support.timeout) {
2233+ clearTimeout(me._timerId);
2234+ delete me._timerId;
2235+ }
2236+ if (!resetting) {
2237+ me.aborted = true;
2238+ me.running = false;
2239+ }
2240+ }
2241+ }
2242+ return me;
2243+ }
2244+
2245+ /**
2246+ * Creates a new benchmark using the same test and options.
2247+ *
2248+ * @memberOf Benchmark
2249+ * @param {Object} options Options object to overwrite cloned options.
2250+ * @returns {Object} The new benchmark instance.
2251+ * @example
2252+ *
2253+ * var bizarro = bench.clone({
2254+ * 'name': 'doppelganger'
2255+ * });
2256+ */
2257+ function clone(options) {
2258+ var me = this,
2259+ result = new me.constructor(extend({}, me, options));
2260+
2261+ // correct the `options` object
2262+ result.options = extend({}, me.options, options);
2263+
2264+ // copy own custom properties
2265+ forOwn(me, function(value, key) {
2266+ if (!hasKey(result, key)) {
2267+ result[key] = deepClone(value);
2268+ }
2269+ });
2270+ return result;
2271+ }
2272+
2273+ /**
2274+ * Determines if a benchmark is faster than another.
2275+ *
2276+ * @memberOf Benchmark
2277+ * @param {Object} other The benchmark to compare.
2278+ * @returns {Number} Returns `-1` if slower, `1` if faster, and `0` if indeterminate.
2279+ */
2280+ function compare(other) {
2281+ var critical,
2282+ zStat,
2283+ me = this,
2284+ sample1 = me.stats.sample,
2285+ sample2 = other.stats.sample,
2286+ size1 = sample1.length,
2287+ size2 = sample2.length,
2288+ maxSize = max(size1, size2),
2289+ minSize = min(size1, size2),
2290+ u1 = getU(sample1, sample2),
2291+ u2 = getU(sample2, sample1),
2292+ u = min(u1, u2);
2293+
2294+ function getScore(xA, sampleB) {
2295+ return reduce(sampleB, function(total, xB) {
2296+ return total + (xB > xA ? 0 : xB < xA ? 1 : 0.5);
2297+ }, 0);
2298+ }
2299+
2300+ function getU(sampleA, sampleB) {
2301+ return reduce(sampleA, function(total, xA) {
2302+ return total + getScore(xA, sampleB);
2303+ }, 0);
2304+ }
2305+
2306+ function getZ(u) {
2307+ return (u - ((size1 * size2) / 2)) / sqrt((size1 * size2 * (size1 + size2 + 1)) / 12);
2308+ }
2309+
2310+ // exit early if comparing the same benchmark
2311+ if (me == other) {
2312+ return 0;
2313+ }
2314+ // reject the null hyphothesis the two samples come from the
2315+ // same population (i.e. have the same median) if...
2316+ if (size1 + size2 > 30) {
2317+ // ...the z-stat is greater than 1.96 or less than -1.96
2318+ // http://www.statisticslectures.com/topics/mannwhitneyu/
2319+ zStat = getZ(u);
2320+ return abs(zStat) > 1.96 ? (zStat > 0 ? -1 : 1) : 0;
2321+ }
2322+ // ...the U value is less than or equal the critical U value
2323+ // http://www.geoib.com/mann-whitney-u-test.html
2324+ critical = maxSize < 5 || minSize < 3 ? 0 : uTable[maxSize][minSize - 3];
2325+ return u <= critical ? (u == u1 ? 1 : -1) : 0;
2326+ }
2327+
2328+ /**
2329+ * Reset properties and abort if running.
2330+ *
2331+ * @memberOf Benchmark
2332+ * @returns {Object} The benchmark instance.
2333+ */
2334+ function reset() {
2335+ var data,
2336+ event,
2337+ me = this,
2338+ index = 0,
2339+ changes = { 'length': 0 },
2340+ queue = { 'length': 0 };
2341+
2342+ if (me.running && !calledBy.abort) {
2343+ // no worries, `reset()` is called within `abort()`
2344+ calledBy.reset = true;
2345+ me.abort();
2346+ delete calledBy.reset;
2347+ }
2348+ else {
2349+ // a non-recursive solution to check if properties have changed
2350+ // http://www.jslab.dk/articles/non.recursive.preorder.traversal.part4
2351+ data = { 'destination': me, 'source': extend({}, me.constructor.prototype, me.options) };
2352+ do {
2353+ forOwn(data.source, function(value, key) {
2354+ var changed,
2355+ destination = data.destination,
2356+ currValue = destination[key];
2357+
2358+ if (value && typeof value == 'object') {
2359+ if (isClassOf(value, 'Array')) {
2360+ // check if an array value has changed to a non-array value
2361+ if (!isClassOf(currValue, 'Array')) {
2362+ changed = currValue = [];
2363+ }
2364+ // or has changed its length
2365+ if (currValue.length != value.length) {
2366+ changed = currValue = currValue.slice(0, value.length);
2367+ currValue.length = value.length;
2368+ }
2369+ }
2370+ // check if an object has changed to a non-object value
2371+ else if (!currValue || typeof currValue != 'object') {
2372+ changed = currValue = {};
2373+ }
2374+ // register a changed object
2375+ if (changed) {
2376+ changes[changes.length++] = { 'destination': destination, 'key': key, 'value': currValue };
2377+ }
2378+ queue[queue.length++] = { 'destination': currValue, 'source': value };
2379+ }
2380+ // register a changed primitive
2381+ else if (value !== currValue && !(value == null || isClassOf(value, 'Function'))) {
2382+ changes[changes.length++] = { 'destination': destination, 'key': key, 'value': value };
2383+ }
2384+ });
2385+ }
2386+ while ((data = queue[index++]));
2387+
2388+ // if changed emit the `reset` event and if it isn't cancelled reset the benchmark
2389+ if (changes.length && (me.emit(event = Event('reset')), !event.cancelled)) {
2390+ forEach(changes, function(data) {
2391+ data.destination[data.key] = data.value;
2392+ });
2393+ }
2394+ }
2395+ return me;
2396+ }
2397+
2398+ /**
2399+ * Displays relevant benchmark information when coerced to a string.
2400+ *
2401+ * @name toString
2402+ * @memberOf Benchmark
2403+ * @returns {String} A string representation of the benchmark instance.
2404+ */
2405+ function toStringBench() {
2406+ var me = this,
2407+ error = me.error,
2408+ hz = me.hz,
2409+ id = me.id,
2410+ stats = me.stats,
2411+ size = stats.sample.length,
2412+ pm = support.java ? '+/-' : '\xb1',
2413+ result = me.name || (isNaN(id) ? id : '<Test #' + id + '>');
2414+
2415+ if (error) {
2416+ result += ': ' + join(error);
2417+ } else {
2418+ result += ' x ' + formatNumber(hz.toFixed(hz < 100 ? 2 : 0)) + ' ops/sec ' + pm +
2419+ stats.rme.toFixed(2) + '% (' + size + ' run' + (size == 1 ? '' : 's') + ' sampled)';
2420+ }
2421+ return result;
2422+ }
2423+
2424+ /*--------------------------------------------------------------------------*/
2425+
2426+ /**
2427+ * Clocks the time taken to execute a test per cycle (secs).
2428+ *
2429+ * @private
2430+ * @param {Object} bench The benchmark instance.
2431+ * @returns {Number} The time taken.
2432+ */
2433+ function clock() {
2434+ var applet,
2435+ options = Benchmark.options,
2436+ template = { 'begin': 's$=new n$', 'end': 'r$=(new n$-s$)/1e3', 'uid': uid },
2437+ timers = [{ 'ns': timer.ns, 'res': max(0.0015, getRes('ms')), 'unit': 'ms' }];
2438+
2439+ // lazy define for hi-res timers
2440+ clock = function(clone) {
2441+ var deferred;
2442+ if (clone instanceof Deferred) {
2443+ deferred = clone;
2444+ clone = deferred.benchmark;
2445+ }
2446+
2447+ var bench = clone._original,
2448+ fn = bench.fn,
2449+ fnArg = deferred ? getFirstArgument(fn) || 'deferred' : '',
2450+ stringable = isStringable(fn);
2451+
2452+ var source = {
2453+ 'setup': getSource(bench.setup, preprocess('m$.setup()')),
2454+ 'fn': getSource(fn, preprocess('m$.fn(' + fnArg + ')')),
2455+ 'fnArg': fnArg,
2456+ 'teardown': getSource(bench.teardown, preprocess('m$.teardown()'))
2457+ };
2458+
2459+ var count = bench.count = clone.count,
2460+ decompilable = support.decompilation || stringable,
2461+ id = bench.id,
2462+ isEmpty = !(source.fn || stringable),
2463+ name = bench.name || (typeof id == 'number' ? '<Test #' + id + '>' : id),
2464+ ns = timer.ns,
2465+ result = 0;
2466+
2467+ // init `minTime` if needed
2468+ clone.minTime = bench.minTime || (bench.minTime = bench.options.minTime = options.minTime);
2469+
2470+ // repair nanosecond timer
2471+ // (some Chrome builds erase the `ns` variable after millions of executions)
2472+ if (applet) {
2473+ try {
2474+ ns.nanoTime();
2475+ } catch(e) {
2476+ // use non-element to avoid issues with libs that augment them
2477+ ns = timer.ns = new applet.Packages.nano;
2478+ }
2479+ }
2480+
2481+ // Compile in setup/teardown functions and the test loop.
2482+ // Create a new compiled test, instead of using the cached `bench.compiled`,
2483+ // to avoid potential engine optimizations enabled over the life of the test.
2484+ var compiled = bench.compiled = createFunction(preprocess('t$'), interpolate(
2485+ preprocess(deferred
2486+ ? 'var d$=this,#{fnArg}=d$,m$=d$.benchmark._original,f$=m$.fn,su$=m$.setup,td$=m$.teardown;' +
2487+ // when `deferred.cycles` is `0` then...
2488+ 'if(!d$.cycles){' +
2489+ // set `deferred.fn`
2490+ 'd$.fn=function(){var #{fnArg}=d$;if(typeof f$=="function"){try{#{fn}\n}catch(e$){f$(d$)}}else{#{fn}\n}};' +
2491+ // set `deferred.teardown`
2492+ 'd$.teardown=function(){d$.cycles=0;if(typeof td$=="function"){try{#{teardown}\n}catch(e$){td$()}}else{#{teardown}\n}};' +
2493+ // execute the benchmark's `setup`
2494+ 'if(typeof su$=="function"){try{#{setup}\n}catch(e$){su$()}}else{#{setup}\n};' +
2495+ // start timer
2496+ 't$.start(d$);' +
2497+ // execute `deferred.fn` and return a dummy object
2498+ '}d$.fn();return{}'
2499+
2500+ : 'var r$,s$,m$=this,f$=m$.fn,i$=m$.count,n$=t$.ns;#{setup}\n#{begin};' +
2501+ 'while(i$--){#{fn}\n}#{end};#{teardown}\nreturn{elapsed:r$,uid:"#{uid}"}'),
2502+ source
2503+ ));
2504+
2505+ try {
2506+ if (isEmpty) {
2507+ // Firefox may remove dead code from Function#toString results
2508+ // http://bugzil.la/536085
2509+ throw new Error('The test "' + name + '" is empty. This may be the result of dead code removal.');
2510+ }
2511+ else if (!deferred) {
2512+ // pretest to determine if compiled code is exits early, usually by a
2513+ // rogue `return` statement, by checking for a return object with the uid
2514+ bench.count = 1;
2515+ compiled = (compiled.call(bench, timer) || {}).uid == uid && compiled;
2516+ bench.count = count;
2517+ }
2518+ } catch(e) {
2519+ compiled = null;
2520+ clone.error = e || new Error(String(e));
2521+ bench.count = count;
2522+ }
2523+ // fallback when a test exits early or errors during pretest
2524+ if (decompilable && !compiled && !deferred && !isEmpty) {
2525+ compiled = createFunction(preprocess('t$'), interpolate(
2526+ preprocess(
2527+ (clone.error && !stringable
2528+ ? 'var r$,s$,m$=this,f$=m$.fn,i$=m$.count'
2529+ : 'function f$(){#{fn}\n}var r$,s$,m$=this,i$=m$.count'
2530+ ) +
2531+ ',n$=t$.ns;#{setup}\n#{begin};m$.f$=f$;while(i$--){m$.f$()}#{end};' +
2532+ 'delete m$.f$;#{teardown}\nreturn{elapsed:r$}'
2533+ ),
2534+ source
2535+ ));
2536+
2537+ try {
2538+ // pretest one more time to check for errors
2539+ bench.count = 1;
2540+ compiled.call(bench, timer);
2541+ bench.compiled = compiled;
2542+ bench.count = count;
2543+ delete clone.error;
2544+ }
2545+ catch(e) {
2546+ bench.count = count;
2547+ if (clone.error) {
2548+ compiled = null;
2549+ } else {
2550+ bench.compiled = compiled;
2551+ clone.error = e || new Error(String(e));
2552+ }
2553+ }
2554+ }
2555+ // assign `compiled` to `clone` before calling in case a deferred benchmark
2556+ // immediately calls `deferred.resolve()`
2557+ clone.compiled = compiled;
2558+ // if no errors run the full test loop
2559+ if (!clone.error) {
2560+ result = compiled.call(deferred || bench, timer).elapsed;
2561+ }
2562+ return result;
2563+ };
2564+
2565+ /*------------------------------------------------------------------------*/
2566+
2567+ /**
2568+ * Gets the current timer's minimum resolution (secs).
2569+ */
2570+ function getRes(unit) {
2571+ var measured,
2572+ begin,
2573+ count = 30,
2574+ divisor = 1e3,
2575+ ns = timer.ns,
2576+ sample = [];
2577+
2578+ // get average smallest measurable time
2579+ while (count--) {
2580+ if (unit == 'us') {
2581+ divisor = 1e6;
2582+ if (ns.stop) {
2583+ ns.start();
2584+ while (!(measured = ns.microseconds())) { }
2585+ } else if (ns[perfName]) {
2586+ divisor = 1e3;
2587+ measured = Function('n', 'var r,s=n.' + perfName + '();while(!(r=n.' + perfName + '()-s)){};return r')(ns);
2588+ } else {
2589+ begin = ns();
2590+ while (!(measured = ns() - begin)) { }
2591+ }
2592+ }
2593+ else if (unit == 'ns') {
2594+ divisor = 1e9;
2595+ if (ns.nanoTime) {
2596+ begin = ns.nanoTime();
2597+ while (!(measured = ns.nanoTime() - begin)) { }
2598+ } else {
2599+ begin = (begin = ns())[0] + (begin[1] / divisor);
2600+ while (!(measured = ((measured = ns())[0] + (measured[1] / divisor)) - begin)) { }
2601+ divisor = 1;
2602+ }
2603+ }
2604+ else {
2605+ begin = new ns;
2606+ while (!(measured = new ns - begin)) { }
2607+ }
2608+ // check for broken timers (nanoTime may have issues)
2609+ // http://alivebutsleepy.srnet.cz/unreliable-system-nanotime/
2610+ if (measured > 0) {
2611+ sample.push(measured);
2612+ } else {
2613+ sample.push(Infinity);
2614+ break;
2615+ }
2616+ }
2617+ // convert to seconds
2618+ return getMean(sample) / divisor;
2619+ }
2620+
2621+ /**
2622+ * Replaces all occurrences of `$` with a unique number and
2623+ * template tokens with content.
2624+ */
2625+ function preprocess(code) {
2626+ return interpolate(code, template).replace(/\$/g, /\d+/.exec(uid));
2627+ }
2628+
2629+ /*------------------------------------------------------------------------*/
2630+
2631+ // detect nanosecond support from a Java applet
2632+ each(doc && doc.applets || [], function(element) {
2633+ return !(timer.ns = applet = 'nanoTime' in element && element);
2634+ });
2635+
2636+ // check type in case Safari returns an object instead of a number
2637+ try {
2638+ if (typeof timer.ns.nanoTime() == 'number') {
2639+ timers.push({ 'ns': timer.ns, 'res': getRes('ns'), 'unit': 'ns' });
2640+ }
2641+ } catch(e) { }
2642+
2643+ // detect Chrome's microsecond timer:
2644+ // enable benchmarking via the --enable-benchmarking command
2645+ // line switch in at least Chrome 7 to use chrome.Interval
2646+ try {
2647+ if ((timer.ns = new (window.chrome || window.chromium).Interval)) {
2648+ timers.push({ 'ns': timer.ns, 'res': getRes('us'), 'unit': 'us' });
2649+ }
2650+ } catch(e) { }
2651+
2652+ // detect `performance.now` microsecond resolution timer
2653+ if ((timer.ns = perfName && perfObject)) {
2654+ timers.push({ 'ns': timer.ns, 'res': getRes('us'), 'unit': 'us' });
2655+ }
2656+
2657+ // detect Node's nanosecond resolution timer available in Node >= 0.8
2658+ if (processObject && typeof (timer.ns = processObject.hrtime) == 'function') {
2659+ timers.push({ 'ns': timer.ns, 'res': getRes('ns'), 'unit': 'ns' });
2660+ }
2661+
2662+ // detect Wade Simmons' Node microtime module
2663+ if (microtimeObject && typeof (timer.ns = microtimeObject.now) == 'function') {
2664+ timers.push({ 'ns': timer.ns, 'res': getRes('us'), 'unit': 'us' });
2665+ }
2666+
2667+ // pick timer with highest resolution
2668+ timer = reduce(timers, function(timer, other) {
2669+ return other.res < timer.res ? other : timer;
2670+ });
2671+
2672+ // remove unused applet
2673+ if (timer.unit != 'ns' && applet) {
2674+ applet = destroyElement(applet);
2675+ }
2676+ // error if there are no working timers
2677+ if (timer.res == Infinity) {
2678+ throw new Error('Benchmark.js was unable to find a working timer.');
2679+ }
2680+ // use API of chosen timer
2681+ if (timer.unit == 'ns') {
2682+ if (timer.ns.nanoTime) {
2683+ extend(template, {
2684+ 'begin': 's$=n$.nanoTime()',
2685+ 'end': 'r$=(n$.nanoTime()-s$)/1e9'
2686+ });
2687+ } else {
2688+ extend(template, {
2689+ 'begin': 's$=n$()',
2690+ 'end': 'r$=n$(s$);r$=r$[0]+(r$[1]/1e9)'
2691+ });
2692+ }
2693+ }
2694+ else if (timer.unit == 'us') {
2695+ if (timer.ns.stop) {
2696+ extend(template, {
2697+ 'begin': 's$=n$.start()',
2698+ 'end': 'r$=n$.microseconds()/1e6'
2699+ });
2700+ } else if (perfName) {
2701+ extend(template, {
2702+ 'begin': 's$=n$.' + perfName + '()',
2703+ 'end': 'r$=(n$.' + perfName + '()-s$)/1e3'
2704+ });
2705+ } else {
2706+ extend(template, {
2707+ 'begin': 's$=n$()',
2708+ 'end': 'r$=(n$()-s$)/1e6'
2709+ });
2710+ }
2711+ }
2712+
2713+ // define `timer` methods
2714+ timer.start = createFunction(preprocess('o$'),
2715+ preprocess('var n$=this.ns,#{begin};o$.elapsed=0;o$.timeStamp=s$'));
2716+
2717+ timer.stop = createFunction(preprocess('o$'),
2718+ preprocess('var n$=this.ns,s$=o$.timeStamp,#{end};o$.elapsed=r$'));
2719+
2720+ // resolve time span required to achieve a percent uncertainty of at most 1%
2721+ // http://spiff.rit.edu/classes/phys273/uncert/uncert.html
2722+ options.minTime || (options.minTime = max(timer.res / 2 / 0.01, 0.05));
2723+ return clock.apply(null, arguments);
2724+ }
2725+
2726+ /*--------------------------------------------------------------------------*/
2727+
2728+ /**
2729+ * Computes stats on benchmark results.
2730+ *
2731+ * @private
2732+ * @param {Object} bench The benchmark instance.
2733+ * @param {Object} options The options object.
2734+ */
2735+ function compute(bench, options) {
2736+ options || (options = {});
2737+
2738+ var async = options.async,
2739+ elapsed = 0,
2740+ initCount = bench.initCount,
2741+ minSamples = bench.minSamples,
2742+ queue = [],
2743+ sample = bench.stats.sample;
2744+
2745+ /**
2746+ * Adds a clone to the queue.
2747+ */
2748+ function enqueue() {
2749+ queue.push(bench.clone({
2750+ '_original': bench,
2751+ 'events': {
2752+ 'abort': [update],
2753+ 'cycle': [update],
2754+ 'error': [update],
2755+ 'start': [update]
2756+ }
2757+ }));
2758+ }
2759+
2760+ /**
2761+ * Updates the clone/original benchmarks to keep their data in sync.
2762+ */
2763+ function update(event) {
2764+ var clone = this,
2765+ type = event.type;
2766+
2767+ if (bench.running) {
2768+ if (type == 'start') {
2769+ // Note: `clone.minTime` prop is inited in `clock()`
2770+ clone.count = bench.initCount;
2771+ }
2772+ else {
2773+ if (type == 'error') {
2774+ bench.error = clone.error;
2775+ }
2776+ if (type == 'abort') {
2777+ bench.abort();
2778+ bench.emit('cycle');
2779+ } else {
2780+ event.currentTarget = event.target = bench;
2781+ bench.emit(event);
2782+ }
2783+ }
2784+ } else if (bench.aborted) {
2785+ // clear abort listeners to avoid triggering bench's abort/cycle again
2786+ clone.events.abort.length = 0;
2787+ clone.abort();
2788+ }
2789+ }
2790+
2791+ /**
2792+ * Determines if more clones should be queued or if cycling should stop.
2793+ */
2794+ function evaluate(event) {
2795+ var critical,
2796+ df,
2797+ mean,
2798+ moe,
2799+ rme,
2800+ sd,
2801+ sem,
2802+ variance,
2803+ clone = event.target,
2804+ done = bench.aborted,
2805+ now = +new Date,
2806+ size = sample.push(clone.times.period),
2807+ maxedOut = size >= minSamples && (elapsed += now - clone.times.timeStamp) / 1e3 > bench.maxTime,
2808+ times = bench.times,
2809+ varOf = function(sum, x) { return sum + pow(x - mean, 2); };
2810+
2811+ // exit early for aborted or unclockable tests
2812+ if (done || clone.hz == Infinity) {
2813+ maxedOut = !(size = sample.length = queue.length = 0);
2814+ }
2815+
2816+ if (!done) {
2817+ // sample mean (estimate of the population mean)
2818+ mean = getMean(sample);
2819+ // sample variance (estimate of the population variance)
2820+ variance = reduce(sample, varOf, 0) / (size - 1) || 0;
2821+ // sample standard deviation (estimate of the population standard deviation)
2822+ sd = sqrt(variance);
2823+ // standard error of the mean (a.k.a. the standard deviation of the sampling distribution of the sample mean)
2824+ sem = sd / sqrt(size);
2825+ // degrees of freedom
2826+ df = size - 1;
2827+ // critical value
2828+ critical = tTable[Math.round(df) || 1] || tTable.infinity;
2829+ // margin of error
2830+ moe = sem * critical;
2831+ // relative margin of error
2832+ rme = (moe / mean) * 100 || 0;
2833+
2834+ extend(bench.stats, {
2835+ 'deviation': sd,
2836+ 'mean': mean,
2837+ 'moe': moe,
2838+ 'rme': rme,
2839+ 'sem': sem,
2840+ 'variance': variance
2841+ });
2842+
2843+ // Abort the cycle loop when the minimum sample size has been collected
2844+ // and the elapsed time exceeds the maximum time allowed per benchmark.
2845+ // We don't count cycle delays toward the max time because delays may be
2846+ // increased by browsers that clamp timeouts for inactive tabs.
2847+ // https://developer.mozilla.org/en/window.setTimeout#Inactive_tabs
2848+ if (maxedOut) {
2849+ // reset the `initCount` in case the benchmark is rerun
2850+ bench.initCount = initCount;
2851+ bench.running = false;
2852+ done = true;
2853+ times.elapsed = (now - times.timeStamp) / 1e3;
2854+ }
2855+ if (bench.hz != Infinity) {
2856+ bench.hz = 1 / mean;
2857+ times.cycle = mean * bench.count;
2858+ times.period = mean;
2859+ }
2860+ }
2861+ // if time permits, increase sample size to reduce the margin of error
2862+ if (queue.length < 2 && !maxedOut) {
2863+ enqueue();
2864+ }
2865+ // abort the invoke cycle when done
2866+ event.aborted = done;
2867+ }
2868+
2869+ // init queue and begin
2870+ enqueue();
2871+ invoke(queue, {
2872+ 'name': 'run',
2873+ 'args': { 'async': async },
2874+ 'queued': true,
2875+ 'onCycle': evaluate,
2876+ 'onComplete': function() { bench.emit('complete'); }
2877+ });
2878+ }
2879+
2880+ /*--------------------------------------------------------------------------*/
2881+
2882+ /**
2883+ * Cycles a benchmark until a run `count` can be established.
2884+ *
2885+ * @private
2886+ * @param {Object} clone The cloned benchmark instance.
2887+ * @param {Object} options The options object.
2888+ */
2889+ function cycle(clone, options) {
2890+ options || (options = {});
2891+
2892+ var deferred;
2893+ if (clone instanceof Deferred) {
2894+ deferred = clone;
2895+ clone = clone.benchmark;
2896+ }
2897+
2898+ var clocked,
2899+ cycles,
2900+ divisor,
2901+ event,
2902+ minTime,
2903+ period,
2904+ async = options.async,
2905+ bench = clone._original,
2906+ count = clone.count,
2907+ times = clone.times;
2908+
2909+ // continue, if not aborted between cycles
2910+ if (clone.running) {
2911+ // `minTime` is set to `Benchmark.options.minTime` in `clock()`
2912+ cycles = ++clone.cycles;
2913+ clocked = deferred ? deferred.elapsed : clock(clone);
2914+ minTime = clone.minTime;
2915+
2916+ if (cycles > bench.cycles) {
2917+ bench.cycles = cycles;
2918+ }
2919+ if (clone.error) {
2920+ event = Event('error');
2921+ event.message = clone.error;
2922+ clone.emit(event);
2923+ if (!event.cancelled) {
2924+ clone.abort();
2925+ }
2926+ }
2927+ }
2928+
2929+ // continue, if not errored
2930+ if (clone.running) {
2931+ // time taken to complete last test cycle
2932+ bench.times.cycle = times.cycle = clocked;
2933+ // seconds per operation
2934+ period = bench.times.period = times.period = clocked / count;
2935+ // ops per second
2936+ bench.hz = clone.hz = 1 / period;
2937+ // avoid working our way up to this next time
2938+ bench.initCount = clone.initCount = count;
2939+ // do we need to do another cycle?
2940+ clone.running = clocked < minTime;
2941+
2942+ if (clone.running) {
2943+ // tests may clock at `0` when `initCount` is a small number,
2944+ // to avoid that we set its count to something a bit higher
2945+ if (!clocked && (divisor = divisors[clone.cycles]) != null) {
2946+ count = floor(4e6 / divisor);
2947+ }
2948+ // calculate how many more iterations it will take to achive the `minTime`
2949+ if (count <= clone.count) {
2950+ count += Math.ceil((minTime - clocked) / period);
2951+ }
2952+ clone.running = count != Infinity;
2953+ }
2954+ }
2955+ // should we exit early?
2956+ event = Event('cycle');
2957+ clone.emit(event);
2958+ if (event.aborted) {
2959+ clone.abort();
2960+ }
2961+ // figure out what to do next
2962+ if (clone.running) {
2963+ // start a new cycle
2964+ clone.count = count;
2965+ if (deferred) {
2966+ clone.compiled.call(deferred, timer);
2967+ } else if (async) {
2968+ delay(clone, function() { cycle(clone, options); });
2969+ } else {
2970+ cycle(clone);
2971+ }
2972+ }
2973+ else {
2974+ // fix TraceMonkey bug associated with clock fallbacks
2975+ // http://bugzil.la/509069
2976+ if (support.browser) {
2977+ runScript(uid + '=1;delete ' + uid);
2978+ }
2979+ // done
2980+ clone.emit('complete');
2981+ }
2982+ }
2983+
2984+ /*--------------------------------------------------------------------------*/
2985+
2986+ /**
2987+ * Runs the benchmark.
2988+ *
2989+ * @memberOf Benchmark
2990+ * @param {Object} [options={}] Options object.
2991+ * @returns {Object} The benchmark instance.
2992+ * @example
2993+ *
2994+ * // basic usage
2995+ * bench.run();
2996+ *
2997+ * // or with options
2998+ * bench.run({ 'async': true });
2999+ */
3000+ function run(options) {
3001+ var me = this,
3002+ event = Event('start');
3003+
3004+ // set `running` to `false` so `reset()` won't call `abort()`
3005+ me.running = false;
3006+ me.reset();
3007+ me.running = true;
3008+
3009+ me.count = me.initCount;
3010+ me.times.timeStamp = +new Date;
3011+ me.emit(event);
3012+
3013+ if (!event.cancelled) {
3014+ options = { 'async': ((options = options && options.async) == null ? me.async : options) && support.timeout };
3015+
3016+ // for clones created within `compute()`
3017+ if (me._original) {
3018+ if (me.defer) {
3019+ Deferred(me);
3020+ } else {
3021+ cycle(me, options);
3022+ }
3023+ }
3024+ // for original benchmarks
3025+ else {
3026+ compute(me, options);
3027+ }
3028+ }
3029+ return me;
3030+ }
3031+
3032+ /*--------------------------------------------------------------------------*/
3033+
3034+ // Firefox 1 erroneously defines variable and argument names of functions on
3035+ // the function itself as non-configurable properties with `undefined` values.
3036+ // The bugginess continues as the `Benchmark` constructor has an argument
3037+ // named `options` and Firefox 1 will not assign a value to `Benchmark.options`,
3038+ // making it non-writable in the process, unless it is the first property
3039+ // assigned by for-in loop of `extend()`.
3040+ extend(Benchmark, {
3041+
3042+ /**
3043+ * The default options copied by benchmark instances.
3044+ *
3045+ * @static
3046+ * @memberOf Benchmark
3047+ * @type Object
3048+ */
3049+ 'options': {
3050+
3051+ /**
3052+ * A flag to indicate that benchmark cycles will execute asynchronously
3053+ * by default.
3054+ *
3055+ * @memberOf Benchmark.options
3056+ * @type Boolean
3057+ */
3058+ 'async': false,
3059+
3060+ /**
3061+ * A flag to indicate that the benchmark clock is deferred.
3062+ *
3063+ * @memberOf Benchmark.options
3064+ * @type Boolean
3065+ */
3066+ 'defer': false,
3067+
3068+ /**
3069+ * The delay between test cycles (secs).
3070+ * @memberOf Benchmark.options
3071+ * @type Number
3072+ */
3073+ 'delay': 0.005,
3074+
3075+ /**
3076+ * Displayed by Benchmark#toString when a `name` is not available
3077+ * (auto-generated if absent).
3078+ *
3079+ * @memberOf Benchmark.options
3080+ * @type String
3081+ */
3082+ 'id': undefined,
3083+
3084+ /**
3085+ * The default number of times to execute a test on a benchmark's first cycle.
3086+ *
3087+ * @memberOf Benchmark.options
3088+ * @type Number
3089+ */
3090+ 'initCount': 1,
3091+
3092+ /**
3093+ * The maximum time a benchmark is allowed to run before finishing (secs).
3094+ *
3095+ * Note: Cycle delays aren't counted toward the maximum time.
3096+ *
3097+ * @memberOf Benchmark.options
3098+ * @type Number
3099+ */
3100+ 'maxTime': 5,
3101+
3102+ /**
3103+ * The minimum sample size required to perform statistical analysis.
3104+ *
3105+ * @memberOf Benchmark.options
3106+ * @type Number
3107+ */
3108+ 'minSamples': 5,
3109+
3110+ /**
3111+ * The time needed to reduce the percent uncertainty of measurement to 1% (secs).
3112+ *
3113+ * @memberOf Benchmark.options
3114+ * @type Number
3115+ */
3116+ 'minTime': 0,
3117+
3118+ /**
3119+ * The name of the benchmark.
3120+ *
3121+ * @memberOf Benchmark.options
3122+ * @type String
3123+ */
3124+ 'name': undefined,
3125+
3126+ /**
3127+ * An event listener called when the benchmark is aborted.
3128+ *
3129+ * @memberOf Benchmark.options
3130+ * @type Function
3131+ */
3132+ 'onAbort': undefined,
3133+
3134+ /**
3135+ * An event listener called when the benchmark completes running.
3136+ *
3137+ * @memberOf Benchmark.options
3138+ * @type Function
3139+ */
3140+ 'onComplete': undefined,
3141+
3142+ /**
3143+ * An event listener called after each run cycle.
3144+ *
3145+ * @memberOf Benchmark.options
3146+ * @type Function
3147+ */
3148+ 'onCycle': undefined,
3149+
3150+ /**
3151+ * An event listener called when a test errors.
3152+ *
3153+ * @memberOf Benchmark.options
3154+ * @type Function
3155+ */
3156+ 'onError': undefined,
3157+
3158+ /**
3159+ * An event listener called when the benchmark is reset.
3160+ *
3161+ * @memberOf Benchmark.options
3162+ * @type Function
3163+ */
3164+ 'onReset': undefined,
3165+
3166+ /**
3167+ * An event listener called when the benchmark starts running.
3168+ *
3169+ * @memberOf Benchmark.options
3170+ * @type Function
3171+ */
3172+ 'onStart': undefined
3173+ },
3174+
3175+ /**
3176+ * Platform object with properties describing things like browser name,
3177+ * version, and operating system.
3178+ *
3179+ * @static
3180+ * @memberOf Benchmark
3181+ * @type Object
3182+ */
3183+ 'platform': req('platform') || window.platform || {
3184+
3185+ /**
3186+ * The platform description.
3187+ *
3188+ * @memberOf Benchmark.platform
3189+ * @type String
3190+ */
3191+ 'description': window.navigator && navigator.userAgent || null,
3192+
3193+ /**
3194+ * The name of the browser layout engine.
3195+ *
3196+ * @memberOf Benchmark.platform
3197+ * @type String|Null
3198+ */
3199+ 'layout': null,
3200+
3201+ /**
3202+ * The name of the product hosting the browser.
3203+ *
3204+ * @memberOf Benchmark.platform
3205+ * @type String|Null
3206+ */
3207+ 'product': null,
3208+
3209+ /**
3210+ * The name of the browser/environment.
3211+ *
3212+ * @memberOf Benchmark.platform
3213+ * @type String|Null
3214+ */
3215+ 'name': null,
3216+
3217+ /**
3218+ * The name of the product's manufacturer.
3219+ *
3220+ * @memberOf Benchmark.platform
3221+ * @type String|Null
3222+ */
3223+ 'manufacturer': null,
3224+
3225+ /**
3226+ * The name of the operating system.
3227+ *
3228+ * @memberOf Benchmark.platform
3229+ * @type String|Null
3230+ */
3231+ 'os': null,
3232+
3233+ /**
3234+ * The alpha/beta release indicator.
3235+ *
3236+ * @memberOf Benchmark.platform
3237+ * @type String|Null
3238+ */
3239+ 'prerelease': null,
3240+
3241+ /**
3242+ * The browser/environment version.
3243+ *
3244+ * @memberOf Benchmark.platform
3245+ * @type String|Null
3246+ */
3247+ 'version': null,
3248+
3249+ /**
3250+ * Return platform description when the platform object is coerced to a string.
3251+ *
3252+ * @memberOf Benchmark.platform
3253+ * @type Function
3254+ * @returns {String} The platform description.
3255+ */
3256+ 'toString': function() {
3257+ return this.description || '';
3258+ }
3259+ },
3260+
3261+ /**
3262+ * The semantic version number.
3263+ *
3264+ * @static
3265+ * @memberOf Benchmark
3266+ * @type String
3267+ */
3268+ 'version': '1.0.0',
3269+
3270+ // an object of environment/feature detection flags
3271+ 'support': support,
3272+
3273+ // clone objects
3274+ 'deepClone': deepClone,
3275+
3276+ // iteration utility
3277+ 'each': each,
3278+
3279+ // augment objects
3280+ 'extend': extend,
3281+
3282+ // generic Array#filter
3283+ 'filter': filter,
3284+
3285+ // generic Array#forEach
3286+ 'forEach': forEach,
3287+
3288+ // generic own property iteration utility
3289+ 'forOwn': forOwn,
3290+
3291+ // converts a number to a comma-separated string
3292+ 'formatNumber': formatNumber,
3293+
3294+ // generic Object#hasOwnProperty
3295+ // (trigger hasKey's lazy define before assigning it to Benchmark)
3296+ 'hasKey': (hasKey(Benchmark, ''), hasKey),
3297+
3298+ // generic Array#indexOf
3299+ 'indexOf': indexOf,
3300+
3301+ // template utility
3302+ 'interpolate': interpolate,
3303+
3304+ // invokes a method on each item in an array
3305+ 'invoke': invoke,
3306+
3307+ // generic Array#join for arrays and objects
3308+ 'join': join,
3309+
3310+ // generic Array#map
3311+ 'map': map,
3312+
3313+ // retrieves a property value from each item in an array
3314+ 'pluck': pluck,
3315+
3316+ // generic Array#reduce
3317+ 'reduce': reduce
3318+ });
3319+
3320+ /*--------------------------------------------------------------------------*/
3321+
3322+ extend(Benchmark.prototype, {
3323+
3324+ /**
3325+ * The number of times a test was executed.
3326+ *
3327+ * @memberOf Benchmark
3328+ * @type Number
3329+ */
3330+ 'count': 0,
3331+
3332+ /**
3333+ * The number of cycles performed while benchmarking.
3334+ *
3335+ * @memberOf Benchmark
3336+ * @type Number
3337+ */
3338+ 'cycles': 0,
3339+
3340+ /**
3341+ * The number of executions per second.
3342+ *
3343+ * @memberOf Benchmark
3344+ * @type Number
3345+ */
3346+ 'hz': 0,
3347+
3348+ /**
3349+ * The compiled test function.
3350+ *
3351+ * @memberOf Benchmark
3352+ * @type Function|String
3353+ */
3354+ 'compiled': undefined,
3355+
3356+ /**
3357+ * The error object if the test failed.
3358+ *
3359+ * @memberOf Benchmark
3360+ * @type Object
3361+ */
3362+ 'error': undefined,
3363+
3364+ /**
3365+ * The test to benchmark.
3366+ *
3367+ * @memberOf Benchmark
3368+ * @type Function|String
3369+ */
3370+ 'fn': undefined,
3371+
3372+ /**
3373+ * A flag to indicate if the benchmark is aborted.
3374+ *
3375+ * @memberOf Benchmark
3376+ * @type Boolean
3377+ */
3378+ 'aborted': false,
3379+
3380+ /**
3381+ * A flag to indicate if the benchmark is running.
3382+ *
3383+ * @memberOf Benchmark
3384+ * @type Boolean
3385+ */
3386+ 'running': false,
3387+
3388+ /**
3389+ * Compiled into the test and executed immediately **before** the test loop.
3390+ *
3391+ * @memberOf Benchmark
3392+ * @type Function|String
3393+ * @example
3394+ *
3395+ * // basic usage
3396+ * var bench = Benchmark({
3397+ * 'setup': function() {
3398+ * var c = this.count,
3399+ * element = document.getElementById('container');
3400+ * while (c--) {
3401+ * element.appendChild(document.createElement('div'));
3402+ * }
3403+ * },
3404+ * 'fn': function() {
3405+ * element.removeChild(element.lastChild);
3406+ * }
3407+ * });
3408+ *
3409+ * // compiles to something like:
3410+ * var c = this.count,
3411+ * element = document.getElementById('container');
3412+ * while (c--) {
3413+ * element.appendChild(document.createElement('div'));
3414+ * }
3415+ * var start = new Date;
3416+ * while (count--) {
3417+ * element.removeChild(element.lastChild);
3418+ * }
3419+ * var end = new Date - start;
3420+ *
3421+ * // or using strings
3422+ * var bench = Benchmark({
3423+ * 'setup': '\
3424+ * var a = 0;\n\
3425+ * (function() {\n\
3426+ * (function() {\n\
3427+ * (function() {',
3428+ * 'fn': 'a += 1;',
3429+ * 'teardown': '\
3430+ * }())\n\
3431+ * }())\n\
3432+ * }())'
3433+ * });
3434+ *
3435+ * // compiles to something like:
3436+ * var a = 0;
3437+ * (function() {
3438+ * (function() {
3439+ * (function() {
3440+ * var start = new Date;
3441+ * while (count--) {
3442+ * a += 1;
3443+ * }
3444+ * var end = new Date - start;
3445+ * }())
3446+ * }())
3447+ * }())
3448+ */
3449+ 'setup': noop,
3450+
3451+ /**
3452+ * Compiled into the test and executed immediately **after** the test loop.
3453+ *
3454+ * @memberOf Benchmark
3455+ * @type Function|String
3456+ */
3457+ 'teardown': noop,
3458+
3459+ /**
3460+ * An object of stats including mean, margin or error, and standard deviation.
3461+ *
3462+ * @memberOf Benchmark
3463+ * @type Object
3464+ */
3465+ 'stats': {
3466+
3467+ /**
3468+ * The margin of error.
3469+ *
3470+ * @memberOf Benchmark#stats
3471+ * @type Number
3472+ */
3473+ 'moe': 0,
3474+
3475+ /**
3476+ * The relative margin of error (expressed as a percentage of the mean).
3477+ *
3478+ * @memberOf Benchmark#stats
3479+ * @type Number
3480+ */
3481+ 'rme': 0,
3482+
3483+ /**
3484+ * The standard error of the mean.
3485+ *
3486+ * @memberOf Benchmark#stats
3487+ * @type Number
3488+ */
3489+ 'sem': 0,
3490+
3491+ /**
3492+ * The sample standard deviation.
3493+ *
3494+ * @memberOf Benchmark#stats
3495+ * @type Number
3496+ */
3497+ 'deviation': 0,
3498+
3499+ /**
3500+ * The sample arithmetic mean.
3501+ *
3502+ * @memberOf Benchmark#stats
3503+ * @type Number
3504+ */
3505+ 'mean': 0,
3506+
3507+ /**
3508+ * The array of sampled periods.
3509+ *
3510+ * @memberOf Benchmark#stats
3511+ * @type Array
3512+ */
3513+ 'sample': [],
3514+
3515+ /**
3516+ * The sample variance.
3517+ *
3518+ * @memberOf Benchmark#stats
3519+ * @type Number
3520+ */
3521+ 'variance': 0
3522+ },
3523+
3524+ /**
3525+ * An object of timing data including cycle, elapsed, period, start, and stop.
3526+ *
3527+ * @memberOf Benchmark
3528+ * @type Object
3529+ */
3530+ 'times': {
3531+
3532+ /**
3533+ * The time taken to complete the last cycle (secs).
3534+ *
3535+ * @memberOf Benchmark#times
3536+ * @type Number
3537+ */
3538+ 'cycle': 0,
3539+
3540+ /**
3541+ * The time taken to complete the benchmark (secs).
3542+ *
3543+ * @memberOf Benchmark#times
3544+ * @type Number
3545+ */
3546+ 'elapsed': 0,
3547+
3548+ /**
3549+ * The time taken to execute the test once (secs).
3550+ *
3551+ * @memberOf Benchmark#times
3552+ * @type Number
3553+ */
3554+ 'period': 0,
3555+
3556+ /**
3557+ * A timestamp of when the benchmark started (ms).
3558+ *
3559+ * @memberOf Benchmark#times
3560+ * @type Number
3561+ */
3562+ 'timeStamp': 0
3563+ },
3564+
3565+ // aborts benchmark (does not record times)
3566+ 'abort': abort,
3567+
3568+ // creates a new benchmark using the same test and options
3569+ 'clone': clone,
3570+
3571+ // compares benchmark's hertz with another
3572+ 'compare': compare,
3573+
3574+ // executes listeners
3575+ 'emit': emit,
3576+
3577+ // get listeners
3578+ 'listeners': listeners,
3579+
3580+ // unregister listeners
3581+ 'off': off,
3582+
3583+ // register listeners
3584+ 'on': on,
3585+
3586+ // reset benchmark properties
3587+ 'reset': reset,
3588+
3589+ // runs the benchmark
3590+ 'run': run,
3591+
3592+ // pretty print benchmark info
3593+ 'toString': toStringBench
3594+ });
3595+
3596+ /*--------------------------------------------------------------------------*/
3597+
3598+ extend(Deferred.prototype, {
3599+
3600+ /**
3601+ * The deferred benchmark instance.
3602+ *
3603+ * @memberOf Benchmark.Deferred
3604+ * @type Object
3605+ */
3606+ 'benchmark': null,
3607+
3608+ /**
3609+ * The number of deferred cycles performed while benchmarking.
3610+ *
3611+ * @memberOf Benchmark.Deferred
3612+ * @type Number
3613+ */
3614+ 'cycles': 0,
3615+
3616+ /**
3617+ * The time taken to complete the deferred benchmark (secs).
3618+ *
3619+ * @memberOf Benchmark.Deferred
3620+ * @type Number
3621+ */
3622+ 'elapsed': 0,
3623+
3624+ /**
3625+ * A timestamp of when the deferred benchmark started (ms).
3626+ *
3627+ * @memberOf Benchmark.Deferred
3628+ * @type Number
3629+ */
3630+ 'timeStamp': 0,
3631+
3632+ // cycles/completes the deferred benchmark
3633+ 'resolve': resolve
3634+ });
3635+
3636+ /*--------------------------------------------------------------------------*/
3637+
3638+ extend(Event.prototype, {
3639+
3640+ /**
3641+ * A flag to indicate if the emitters listener iteration is aborted.
3642+ *
3643+ * @memberOf Benchmark.Event
3644+ * @type Boolean
3645+ */
3646+ 'aborted': false,
3647+
3648+ /**
3649+ * A flag to indicate if the default action is cancelled.
3650+ *
3651+ * @memberOf Benchmark.Event
3652+ * @type Boolean
3653+ */
3654+ 'cancelled': false,
3655+
3656+ /**
3657+ * The object whose listeners are currently being processed.
3658+ *
3659+ * @memberOf Benchmark.Event
3660+ * @type Object
3661+ */
3662+ 'currentTarget': undefined,
3663+
3664+ /**
3665+ * The return value of the last executed listener.
3666+ *
3667+ * @memberOf Benchmark.Event
3668+ * @type Mixed
3669+ */
3670+ 'result': undefined,
3671+
3672+ /**
3673+ * The object to which the event was originally emitted.
3674+ *
3675+ * @memberOf Benchmark.Event
3676+ * @type Object
3677+ */
3678+ 'target': undefined,
3679+
3680+ /**
3681+ * A timestamp of when the event was created (ms).
3682+ *
3683+ * @memberOf Benchmark.Event
3684+ * @type Number
3685+ */
3686+ 'timeStamp': 0,
3687+
3688+ /**
3689+ * The event type.
3690+ *
3691+ * @memberOf Benchmark.Event
3692+ * @type String
3693+ */
3694+ 'type': ''
3695+ });
3696+
3697+ /*--------------------------------------------------------------------------*/
3698+
3699+ /**
3700+ * The default options copied by suite instances.
3701+ *
3702+ * @static
3703+ * @memberOf Benchmark.Suite
3704+ * @type Object
3705+ */
3706+ Suite.options = {
3707+
3708+ /**
3709+ * The name of the suite.
3710+ *
3711+ * @memberOf Benchmark.Suite.options
3712+ * @type String
3713+ */
3714+ 'name': undefined
3715+ };
3716+
3717+ /*--------------------------------------------------------------------------*/
3718+
3719+ extend(Suite.prototype, {
3720+
3721+ /**
3722+ * The number of benchmarks in the suite.
3723+ *
3724+ * @memberOf Benchmark.Suite
3725+ * @type Number
3726+ */
3727+ 'length': 0,
3728+
3729+ /**
3730+ * A flag to indicate if the suite is aborted.
3731+ *
3732+ * @memberOf Benchmark.Suite
3733+ * @type Boolean
3734+ */
3735+ 'aborted': false,
3736+
3737+ /**
3738+ * A flag to indicate if the suite is running.
3739+ *
3740+ * @memberOf Benchmark.Suite
3741+ * @type Boolean
3742+ */
3743+ 'running': false,
3744+
3745+ /**
3746+ * An `Array#forEach` like method.
3747+ * Callbacks may terminate the loop by explicitly returning `false`.
3748+ *
3749+ * @memberOf Benchmark.Suite
3750+ * @param {Function} callback The function called per iteration.
3751+ * @returns {Object} The suite iterated over.
3752+ */
3753+ 'forEach': methodize(forEach),
3754+
3755+ /**
3756+ * An `Array#indexOf` like method.
3757+ *
3758+ * @memberOf Benchmark.Suite
3759+ * @param {Mixed} value The value to search for.
3760+ * @returns {Number} The index of the matched value or `-1`.
3761+ */
3762+ 'indexOf': methodize(indexOf),
3763+
3764+ /**
3765+ * Invokes a method on all benchmarks in the suite.
3766+ *
3767+ * @memberOf Benchmark.Suite
3768+ * @param {String|Object} name The name of the method to invoke OR options object.
3769+ * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the method with.
3770+ * @returns {Array} A new array of values returned from each method invoked.
3771+ */
3772+ 'invoke': methodize(invoke),
3773+
3774+ /**
3775+ * Converts the suite of benchmarks to a string.
3776+ *
3777+ * @memberOf Benchmark.Suite
3778+ * @param {String} [separator=','] A string to separate each element of the array.
3779+ * @returns {String} The string.
3780+ */
3781+ 'join': [].join,
3782+
3783+ /**
3784+ * An `Array#map` like method.
3785+ *
3786+ * @memberOf Benchmark.Suite
3787+ * @param {Function} callback The function called per iteration.
3788+ * @returns {Array} A new array of values returned by the callback.
3789+ */
3790+ 'map': methodize(map),
3791+
3792+ /**
3793+ * Retrieves the value of a specified property from all benchmarks in the suite.
3794+ *
3795+ * @memberOf Benchmark.Suite
3796+ * @param {String} property The property to pluck.
3797+ * @returns {Array} A new array of property values.
3798+ */
3799+ 'pluck': methodize(pluck),
3800+
3801+ /**
3802+ * Removes the last benchmark from the suite and returns it.
3803+ *
3804+ * @memberOf Benchmark.Suite
3805+ * @returns {Mixed} The removed benchmark.
3806+ */
3807+ 'pop': [].pop,
3808+
3809+ /**
3810+ * Appends benchmarks to the suite.
3811+ *
3812+ * @memberOf Benchmark.Suite
3813+ * @returns {Number} The suite's new length.
3814+ */
3815+ 'push': [].push,
3816+
3817+ /**
3818+ * Sorts the benchmarks of the suite.
3819+ *
3820+ * @memberOf Benchmark.Suite
3821+ * @param {Function} [compareFn=null] A function that defines the sort order.
3822+ * @returns {Object} The sorted suite.
3823+ */
3824+ 'sort': [].sort,
3825+
3826+ /**
3827+ * An `Array#reduce` like method.
3828+ *
3829+ * @memberOf Benchmark.Suite
3830+ * @param {Function} callback The function called per iteration.
3831+ * @param {Mixed} accumulator Initial value of the accumulator.
3832+ * @returns {Mixed} The accumulator.
3833+ */
3834+ 'reduce': methodize(reduce),
3835+
3836+ // aborts all benchmarks in the suite
3837+ 'abort': abortSuite,
3838+
3839+ // adds a benchmark to the suite
3840+ 'add': add,
3841+
3842+ // creates a new suite with cloned benchmarks
3843+ 'clone': cloneSuite,
3844+
3845+ // executes listeners of a specified type
3846+ 'emit': emit,
3847+
3848+ // creates a new suite of filtered benchmarks
3849+ 'filter': filterSuite,
3850+
3851+ // get listeners
3852+ 'listeners': listeners,
3853+
3854+ // unregister listeners
3855+ 'off': off,
3856+
3857+ // register listeners
3858+ 'on': on,
3859+
3860+ // resets all benchmarks in the suite
3861+ 'reset': resetSuite,
3862+
3863+ // runs all benchmarks in the suite
3864+ 'run': runSuite,
3865+
3866+ // array methods
3867+ 'concat': concat,
3868+
3869+ 'reverse': reverse,
3870+
3871+ 'shift': shift,
3872+
3873+ 'slice': slice,
3874+
3875+ 'splice': splice,
3876+
3877+ 'unshift': unshift
3878+ });
3879+
3880+ /*--------------------------------------------------------------------------*/
3881+
3882+ // expose Deferred, Event and Suite
3883+ extend(Benchmark, {
3884+ 'Deferred': Deferred,
3885+ 'Event': Event,
3886+ 'Suite': Suite
3887+ });
3888+
3889+ // expose Benchmark
3890+ // some AMD build optimizers, like r.js, check for specific condition patterns like the following:
3891+ if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
3892+ // define as an anonymous module so, through path mapping, it can be aliased
3893+ define(function() {
3894+ return Benchmark;
3895+ });
3896+ }
3897+ // check for `exports` after `define` in case a build optimizer adds an `exports` object
3898+ else if (freeExports) {
3899+ // in Node.js or RingoJS v0.8.0+
3900+ if (typeof module == 'object' && module && module.exports == freeExports) {
3901+ (module.exports = Benchmark).Benchmark = Benchmark;
3902+ }
3903+ // in Narwhal or RingoJS v0.7.0-
3904+ else {
3905+ freeExports.Benchmark = Benchmark;
3906+ }
3907+ }
3908+ // in a browser or Rhino
3909+ else {
3910+ // use square bracket notation so Closure Compiler won't munge `Benchmark`
3911+ // http://code.google.com/closure/compiler/docs/api-tutorial3.html#export
3912+ window['Benchmark'] = Benchmark;
3913+ }
3914+
3915+ // trigger clock's lazy define early to avoid a security error
3916+ if (support.air) {
3917+ clock({ '_original': { 'fn': noop, 'count': 1, 'options': {} } });
3918+ }
3919+}(this));
bench/src/PatternMatchBench.elmnew file+70
@@ -0,0 +1,70 @@
1+module PatternMatchBench where
2+
3+type NestedStructure =
4+ Nest Float (NestedStructure)
5+ | End Float
6+
7+
8+intToNest : Int -> NestedStructure
9+intToNest i =
10+ let
11+ helper i accum =
12+ case (i % 20) of
13+ 0 ->
14+ accum
15+
16+ _ ->
17+ helper (i-1) <| Nest (toFloat <| i * i) accum
18+ in
19+ helper i (End <| toFloat i)
20+
21+deepMatchingFunction : NestedStructure -> Float
22+deepMatchingFunction struct =
23+ case struct of
24+ (Nest x1 (Nest x2 (Nest x3 (Nest x4 (Nest x5 (Nest x6 (Nest x7 (Nest x8 (Nest x9 (Nest x10 (Nest x11 (Nest x12 (Nest x13 (Nest x14 (Nest x15 (Nest x16 (Nest x17 (End x18 ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ->
25+ x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18
26+
27+ Nest x _ ->
28+ x
29+
30+ End x ->
31+ x
32+
33+
34+wildcardMatchingFunction : NestedStructure -> Float
35+wildcardMatchingFunction struct =
36+ case struct of
37+ (Nest x (Nest _ (Nest _ (Nest _ (Nest _ (Nest _ (Nest _ (Nest _ (Nest _ (Nest _ (Nest _ (Nest _ (Nest _ (Nest _ (Nest _ (Nest _ (Nest _ (End y ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ->
38+ x + y + x + y + x + y + x + y + x + y + x + y + x + y + x + y + x + y
39+
40+ Nest x _ ->
41+ x
42+
43+ End x ->
44+ x
45+
46+
47+shallowMatchingFunction : NestedStructure -> Float
48+shallowMatchingFunction struct =
49+ case struct of
50+ (Nest x1 (Nest x2 (Nest x3 (End x4) ) ) ) ->
51+ x1 + x2 + x3 + x4 + x1 + x2 + x3 + x4 + x1 + x2 + x3 + x4 + x1 + x2 + x3 + x4 + x1 + x2
52+
53+ Nest x _ ->
54+ x
55+
56+ End x ->
57+ x
58+
59+sumStructures : (NestedStructure -> Float) -> List NestedStructure -> Float
60+sumStructures f inList =
61+ List.foldr (\x sumSoFar -> sumSoFar + f x) 0.0 inList
62+
63+
64+deepMatchSum = sumStructures deepMatchingFunction
65+
66+
67+shallowMatchSum = sumStructures shallowMatchingFunction
68+
69+
70+wildcardMatchSum = sumStructures wildcardMatchingFunction
bench/src/RecordBench.elmnew file+76
@@ -0,0 +1,76 @@
1+module RecordBench where
2+
3+type alias BigRecord =
4+ { myLargeNamedField1 : Float
5+ , myLargeNamedField2 : Float
6+ , myLargeNamedField3 : Float
7+ , myLargeNamedField4 : Float
8+ , myLargeNamedField5 : Float
9+ , myLargeNamedField6 : Float
10+ , myLargeNamedField7 : Float
11+ , myLargeNamedField8 : Float
12+ , myLargeNamedField9 : Float
13+ , myLargeNamedField10 : Float
14+ , myLargeNamedField11 : Float
15+ , myLargeNamedField12 : Float
16+ , myLargeNamedField13 : Float
17+ , myLargeNamedField14 : Float
18+ , myLargeNamedField15 : Float
19+ , myLargeNamedField16 : Float
20+ , myLargeNamedField17 : Float
21+ , myLargeNamedField18 : Float
22+ , myLargeNamedField19 : Float
23+ , myLargeNamedField20 : Float
24+ }
25+
26+defaultRec =
27+ BigRecord 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0
28+ 11.0 12.0 13.0 14.0 15.0 16.0 17.0 18.0 19.0 20.0
29+
30+getField i =
31+ case (i % 20) of
32+ 0 ->
33+ defaultRec.myLargeNamedField20
34+ 1 ->
35+ defaultRec.myLargeNamedField1
36+ 2 ->
37+ defaultRec.myLargeNamedField2
38+ 3 ->
39+ defaultRec.myLargeNamedField3
40+ 4 ->
41+ defaultRec.myLargeNamedField4
42+ 5 ->
43+ defaultRec.myLargeNamedField5
44+ 6 ->
45+ defaultRec.myLargeNamedField6
46+ 7 ->
47+ defaultRec.myLargeNamedField7
48+ 8 ->
49+ defaultRec.myLargeNamedField8
50+ 9 ->
51+ defaultRec.myLargeNamedField9
52+ 10 ->
53+ defaultRec.myLargeNamedField10
54+ 11 ->
55+ defaultRec.myLargeNamedField11
56+ 12 ->
57+ defaultRec.myLargeNamedField12
58+ 13 ->
59+ defaultRec.myLargeNamedField13
60+ 14 ->
61+ defaultRec.myLargeNamedField14
62+ 15 ->
63+ defaultRec.myLargeNamedField15
64+ 16 ->
65+ defaultRec.myLargeNamedField16
66+ 17 ->
67+ defaultRec.myLargeNamedField17
68+ 18 ->
69+ defaultRec.myLargeNamedField18
70+ 19 ->
71+ defaultRec.myLargeNamedField19
72+
73+
74+sumRandomElems : List Int -> Float
75+sumRandomElems randomInts =
76+ List.foldr (\i sumSoFar -> (getField i) + sumSoFar ) 0.0 randomInts
bench/src/SmallCtorBench.elmnew file+76
@@ -0,0 +1,76 @@
1+module SmallCtorBench where
2+
3+type ManyCtors =
4+ MyLongNamedCtor1 Float Float Float
5+ | MyLongNamedCtor2 Float Float
6+ | MyLongNamedCtor3 Float Float Float
7+ | MyLongNamedCtor4 Float Float
8+ | MyLongNamedCtor5 Float Float Float
9+ | MyLongNamedCtor6 Float Float
10+ | MyLongNamedCtor7 Float Float Float
11+ | MyLongNamedCtor8 Float Float
12+ | MyLongNamedCtor9 Float Float Float
13+ | MyLongNamedCtor10 Float Float
14+
15+
16+getFieldSum someData =
17+ case someData of
18+ MyLongNamedCtor1 x y z ->
19+ x + y + z
20+
21+ MyLongNamedCtor3 x y z ->
22+ x + y + z
23+
24+ MyLongNamedCtor5 x y z ->
25+ x + y + z
26+
27+ MyLongNamedCtor7 x y z ->
28+ x + y + z
29+
30+ MyLongNamedCtor9 x y z ->
31+ x + y + z
32+
33+ MyLongNamedCtor10 x y ->
34+ x + y
35+
36+ MyLongNamedCtor8 x y ->
37+ x + y
38+
39+ MyLongNamedCtor6 x y ->
40+ x + y
41+
42+ MyLongNamedCtor4 x y ->
43+ x + y
44+
45+ MyLongNamedCtor2 x y ->
46+ x + y
47+
48+
49+makeRandomData i =
50+ case (i % 10) of
51+ 0 ->
52+ MyLongNamedCtor10 (toFloat i) (toFloat <| i*i)
53+ 1 ->
54+ MyLongNamedCtor1 (toFloat i) (toFloat <| i*i) (toFloat <| i*i*i)
55+ 2 ->
56+ MyLongNamedCtor2 (toFloat i) (toFloat <| i*i)
57+ 3 ->
58+ MyLongNamedCtor3 (toFloat i) (toFloat <| i*i) (toFloat <| i*i*i)
59+ 4 ->
60+ MyLongNamedCtor4 (toFloat i) (toFloat <| i*i)
61+ 5 ->
62+ MyLongNamedCtor5 (toFloat i) (toFloat <| i*i) (toFloat <| i*i*i)
63+ 6 ->
64+ MyLongNamedCtor6 (toFloat i) (toFloat <| i*i)
65+ 7 ->
66+ MyLongNamedCtor7 (toFloat i) (toFloat <| i*i) (toFloat <| i*i*i)
67+ 8 ->
68+ MyLongNamedCtor8 (toFloat i) (toFloat <| i*i)
69+ 9 ->
70+ MyLongNamedCtor9 (toFloat i) (toFloat <| i*i) (toFloat <| i*i*i)
71+
72+
73+
74+sumFieldsList : List ManyCtors -> Float
75+sumFieldsList dataList =
76+ List.foldr (\val sumSoFar -> (getFieldSum val) + sumSoFar ) 0.0 dataList
bench/src/SmallRecordBench.elmnew file+42
@@ -0,0 +1,42 @@
1+module SmallRecordBench where
2+
3+type alias SmallRecord =
4+ { myLargeNamedField1 : Float
5+ , myLargeNamedField2 : Float
6+ , myLargeNamedField3 : Float
7+ , myLargeNamedField4 : Float
8+ , myLargeNamedField5 : Float
9+ , myLargeNamedField6 : Float
10+ , myLargeNamedField7 : Float
11+ , myLargeNamedField8 : Float
12+ , myLargeNamedField9 : Float
13+ }
14+
15+defaultRec =
16+ SmallRecord 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0
17+
18+getField i =
19+ case (i % 9) of
20+ 1 ->
21+ defaultRec.myLargeNamedField1
22+ 2 ->
23+ defaultRec.myLargeNamedField2
24+ 3 ->
25+ defaultRec.myLargeNamedField3
26+ 4 ->
27+ defaultRec.myLargeNamedField4
28+ 5 ->
29+ defaultRec.myLargeNamedField5
30+ 6 ->
31+ defaultRec.myLargeNamedField6
32+ 7 ->
33+ defaultRec.myLargeNamedField7
34+ 8 ->
35+ defaultRec.myLargeNamedField8
36+ 0 ->
37+ defaultRec.myLargeNamedField9
38+
39+
40+sumRandomElems : List Int -> Float
41+sumRandomElems randomInts =
42+ List.foldr (\i sumSoFar -> (getField i) + sumSoFar ) 0.0 randomInts
bench/src/SmallTupleBench.elmnew file+30
@@ -0,0 +1,30 @@
1+module SmallTupleBench where
2+
3+type alias SmallTuple =
4+ ( Float
5+ , Float
6+ , Float
7+ , Float
8+ , Float
9+ , Float
10+ , Float
11+ , Float
12+ , Float
13+ )
14+
15+defaultTuple =
16+ (1.0, 2.0, 3.0)
17+
18+getField (x1, x2, x3) i =
19+ case (i % 3) of
20+ 1 ->
21+ x1
22+ 2 ->
23+ x2
24+ 0 ->
25+ x3
26+
27+
28+sumRandomElems : List Int -> Float
29+sumRandomElems randomInts =
30+ List.foldr (\i sumSoFar -> (getField defaultTuple i) + sumSoFar ) 0.0 randomInts
bench/src/TodoBench.elmnew file+132
@@ -0,0 +1,132 @@
1+module TodoBench where
2+
3+import String
4+
5+---- MODEL ----
6+
7+-- The full application state of our todo app.
8+type alias Model =
9+ { tasks : List Task
10+ , field : String
11+ , uid : Int
12+ , visibility : String
13+ }
14+
15+
16+type alias Task =
17+ { description : String
18+ , completed : Bool
19+ , editing : Bool
20+ , id : Int
21+ }
22+
23+
24+newTask : String -> Int -> Task
25+newTask desc id =
26+ { description = desc
27+ , completed = False
28+ , editing = False
29+ , id = id
30+ }
31+
32+
33+emptyModel : Model
34+emptyModel =
35+ { tasks = []
36+ , visibility = "All"
37+ , field = ""
38+ , uid = 0
39+ }
40+
41+
42+---- UPDATE ----
43+
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
47+type Action
48+ = NoOp
49+ | UpdateField String
50+ | EditingTask Int Bool
51+ | UpdateTask Int String
52+ | Add
53+ | Delete Int
54+ | DeleteComplete
55+ | Check Int Bool
56+ | CheckAll Bool
57+ | ChangeVisibility String
58+
59+
60+-- How we update our Model on a given Action?
61+update : Action -> Model -> Model
62+update action model =
63+ case action of
64+ NoOp -> model
65+
66+ Add ->
67+ { model |
68+ uid <- model.uid + 1,
69+ field <- "",
70+ tasks <-
71+ if String.isEmpty model.field
72+ then model.tasks
73+ else model.tasks ++ [newTask model.field model.uid]
74+ }
75+
76+ UpdateField str ->
77+ { model | field <- str }
78+
79+ EditingTask id isEditing ->
80+ let updateTask t = if t.id == id then { t | editing <- isEditing } else t
81+ in
82+ { model | tasks <- List.map updateTask model.tasks }
83+
84+ UpdateTask id task ->
85+ let updateTask t = if t.id == id then { t | description <- task } else t
86+ in
87+ { model | tasks <- List.map updateTask model.tasks }
88+
89+ Delete id ->
90+ { model | tasks <- List.filter (\t -> t.id /= id) model.tasks }
91+
92+ DeleteComplete ->
93+ { model | tasks <- List.filter (not << .completed) model.tasks }
94+
95+ Check id isCompleted ->
96+ let updateTask t = if t.id == id then { t | completed <- isCompleted } else t
97+ in
98+ { model | tasks <- List.map updateTask model.tasks }
99+
100+ CheckAll isCompleted ->
101+ let updateTask t = { t | completed <- isCompleted }
102+ in
103+ { model | tasks <- List.map updateTask model.tasks }
104+
105+ 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
bench/src/TupleBench.elmnew file+42
@@ -0,0 +1,42 @@
1+module TupleBench where
2+
3+type alias BigTuple =
4+ ( Float
5+ , Float
6+ , Float
7+ , Float
8+ , Float
9+ , Float
10+ , Float
11+ , Float
12+ , Float
13+ )
14+
15+defaultTuple =
16+ (1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0)
17+
18+getField (x1, x2, x3, x4, x5, x6, x7, x8, x9) i =
19+ case (i % 9) of
20+ 1 ->
21+ x1
22+ 2 ->
23+ x2
24+ 3 ->
25+ x3
26+ 4 ->
27+ x4
28+ 5 ->
29+ x5
30+ 6 ->
31+ x6
32+ 7 ->
33+ x7
34+ 8 ->
35+ x8
36+ 0 ->
37+ x9
38+
39+
40+sumRandomElems : List Int -> Float
41+sumRandomElems randomInts =
42+ List.foldr (\i sumSoFar -> (getField defaultTuple i) + sumSoFar ) 0.0 randomInts