jvpp-benchmark: measure classifyAddDelTable 78/12778/1
authorMarek Gradzki <[email protected]>
Mon, 28 May 2018 15:56:18 +0000 (17:56 +0200)
committerMarek Gradzki <[email protected]>
Tue, 29 May 2018 07:05:50 +0000 (09:05 +0200)
Synchronously creates classify tables.
By default 20x2s warmup
and 100x2s measurement iterations are performed.

VPP is restarted after each iteration.

Each invocation of classifyAddDelTable uses tables
from precomputed set of size tableSetSize.
Tables from the set are used in round-robin fashion.

Run with:

sudo java -jar ./target/jvpp-benchmark-exec.jar \
ClassifyTableCreateBenchmark

To specify aclSetSize (default=100), use:

sudo java -jar ./target/jvpp-benchmark-exec.jar \
ClassifyTableCreateBenchmark -p tableSetSize=1000

To see more options, use

java -jar ./target/jvpp-benchmark-exec.jar -h

Change-Id: I387d879bc99dce45f93d66e8a99f7206f067b443
Signed-off-by: Marek Gradzki <[email protected]>
it/jvpp-benchmark/asciidoc/Readme.adoc
it/jvpp-benchmark/src/main/java/io/fd/hc2vpp/it/jvpp/benchmark/acl/AclProvider.java [moved from it/jvpp-benchmark/src/main/java/io/fd/hc2vpp/it/jvpp/benchmark/AclProvider.java with 94% similarity]
it/jvpp-benchmark/src/main/java/io/fd/hc2vpp/it/jvpp/benchmark/acl/AclProviderImpl.java [moved from it/jvpp-benchmark/src/main/java/io/fd/hc2vpp/it/jvpp/benchmark/AclProviderImpl.java with 98% similarity]
it/jvpp-benchmark/src/main/java/io/fd/hc2vpp/it/jvpp/benchmark/acl/AclUpdateBenchmark.java [moved from it/jvpp-benchmark/src/main/java/io/fd/hc2vpp/it/jvpp/benchmark/AclUpdateBenchmark.java with 96% similarity]
it/jvpp-benchmark/src/main/java/io/fd/hc2vpp/it/jvpp/benchmark/classify/ClassifyTableCreateBenchmark.java [new file with mode: 0644]
it/jvpp-benchmark/src/main/java/io/fd/hc2vpp/it/jvpp/benchmark/classify/ClassifyTableProvider.java [new file with mode: 0644]
it/jvpp-benchmark/src/main/java/io/fd/hc2vpp/it/jvpp/benchmark/classify/ClassifyTableProviderImpl.java [new file with mode: 0644]
it/jvpp-benchmark/src/test/java/io/fd/hc2vpp/it/jvpp/benchmark/acl/AclProviderImplTest.java [moved from it/jvpp-benchmark/src/test/java/io/fd/hc2vpp/it/jvpp/benchmark/AclProviderImplTest.java with 98% similarity]
it/jvpp-benchmark/src/test/java/io/fd/hc2vpp/it/jvpp/benchmark/classify/ClassifyTableProviderImplTest.java [new file with mode: 0644]

index 8c787d4..a8e5d2c 100644 (file)
@@ -2,14 +2,26 @@
 
 Provides JMH based benchmarks JVpp (Java API for VPP).
 
+Compile:
+[source,shell]
+---
+cd $HC2VPP_ROOT/it/jvpp-benchmark
+mvn clean install
+---
+
+To display JMH options, use
+[source,shell]
+---
+java -jar ./target/jvpp-benchmark-exec.jar -h
+---
+
 == AclUpdateBenchmark
 
 Creates ACL of size aclSize using acl_add_replace,
 then assigns it to loopback interface using acl_interface_set_acl_list.
 
 Then ACL is updated synchronously using acl_add_replace.
-By default 20x2s warmup and 100x2s measurment iterations
-are performed.
+By default 20x2s warmup and 100x2s measurement iterations are performed.
 
 VPP is restarted after each iteration.
 
