Midway adding covar

Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
This commit is contained in:
Jakub Sztandera 2020-06-30 01:31:09 +02:00
parent 21148033e2
commit 2caa7164a6
No known key found for this signature in database
GPG Key ID: 9A9AF56F8B3879BA

View File

@ -230,49 +230,120 @@ func compStats(vals []float64) (float64, float64) {
} }
type stats struct { type stats struct {
count float64 timeTaken meanVar
gasRatio meanVar
extra *meanVar
extraCovar *covar
}
type covar struct {
meanX float64
meanY float64
c float64
n float64
m2 float64
}
func (cov1 *covar) Covariance() float64 {
return cov1.c / (cov1.n - 1)
}
func (cov1 *covar) AddPoint(x, y float64) {
cov1.n += 1
dx := x - cov1.meanX
cov1.meanX += dx / cov1.n
dx2 := x - cov1.meanX // compute x variance using partial result for covariance
cov1.m2 += dx * dx2
cov1.meanY += (y - cov1.meanY) / cov1.n
cov1.c += dx * (y - cov1.meanY)
}
func (cov1 *covar) Combine(cov2 *covar) {
if cov1.n == 0 {
*cov1 = *cov2
return
}
if cov2.n == 0 {
return
}
if cov1.n == 1 {
cpy := *cov2
cpy.AddPoint(cov2.meanX, cov2.meanY)
*cov1 = cpy
return
}
if cov2.n == 1 {
cov1.AddPoint(cov2.meanX, cov2.meanY)
}
out := covar{}
out.n = cov1.n + cov2.n
dx := cov1.meanX - cov2.meanX
out.meanX = cov1.meanX + dx*cov2.n/out.n
out.m2 = cov1.m2 + cov2.m2 + dx*dx*cov1.n*cov2.n/out.n
dy := cov1.meanY - cov2.meanY
out.meanY = cov1.meanY + dy*cov2.n/out.n
out.c = cov1.c + cov2.c + dx*dy*cov1.n*cov2.n/out.n
*cov1 = out
}
type meanVar struct {
n float64
mean float64 mean float64
m2 float64 m2 float64
} }
func (s *stats) AddPoint(value float64) { func (v1 *meanVar) AddPoint(value float64) {
// based on https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm // based on https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm
s.count += 1 v1.n += 1
delta := value - s.mean delta := value - v1.mean
s.mean += delta / s.count v1.mean += delta / v1.n
delta2 := value - s.mean delta2 := value - v1.mean
s.m2 += delta * delta2 v1.m2 += delta * delta2
} }
func (s *stats) variance() float64 { func (v1 *meanVar) Variance() float64 {
return s.m2 / (s.count - 1) return v1.m2 / (v1.n - 1)
}
func (v1 *meanVar) Mean() float64 {
return v1.mean
}
func (v1 *meanVar) Stddev() float64 {
return math.Sqrt(v1.Variance())
} }
func (s1 *stats) Combine(s2 *stats) { func (v1 *meanVar) Combine(v2 *meanVar) {
if s1.count == 0 { if v1.n == 0 {
*s1 = *s2 *v1 = *v2
return return
} }
if s2.count == 0 { if v2.n == 0 {
return return
} }
if s1.count == 1 { if v1.n == 1 {
s2.AddPoint(s1.mean) cpy := *v2
*s1 = *s2 cpy.AddPoint(v1.mean)
*v1 = cpy
return return
} }
if s2.count == 1 { if v2.n == 1 {
s1.AddPoint(s2.mean) v1.AddPoint(v2.mean)
return return
} }
newCount := s1.count + s2.count newCount := v1.n + v2.n
delta := s2.mean - s1.mean delta := v2.mean - v1.mean
meanDelta := delta * s2.count / newCount meanDelta := delta * v2.n / newCount
m2 := s1.m2 + s2.m2 + delta*meanDelta*s1.count m2 := v1.m2 + v2.m2 + delta*meanDelta*v1.n
s1.count = newCount v1.n = newCount
s1.mean += meanDelta v1.mean += meanDelta
s1.m2 = m2 v1.m2 = m2
} }
func tallyGasCharges(charges map[string]*stats, et types.ExecutionTrace) { func tallyGasCharges(charges map[string]*stats, et types.ExecutionTrace) {
@ -287,24 +358,17 @@ func tallyGasCharges(charges map[string]*stats, et types.ExecutionTrace) {
compGas := gc.VirtualComputeGas compGas := gc.VirtualComputeGas
if compGas == 0 { if compGas == 0 {
name += "-zerogas"
compGas = 1 compGas = 1
} }
ratio := float64(compGas) / float64(gc.TimeTaken.Nanoseconds())
ratio = 1 / ratio
if math.IsNaN(ratio) {
log.Errorf("NaN: comGas: %f, taken: %d", compGas, gc.TimeTaken.Nanoseconds())
}
s := charges[name] s := charges[name]
if s == nil { if s == nil {
s = new(stats) s = new(stats)
charges[name] = s charges[name] = s
} }
s.timeTaken.AddPoint(float64(gc.TimeTaken.Nanoseconds()))
s.AddPoint(ratio) ratio := float64(gc.TimeTaken.Nanoseconds()) / float64(compGas) * GasPerNs
//fmt.Printf("%s: %d, %s: %0.2f\n", gc.Name, compGas, gc.TimeTaken, 1/(ratio/GasPerNs)) s.gasRatio.AddPoint(ratio)
} }
for _, sub := range et.Subcalls { for _, sub := range et.Subcalls {
tallyGasCharges(charges, sub) tallyGasCharges(charges, sub)
@ -425,7 +489,8 @@ var importAnalyzeCmd = &cli.Command{
s = new(stats) s = new(stats)
charges[k] = s charges[k] = s
} }
s.Combine(v) s.timeTaken.Combine(&v.timeTaken)
s.gasRatio.Combine(&v.gasRatio)
} }
totalTime += res.totalTime totalTime += res.totalTime
} }
@ -439,7 +504,7 @@ var importAnalyzeCmd = &cli.Command{
sort.Strings(keys) sort.Strings(keys)
for _, k := range keys { for _, k := range keys {
s := charges[k] s := charges[k]
fmt.Printf("%s: incr by %f (stddev: %f, count: %f)\n", k, s.mean, math.Sqrt(s.variance()), s.count) fmt.Printf("%s: incr by %f~%f\n", k, s.gasRatio.mean, s.gasRatio.Stddev())
} }
sort.Slice(invocs, func(i, j int) bool { sort.Slice(invocs, func(i, j int) bool {