-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathexperiment.go
109 lines (82 loc) · 2.09 KB
/
experiment.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package scientist
import (
"math/rand"
"time"
)
type Result struct {
ControlDuration float64
CandidateDuration float64
ResultsAreEqual bool
Duration float64
ControlResult interface{}
CandidateResult interface{}
CandidateError error
ControlError error
}
type Experiment struct {
Name string
Result
functions map[string]func() (interface{}, error)
random bool
}
func (e *Experiment) Use(runner func() (interface{}, error)) {
e.functions["control"] = func() (interface{}, error) {
start := time.Now()
result, err := runner()
if err != nil {
e.Result.ControlResult = nil
return nil, err
} else {
e.Result.ControlResult = result
}
defer func() {
diff := float64(time.Since(start) / time.Second)
e.Result.ControlDuration = diff
}()
return result, nil
}
}
func (e *Experiment) Try(runner func() (interface{}, error)) {
e.functions["candidate"] = func() (interface{}, error) {
start := time.Now()
result, err := runner()
if err != nil {
e.Result.CandidateError = err
}
e.Result.CandidateResult = result
defer func() {
diff := float64(time.Since(start) / time.Second)
e.Result.CandidateDuration = diff
}()
return result, nil
}
}
func (e *Experiment) Run() (interface{}, error) {
defer func() {
e.Result.Duration = e.Result.ControlDuration + e.Result.CandidateDuration
e.Result.ResultsAreEqual = e.Result.ControlResult == e.Result.CandidateResult
}()
s1 := rand.NewSource(time.Now().UnixNano())
r1 := rand.New(s1)
if e.random == true {
value := r1.Intn(100)
if value < 50 { // run candidate or control first
e.functions["candidate"]()
} else {
e.functions["control"]()
}
if value < 50 { // run control or candidate next
e.functions["control"]()
} else {
e.functions["candidate"]()
}
} else {
e.functions["candidate"]()
return e.functions["control"]()
}
return e.Result.ControlResult, e.Result.ControlError
}
func New(name string, random bool) *Experiment {
exp := Experiment{Name: name, random: random, functions: make(map[string]func() (interface{}, error))}
return &exp
}