Improve performance of ComputeWinCount
As it turns out `big.Int#Mul` doesn't like it when you reuse input as output. ``` name old time/op new time/op delta WinCounts-8 4.56µs ± 1% 3.90µs ± 2% -14.44% (p=0.000 n=9+10) name old alloc/op new alloc/op delta WinCounts-8 3.50kB ± 0% 1.15kB ± 0% -67.23% (p=0.000 n=10+10) name old allocs/op new allocs/op delta WinCounts-8 45.0 ± 0% 24.0 ± 0% -46.67% (p=0.000 n=10+10) ``` Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
This commit is contained in:
parent
ee5639aad9
commit
f523b17a35
@ -83,11 +83,13 @@ func expneg(x *big.Int) *big.Int {
|
||||
|
||||
// polyval evaluates a polynomial given by coefficients `p` in Q.256 format,
|
||||
// at point `x` in Q.256 format, output is in Q.256
|
||||
|
||||
func polyval(p []*big.Int, x *big.Int) *big.Int {
|
||||
res := new(big.Int).Set(p[0]) // Q.256
|
||||
tmp := new(big.Int) // big.Int.Mul doesn't like when input is reused as output
|
||||
for _, c := range p[1:] {
|
||||
res = res.Mul(res, x) // Q.256 * Q.256 => Q.512
|
||||
res = res.Rsh(res, precision) // Q.512 >> 256 => Q.256
|
||||
tmp = tmp.Mul(res, x) // Q.256 * Q.256 => Q.512
|
||||
res = res.Rsh(tmp, precision) // Q.512 >> 256 => Q.256
|
||||
res = res.Add(res, c)
|
||||
}
|
||||
|
||||
@ -129,12 +131,13 @@ func (ep *ElectionProof) ComputeWinCount(power BigInt, totalPower BigInt) uint64
|
||||
rhs = rhs.Lsh(rhs, precision) // Q.256
|
||||
rhs = rhs.Sub(rhs, elam) // Q.256
|
||||
|
||||
tmp := new(big.Int) // big.Int.Mul doesn't like when input is reused as output
|
||||
var j uint64
|
||||
for lhs.Cmp(rhs) < 0 && j < MaxWinCount {
|
||||
j++
|
||||
pmf = pmf.Mul(pmf, lam) // Q.256 * Q.256 => Q.512
|
||||
pmf = pmf.Rsh(pmf, precision) // Q.512 >> 256 => Q.256
|
||||
pmf = pmf.Div(pmf, new(big.Int).SetUint64(j) /* Q.0 */) // Q.256 / Q.0 => Q.256
|
||||
tmp = tmp.Mul(pmf, lam) // Q.256 * Q.256 => Q.512
|
||||
pmf = pmf.Rsh(tmp, precision) // Q.512 >> 256 => Q.256
|
||||
rhs = rhs.Sub(rhs, pmf)
|
||||
}
|
||||
|
||||
|
@ -18,23 +18,43 @@ func TestElectionLam(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestElectionExp(t *testing.T) {
|
||||
t.Skip()
|
||||
t.SkipNow()
|
||||
const N = 256
|
||||
|
||||
step := big.NewInt(5)
|
||||
step = step.Lsh(step, 256) // Q.256
|
||||
step = step.Div(step, big.NewInt(N-1))
|
||||
|
||||
f, _ := os.Create("exp.csv")
|
||||
|
||||
x := big.NewInt(0)
|
||||
for i := 0; i < N; i++ {
|
||||
y := expneg(x)
|
||||
fmt.Printf("\"%s\" \"%s\";\n", x, y)
|
||||
fmt.Fprintf(f, "%s,%s\n", x, y)
|
||||
x = x.Add(x, step)
|
||||
}
|
||||
}
|
||||
|
||||
var Res uint64
|
||||
|
||||
func BenchmarkWinCounts(b *testing.B) {
|
||||
totalPower := NewInt(100)
|
||||
power := NewInt(100)
|
||||
ep := &ElectionProof{VRFProof: nil}
|
||||
var res uint64
|
||||
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
ep.VRFProof = []byte{byte(i), byte(i >> 8), byte(i >> 16), byte(i >> 24), byte(i >> 32)}
|
||||
j := ep.ComputeWinCount(power, totalPower)
|
||||
res += j
|
||||
}
|
||||
Res += res
|
||||
}
|
||||
|
||||
func TestWinCounts(t *testing.T) {
|
||||
t.Skip()
|
||||
t.SkipNow()
|
||||
totalPower := NewInt(100)
|
||||
power := NewInt(30)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user