@@ -17,39 +29,50 @@ Each invocation of acl_add_replace uses ACL from precomputed
 set of ACLs of size aclSetSize.
 ACLs from the set are used in round-robin fashion.
 
-Compile:
-[source,shell]
----
-cd $HC2VPP_ROOT/it/jvpp-benchmark
-mvn clean install
----
-
 Run with:
 [source,shell]
 ---
-sudo java -jar ./target/jvpp-benchmark-exec.jar
+sudo java -jar ./target/jvpp-benchmark-exec.jar AclUpdateBenchmark
 ---
 
 To specify aclSize (default=100), use:
 [source,shell]
 ---
-sudo java -jar ./target/jvpp-benchmark-exec.jar -p aclSize=1000
+sudo java -jar ./target/jvpp-benchmark-exec.jar -p aclSize=1000 AclUpdateBenchmark
 ---
 
 To specify aclSetSize (default=100), use:
 [source,shell]
 ---
-sudo java -jar ./target/jvpp-benchmark-exec.jar -p aclSetSize=1000
+sudo java -jar ./target/jvpp-benchmark-exec.jar -p aclSetSize=1000 AclUpdateBenchmark
 ---
 
 To test interface in bridged (L2) / routed (L3) mode (default=L3), use:
 [source,shell]
 ---
-sudo java -jar ./target/jvpp-benchmark-exec.jar -p mode=L2
+sudo java -jar ./target/jvpp-benchmark-exec.jar -p mode=L2 AclUpdateBenchmark
 ---
 
-To see more options, use
+
+== ClassifyTableCreateBenchmark
+
+Synchronously creates classify tables using classifyAddDelTable operation.
+By default 20x2s warmup and 100x2s measurement iterations are performed.
+
+VPP is restarted after each iteration.
+
+Each invocation of classifyAddDelTable uses tables
+from precomputed set of size tableSetSize.
+Tables from the set are used in round-robin fashion.
+
+Run with:
 [source,shell]
 ---
-java -jar ./target/jvpp-benchmark-exec.jar -h
+sudo java -jar ./target/jvpp-benchmark-exec.jar ClassifyTableCreateBenchmark
+---
+
+To specify tableSetSize (default=100), use:
+[source,shell]
+---
+sudo java -jar ./target/jvpp-benchmark-exec.jar ClassifyTableCreateBenchmark -p aclSetSize=1000
 ---
  * limitations under the License.
  */
 
-package io.fd.hc2vpp.it.jvpp.benchmark;
+package io.fd.hc2vpp.it.jvpp.benchmark.acl;
 
-import static io.fd.hc2vpp.it.jvpp.benchmark.AclUpdateBenchmark.InterfaceMode.L2;
-import static io.fd.hc2vpp.it.jvpp.benchmark.AclUpdateBenchmark.InterfaceMode.L3;
+import static io.fd.hc2vpp.it.jvpp.benchmark.acl.AclUpdateBenchmark.InterfaceMode.L2;
+import static io.fd.hc2vpp.it.jvpp.benchmark.acl.AclUpdateBenchmark.InterfaceMode.L3;
 
 import com.google.common.io.CharStreams;
 import io.fd.vpp.jvpp.JVppRegistryImpl;
@@ -58,7 +58,6 @@ import org.openjdk.jmh.annotations.Warmup;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-
 @BenchmarkMode(Mode.AverageTime)
 @State(Scope.Thread)
 @Fork(1)
