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();
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 {
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
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<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) {
idsToFilter.removeLong(i);
eventsToFilter.remove(i);

View File

@ -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<DroppedEvent> droppedEvents = getEffectivelyDroppedEvents(clientEventIds, clientEvents);
java.util.List<DroppedEvent> 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<DroppedEvent> getEffectivelyDroppedEvents(long[] clientEventIds, TdApi.Object[] clientEvents) {
java.util.List<DroppedEvent> droppedEvents = new ArrayList<>(clientEvents.length);
for (int i = 0; i < clientEvents.length; i++) {
private List<DroppedEvent> getEffectivelyDroppedEvents(long[] clientEventIds, TdApi.Object[] clientEvents,
int arrayOffset, int arrayLength) {
java.util.List<DroppedEvent> droppedEvents = new ArrayList<>(arrayLength);
for (int i = arrayOffset; i < arrayOffset + arrayLength; i++) {
long id = clientEventIds[i];
TdApi.Object event = clientEvents[i];
boolean mustPrintError = true;

View File

@ -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]);
}

View File

@ -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<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) {
@ -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<Integer> clientIds = eventsList.stream().map(e -> e.clientId).collect(Collectors.toSet());
for (int clientId : clientIds) {
List<Event> clientEventsList = eventsList.stream().filter(e -> e.clientId == clientId).collect(Collectors.toList());
long[] clientEventIds = new long[clientEventsList.size()];
Object[] clientEvents = new Object[clientEventsList.size()];
List<Event> 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);