From 589011f95663e8833b74650cd7a309aefb71407a Mon Sep 17 00:00:00 2001 From: ceroma <678940+ceroma@users.noreply.github.com> Date: Fri, 27 Sep 2024 05:09:28 -0300 Subject: [PATCH] Feature/improve performance of portfolio snapshot computation After doing some perf analysis on the portfolio snapshot computation, this line turned out to be the biggest offender on my machine (Raspberry Pi 4). My current DB consists of 5189 activities and 478 different symbols. The majority (about 400) of the symbols represent single `INTEREST` data points. This line runs for each `SymbolProfile`, and deep-cloning is very expensive. Specially if most of the time (in my case) it ends up filtering out just one element out of the entire clone. On my machine, this line averaged 280ms per invocation, amounting to over 2 minutes during a snapshot computation. After this diff, this line averaged 1.5ms per symbol, with a peak of 56ms for my symbol with the highest number of activities (1500). The total time spent filtering and deep-cloning is now less than a second (~750ms). Per my understanding of the code, this change should preserve the same behavior as before, but I'm not too familiar with TypeScript so please feel free to be very pedantic in the review. Test Plan: Check that result of portfolio snapshot computation is the same before and after this diff: 1. Flush portfolio snapshot cache: ``` $ docker exec -it ghostfolio-redis-1 redis-cli --pass $REDIS_PASSWORD del "portfolio-snapshot-f9e4c63e-4b8e-46fc-b6ed-75ca0205f12b" ``` 2. Open Accounts to trigger snapshot calculation 3. Dump portfolio snapshot to a file: ``` $ docker exec -it ghostfolio-redis-1 redis-cli --pass $REDIS_PASSWORD --no-auth-warning get "portfolio-snapshot-f9e4c63e-4b8e-46fc-b6ed-75ca0205f12b" | python -c "import json, sys; json.dump(json.loads(json.loads(json.load(sys.stdin))), sys.stdout, indent=2, sort_keys=True)" > snapshot-before.json ``` 4. Apply this patch 5. Repeat steps 1-3 6. Compare results, check everything matches except for expiration time: ``` $ diff snapshot-before.json snapshot-after.json 2c2 < "expiration": 1727423725104, --- > "expiration": 1727424454187, ``` --- .../app/portfolio/calculator/twr/portfolio-calculator.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts index fba0ead84..3b64cd185 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts @@ -180,10 +180,10 @@ export class TWRPortfolioCalculator extends PortfolioCalculator { let valueAtStartDateWithCurrencyEffect: Big; // Clone orders to keep the original values in this.orders - let orders: PortfolioOrderItem[] = cloneDeep(this.activities).filter( - ({ SymbolProfile }) => { + let orders: PortfolioOrderItem[] = cloneDeep( + this.activities.filter(({ SymbolProfile }) => { return SymbolProfile.symbol === symbol; - } + }) ); if (orders.length <= 0) {