@@ -86,6 +85,7 @@ public class AclUpdateBenchmark {
 
     @Benchmark
     public void testMethod() throws Exception {
+        // In real application, reply may be ignored by the caller, so we ignore as well.
         jvppAcl.aclAddReplace(aclProvider.next()).toCompletableFuture().get();
     }
 
diff --git a/it/jvpp-benchmark/src/main/java/io/fd/hc2vpp/it/jvpp/benchmark/classify/ClassifyTableCreateBenchmark.java b/it/jvpp-benchmark/src/main/java/io/fd/hc2vpp/it/jvpp/benchmark/classify/ClassifyTableCreateBenchmark.java
new file mode 100644 (file)
index 0000000..3270093
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2018 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.hc2vpp.it.jvpp.benchmark.classify;
+
+import com.google.common.io.CharStreams;
+import io.fd.vpp.jvpp.JVppRegistryImpl;
+import io.fd.vpp.jvpp.core.JVppCoreImpl;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTableReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCoreFacade;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Level;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Param;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.TearDown;
+import org.openjdk.jmh.annotations.Threads;
+import org.openjdk.jmh.annotations.Timeout;
+import org.openjdk.jmh.annotations.Warmup;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@BenchmarkMode(Mode.AverageTime)
+@State(Scope.Thread)
+@Fork(1)
+@Threads(1)
+@Timeout(time = 5)
+@Warmup(iterations = 20, time = 2)
+@Measurement(iterations = 100, time = 2)
+@OutputTimeUnit(TimeUnit.MILLISECONDS)
+public class ClassifyTableCreateBenchmark {
+    private static final Logger LOG = LoggerFactory.getLogger(ClassifyTableCreateBenchmark.class);
+
+    @Param( {"100"})
+    private int tableSetSize;
+
+    private JVppRegistryImpl registry;
+    private FutureJVppCoreFacade jvppCore;
+    private ClassifyTableProvider classifyTableProvider;
+
+    @Benchmark
+    public ClassifyAddDelTableReply testMethod() throws Exception {
+        // Caller may want to process reply, so return it to prevent JVM from dead code elimination
+        return jvppCore.classifyAddDelTable(classifyTableProvider.next()).toCompletableFuture().get();
+    }
+
+    @Setup(Level.Iteration)
+    public void setup() throws Exception {
+        initProvider();
+        startVpp();
+        connect();
+    }
+
+    @TearDown(Level.Iteration)
+    public void tearDown() throws Exception {
+        disconnect();
+        stopVpp();
+    }
+
+    private void initProvider() {
+        classifyTableProvider = new ClassifyTableProviderImpl(tableSetSize);
+    }
+
+    private void startVpp() throws Exception {
+        LOG.info("Starting VPP ...");
+        final String[] cmd = {"/bin/sh", "-c", "sudo service vpp start"};
+        exec(cmd);
+        LOG.info("VPP started successfully");
+    }
+
+    private void stopVpp() throws Exception {
+        LOG.info("Stopping VPP ...");
+        final String[] cmd = {"/bin/sh", "-c", "sudo service vpp stop"};
+        exec(cmd);
+
+        // Wait to be sure VPP was stopped.
+        // Prevents VPP start failure: "vpp.service: Start request repeated too quickly".
+        Thread.sleep(1500);
+        LOG.info("VPP stopped successfully");
+    }
+
+    private static void exec(String[] command) throws IOException, InterruptedException {
+        Process process = Runtime.getRuntime().exec(command);
+        process.waitFor();
+        if (process.exitValue() != 0) {
+            String error_msg = "Failed to execute " + Arrays.toString(command) + ": " +
+                CharStreams.toString(new InputStreamReader(process.getErrorStream(), StandardCharsets.UTF_8));
+            throw new IllegalStateException(error_msg);
+        }
+    }
+
+    private void connect() throws IOException {
+        LOG.info("Connecting to JVPP ...");
+        registry = new JVppRegistryImpl("ACLUpdateBenchmark");
+        jvppCore = new FutureJVppCoreFacade(registry, new JVppCoreImpl());
+        LOG.info("Successfully connected to JVPP");
+    }
+
+    private void disconnect() throws Exception {
+        LOG.info("Disconnecting ...");
+        jvppCore.close();
+        registry.close();
+        LOG.info("Successfully disconnected ...");
+    }
+}
diff --git a/it/jvpp-benchmark/src/main/java/io/fd/hc2vpp/it/jvpp/benchmark/classify/ClassifyTableProvider.java b/it/jvpp-benchmark/src/main/java/io/fd/hc2vpp/it/jvpp/benchmark/classify/ClassifyTableProvider.java
new file mode 100644 (file)
index 0000000..e23ecc6
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018 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.hc2vpp.it.jvpp.benchmark.classify;
+
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
+
+interface ClassifyTableProvider {
+    ClassifyAddDelTable next();
+}
diff --git a/it/jvpp-benchmark/src/main/java/io/fd/hc2vpp/it/jvpp/benchmark/classify/ClassifyTableProviderImpl.java b/it/jvpp-benchmark/src/main/java/io/fd/hc2vpp/it/jvpp/benchmark/classify/ClassifyTableProviderImpl.java
new file mode 100644 (file)
index 0000000..80ebdcc
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2018 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.hc2vpp.it.jvpp.benchmark.classify;
+
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
+import java.io.Serializable;
+import java.util.Random;
+import javax.annotation.concurrent.NotThreadSafe;
+
+@NotThreadSafe
+class ClassifyTableProviderImpl implements ClassifyTableProvider {
+    /**
+     * Static seed to make rnd.nextBytes() output the same for all test run.
+     */
+    private static final long SEED = -2084670072119134328L;
+    private final int tableSetSize;
+    private final ClassifyAddDelTable[] tables;
+    private final Random rnd = new Random(SEED);
+
+    /**
+     * Pointer to Classify table to be returned by invocation of {@link #next()} method.
+     */
+    private int currentTable = 0;
+
+    ClassifyTableProviderImpl(final int tableSetSize) {
+        this.tableSetSize = tableSetSize;
+        tables = new ClassifyAddDelTable[tableSetSize];
+        initTables(tableSetSize);
+    }
+
+    @Override
+    public ClassifyAddDelTable next() {
+        final ClassifyAddDelTable result = tables[currentTable];
+        currentTable = (currentTable + 1) % tableSetSize;
+        return result;
+    }
+
+    private void initTables(final int tableSetSize) {
+        for (int i = 0; i < tableSetSize; ++i) {
+            tables[i] = createTable();
+        }
+    }
+
+    private ClassifyAddDelTable createTable() {
+        final ClassifyAddDelTable addDelTable = new ClassifyAddDelTable();
+        addDelTable.isAdd = 1;
+        addDelTable.tableIndex = -1;
+        addDelTable.nbuckets = 2;
+        addDelTable.memorySize = 2 << 20;
+        addDelTable.nextTableIndex = ~0;
+        addDelTable.missNextIndex = ~0;
+        addDelTable.skipNVectors = 0;
+        addDelTable.matchNVectors = 1;
+        addDelTable.mask = new byte[16];
+        rnd.nextBytes(addDelTable.mask);
+        return addDelTable;
+    }
+}
diff --git a/it/jvpp-benchmark/src/test/java/io/fd/hc2vpp/it/jvpp/benchmark/classify/ClassifyTableProviderImplTest.java b/it/jvpp-benchmark/src/test/java/io/fd/hc2vpp/it/jvpp/benchmark/classify/ClassifyTableProviderImplTest.java
new file mode 100644 (file)
index 0000000..8f11077
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018 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.hc2vpp.it.jvpp.benchmark.classify;
+
+import static org.junit.Assert.*;
+
+import io.fd.vpp.jvpp.acl.dto.AclAddReplace;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
+import org.junit.Test;
+
+public class ClassifyTableProviderImplTest {
+    @Test
+    public void testTablesDiffer() throws Exception {
+        final ClassifyTableProviderImpl provider = new ClassifyTableProviderImpl(2);
+        final ClassifyAddDelTable table0 = provider.next();
+        final ClassifyAddDelTable table1 = provider.next();
+        final ClassifyAddDelTable table2 = provider.next();
+        final ClassifyAddDelTable table3 = provider.next();
+
+        // Test if ACLs are provided in round-robin fashion
+        assertEquals("Tables 0 and 2 should be equal", table0, table2);
+        assertEquals("Tables 1 and 3 should be equal", table1, table3);
+        assertNotEquals("Tables 0 and 1 should be different", table0, table1);
+    }
+}
\ No newline at end of file