Skip to content

Commit

Permalink
Run getUsdAveragePriceMapsPerTickUnit and getTradeStatisticsForCurrency
Browse files Browse the repository at this point in the history
in parallel and once both are done we call asyncUpdateChartData (not yet refactored).

Clear all data at deactivate
This cause a bit of costs when we activate again but as we delegate
now all work to threads it should be OK. It decreases the memory usage
if we do not keep those data in the fields. The View classes are cached
in the view loader so all data in fields stays in memory once it was
activated once and not manually cleared in deactivate.

Move getTradeStatisticsForCurrency to ChartCalculations
Rename buildUsdPricesPerTickUnit to getUsdAveragePriceMapsPerTickUnit
Rename selectedTradeStatistics to tradeStatisticsByCurrency
Make itemsPerInterval final
Remove modelReady
Add deactivateCalled flag
  • Loading branch information
chimp1984 committed Nov 4, 2021
1 parent 96f77f0 commit d9e99c7
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,12 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

public class ChartCalculations {
static final ZoneId ZONE_ID = ZoneId.systemDefault();

static CompletableFuture<Map<TradesChartsViewModel.TickUnit, Map<Long, Long>>> buildUsdPricesPerTickUnit(Set<TradeStatistics3> tradeStatisticsSet) {
static CompletableFuture<Map<TradesChartsViewModel.TickUnit, Map<Long, Long>>> getUsdAveragePriceMapsPerTickUnit(Set<TradeStatistics3> tradeStatisticsSet) {
return CompletableFuture.supplyAsync(() -> {
Map<TradesChartsViewModel.TickUnit, Map<Long, Long>> usdAveragePriceMapsPerTickUnit = new HashMap<>();
Map<TradesChartsViewModel.TickUnit, Map<Long, List<TradeStatistics3>>> dateMapsPerTickUnit = new HashMap<>();
Expand Down Expand Up @@ -66,6 +67,15 @@ static CompletableFuture<Map<TradesChartsViewModel.TickUnit, Map<Long, Long>>> b
});
}

static CompletableFuture<List<TradeStatistics3>> getTradeStatisticsForCurrency(Set<TradeStatistics3> tradeStatisticsSet,
String currencyCode,
boolean showAllTradeCurrencies) {
return CompletableFuture.supplyAsync(() -> {
return tradeStatisticsSet.stream()
.filter(e -> showAllTradeCurrencies || e.getCurrency().equals(currencyCode))
.collect(Collectors.toList());
});
}

static long getAveragePrice(List<TradeStatistics3> tradeStatisticsList) {
long accumulatedAmount = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import bisq.core.user.Preferences;

import bisq.common.UserThread;
import bisq.common.util.CompletableFutureUtils;
import bisq.common.util.MathUtils;

import org.bitcoinj.core.Coin;
Expand Down Expand Up @@ -70,6 +71,7 @@
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -103,18 +105,18 @@ public enum TickUnit {
final BooleanProperty showAllTradeCurrenciesProperty = new SimpleBooleanProperty(false);
private final CurrencyList currencyListItems;
private final CurrencyListItem showAllCurrencyListItem = new CurrencyListItem(new CryptoCurrency(GUIUtil.SHOW_ALL_FLAG, ""), -1);
final ObservableList<TradeStatistics3> selectedTradeStatistics = FXCollections.observableArrayList();
final ObservableList<TradeStatistics3> tradeStatisticsByCurrency = FXCollections.observableArrayList();
final ObservableList<XYChart.Data<Number, Number>> priceItems = FXCollections.observableArrayList();
final ObservableList<XYChart.Data<Number, Number>> volumeItems = FXCollections.observableArrayList();
final ObservableList<XYChart.Data<Number, Number>> volumeInUsdItems = FXCollections.observableArrayList();
private Map<Long, Pair<Date, Set<TradeStatistics3>>> itemsPerInterval;
private final Map<Long, Pair<Date, Set<TradeStatistics3>>> itemsPerInterval = new HashMap<>();

TickUnit tickUnit;
final int maxTicks = 90;
private int selectedTabIndex;
final Map<TickUnit, Map<Long, Long>> usdAveragePriceMapsPerTickUnit = new HashMap<>();
private boolean fillTradeCurrenciesOnActivateCalled;
final BooleanProperty modelReady = new SimpleBooleanProperty(false);
private volatile boolean deactivateCalled;


///////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -149,6 +151,10 @@ public enum TickUnit {

@Override
protected void activate() {
deactivateCalled = false;
long ts = System.currentTimeMillis();


tradeStatisticsManager.getObservableTradeStatisticsSet().addListener(setChangeListener);
if (!fillTradeCurrenciesOnActivateCalled) {
fillTradeCurrencies();
Expand All @@ -157,32 +163,92 @@ protected void activate() {
syncPriceFeedCurrency();
setMarketPriceFeedCurrency();

ChartCalculations.buildUsdPricesPerTickUnit(tradeStatisticsManager.getObservableTradeStatisticsSet())
.whenComplete((usdAveragePriceMapsPerTickUnit, throwable) -> {
long ts1 = System.currentTimeMillis();

List<CompletableFuture<Boolean>> allFutures = new ArrayList<>();
CompletableFuture<Boolean> task1Done = new CompletableFuture<>();
allFutures.add(task1Done);
CompletableFuture<Boolean> task2Done = new CompletableFuture<>();
allFutures.add(task2Done);
CompletableFutureUtils.allOf(allFutures)
.whenComplete((res, throwable) -> {
if (deactivateCalled) {
return;
}
if (throwable != null) {
log.error(throwable.toString());
return;
}
//Once getUsdAveragePriceMapsPerTickUnit and getUsdAveragePriceMapsPerTickUnit are both completed we
// call updateChartData2
UserThread.execute(this::asyncUpdateChartData);
});

// We start getUsdAveragePriceMapsPerTickUnit and getUsdAveragePriceMapsPerTickUnit in parallel threads for
// better performance
ChartCalculations.getUsdAveragePriceMapsPerTickUnit(tradeStatisticsManager.getObservableTradeStatisticsSet())
.whenComplete((usdAveragePriceMapsPerTickUnit, throwable) -> {
if (deactivateCalled) {
return;
}
if (throwable != null) {
log.error(throwable.toString());
task1Done.completeExceptionally(throwable);
return;
}
UserThread.execute(() -> {
this.usdAveragePriceMapsPerTickUnit.clear();
this.usdAveragePriceMapsPerTickUnit.putAll(usdAveragePriceMapsPerTickUnit);
log.error("getUsdAveragePriceMapsPerTickUnit took {}", System.currentTimeMillis() - ts1);
task1Done.complete(true);
});
});

List<TradeStatistics3> list = getTradeStatisticsForCurrency(tradeStatisticsManager.getObservableTradeStatisticsSet(),
getCurrencyCode(),
showAllTradeCurrenciesProperty.get());
selectedTradeStatistics.setAll(list);
long ts2 = System.currentTimeMillis();
ChartCalculations.getTradeStatisticsForCurrency(tradeStatisticsManager.getObservableTradeStatisticsSet(),
getCurrencyCode(),
showAllTradeCurrenciesProperty.get())
.whenComplete((list, throwable) -> {
if (deactivateCalled) {
return;
}
if (throwable != null) {
log.error(throwable.toString());
task2Done.completeExceptionally(throwable);
return;
}

updateChartData();
modelReady.set(true);
UserThread.execute(() -> {
tradeStatisticsByCurrency.setAll(list);
log.error("getTradeStatisticsForCurrency took {}", System.currentTimeMillis() - ts2);
task2Done.complete(true);
});
});

log.error("activate took {}", System.currentTimeMillis() - ts);
}

private void asyncUpdateChartData() {
long ts = System.currentTimeMillis();
updateChartData();
log.error("updateChartData took {}", System.currentTimeMillis() - ts);
}

@Override
protected void deactivate() {
deactivateCalled = true;
tradeStatisticsManager.getObservableTradeStatisticsSet().removeListener(setChangeListener);
usdAveragePriceMapsPerTickUnit.clear();

// We want to avoid to trigger listeners in the view so we delay a bit. Deactivate on model is called before
// deactivate on view.
UserThread.execute(() -> {
usdAveragePriceMapsPerTickUnit.clear();
tradeStatisticsByCurrency.clear();
priceItems.clear();
volumeItems.clear();
volumeInUsdItems.clear();
itemsPerInterval.clear();
});
}

///////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -271,7 +337,7 @@ private void syncPriceFeedCurrency() {

private void updateChartData() {
// Generate date range and create sets for all ticks
itemsPerInterval = new HashMap<>();
itemsPerInterval.clear();
Date time = new Date();
for (long i = maxTicks + 1; i >= 0; --i) {
Pair<Date, Set<TradeStatistics3>> pair = new Pair<>((Date) time.clone(), new HashSet<>());
Expand All @@ -282,7 +348,7 @@ private void updateChartData() {
}

// Get all entries for the defined time interval
selectedTradeStatistics.forEach(tradeStatistics -> {
tradeStatisticsByCurrency.forEach(tradeStatistics -> {
for (long i = maxTicks; i > 0; --i) {
Pair<Date, Set<TradeStatistics3>> pair = itemsPerInterval.get(i);
if (tradeStatistics.getDate().after(pair.getKey())) {
Expand Down Expand Up @@ -322,16 +388,8 @@ private void updateChartData() {
.collect(Collectors.toList()));
}

private static List<TradeStatistics3> getTradeStatisticsForCurrency(Set<TradeStatistics3> tradeStatisticsSet,
String currencyCode,
boolean showAllTradeCurrencies) {
return tradeStatisticsSet.stream()
.filter(e -> showAllTradeCurrencies || e.getCurrency().equals(currencyCode))
.collect(Collectors.toList());
}

private void updateSelectedTradeStatistics(String currencyCode) {
selectedTradeStatistics.setAll(tradeStatisticsManager.getObservableTradeStatisticsSet().stream()
tradeStatisticsByCurrency.setAll(tradeStatisticsManager.getObservableTradeStatisticsSet().stream()
.filter(e -> showAllTradeCurrenciesProperty.get() || e.getCurrency().equals(currencyCode))
.collect(Collectors.toList()));
}
Expand Down

0 comments on commit d9e99c7

Please sign in to comment.