From dfde7ec43f4222896608aeb5cbbf2625a45db8da Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Wed, 11 Oct 2023 15:19:24 +0200 Subject: [PATCH] serum health: use lower-precision division (#750) This saves around 1/3rd of the compute for active serum markets. --- programs/mango-v4/src/health/cache.rs | 11 +++++++---- programs/mango-v4/tests/cases/test_health_compute.rs | 4 ++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/programs/mango-v4/src/health/cache.rs b/programs/mango-v4/src/health/cache.rs index 68f1eabbf..88aae888f 100644 --- a/programs/mango-v4/src/health/cache.rs +++ b/programs/mango-v4/src/health/cache.rs @@ -19,6 +19,7 @@ use anchor_lang::prelude::*; use fixed::types::I80F48; use crate::error::*; +use crate::i80f48::LowPrecisionDivision; use crate::serum3_cpi::{OpenOrdersAmounts, OpenOrdersSlim}; use crate::state::{ Bank, MangoAccountRef, PerpMarket, PerpMarketIndex, PerpPosition, Serum3MarketIndex, @@ -293,8 +294,9 @@ impl Serum3Info { ) -> I80F48 { let quote_asset = quote_info.prices.asset(health_type); let base_liab = base_info.prices.liab(health_type); - // OPTIMIZATION: These divisions can be extremely expensive (up to 5k CU each) - let reserved_quote_as_base_oracle = self.reserved_quote * quote_asset / base_liab; + let reserved_quote_as_base_oracle = (self.reserved_quote * quote_asset) + .checked_div_f64_precision(base_liab) + .unwrap(); if self.reserved_quote_as_base_highest_bid != 0 { self.reserved_base + reserved_quote_as_base_oracle.min(self.reserved_quote_as_base_highest_bid) @@ -312,8 +314,9 @@ impl Serum3Info { ) -> I80F48 { let base_asset = base_info.prices.asset(health_type); let quote_liab = quote_info.prices.liab(health_type); - // OPTIMIZATION: These divisions can be extremely expensive (up to 5k CU each) - let reserved_base_as_quote_oracle = self.reserved_base * base_asset / quote_liab; + let reserved_base_as_quote_oracle = (self.reserved_base * base_asset) + .checked_div_f64_precision(quote_liab) + .unwrap(); if self.reserved_base_as_quote_lowest_ask != 0 { self.reserved_quote + reserved_base_as_quote_oracle.min(self.reserved_base_as_quote_lowest_ask) diff --git a/programs/mango-v4/tests/cases/test_health_compute.rs b/programs/mango-v4/tests/cases/test_health_compute.rs index 917b1de7c..f3d018adb 100644 --- a/programs/mango-v4/tests/cases/test_health_compute.rs +++ b/programs/mango-v4/tests/cases/test_health_compute.rs @@ -77,7 +77,7 @@ async fn test_health_compute_tokens() -> Result<(), TransportError> { #[tokio::test] async fn test_health_compute_serum() -> Result<(), TransportError> { let mut test_builder = TestContextBuilder::new(); - test_builder.test().set_compute_max_units(150_000); + test_builder.test().set_compute_max_units(130_000); let context = test_builder.start_default().await; let solana = &context.solana.clone(); @@ -244,7 +244,7 @@ async fn test_health_compute_serum() -> Result<(), TransportError> { let avg_cu_increase = cu_measurements.windows(2).map(|p| p[1] - p[0]).sum::() / (cu_measurements.len() - 1) as u64; println!("average cu increase: {avg_cu_increase}"); - assert!(avg_cu_increase < 10000); + assert!(avg_cu_increase < 7000); Ok(()) }