From 6558bd9ba94936abf8f3cdda893a079f43615059 Mon Sep 17 00:00:00 2001 From: Andrea Cavalli Date: Thu, 21 Oct 2021 09:52:59 +0200 Subject: [PATCH] Performance optimization Reuse the same arrays Clear only the range that needs to be cleared Reduce the MAX_EVENTS constant to 100 --- .../tdlight/common/ClientEventsHandler.java | 2 +- .../java/it/tdlight/common/EventsHandler.java | 7 ++- .../common/internal/InternalClient.java | 5 +- .../internal/InternalClientManager.java | 15 +++-- .../internal/InternalReactiveClient.java | 5 +- .../common/internal/ResponseReceiver.java | 63 ++++++++++++------- 6 files changed, 64 insertions(+), 33 deletions(-) diff --git a/src/main/java/it/tdlight/common/ClientEventsHandler.java b/src/main/java/it/tdlight/common/ClientEventsHandler.java index 7e091e7..5eb6503 100644 --- a/src/main/java/it/tdlight/common/ClientEventsHandler.java +++ b/src/main/java/it/tdlight/common/ClientEventsHandler.java @@ -6,5 +6,5 @@ public interface ClientEventsHandler { int getClientId(); - void handleEvents(boolean isClosed, long[] eventIds, Object[] events); + void handleEvents(boolean isClosed, long[] eventIds, Object[] events, int arrayOffset, int arrayLength); } diff --git a/src/main/java/it/tdlight/common/EventsHandler.java b/src/main/java/it/tdlight/common/EventsHandler.java index a9c8236..970959b 100644 --- a/src/main/java/it/tdlight/common/EventsHandler.java +++ b/src/main/java/it/tdlight/common/EventsHandler.java @@ -4,5 +4,10 @@ import it.tdlight.jni.TdApi.Object; public interface EventsHandler { - void handleClientEvents(int clientId, boolean isClosed, long[] clientEventIds, Object[] clientEvents); + void handleClientEvents(int clientId, + boolean isClosed, + long[] clientEventIds, + Object[] clientEvents, + int arrayOffset, + int arrayLength); } diff --git a/src/main/java/it/tdlight/common/internal/InternalClient.java b/src/main/java/it/tdlight/common/internal/InternalClient.java index 487996c..61ab91d 100644 --- a/src/main/java/it/tdlight/common/internal/InternalClient.java +++ b/src/main/java/it/tdlight/common/internal/InternalClient.java @@ -46,12 +46,13 @@ public final class InternalClient implements ClientEventsHandler, TelegramClient } @Override - public void handleEvents(boolean isClosed, long[] eventIds, TdApi.Object[] events) { + public void handleEvents(boolean isClosed, long[] eventIds, TdApi.Object[] events, + int arrayOffset, int arrayLength) { if (updatesHandler != null) { LongArrayList idsToFilter = new LongArrayList(eventIds); ObjectArrayList eventsToFilter = new ObjectArrayList<>(events); - for (int i = eventIds.length - 1; i >= 0; i--) { + for (int i = (arrayOffset + arrayLength) - 1; i >= arrayOffset; i--) { if (eventIds[i] != 0) { idsToFilter.removeLong(i); eventsToFilter.remove(i); diff --git a/src/main/java/it/tdlight/common/internal/InternalClientManager.java b/src/main/java/it/tdlight/common/internal/InternalClientManager.java index f39dc04..4006fda 100644 --- a/src/main/java/it/tdlight/common/internal/InternalClientManager.java +++ b/src/main/java/it/tdlight/common/internal/InternalClientManager.java @@ -73,13 +73,15 @@ public final class InternalClientManager implements AutoCloseable { return clientManager; } - private void handleClientEvents(int clientId, boolean isClosed, long[] clientEventIds, TdApi.Object[] clientEvents) { + private void handleClientEvents(int clientId, boolean isClosed, long[] clientEventIds, TdApi.Object[] clientEvents, + int arrayOffset, int arrayLength) { ClientEventsHandler handler = registeredClientEventHandlers.get(clientId); if (handler != null) { - handler.handleEvents(isClosed, clientEventIds, clientEvents); + handler.handleEvents(isClosed, clientEventIds, clientEvents, arrayOffset, arrayLength); } else { - java.util.List droppedEvents = getEffectivelyDroppedEvents(clientEventIds, clientEvents); + java.util.List droppedEvents + = getEffectivelyDroppedEvents(clientEventIds, clientEvents, arrayOffset, arrayLength); if (!droppedEvents.isEmpty()) { logger.error("Unknown client id \"{}\"! {} events have been dropped!", clientId, droppedEvents.size()); @@ -101,9 +103,10 @@ public final class InternalClientManager implements AutoCloseable { /** * Get only events that have been dropped, ignoring synthetic errors related to the closure of a client */ - private List getEffectivelyDroppedEvents(long[] clientEventIds, TdApi.Object[] clientEvents) { - java.util.List droppedEvents = new ArrayList<>(clientEvents.length); - for (int i = 0; i < clientEvents.length; i++) { + private List getEffectivelyDroppedEvents(long[] clientEventIds, TdApi.Object[] clientEvents, + int arrayOffset, int arrayLength) { + java.util.List droppedEvents = new ArrayList<>(arrayLength); + for (int i = arrayOffset; i < arrayOffset + arrayLength; i++) { long id = clientEventIds[i]; TdApi.Object event = clientEvents[i]; boolean mustPrintError = true; diff --git a/src/main/java/it/tdlight/common/internal/InternalReactiveClient.java b/src/main/java/it/tdlight/common/internal/InternalReactiveClient.java index 3d310ae..9fe7bdf 100644 --- a/src/main/java/it/tdlight/common/internal/InternalReactiveClient.java +++ b/src/main/java/it/tdlight/common/internal/InternalReactiveClient.java @@ -60,8 +60,9 @@ public final class InternalReactiveClient implements ClientEventsHandler, Reacti } @Override - public void handleEvents(boolean isClosed, long[] eventIds, TdApi.Object[] events) { - for (int i = 0; i < eventIds.length; i++) { + public void handleEvents(boolean isClosed, long[] eventIds, TdApi.Object[] events, + int arrayOffset, int arrayLength) { + for (int i = arrayOffset; i < arrayOffset + arrayLength; i++) { handleEvent(eventIds[i], events[i]); } diff --git a/src/main/java/it/tdlight/common/internal/ResponseReceiver.java b/src/main/java/it/tdlight/common/internal/ResponseReceiver.java index f03fab5..c0a55de 100644 --- a/src/main/java/it/tdlight/common/internal/ResponseReceiver.java +++ b/src/main/java/it/tdlight/common/internal/ResponseReceiver.java @@ -21,7 +21,7 @@ public final class ResponseReceiver extends Thread implements AutoCloseable { "tdlight.dispatcher.use_optimized_dispatcher", "true" )); - private static final int MAX_EVENTS = 1000; + private static final int MAX_EVENTS = 100; private static final int[] originalSortingSource = new int[MAX_EVENTS]; static { for (int i = 0; i < originalSortingSource.length; i++) { @@ -37,9 +37,15 @@ public final class ResponseReceiver extends Thread implements AutoCloseable { private final int[] clientIds = new int[MAX_EVENTS]; private final long[] eventIds = new long[MAX_EVENTS]; private final TdApi.Object[] events = new TdApi.Object[MAX_EVENTS]; + private int eventsLastUsedLength = 0; + + private final long[] clientEventIds = new long[MAX_EVENTS]; + private final TdApi.Object[] clientEvents = new TdApi.Object[MAX_EVENTS]; + private int clientEventsLastUsedLength = 0; private final CountDownLatch closeWait = new CountDownLatch(1); - private final Set registeredClients = new ConcurrentHashMap().keySet(new java.lang.Object()); + private final Set registeredClients + = new ConcurrentHashMap().keySet(new java.lang.Object()); public ResponseReceiver(EventsHandler eventsHandler) { @@ -89,22 +95,24 @@ public final class ResponseReceiver extends Thread implements AutoCloseable { if (i == resultsCount || (i != 0 && clientIds[sortIndex[i]] != lastClientId)) { if (lastClientIdEventsCount > 0) { int clientId = lastClientId; - long[] clientEventIds = new long[lastClientIdEventsCount]; - TdApi.Object[] clientEvents = new TdApi.Object[lastClientIdEventsCount]; for (int j = 0; j < lastClientIdEventsCount; j++) { clientEventIds[j] = eventIds[sortIndex[i - lastClientIdEventsCount + j]]; clientEvents[j] = events[sortIndex[i - lastClientIdEventsCount + j]]; - if (clientEventIds[j] == 0 && clientEvents[j] instanceof TdApi.UpdateAuthorizationState) { - TdApi.AuthorizationState authorizationState = ((TdApi.UpdateAuthorizationState) clientEvents[j]).authorizationState; - if (authorizationState instanceof TdApi.AuthorizationStateClosed) { + if (clientEventIds[j] == 0 + && clientEvents[j].getConstructor() == TdApi.UpdateAuthorizationState.CONSTRUCTOR) { + TdApi.AuthorizationState authorizationState + = ((TdApi.UpdateAuthorizationState) clientEvents[j]).authorizationState; + if (authorizationState.getConstructor() == TdApi.AuthorizationStateClosed.CONSTRUCTOR) { lastClientClosed = true; closedClients.add(clientId); } } } + cleanClientEventsArray(lastClientIdEventsCount); - eventsHandler.handleClientEvents(clientId, lastClientClosed, clientEventIds, clientEvents); + eventsHandler.handleClientEvents(clientId, lastClientClosed, clientEventIds, clientEvents, + 0, lastClientIdEventsCount); } if (i < resultsCount) { @@ -138,30 +146,31 @@ public final class ResponseReceiver extends Thread implements AutoCloseable { } Set clientIds = eventsList.stream().map(e -> e.clientId).collect(Collectors.toSet()); for (int clientId : clientIds) { - List clientEventsList = eventsList.stream().filter(e -> e.clientId == clientId).collect(Collectors.toList()); - long[] clientEventIds = new long[clientEventsList.size()]; - Object[] clientEvents = new Object[clientEventsList.size()]; + List clientEventsList = eventsList.stream() + .filter(e -> e.clientId == clientId) + .collect(Collectors.toList()); boolean closed = false; for (int i = 0; i < clientEventsList.size(); i++) { Event e = clientEventsList.get(i); clientEventIds[i] = e.eventId; clientEvents[i] = e.event; - if (e.eventId == 0 && e.event instanceof TdApi.UpdateAuthorizationState) { - TdApi.AuthorizationState authorizationState = ((TdApi.UpdateAuthorizationState) e.event).authorizationState; - if (authorizationState instanceof TdApi.AuthorizationStateClosed) { + if (e.eventId == 0 && e.event.getConstructor() == TdApi.UpdateAuthorizationState.CONSTRUCTOR) { + TdApi.AuthorizationState authorizationState + = ((TdApi.UpdateAuthorizationState) e.event).authorizationState; + if (authorizationState.getConstructor() == TdApi.AuthorizationStateClosed.CONSTRUCTOR) { closed = true; closedClients.add(clientId); } } } - eventsHandler.handleClientEvents(clientId, closed, clientEventIds, clientEvents); + cleanClientEventsArray(clientEventsList.size()); + eventsHandler.handleClientEvents(clientId, closed, clientEventIds, clientEvents, + 0, clientEventsList.size()); } } - Arrays.fill(clientIds, 0); - Arrays.fill(eventIds, 0); - Arrays.fill(events, null); + cleanEventsArray(resultsCount); if (!closedClients.isEmpty()) { this.registeredClients.removeAll(closedClients); @@ -171,9 +180,7 @@ public final class ResponseReceiver extends Thread implements AutoCloseable { if (interrupted) { if (!jvmShutdown.get()) { for (Integer clientId : this.registeredClients) { - long[] clientEventIds = new long[0]; - TdApi.Object[] clientEvents = new TdApi.Object[0]; - eventsHandler.handleClientEvents(clientId, true, clientEventIds, clientEvents); + eventsHandler.handleClientEvents(clientId, true, clientEventIds, clientEvents, 0, 0); } } } @@ -182,6 +189,20 @@ public final class ResponseReceiver extends Thread implements AutoCloseable { } } + private void cleanEventsArray(int eventsCount) { + if (eventsLastUsedLength > eventsCount) { + Arrays.fill(events, eventsCount, eventsLastUsedLength, null); + } + eventsLastUsedLength = eventsCount; + } + + private void cleanClientEventsArray(int clientEventsCount) { + if (clientEventsLastUsedLength > clientEventsCount) { + Arrays.fill(clientEvents, clientEventsCount, clientEventsLastUsedLength, null); + } + clientEventsLastUsedLength = clientEventsCount; + } + @SuppressWarnings("SameParameterValue") private int[] generateSortIndex(int from, int to, int[] data) { int[] sortedIndices = Arrays.copyOfRange(originalSortingSource, from, to);