serum health: use lower-precision division (#750)

This saves around 1/3rd of the compute for active serum markets.
This commit is contained in:
Christian Kamm 2023-10-11 15:19:24 +02:00 committed by GitHub
parent 20eb02af01
commit dfde7ec43f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 9 additions and 6 deletions

View File

@ -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)

View File

@ -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::<u64>()
/ (cu_measurements.len() - 1) as u64;
println!("average cu increase: {avg_cu_increase}");
assert!(avg_cu_increase < 10000);
assert!(avg_cu_increase < 7000);
Ok(())
}