Skip to content

Commit

Permalink
Speed up sorting (#2046)
Browse files Browse the repository at this point in the history
# Description
Sorting orders based on their price achievability takes a surprisingly
long amount of time.

# Changes
Used `sort_by_cached_key()` to speed up sorting from ~1.5s to ~0.2s
(prod mainnet auction).
Note that unlike fetching balances this currently has to happen for
every configured driver. Meaning that when an auction starts we slam the
`driver` pod with >10 200ms tasks at the same time. As an additional
optimization step specifically for multiplexing solvers we should find a
way to deduplicate this work as well. But this should happen in another
PR.

I also used `spawn_blocking()` to run the sorting task since regular
tokio tasks are not supposed to be blocked for more than 100µs according
to this [blog article](https://ryhl.io/blog/async-what-is-blocking/)
(although I'm not sure whether these numbers are still accurate since
the tokio runtime started to keep track of every task's compute budget).

## How to test
e2e
  • Loading branch information
MartinquaXD authored Nov 7, 2023
1 parent 327b5eb commit 461a81e
Showing 1 changed file with 26 additions and 21 deletions.
47 changes: 26 additions & 21 deletions crates/driver/src/domain/competition/auction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,26 +81,31 @@ impl Auction {
///
/// Prioritization is skipped during quoting. It's only used during
/// competition.
pub async fn prioritize(mut self, eth: &Ethereum, balances: &eth::balances::Cache) -> Self {
pub async fn prioritize(self, eth: &Ethereum, balances: &eth::balances::Cache) -> Self {
// Sort orders so that most likely to be fulfilled come first.
self.orders.sort_by_key(|order| {
// Market orders are preferred over limit orders, as the expectation is that
// they should be immediately fulfillable. Liquidity orders come last, as they
// are the most niche and rarely used.
let class = match order.kind {
competition::order::Kind::Market => 2,
competition::order::Kind::Limit { .. } => 1,
competition::order::Kind::Liquidity => 0,
};
std::cmp::Reverse((
class,
// If the orders are of the same kind, then sort by likelihood of fulfillment
// based on token prices.
order.likelihood(&self.tokens),
))
});

let balances = balances.get_or_fetch(eth, self.orders()).await;
let mut auction = self;
let sort = || {
auction.orders.sort_by_cached_key(|order| {
// Market orders are preferred over limit orders, as the expectation is that
// they should be immediately fulfillable. Liquidity orders come last, as they
// are the most niche and rarely used.
let class = match order.kind {
competition::order::Kind::Market => 2,
competition::order::Kind::Limit { .. } => 1,
competition::order::Kind::Liquidity => 0,
};
std::cmp::Reverse((
class,
// If the orders are of the same kind, then sort by likelihood of fulfillment
// based on token prices.
order.likelihood(&auction.tokens),
))
});
auction
};
let mut auction = tokio::task::spawn_blocking(sort).await.unwrap();

let balances = balances.get_or_fetch(eth, auction.orders()).await;
let mut balances = (*balances).clone();

// The auction that we receive from the `autopilot` assumes that there
Expand All @@ -112,7 +117,7 @@ impl Auction {
// down in case the available user balance is only enough to partially
// cover the rest of the order.
let weth = eth.contracts().weth_address();
self.orders.retain_mut(|order| {
auction.orders.retain_mut(|order| {
let remaining_balance = match balances.get_mut(&(
order.trader(),
order.sell.token,
Expand Down Expand Up @@ -183,7 +188,7 @@ impl Auction {
true
});

self
auction
}

/// The tokens used in the auction.
Expand Down

0 comments on commit 461a81e

Please sign in to comment.