Performance optimization

Reuse the same arrays
Clear only the range that needs to be cleared
Reduce the MAX_EVENTS constant to 100
This commit is contained in:
Andrea Cavalli 2021-10-21 09:52:59 +02:00
parent 887d95f2c2
commit 6558bd9ba9
6 changed files with 64 additions and 33 deletions

View File

@ -6,5 +6,5 @@ public interface ClientEventsHandler {
int getClientId(); int getClientId();
void handleEvents(boolean isClosed, long[] eventIds, Object[] events); void handleEvents(boolean isClosed, long[] eventIds, Object[] events, int arrayOffset, int arrayLength);
} }

View File

@ -4,5 +4,10 @@ import it.tdlight.jni.TdApi.Object;
public interface EventsHandler { 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);
} }

View File

@ -46,12 +46,13 @@ public final class InternalClient implements ClientEventsHandler, TelegramClient
} }
@Override @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) { if (updatesHandler != null) {
LongArrayList idsToFilter = new LongArrayList(eventIds); LongArrayList idsToFilter = new LongArrayList(eventIds);
ObjectArrayList<TdApi.Object> eventsToFilter = new ObjectArrayList<>(events); ObjectArrayList<TdApi.Object> 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) { if (eventIds[i] != 0) {
idsToFilter.removeLong(i); idsToFilter.removeLong(i);
eventsToFilter.remove(i); eventsToFilter.remove(i);

View File

@ -73,13 +73,15 @@ public final class InternalClientManager implements AutoCloseable {
return clientManager; 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); ClientEventsHandler handler = registeredClientEventHandlers.get(clientId);
if (handler != null) { if (handler != null) {
handler.handleEvents(isClosed, clientEventIds, clientEvents); handler.handleEvents(isClosed, clientEventIds, clientEvents, arrayOffset, arrayLength);
} else { } else {
java.util.List<DroppedEvent> droppedEvents = getEffectivelyDroppedEvents(clientEventIds, clientEvents); java.util.List<DroppedEvent> droppedEvents
= getEffectivelyDroppedEvents(clientEventIds, clientEvents, arrayOffset, arrayLength);
if (!droppedEvents.isEmpty()) { if (!droppedEvents.isEmpty()) {
logger.error("Unknown client id \"{}\"! {} events have been dropped!", clientId, droppedEvents.size()); 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 * Get only events that have been dropped, ignoring synthetic errors related to the closure of a client
*/ */
private List<DroppedEvent> getEffectivelyDroppedEvents(long[] clientEventIds, TdApi.Object[] clientEvents) { private List<DroppedEvent> getEffectivelyDroppedEvents(long[] clientEventIds, TdApi.Object[] clientEvents,
java.util.List<DroppedEvent> droppedEvents = new ArrayList<>(clientEvents.length); int arrayOffset, int arrayLength) {
for (int i = 0; i < clientEvents.length; i++) { java.util.List<DroppedEvent> droppedEvents = new ArrayList<>(arrayLength);
for (int i = arrayOffset; i < arrayOffset + arrayLength; i++) {
long id = clientEventIds[i]; long id = clientEventIds[i];
TdApi.Object event = clientEvents[i]; TdApi.Object event = clientEvents[i];
boolean mustPrintError = true; boolean mustPrintError = true;

View File

@ -60,8 +60,9 @@ public final class InternalReactiveClient implements ClientEventsHandler, Reacti
} }
@Override @Override
public void handleEvents(boolean isClosed, long[] eventIds, TdApi.Object[] events) { public void handleEvents(boolean isClosed, long[] eventIds, TdApi.Object[] events,
for (int i = 0; i < eventIds.length; i++) { int arrayOffset, int arrayLength) {
for (int i = arrayOffset; i < arrayOffset + arrayLength; i++) {
handleEvent(eventIds[i], events[i]); handleEvent(eventIds[i], events[i]);
} }

View File

@ -21,7 +21,7 @@ public final class ResponseReceiver extends Thread implements AutoCloseable {
"tdlight.dispatcher.use_optimized_dispatcher", "tdlight.dispatcher.use_optimized_dispatcher",
"true" "true"
)); ));
private static final int MAX_EVENTS = 1000; private static final int MAX_EVENTS = 100;
private static final int[] originalSortingSource = new int[MAX_EVENTS]; private static final int[] originalSortingSource = new int[MAX_EVENTS];
static { static {
for (int i = 0; i < originalSortingSource.length; i++) { 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 int[] clientIds = new int[MAX_EVENTS];
private final long[] eventIds = new long[MAX_EVENTS]; private final long[] eventIds = new long[MAX_EVENTS];
private final TdApi.Object[] events = new TdApi.Object[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 CountDownLatch closeWait = new CountDownLatch(1);
private final Set<Integer> registeredClients = new ConcurrentHashMap<Integer, java.lang.Object>().keySet(new java.lang.Object()); private final Set<Integer> registeredClients
= new ConcurrentHashMap<Integer, java.lang.Object>().keySet(new java.lang.Object());
public ResponseReceiver(EventsHandler eventsHandler) { 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 (i == resultsCount || (i != 0 && clientIds[sortIndex[i]] != lastClientId)) {
if (lastClientIdEventsCount > 0) { if (lastClientIdEventsCount > 0) {
int clientId = lastClientId; int clientId = lastClientId;
long[] clientEventIds = new long[lastClientIdEventsCount];
TdApi.Object[] clientEvents = new TdApi.Object[lastClientIdEventsCount];
for (int j = 0; j < lastClientIdEventsCount; j++) { for (int j = 0; j < lastClientIdEventsCount; j++) {
clientEventIds[j] = eventIds[sortIndex[i - lastClientIdEventsCount + j]]; clientEventIds[j] = eventIds[sortIndex[i - lastClientIdEventsCount + j]];
clientEvents[j] = events[sortIndex[i - lastClientIdEventsCount + j]]; clientEvents[j] = events[sortIndex[i - lastClientIdEventsCount + j]];
if (clientEventIds[j] == 0 && clientEvents[j] instanceof TdApi.UpdateAuthorizationState) { if (clientEventIds[j] == 0
TdApi.AuthorizationState authorizationState = ((TdApi.UpdateAuthorizationState) clientEvents[j]).authorizationState; && clientEvents[j].getConstructor() == TdApi.UpdateAuthorizationState.CONSTRUCTOR) {
if (authorizationState instanceof TdApi.AuthorizationStateClosed) { TdApi.AuthorizationState authorizationState
= ((TdApi.UpdateAuthorizationState) clientEvents[j]).authorizationState;
if (authorizationState.getConstructor() == TdApi.AuthorizationStateClosed.CONSTRUCTOR) {
lastClientClosed = true; lastClientClosed = true;
closedClients.add(clientId); closedClients.add(clientId);
} }
} }
} }
cleanClientEventsArray(lastClientIdEventsCount);
eventsHandler.handleClientEvents(clientId, lastClientClosed, clientEventIds, clientEvents); eventsHandler.handleClientEvents(clientId, lastClientClosed, clientEventIds, clientEvents,
0, lastClientIdEventsCount);
} }
if (i < resultsCount) { if (i < resultsCount) {
@ -138,30 +146,31 @@ public final class ResponseReceiver extends Thread implements AutoCloseable {
} }
Set<Integer> clientIds = eventsList.stream().map(e -> e.clientId).collect(Collectors.toSet()); Set<Integer> clientIds = eventsList.stream().map(e -> e.clientId).collect(Collectors.toSet());
for (int clientId : clientIds) { for (int clientId : clientIds) {
List<Event> clientEventsList = eventsList.stream().filter(e -> e.clientId == clientId).collect(Collectors.toList()); List<Event> clientEventsList = eventsList.stream()
long[] clientEventIds = new long[clientEventsList.size()]; .filter(e -> e.clientId == clientId)
Object[] clientEvents = new Object[clientEventsList.size()]; .collect(Collectors.toList());
boolean closed = false; boolean closed = false;
for (int i = 0; i < clientEventsList.size(); i++) { for (int i = 0; i < clientEventsList.size(); i++) {
Event e = clientEventsList.get(i); Event e = clientEventsList.get(i);
clientEventIds[i] = e.eventId; clientEventIds[i] = e.eventId;
clientEvents[i] = e.event; clientEvents[i] = e.event;
if (e.eventId == 0 && e.event instanceof TdApi.UpdateAuthorizationState) { if (e.eventId == 0 && e.event.getConstructor() == TdApi.UpdateAuthorizationState.CONSTRUCTOR) {
TdApi.AuthorizationState authorizationState = ((TdApi.UpdateAuthorizationState) e.event).authorizationState; TdApi.AuthorizationState authorizationState
if (authorizationState instanceof TdApi.AuthorizationStateClosed) { = ((TdApi.UpdateAuthorizationState) e.event).authorizationState;
if (authorizationState.getConstructor() == TdApi.AuthorizationStateClosed.CONSTRUCTOR) {
closed = true; closed = true;
closedClients.add(clientId); 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); cleanEventsArray(resultsCount);
Arrays.fill(eventIds, 0);
Arrays.fill(events, null);
if (!closedClients.isEmpty()) { if (!closedClients.isEmpty()) {
this.registeredClients.removeAll(closedClients); this.registeredClients.removeAll(closedClients);
@ -171,9 +180,7 @@ public final class ResponseReceiver extends Thread implements AutoCloseable {
if (interrupted) { if (interrupted) {
if (!jvmShutdown.get()) { if (!jvmShutdown.get()) {
for (Integer clientId : this.registeredClients) { for (Integer clientId : this.registeredClients) {
long[] clientEventIds = new long[0]; eventsHandler.handleClientEvents(clientId, true, clientEventIds, clientEvents, 0, 0);
TdApi.Object[] clientEvents = new TdApi.Object[0];
eventsHandler.handleClientEvents(clientId, true, clientEventIds, clientEvents);
} }
} }
} }
@ -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") @SuppressWarnings("SameParameterValue")
private int[] generateSortIndex(int from, int to, int[] data) { private int[] generateSortIndex(int from, int to, int[] data) {
int[] sortedIndices = Arrays.copyOfRange(originalSortingSource, from, to); int[] sortedIndices = Arrays.copyOfRange(originalSortingSource, from, to);