Reduce memory usage of perf-client 95/95395/7
authorIaroslav <iaroslav.kholiavko@pantheon.tech>
Mon, 1 Mar 2021 11:06:02 +0000 (13:06 +0200)
committerTomas Cere <tomas.cere@pantheon.tech>
Thu, 18 Mar 2021 13:57:30 +0000 (13:57 +0000)
Moved payload creation from test tool start to message send. It will
prevent store huge amount of the objects and reduce memory usage.

JIRA: NETCONF-762
Change-Id: I4932f259391af5770edf8d941f9dc27f022f2277
Signed-off-by: Iaroslav <iaroslav.kholiavko@pantheon.tech>
netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/http/perf/AsyncExecutionStrategy.java
netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/http/perf/PerfClientCallable.java
netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/http/perf/RequestMessageUtils.java [new file with mode: 0644]
netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/http/perf/RestPerfClient.java
netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/http/perf/SyncExecutionStrategy.java

index ecbb6de768f0b2dfe9ceff8b358231219e846ff9..1b23dcc47571d58066adac59aa3b79adf004eb2f 100644 (file)
@@ -8,12 +8,13 @@
 
 package org.opendaylight.netconf.test.tool.client.http.perf;
 
+import static org.opendaylight.netconf.test.tool.client.http.perf.RequestMessageUtils.formRequest;
+
 import com.ning.http.client.AsyncCompletionHandler;
 import com.ning.http.client.AsyncHttpClient;
 import com.ning.http.client.HttpResponseStatus;
 import com.ning.http.client.Request;
 import com.ning.http.client.Response;
-import java.util.ArrayList;
 import java.util.concurrent.Semaphore;
 import org.opendaylight.netconf.test.tool.client.stress.ExecutionStrategy;
 import org.slf4j.Logger;
