Skip to content

Commit

Permalink
exp/orderbook: Update orderbook benchmark to use liquidity pools from…
Browse files Browse the repository at this point in the history
… history archives (stellar#4091)

Update orderbook benchmark to use liquidity pools from history archives and report memory allocations.
  • Loading branch information
tamirms authored and erika-sdf committed Dec 3, 2021
1 parent 8985a82 commit 2d25f3c
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 71 deletions.
118 changes: 61 additions & 57 deletions exp/orderbook/graph_benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package orderbook

import (
"context"
"encoding/binary"
"flag"
"io/ioutil"
"math"
Expand All @@ -20,79 +19,46 @@ import (
var (
// offersFile should contain a list of offers
// each line in the offers file is the base 64 encoding of an offer entry xdr
offersFile = flag.String("offers", "", "offers file generated by the dump-orderbook tool")
includePools = flag.Bool("pools", false, "include pools in the benchmark")
offersFile = flag.String("offers", "", "offers file generated by the dump-orderbook tool")
poolsFile = flag.String("pools", "", "pools file generated by the dump-orderbook tool")
)

func assetFromString(s string) xdr.Asset {
if s == "native" {
return xdr.MustNewNativeAsset()
}
parts := strings.Split(s, "/")
asset, err := xdr.BuildAsset(parts[0], parts[2], parts[1])
// loadGraphFromFiles reads an offers and pools file generated by the dump-orderbook tool
// and returns an orderbook built from those offers / pools
func loadGraphFromFiles(offerFilePath, poolFilePath string) (*OrderBookGraph, error) {
graph := NewOrderBookGraph()
offerDumpBytes, err := ioutil.ReadFile(offerFilePath)
if err != nil {
panic(err)
return nil, errors.Wrap(err, "could not read offers file")
}
return asset
}

// loadGraphFromFile reads an offers file generated by the dump-orderbook tool
// and returns an orderbook built from those offers
func loadGraphFromFile(filePath string) (*OrderBookGraph, error) {
graph := NewOrderBookGraph()
rawBytes, err := ioutil.ReadFile(filePath)
poolDumpBytes, err := ioutil.ReadFile(poolFilePath)
if err != nil {
return nil, errors.Wrap(err, "could not read file")
return nil, errors.Wrap(err, "could not read pools file")
}

for _, line := range strings.Split(string(rawBytes), "\n") {
for _, line := range strings.Split(string(offerDumpBytes), "\n") {
offer := xdr.OfferEntry{}
if err := xdr.SafeUnmarshalBase64(line, &offer); err != nil {
return nil, errors.Wrap(err, "could not base64 decode entry")
}

graph.AddOffers(offer)
}
if err := graph.Apply(1); err != nil {
return nil, err
}

if *includePools {
addLiquidityPools(graph)
if err := graph.Apply(2); err != nil {
return nil, err
for _, line := range strings.Split(string(poolDumpBytes), "\n") {
pool := xdr.LiquidityPoolEntry{}
if err := xdr.SafeUnmarshalBase64(line, &pool); err != nil {
return nil, errors.Wrap(err, "could not base64 decode entry")
}

graph.AddLiquidityPools(pool)
}
return graph, nil
}

func addLiquidityPools(graph *OrderBookGraph) {
set := map[tradingPair]bool{}
for i, tp := range graph.tradingPairForOffer {
if !set[tp] {
a, b := assetFromString(tp.buyingAsset), assetFromString(tp.sellingAsset)
poolEntry := xdr.LiquidityPoolEntry{
LiquidityPoolId: xdr.PoolId{},
Body: xdr.LiquidityPoolEntryBody{
Type: xdr.LiquidityPoolTypeLiquidityPoolConstantProduct,
ConstantProduct: &xdr.LiquidityPoolEntryConstantProduct{
Params: xdr.LiquidityPoolConstantProductParameters{
AssetA: a,
AssetB: b,
Fee: 30,
},
ReserveA: 10000,
ReserveB: 10000,
TotalPoolShares: 1,
PoolSharesTrustLineCount: 1,
},
},
}
binary.PutVarint(poolEntry.LiquidityPoolId[:], int64(i))
graph.addPool(poolEntry)
set[tp] = true
}
if err := graph.Apply(1); err != nil {
return nil, err
}

return graph, nil
}

type request struct {
Expand Down Expand Up @@ -145,6 +111,38 @@ func loadRequestsFromFile(filePath string) ([]request, error) {
return requests, nil
}

// BenchmarkVibrantPath benchmarks the most commonly requested path payment from the vibrant app.
func BenchmarkVibrantPath(b *testing.B) {
if *offersFile == "" {
b.Skip("missing offers file")
}
graph, err := loadGraphFromFiles(*offersFile, *poolsFile)
if err != nil {
b.Fatalf("could not read graph from file: %v", err)
}

b.ResetTimer()
b.ReportAllocs()
// https://horizon.stellar.org/paths/strict-send?source_asset_type=credit_alphanum4&source_asset_code=USDC&source_asset_issuer=GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN&source_amount=10&destination_assets=ARST%3AGCSAZVWXZKWS4XS223M5F54H2B6XPIIXZZGP7KEAIU6YSL5HDRGCI3DG

for i := 0; i < b.N; i++ {
_, _, err := graph.FindFixedPaths(
context.Background(),
3,
xdr.MustNewCreditAsset("USDC", "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN"),
amount.MustParse("10"),
[]xdr.Asset{
xdr.MustNewCreditAsset("ARST", "GCSAZVWXZKWS4XS223M5F54H2B6XPIIXZZGP7KEAIU6YSL5HDRGCI3DG"),
},
5,
true,
)
if err != nil {
b.Fatal("could not find path")
}
}
}

// BenchmarkMultipleDestinationAssets benchmarks the path finding function
// on a request which has multiple destination assets. Most requests to the
// path finding endpoint only specify a single destination asset, so I
Expand All @@ -154,12 +152,13 @@ func BenchmarkMultipleDestinationAssets(b *testing.B) {
if *offersFile == "" {
b.Skip("missing offers file")
}
graph, err := loadGraphFromFile(*offersFile)
graph, err := loadGraphFromFiles(*offersFile, *poolsFile)
if err != nil {
b.Fatalf("could not read graph from file: %v", err)
}

b.ResetTimer()
b.ReportAllocs()

for i := 0; i < b.N; i++ {
_, _, err := graph.FindFixedPaths(
Expand Down Expand Up @@ -188,7 +187,7 @@ func BenchmarkTestData(b *testing.B) {
if *offersFile == "" {
b.Skip("missing offers file")
}
graph, err := loadGraphFromFile(*offersFile)
graph, err := loadGraphFromFiles(*offersFile, *poolsFile)
if err != nil {
b.Fatalf("could not read graph from file: %v", err)
}
Expand All @@ -199,6 +198,7 @@ func BenchmarkTestData(b *testing.B) {
}

b.ResetTimer()
b.ReportAllocs()

for i := 0; i < b.N; i++ {
for _, req := range requests {
Expand Down Expand Up @@ -234,6 +234,8 @@ func BenchmarkLiquidityPoolDeposits(b *testing.B) {
amounts := createRandomAmounts(b.N)

b.ResetTimer()
b.ReportAllocs()

for _, amount := range amounts {
makeTrade(eurUsdLiquidityPool, usdAsset, tradeTypeDeposit, amount)
}
Expand All @@ -243,6 +245,8 @@ func BenchmarkLiquidityPoolExpectations(b *testing.B) {
amounts := createRandomAmounts(b.N)

b.ResetTimer()
b.ReportAllocs()

for _, amount := range amounts {
makeTrade(eurUsdLiquidityPool, usdAsset, tradeTypeExpectation, amount)
}
Expand Down
44 changes: 30 additions & 14 deletions exp/tools/dump-orderbook/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ func main() {
0,
"checkpoint ledger sequence to ingest, if omitted will use latest checkpoint ledger.",
)
output := flag.String("output", "offers.dump", "output file which will be populated with offerss")
offersOutput := flag.String("offers-output", "offers.dump", "output file which will be populated with offerss")
poolsOutput := flag.String("pools-output", "pools.dump", "output file which will be populated with pools")

flag.Parse()

archive, err := archive(*testnet)
Expand Down Expand Up @@ -55,13 +57,17 @@ func main() {
log.WithField("err", err).Fatal("cannot construct change reader")
}
defer changeReader.Close()
var file *os.File
file, err = os.Create(*output)
if err != nil {
var offersFile, poolsFile *os.File

if offersFile, err = os.Create(*offersOutput); err != nil {
log.WithField("err", err).Fatal("could not create offers file")
}
if poolsFile, err = os.Create(*poolsOutput); err != nil {
log.WithField("err", err).Fatal("could not create pools file")
}

var offerXDRs []string
var poolXDRs []string

for {
var change ingest.Change
Expand All @@ -73,19 +79,29 @@ func main() {
log.WithField("err", err).Fatal("could not read change")
}

if change.Type != xdr.LedgerEntryTypeOffer {
continue
switch change.Type {
case xdr.LedgerEntryTypeOffer:
var serialized string
serialized, err = xdr.MarshalBase64(change.Post.Data.MustOffer())
if err != nil {
log.WithField("err", err).Fatal("could not marshall offer")
}
offerXDRs = append(offerXDRs, serialized)
case xdr.LedgerEntryTypeLiquidityPool:
var serialized string
serialized, err = xdr.MarshalBase64(change.Post.Data.MustLiquidityPool())
if err != nil {
log.WithField("err", err).Fatal("could not marshall liquidity pool")
}
poolXDRs = append(poolXDRs, serialized)
}
var serialized string
serialized, err = xdr.MarshalBase64(change.Post.Data.MustOffer())
if err != nil {
log.WithField("err", err).Fatal("could not marshall offer")
}
offerXDRs = append(offerXDRs, serialized)
}

if _, err = io.Copy(file, bytes.NewBufferString(strings.Join(offerXDRs, "\n"))); err != nil {
log.WithField("err", err).Fatal("could not write dump file")
if _, err = io.Copy(offersFile, bytes.NewBufferString(strings.Join(offerXDRs, "\n"))); err != nil {
log.WithField("err", err).Fatal("could not write offer dump file")
}
if _, err = io.Copy(poolsFile, bytes.NewBufferString(strings.Join(poolXDRs, "\n"))); err != nil {
log.WithField("err", err).Fatal("could not write pool dump file")
}
}

Expand Down

0 comments on commit 2d25f3c

Please sign in to comment.