From c65fdbf34982b2444d14ef74e287b51786e8cc06 Mon Sep 17 00:00:00 2001 From: Matej Date: Thu, 12 Oct 2017 15:54:09 +0200 Subject: jvpp: test measuring number of invocations per time (VPP-619) test provide two ways to count invocations: 1) maximum number of invocations and received replyies within 1 sec 2) measure time in ns from first request to receiving last reply over set amount of requests specific command is included in Readme results from testing on my local machine were: 350K/sec Callback Api Read - show version 250K/Sec Future Api Read - show version 120K/sec allback Api Write - add table Change-Id: Ie0383d848b98ee2b4b90c38a827a24acd28cac72 Signed-off-by: Matej --- .../core/examples/CallbackApiReadPerfTest.java | 146 +++++++++++++++++++ .../core/examples/CallbackApiWritePerfTest.java | 162 +++++++++++++++++++++ .../jvpp/core/examples/FutureApiReadPerfTest.java | 137 +++++++++++++++++ .../io/fd/vpp/jvpp/core/examples/Readme.txt | 11 +- 4 files changed, 454 insertions(+), 2 deletions(-) create mode 100644 src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/examples/CallbackApiReadPerfTest.java create mode 100644 src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/examples/CallbackApiWritePerfTest.java create mode 100644 src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/examples/FutureApiReadPerfTest.java diff --git a/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/examples/CallbackApiReadPerfTest.java b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/examples/CallbackApiReadPerfTest.java new file mode 100644 index 00000000000..6ff440dccc0 --- /dev/null +++ b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/examples/CallbackApiReadPerfTest.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.vpp.jvpp.core.examples; + +import io.fd.vpp.jvpp.JVpp; +import io.fd.vpp.jvpp.JVppRegistry; +import io.fd.vpp.jvpp.JVppRegistryImpl; +import io.fd.vpp.jvpp.VppCallbackException; +import io.fd.vpp.jvpp.core.JVppCoreImpl; +import io.fd.vpp.jvpp.core.callback.ShowVersionReplyCallback; +import io.fd.vpp.jvpp.core.dto.*; + +import java.util.logging.Logger; + +public class CallbackApiReadPerfTest { + + private static final Logger LOG = Logger.getLogger(CallbackApiReadPerfTest.class.getName()); + private static final ShowVersion REQUEST = new ShowVersion(); + + /** + * + * @param args - for running for one sec requires no parameter + * - for running for set amount of requests requires one parameters, desired REQUEST amount + * @throws Exception if arguments aren't String representations of numbers + */ + public static void main(String[] args) throws Exception { + if (args.length != 0) { + testInvokeCounter(true, Integer.parseUnsignedInt(args[0])); + } else { + testInvokeCounter(false, 0); + } + } + + /** + * + * @param setCount true = run with set amount of requests, false = run for 1 sec + * @param count number of request with which test should be run + * @throws Exception + */ + private static void testInvokeCounter(boolean setCount, int count) throws Exception { + LOG.info("Testing callback API Invocation Counter"); + try (final JVppRegistry registry = new JVppRegistryImpl("CallbackApiReadPerfTest"); + final JVpp jvpp = new JVppCoreImpl()) { + TestCallback callback = new TestCallback(count); + registry.register(jvpp, callback); + if (!setCount) { + for(int i = 0; i < 5; i++) { + callback.reset(); + LOG.info("Starting invocation for 1sec"); + long time = System.nanoTime(); + do { + jvpp.send(REQUEST); + } while (System.nanoTime() - time < 1000000000 || callback.stop()); + int replyCount = callback.getReplyCounter(); + LOG.info(String.format("Invocation count within 1 second: %d", replyCount)); + } + } else { + for (int i = 0; i < 5; i++) { + LOG.info("Starting invocations"); + callback.reset(); + long time = System.nanoTime(); + for (int x = 0; x < count; x++) { + jvpp.send(REQUEST); + } + long timeAfter = callback.getTime(); + LOG.info(String.format("Invocations took %d ns (%f invocations/s)", timeAfter - time, + count * (1000000000.0/(timeAfter - time)))); + } + } + + + Thread.sleep(1000); + LOG.info("Disconnecting..."); + } + Thread.sleep(1000); + } + + static class TestCallback implements ShowVersionReplyCallback { + + private int replyCounter = 0; + private int count; + private long time = 0; + private boolean stop = false; + + public TestCallback(int count) throws Exception { + this.count = count; + } + + public int getReplyCounter() { + return replyCounter; + } + + public void reset() { + replyCounter = 0; + time = 0; + stop = false; + } + + public boolean stop() { + this.stop = true; + return false; + } + + /* actual method called from VPP + not thread safe but since there's only one VPP thread listening for requests and calling + this method it's OK + */ + @Override + public void onShowVersionReply(final ShowVersionReply msg) { + if (stop) { + return; + } + replyCounter++; + if (replyCounter == count ) { + time = System.nanoTime(); + } + } + + @Override + public void onError(VppCallbackException ex) { + System.out.printf("Received onError exception: call=%s, context=%d, retval=%d%n", ex.getMethodName(), + ex.getCtxId(), ex.getErrorCode()); + } + + public long getTime() throws Exception { + while(time == 0) { + Thread.sleep(1000); + } + return time; + } + } +} diff --git a/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/examples/CallbackApiWritePerfTest.java b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/examples/CallbackApiWritePerfTest.java new file mode 100644 index 00000000000..1940ddcf378 --- /dev/null +++ b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/examples/CallbackApiWritePerfTest.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.vpp.jvpp.core.examples; + +import io.fd.vpp.jvpp.JVpp; +import io.fd.vpp.jvpp.JVppRegistry; +import io.fd.vpp.jvpp.JVppRegistryImpl; +import io.fd.vpp.jvpp.VppCallbackException; +import io.fd.vpp.jvpp.core.JVppCoreImpl; +import io.fd.vpp.jvpp.core.dto.*; +import io.fd.vpp.jvpp.core.callback.ClassifyAddDelTableReplyCallback; + +import java.util.logging.Logger; + +public class CallbackApiWritePerfTest { + + private static final Logger LOG = Logger.getLogger(CallbackApiWritePerfTest.class.getName()); + private static final ClassifyAddDelTable REQUEST = createAddDelTable(); + + private static ClassifyAddDelTable createAddDelTable () { + ClassifyAddDelTable addDelTable = new ClassifyAddDelTable(); + addDelTable.isAdd = 1; + addDelTable.tableIndex = -1; + addDelTable.nbuckets = 2; + addDelTable.memorySize = 2 << 20; + addDelTable.nextTableIndex = ~0; // default + addDelTable.missNextIndex = ~0; // default + addDelTable.skipNVectors = 0; + addDelTable.matchNVectors = 1; + addDelTable.mask = + new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, 0x00, 0x00, 0x00, 0x00}; + return addDelTable; + }; + + /** + * + * @param args - for running for one sec requires no parameter + * - for running for set amount of requests requires one parameters, desired REQUEST amount + * @throws Exception if arguments aren't String representations of numbers + */ + public static void main(String[] args) throws Exception { + if (args.length != 0) { + testInvokeCounter(true, Integer.parseUnsignedInt(args[0])); + } else { + testInvokeCounter(false, 0); + } + } + + /** + * + * @param setCount true = run with set amount of requests, false = run for 1 sec + * @param count number of requests with which test should be run + * @throws Exception + */ + private static void testInvokeCounter(boolean setCount, int count) throws Exception { + LOG.info("Testing callback API Invocation Counter"); + try (final JVppRegistry registry = new JVppRegistryImpl("CallbackApiWritePerfTest"); + final JVpp jvpp = new JVppCoreImpl()) { + TestCallback callback = new TestCallback(count); + registry.register(jvpp, callback); + if (!setCount) { + for(int i = 0; i < 5; i++) { + callback.reset(); + LOG.info("Starting invocation for 1sec"); + long time = System.nanoTime(); + do { + jvpp.send(REQUEST); + } while (System.nanoTime() - time < 1000000000 || callback.stop()); + int replyCount = callback.getReplyCounter(); + LOG.info(String.format("Invocation count within 1 second: %d", replyCount)); + } + } else { + for(int i = 0; i < 5; i++) { + LOG.info("Starting invocations"); + callback.reset(); + long time = System.nanoTime(); + for (int x = 1; x <= count; x++) { + jvpp.send(REQUEST); + } + long timeAfter = callback.getTime(); + LOG.info(String.format("Invocations took %d ns (%f invocations/s)", timeAfter - time, + count * (1000000000.0 / (timeAfter - time)))); + } + } + + + Thread.sleep(1000); + LOG.info("Disconnecting..."); + } + Thread.sleep(1000); + } + + static class TestCallback implements ClassifyAddDelTableReplyCallback { + + private int replyCounter = 0; + private int count; + private long time = 0; + private boolean stop = false; + + public TestCallback(int count) throws Exception { + this.count = count; + } + + public int getReplyCounter() { + return replyCounter; + } + + public void reset() { + replyCounter = 0; + time = 0; + stop = false; + } + + public boolean stop() { + this.stop = true; + return false; + } + + /* actual method called from VPP + not thread safe but since there's only one VPP thread listening for requests and calling + this method it's OK + */ + @Override + public void onClassifyAddDelTableReply(final ClassifyAddDelTableReply msg) { + if (stop) { + return; + } + replyCounter++; + if (replyCounter == count ) { + time = System.nanoTime(); + } + } + + @Override + public void onError(VppCallbackException ex) { + System.out.printf("Received onError exception: call=%s, context=%d, retval=%d%n", ex.getMethodName(), + ex.getCtxId(), ex.getErrorCode()); + } + + public long getTime() throws Exception { + while(time == 0) { + Thread.sleep(1000); + } + return time; + } + } +} diff --git a/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/examples/FutureApiReadPerfTest.java b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/examples/FutureApiReadPerfTest.java new file mode 100644 index 00000000000..f335b28dfa3 --- /dev/null +++ b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/examples/FutureApiReadPerfTest.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.vpp.jvpp.core.examples; + +import io.fd.vpp.jvpp.JVppRegistry; +import io.fd.vpp.jvpp.JVppRegistryImpl; +import io.fd.vpp.jvpp.core.JVppCoreImpl; +import io.fd.vpp.jvpp.core.callback.ShowVersionReplyCallback; +import io.fd.vpp.jvpp.core.dto.*; +import io.fd.vpp.jvpp.core.future.FutureJVppCoreFacade; + +import java.util.concurrent.CompletableFuture; +import java.util.logging.Logger; + +public class FutureApiReadPerfTest { + + private static final Logger LOG = Logger.getLogger(FutureApiReadPerfTest.class.getName()); + private static final ShowVersion REQUEST = new ShowVersion(); + private static volatile int currentCount = 0; + private static int desiredCount = 0; + private static long timeAfter = 0; + private static volatile boolean stop = false; + /** + * Run after reply message is received + * in case of running for 1 sec check if time passed (stop variable) and if it does skip processing + * in case of running for set amount of REQUEST, record time in which was last reply received + * not thread save but since reading part process only one message at a time it's ok + */ + private static Runnable replyFc = () -> { + if (stop) { + return; + } + currentCount++; + if(currentCount == desiredCount) { + timeAfter = System.nanoTime(); + } + }; + + /** + * Used to reset counters and flags between runs + */ + private static void reset() { + currentCount = 0; + timeAfter = 0; + stop = false; + } + + public static boolean stop() { + stop = true; + return false; + } + + /** + * + * @return time of last reply received + * @throws Exception during thread sleep + */ + private static long getTime() throws Exception { + while(timeAfter == 0) { + LOG.info(String.format("Received %d replies", currentCount)); + Thread.sleep(1000); + } + return timeAfter; + } + + /** + * + * @param args - for running for one sec requires no parameter + * - for running for set amount of requests requires one parameters, desired REQUEST amount + * @throws Exception if arguments aren't String representations of numbers + */ + public static void main(String[] args) throws Exception { + if (args.length == 1) { + desiredCount = Integer.parseUnsignedInt(args[0]); + testInvokeCounter(true); + } else { + testInvokeCounter(false); + } + } + + /** + * + * @param setCount true = run with set amount of requests, false = run for 1 sec + * @throws Exception + */ + private static void testInvokeCounter(boolean setCount) throws Exception { + LOG.info("Testing callback API Invocation Counter"); + try (final JVppRegistry registry = new JVppRegistryImpl("FutureApiReadPerfTest"); + final FutureJVppCoreFacade jvpp = new FutureJVppCoreFacade(registry, new JVppCoreImpl())) { + if (!setCount) { + for(int i = 0; i < 5; i++) { + reset(); + LOG.info("Starting invocation for 1sec"); + long time = System.nanoTime(); + do { + CompletableFuture replyFuture = jvpp.showVersion(REQUEST).toCompletableFuture(); + replyFuture.thenRun(replyFc); + } while (System.nanoTime() - time < 1000000000 || stop()); + LOG.info(String.format("Invocation count within 1 second: %d", currentCount)); + } + } else { + for (int i = 0; i < 5; i++) { + LOG.info("Starting invocations"); + reset(); + long time = System.nanoTime(); + for (int x = 0; x < desiredCount; x++) { + CompletableFuture replyFuture = jvpp.showVersion(REQUEST).toCompletableFuture(); + replyFuture.thenRun(replyFc); + } + LOG.info("Invocations send"); + long timeAfter = getTime(); + LOG.info(String.format("Invocations took %d ns (%f invocations/s)", timeAfter - time, + desiredCount * (1000000000.0/(timeAfter - time)))); + } + } + + + Thread.sleep(1000); + LOG.info("Disconnecting..."); + } + Thread.sleep(1000); + } +} diff --git a/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/examples/Readme.txt b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/examples/Readme.txt index 10c603f5b3a..9fe3c7ac702 100644 --- a/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/examples/Readme.txt +++ b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/examples/Readme.txt @@ -2,8 +2,8 @@ This package contains basic examples for jvpp. To run the examples: - Make sure VPP is running - From VPP's build-root/ folder execute: - - release version: sudo java -cp build-vpp-native/vpp/vpp-api/java/jvpp-registry-17.10.jar:build-vpp-native/vpp/vpp-api/java/jvpp-core-17.10.jar io.fd.vpp.jvpp.core.examples.[test name] - - debug version: sudo java -cp build-vpp_debug-native/vpp/vpp-api/java/jvpp-registry-17.10.jar:build-vpp_debug-native/vpp/vpp-api/java/jvpp-core-17.10.jar io.fd.vpp.jvpp.core.examples.[test name] + - release version: sudo java -cp build-vpp-native/vpp/vpp-api/java/jvpp-registry-18.01.jar:build-vpp-native/vpp/vpp-api/java/jvpp-core-18.01.jar io.fd.vpp.jvpp.core.examples.[test name] + - debug version: sudo java -cp build-vpp_debug-native/vpp/vpp-api/java/jvpp-registry-18.01.jar:build-vpp_debug-native/vpp/vpp-api/java/jvpp-core-18.01.jar io.fd.vpp.jvpp.core.examples.[test name] Available examples: CallbackApiExample - Similar to ControlPingTest, invokes more complex calls (e.g. interface dump) using low level JVpp APIs @@ -15,3 +15,10 @@ FutureApiNotificationExample - Example of interface notifications using Future b FutureApiExample - Execution of more complex calls using Future based JVpp facade L2AclExample - Example of L2 ACL creation LispAdjacencyExample - Example of lisp adjacency creation and read (custom vpe.api type support showcase) + +CallbackApiReadPerfTest, FutureApiReadPerfTest, CallbackApiWritePerfTest - test provide two ways to count invocations: +1) maximum number of invocations and received replyies within 1 sec +sudo java -cp build-vpp-native/vpp/vpp-api/java/jvpp-registry-18.01.jar:build-vpp-native/vpp/vpp-api/java/jvpp-core-18.01.jar io.fd.vpp.jvpp.core.examples.[test name] +2) measure time in ns from first request to receiving last reply over set amount of requests +sudo java -cp build-vpp-native/vpp/vpp-api/java/jvpp-registry-18.01.jar:build-vpp-native/vpp/vpp-api/java/jvpp-core-18.01.jar io.fd.vpp.jvpp.core.examples.[test name] [number of request to send] + -- cgit 1.2.3-korg