Skip to content

Commit

Permalink
Improve the performance of BaseToQuoteQuantums & BigRatMulPpm (#1546
Browse files Browse the repository at this point in the history
)

* add benchmark for BaseToQuoteQuantums

* improve functions
  • Loading branch information
BrendanChou authored May 20, 2024
1 parent 333df84 commit 3b5043e
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 13 deletions.
10 changes: 3 additions & 7 deletions protocol/lib/big_math.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,9 @@ func BigMax(a, b *big.Int) *big.Int {

// BigRatMulPpm takes a `big.Rat` and returns the result of `input * ppm / 1_000_000`.
func BigRatMulPpm(input *big.Rat, ppm uint32) *big.Rat {
return new(big.Rat).Mul(
input,
new(big.Rat).SetFrac64(
int64(ppm),
int64(OneMillion),
),
)
num := new(big.Int).Mul(input.Num(), big.NewInt(int64(ppm)))
den := new(big.Int).Mul(input.Denom(), big.NewInt(int64(OneMillion)))
return new(big.Rat).SetFrac(num, den)
}

// bigGenericClamp is a helper function for BigRatClamp and BigIntClamp
Expand Down
20 changes: 20 additions & 0 deletions protocol/lib/big_math_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,26 @@ func TestBigRatMulPpm(t *testing.T) {
ppm: 10_000,
expectedResult: big_testutil.MustFirst(new(big.Rat).SetString("10000000000000000000000")),
},
"Positive with a common divisor": {
input: big.NewRat(3, 1),
ppm: 500_000,
expectedResult: big.NewRat(3, 2),
},
"Negative with a common divisor": {
input: big.NewRat(-3, 1),
ppm: 500_000,
expectedResult: big.NewRat(-3, 2),
},
"Positive with no common divisor": {
input: big.NewRat(117, 61),
ppm: 419,
expectedResult: big.NewRat(49023, 61000000),
},
"Negative with no common divisor": {
input: big.NewRat(-117, 61),
ppm: 419,
expectedResult: big.NewRat(-49023, 61000000),
},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
Expand Down
24 changes: 18 additions & 6 deletions protocol/lib/quantums.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,24 @@ func BaseToQuoteQuantums(
priceValue uint64,
priceExponent int32,
) (bigNotional *big.Int) {
return multiplyByPrice(
new(big.Rat).SetInt(bigBaseQuantums),
baseCurrencyAtomicResolution,
priceValue,
priceExponent,
)
// Multiply all numerators.
numResult := new(big.Int).SetUint64(priceValue)
numResult.Mul(numResult, bigBaseQuantums)
exponent := priceExponent + baseCurrencyAtomicResolution - QuoteCurrencyAtomicResolution

// Special case: if the exponent is zero, we can return early.
if exponent == 0 {
return numResult
}

// Otherwise multiply or divide by the 1e^exponent.
ePow := bigPow10Helper(uint64(AbsInt32(exponent)))
if exponent > 0 {
return numResult.Mul(numResult, ePow)
} else {
// Trucated division (towards zero) instead of Euclidean division.
return numResult.Quo(numResult, ePow)
}
}

// QuoteToBaseQuantums converts an amount denoted in quote quantums, to an equivalent amount denoted in base
Expand Down
31 changes: 31 additions & 0 deletions protocol/lib/quantums_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/dydxprotocol/v4-chain/protocol/lib"
big_testutil "github.com/dydxprotocol/v4-chain/protocol/testutil/big"
"github.com/stretchr/testify/require"
)

func TestBaseToQuoteQuantums(t *testing.T) {
Expand Down Expand Up @@ -220,3 +221,33 @@ func TestQuoteToBaseQuantums(t *testing.T) {
})
}
}

func BenchmarkBaseToQuoteQuantums(b *testing.B) {
value := big.NewInt(1234123412341)
baseCurrencyAtomicResolution := int32(-8)
priceValue := uint64(18446744073709551610)
priceExponent1 := int32(-10)
priceExponent2 := int32(10)
var result1 *big.Int
var result2 *big.Int

for i := 0; i < b.N; i++ {
result1 = lib.BaseToQuoteQuantums(
value,
baseCurrencyAtomicResolution,
priceValue,
priceExponent1,
)
result2 = lib.BaseToQuoteQuantums(
value,
baseCurrencyAtomicResolution,
priceValue,
priceExponent2,
)
}

expected1, _ := new(big.Int).SetString("22765558742827551059", 10)
require.Equal(b, expected1, result1)
expected2, _ := new(big.Int).SetString("2276555874282755105905825041901000000000", 10)
require.Equal(b, expected2, result2)
}

0 comments on commit 3b5043e

Please sign in to comment.