@@ -24,12 +25,12 @@ public class AsyncExecutionStrategy implements ExecutionStrategy {
     private static final Logger LOG = LoggerFactory.getLogger(AsyncExecutionStrategy.class);
 
     private final Parameters params;
-    private final ArrayList<Request> payloads;
     private final AsyncHttpClient asyncHttpClient;
     private final Semaphore semaphore;
+    RestPerfClient.RequestData payloads;
 
     AsyncExecutionStrategy(final Parameters params, final AsyncHttpClient asyncHttpClient,
-                           final ArrayList<Request> payloads) {
+                           final RestPerfClient.RequestData payloads) {
         this.params = params;
         this.asyncHttpClient = asyncHttpClient;
         this.payloads = payloads;
@@ -40,7 +41,10 @@ public class AsyncExecutionStrategy implements ExecutionStrategy {
     public void invoke() {
         LOG.info("Begin sending async requests");
 
-        for (final Request request : payloads) {
+        for (int i = 0; i < payloads.getRequests(); i++) {
+            String message = RequestMessageUtils.prepareMessage(payloads.getThreadId(), i,
+                    payloads.getContentString(), payloads.getPort());
+            Request request = formRequest(asyncHttpClient, payloads.getDestination(), params, message);
             try {
                 semaphore.acquire();
             } catch (InterruptedException e) {
index 59ff9260c9a8ae658e20f3f4b3f8c5a186f24093..2ec721f29ee7401b9e305b2c0c6ed762e455f36f 100644 (file)
@@ -10,11 +10,8 @@ package org.opendaylight.netconf.test.tool.client.http.perf;
 
 import com.ning.http.client.AsyncHttpClient;
 import com.ning.http.client.AsyncHttpClientConfig;
-import com.ning.http.client.Realm;
-import com.ning.http.client.Request;
-import java.util.ArrayList;
 import java.util.concurrent.Callable;
-import org.opendaylight.netconf.test.tool.client.http.perf.RestPerfClient.DestToPayload;
+import org.opendaylight.netconf.test.tool.client.http.perf.RestPerfClient.RequestData;
 import org.opendaylight.netconf.test.tool.client.stress.ExecutionStrategy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -23,36 +20,18 @@ public class PerfClientCallable implements Callable<Void> {
     private static final Logger LOG = LoggerFactory.getLogger(PerfClientCallable.class);
 
     private final Parameters params;
-    private final ArrayList<Request> payloads;
     private final AsyncHttpClient asyncHttpClient;
     private ExecutionStrategy executionStrategy;
+    private RequestData payloads;
 
-    public PerfClientCallable(Parameters params, ArrayList<DestToPayload> payloads) {
+    public PerfClientCallable(Parameters params, RequestData payloads) {
         this.params = params;
+        this.payloads = payloads;
         this.asyncHttpClient = new AsyncHttpClient(new AsyncHttpClientConfig.Builder()
                 .setConnectTimeout(Integer.MAX_VALUE)
                 .setRequestTimeout(Integer.MAX_VALUE)
                 .setAllowPoolingConnections(true)
                 .build());
-        this.payloads = new ArrayList<>();
-        for (DestToPayload payload : payloads) {
-            AsyncHttpClient.BoundRequestBuilder requestBuilder = asyncHttpClient.preparePost(payload.getDestination())
-                    .addHeader("content-type", "application/json")
-                    .addHeader("Accept", "application/xml")
-                    .setBody(payload.getPayload())
-                    .setRequestTimeout(Integer.MAX_VALUE);
-
-            if (params.auth != null) {
-                requestBuilder.setRealm(new Realm.RealmBuilder()
-                        .setScheme(Realm.AuthScheme.BASIC)
-                        .setPrincipal(params.auth.get(0))
-                        .setPassword(params.auth.get(1))
-                        .setUsePreemptiveAuth(true)
-                        .build());
-            }
-
-            this.payloads.add(requestBuilder.build());
-        }
         executionStrategy = getExecutionStrategy();
     }
 
diff --git a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/http/perf/RequestMessageUtils.java b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/http/perf/RequestMessageUtils.java
new file mode 100644 (file)
index 0000000..6267d05
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2021 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netconf.test.tool.client.http.perf;
+
+import com.ning.http.client.AsyncHttpClient;
+import com.ning.http.client.Realm;
+import com.ning.http.client.Request;
+import org.opendaylight.netconf.test.tool.TestToolUtils;
+
+public final class RequestMessageUtils {
+
+    private static final String PEER_KEY = "{PEERID}";
+    private static final String INT_LEAF_KEY = "{INTLEAF}";
+
+    private static final String PHYS_ADDR_PLACEHOLDER = "{PHYS_ADDR}";
+
+    private static final String HOST_KEY = "{HOST}";
+    private static final String PORT_KEY = "{PORT}";
+    private static final String DEVICE_PORT_KEY = "{DEVICE_PORT}";
+
+
+    private static final String DEST = "http://{HOST}:{PORT}";
+
+    private static long macStart = 0xAABBCCDD0000L;
+
+    private RequestMessageUtils(){
+    }
+
+    public static String prepareMessage(final int idi, final int idj, final String editContentString,
+                                        final int devicePort) {
+        StringBuilder messageBuilder = new StringBuilder(editContentString);
+        if (editContentString.contains(PEER_KEY)) {
+            messageBuilder.replace(
+                    messageBuilder.indexOf(PEER_KEY),
+                    messageBuilder.indexOf(PEER_KEY) + PEER_KEY.length(),
+                    Integer.toString(idi))
+                    .replace(
+                            messageBuilder.indexOf(INT_LEAF_KEY),
+                            messageBuilder.indexOf(INT_LEAF_KEY) + INT_LEAF_KEY.length(),
+                            Integer.toString(idj));
+        }
+
+        if (messageBuilder.indexOf(DEVICE_PORT_KEY) != -1) {
+            messageBuilder.replace(
+                    messageBuilder.indexOf(DEVICE_PORT_KEY),
+                    messageBuilder.indexOf(DEVICE_PORT_KEY) + DEVICE_PORT_KEY.length(),
+                    Integer.toString(devicePort));
+        }
+
+        int idx = messageBuilder.indexOf(PHYS_ADDR_PLACEHOLDER);
+
+        while (idx != -1) {
+            messageBuilder.replace(idx, idx + PHYS_ADDR_PLACEHOLDER.length(), TestToolUtils.getMac(macStart++));
+            idx = messageBuilder.indexOf(PHYS_ADDR_PLACEHOLDER);
+        }
+
+        return messageBuilder.toString();
+    }
+
+    public static RestPerfClient.RequestData formPayload(Parameters parameters, String editContentString,
+                                                         int threadId, int requests) {
+        final int devicePort = parameters.sameDevice
+                ? parameters.devicePortRangeStart : parameters.devicePortRangeStart + threadId;
+        final StringBuilder destBuilder = new StringBuilder(DEST);
+        destBuilder.replace(
+                destBuilder.indexOf(HOST_KEY),
+                destBuilder.indexOf(HOST_KEY) + HOST_KEY.length(),
+                parameters.ip)
+                .replace(
+                        destBuilder.indexOf(PORT_KEY),
+                        destBuilder.indexOf(PORT_KEY) + PORT_KEY.length(),
+                        parameters.port + "");
+        final StringBuilder suffixBuilder = new StringBuilder(parameters.destination);
+        if (suffixBuilder.indexOf(DEVICE_PORT_KEY) != -1) {
+            suffixBuilder.replace(
+                    suffixBuilder.indexOf(DEVICE_PORT_KEY),
+                    suffixBuilder.indexOf(DEVICE_PORT_KEY) + DEVICE_PORT_KEY.length(),
+                    devicePort + "");
+        }
+        destBuilder.append(suffixBuilder);
+
+
+        return new RestPerfClient.RequestData(destBuilder.toString(), editContentString,
+                threadId, devicePort, requests);
+    }
+
+    public static Request formRequest(AsyncHttpClient asyncHttpClient, String url, Parameters params, String msg) {
+        AsyncHttpClient.BoundRequestBuilder requestBuilder = asyncHttpClient.preparePost(url)
+                .addHeader("content-type", "application/json")
+                .addHeader("Accept", "application/xml")
+                .setBody(msg)
+                .setRequestTimeout(Integer.MAX_VALUE);
+
+        if (params.auth != null) {
+            requestBuilder.setRealm(new Realm.RealmBuilder()
+                    .setScheme(Realm.AuthScheme.BASIC)
+                    .setPrincipal(params.auth.get(0))
+                    .setPassword(params.auth.get(1))
+                    .setUsePreemptiveAuth(true)
+                    .build());
+        }
+        return requestBuilder.build();
+    }
+
+
+}
index 013f8896b63abfd17bd80ef661ea4e1421ee5d8e..41655467db5f96d043684c51bdf932500f6dd64b 100644 (file)
@@ -8,6 +8,8 @@
 
 package org.opendaylight.netconf.test.tool.client.http.perf;
 
+import static org.opendaylight.netconf.test.tool.client.http.perf.RequestMessageUtils.formPayload;
+
 import com.google.common.base.Stopwatch;
 import com.google.common.io.Files;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@@ -22,51 +24,55 @@ import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import net.sourceforge.argparse4j.inf.ArgumentParser;
 import net.sourceforge.argparse4j.inf.ArgumentParserException;
-import org.opendaylight.netconf.test.tool.TestToolUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+
 @SuppressFBWarnings("DM_EXIT")
 public final class RestPerfClient {
 
     private static final Logger LOG = LoggerFactory.getLogger(RestPerfClient.class);
 
-    private static final String HOST_KEY = "{HOST}";
-    private static final String PORT_KEY = "{PORT}";
-    private static final String DEVICE_PORT_KEY = "{DEVICE_PORT}";
-
-    private static final String PEER_KEY = "{PEERID}";
-    private static final String INT_LEAF_KEY = "{INTLEAF}";
-
-    private static final String PHYS_ADDR_PLACEHOLDER = "{PHYS_ADDR}";
-
-    private static final String DEST = "http://{HOST}:{PORT}";
-
-    private static long macStart = 0xAABBCCDD0000L;
-
     static int throttle;
 
-    static final class DestToPayload {
+    static final class RequestData {
 
         private final String destination;
-        private final String payload;
+        private final String contentString;
+        private final int threadId;
+        private final int port;
+        private final int requests;
 
-        DestToPayload(final String destination, final String payload) {
+        RequestData(final String destination, final String contentString, int threadId, int port, int requests) {
             this.destination = destination;
-            this.payload = payload;
+            this.contentString = contentString;
+            this.threadId = threadId;
+            this.port = port;
+            this.requests = requests;
         }
 
         public String getDestination() {
             return destination;
         }
 
-        public String getPayload() {
-            return payload;
+        public String getContentString() {
+            return contentString;
+        }
+
+        public int getThreadId() {
+            return threadId;
+        }
+
+        public int getPort() {
+            return port;
+        }
+
+        public int getRequests() {
+            return requests;
         }
     }
 
     private RestPerfClient() {
-
     }
 
     public static void main(final String[] args) {
@@ -93,67 +99,21 @@ public final class RestPerfClient {
         final int leftoverRequests = parameters.editCount % parameters.threadAmount;
         LOG.info("leftoverRequests: {}", leftoverRequests);
 
-        final ArrayList<ArrayList<DestToPayload>> allThreadsPayloads = new ArrayList<>();
-        for (int i = 0; i < threadAmount; i++) {
-            final ArrayList<DestToPayload> payloads = new ArrayList<>();
-            for (int j = 0; j < requestsPerThread; j++) {
-                final int devicePort = parameters.sameDevice
-                    ? parameters.devicePortRangeStart : parameters.devicePortRangeStart + i;
-                final StringBuilder destBuilder = new StringBuilder(DEST);
-                destBuilder.replace(
-                        destBuilder.indexOf(HOST_KEY),
-                        destBuilder.indexOf(HOST_KEY) + HOST_KEY.length(),
-                        parameters.ip)
-                    .replace(
-                        destBuilder.indexOf(PORT_KEY),
-                        destBuilder.indexOf(PORT_KEY) + PORT_KEY.length(),
-                        parameters.port + "");
-                final StringBuilder suffixBuilder = new StringBuilder(parameters.destination);
-                if (suffixBuilder.indexOf(DEVICE_PORT_KEY) != -1) {
-                    suffixBuilder.replace(
-                        suffixBuilder.indexOf(DEVICE_PORT_KEY),
-                        suffixBuilder.indexOf(DEVICE_PORT_KEY) + DEVICE_PORT_KEY.length(),
-                        devicePort + "");
-                }
-                destBuilder.append(suffixBuilder);
+        final ArrayList<RequestData> allThreadsPayloads = new ArrayList<>();
 
-                payloads.add(
-                    new DestToPayload(destBuilder.toString(), prepareMessage(i, j, editContentString, devicePort)));
-            }
-            allThreadsPayloads.add(payloads);
-        }
-
-        for (int i = 0; i < leftoverRequests; i++) {
-            final int devicePort = parameters.sameDevice
-                ? parameters.devicePortRangeStart : parameters.devicePortRangeStart + threadAmount - 1;
-            final StringBuilder destBuilder = new StringBuilder(DEST);
-            destBuilder.replace(
-                    destBuilder.indexOf(HOST_KEY),
-                    destBuilder.indexOf(HOST_KEY) + HOST_KEY.length(),
-                    parameters.ip)
-                .replace(
-                    destBuilder.indexOf(PORT_KEY),
-                    destBuilder.indexOf(PORT_KEY) + PORT_KEY.length(),
-                    parameters.port + "");
-            final StringBuilder suffixBuilder = new StringBuilder(parameters.destination);
-            if (suffixBuilder.indexOf(DEVICE_PORT_KEY) != -1) {
-                suffixBuilder.replace(
-                    suffixBuilder.indexOf(DEVICE_PORT_KEY),
-                    suffixBuilder.indexOf(DEVICE_PORT_KEY) + DEVICE_PORT_KEY.length(),
-                    devicePort + "");
+        for (int i = 0; i < threadAmount; i++) {
+            int numberOfReq = requestsPerThread;
+            if (i == (threadAmount - 1)) {
+                numberOfReq += leftoverRequests;
             }
-            destBuilder.append(suffixBuilder);
 
-            final ArrayList<DestToPayload> payloads = allThreadsPayloads.get(allThreadsPayloads.size() - 1);
-            payloads.add(
-                new DestToPayload(
-                    destBuilder.toString(),
-                    prepareMessage(threadAmount - 1, requestsPerThread + i, editContentString, devicePort)));
+            RequestData payload = formPayload(parameters, editContentString, i, numberOfReq);
+            allThreadsPayloads.add(payload);
         }
 
         final ArrayList<PerfClientCallable> callables = new ArrayList<>();
-        for (ArrayList<DestToPayload> payloads : allThreadsPayloads) {
-            callables.add(new PerfClientCallable(parameters, payloads));
+        for (RequestData payload : allThreadsPayloads) {
+            callables.add(new PerfClientCallable(parameters, payload));
         }
 
         final ExecutorService executorService = Executors.newFixedThreadPool(threadAmount);
@@ -163,7 +123,7 @@ public final class RestPerfClient {
         final Stopwatch started = Stopwatch.createStarted();
         try {
             final List<Future<Void>> futures = executorService.invokeAll(
-                callables, parameters.timeout, TimeUnit.MINUTES);
+                    callables, parameters.timeout, TimeUnit.MINUTES);
             for (int i = 0; i < futures.size(); i++) {
                 Future<Void> future = futures.get(i);
                 if (future.isCancelled()) {
@@ -190,7 +150,7 @@ public final class RestPerfClient {
         // and do not log it
         if (allThreadsCompleted) {
             LOG.info(
-                "Requests per second: {}", parameters.editCount * 1000.0 / started.elapsed(TimeUnit.MILLISECONDS));
+                    "Requests per second: {}", parameters.editCount * 1000.0 / started.elapsed(TimeUnit.MILLISECONDS));
         }
         System.exit(0);
     }
@@ -208,34 +168,4 @@ public final class RestPerfClient {
         return null;
     }
 
-    private static String prepareMessage(final int idi, final int idj, final String editContentString,
-                                         final int devicePort) {
-        StringBuilder messageBuilder = new StringBuilder(editContentString);
-        if (editContentString.contains(PEER_KEY)) {
-            messageBuilder.replace(
-                    messageBuilder.indexOf(PEER_KEY),
-                    messageBuilder.indexOf(PEER_KEY) + PEER_KEY.length(),
-                    Integer.toString(idi))
-                .replace(
-                    messageBuilder.indexOf(INT_LEAF_KEY),
-                    messageBuilder.indexOf(INT_LEAF_KEY) + INT_LEAF_KEY.length(),
-                    Integer.toString(idj));
-        }
-
-        if (messageBuilder.indexOf(DEVICE_PORT_KEY) != -1) {
-            messageBuilder.replace(
-                messageBuilder.indexOf(DEVICE_PORT_KEY),
-                messageBuilder.indexOf(DEVICE_PORT_KEY) + DEVICE_PORT_KEY.length(),
-                Integer.toString(devicePort));
-        }
-
-        int idx = messageBuilder.indexOf(PHYS_ADDR_PLACEHOLDER);
-
-        while (idx != -1) {
-            messageBuilder.replace(idx, idx + PHYS_ADDR_PLACEHOLDER.length(), TestToolUtils.getMac(macStart++));
-            idx = messageBuilder.indexOf(PHYS_ADDR_PLACEHOLDER);
-        }
-
-        return messageBuilder.toString();
-    }
 }
index 1aeb843f5165408ff4f80b14c7b9b1a1bde56e1f..79cb2450ee6f9ce00c92a67d057a61119738294a 100644 (file)
@@ -7,26 +7,28 @@
  */
 package org.opendaylight.netconf.test.tool.client.http.perf;
 
+import static org.opendaylight.netconf.test.tool.client.http.perf.RequestMessageUtils.formRequest;
+
 import com.ning.http.client.AsyncHttpClient;
 import com.ning.http.client.Request;
 import com.ning.http.client.Response;
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.concurrent.ExecutionException;
 import org.opendaylight.netconf.test.tool.client.stress.ExecutionStrategy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+
 public class SyncExecutionStrategy implements ExecutionStrategy {
 
     private static final Logger LOG = LoggerFactory.getLogger(SyncExecutionStrategy.class);
 
     private final Parameters params;
-    private final ArrayList<Request> payloads;
+    private final RestPerfClient.RequestData payloads;
     private final AsyncHttpClient asyncHttpClient;
 
     SyncExecutionStrategy(final Parameters params, final AsyncHttpClient asyncHttpClient,
-                          final ArrayList<Request> payloads) {
+                          final RestPerfClient.RequestData payloads) {
         this.params = params;
         this.asyncHttpClient = asyncHttpClient;
         this.payloads = payloads;
@@ -36,7 +38,10 @@ public class SyncExecutionStrategy implements ExecutionStrategy {
     public void invoke() {
 
         LOG.info("Begin sending sync requests");
-        for (Request request : payloads) {
+        for (int i = 0; i < payloads.getRequests(); i++) {
+            String message = RequestMessageUtils.prepareMessage(payloads.getThreadId(), i,
+                    payloads.getContentString(), payloads.getPort());
+            Request request = formRequest(asyncHttpClient, payloads.getDestination(), params, message);
             try {
                 Response response = asyncHttpClient.executeRequest(request).get();
                 if (response.getStatusCode() != 200 && response.getStatusCode() != 204) {