HONEYCOMB-293 - Memory benchmarking 38/4838/6
authorJan Srnicek <jsrnicek@cisco.com>
Tue, 31 Jan 2017 09:00:51 +0000 (10:00 +0100)
committerJan Srnicek <jsrnicek@cisco.com>
Tue, 31 Jan 2017 09:00:51 +0000 (10:00 +0100)
Contains configuration for benchmarks:
- Honeycomb on rest(just infra, no data)
- Honeycomb with 1000 data nodes
- Honeycomb with 10000 data nodes

Each benchmark outputs two files:
- out_path_name-HeapMemoryUsage.csv
- out_path_name-NonHeapMemoryUsage.csv

Both files are in format :
committed,init,max,used
109576192,109051904,1525153792,12194752

Data sample sizes can be easily adjusted, just by changing
start parameter -DsampleSize

Change-Id: If6f9919307574237689326b4a38d410ec563200a
Signed-off-by: Marek Gradzki <mgradzki@cisco.com>
Signed-off-by: Jan Srnicek <jsrnicek@cisco.com>
27 files changed:
infra/it/management/asciidoc/Readme.adoc [new file with mode: 0644]
infra/it/management/pom.xml [new file with mode: 0644]
infra/it/management/src/main/java/io/fd/honeycomb/management/jmx/ConnectorServerProvider.java [new file with mode: 0644]
infra/it/management/src/main/java/io/fd/honeycomb/management/jmx/HoneycombManagementConfig.java [new file with mode: 0644]
infra/it/management/src/main/java/io/fd/honeycomb/management/jmx/HoneycombManagementModule.java [new file with mode: 0644]
infra/it/management/src/main/java/io/fd/honeycomb/management/jmx/JMXBeanProvider.java [new file with mode: 0644]
infra/it/management/src/main/java/io/fd/honeycomb/management/jmx/JMXServiceUrlProvider.java [new file with mode: 0644]
infra/it/management/src/main/resources/management.json [new file with mode: 0644]
infra/it/memory-benchmark-api/asciidoc/Readme.adoc [new file with mode: 0644]
infra/it/memory-benchmark-api/pom.xml [new file with mode: 0644]
infra/it/memory-benchmark-api/src/main/yang/memory-benchmark.yang [new file with mode: 0644]
infra/it/memory-benchmark-scripts/pom.xml [new file with mode: 0644]
infra/it/memory-benchmark-scripts/src/main/groovy/io/fd/honeycomb/benchmark/script/MemoryBenchmarkStartupScriptGenerator.groovy [new file with mode: 0644]
infra/it/memory-benchmark-scripts/src/main/resources/memoryBenchmarkScript [new file with mode: 0644]
infra/it/memory-benchmark/asciidoc/Readme.adoc [new file with mode: 0644]
infra/it/memory-benchmark/pom.xml [new file with mode: 0644]
infra/it/memory-benchmark/src/main/assembly/assembly.xml [new file with mode: 0644]
infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/BenchmarkFilesProvider.java [new file with mode: 0644]
infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/MemoryFootprintBenchmark.java [new file with mode: 0644]
infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/MemoryInfo.java [new file with mode: 0644]
infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/config/BindableCfgAttrsModule.java [new file with mode: 0644]
infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/config/StaticHoneycombConfiguration.java [new file with mode: 0644]
infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/config/StaticHoneycombManagementModule.java [new file with mode: 0644]
infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/write/NoopWriter.java [new file with mode: 0644]
infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/write/NoopWritersModule.java [new file with mode: 0644]
infra/it/memory-benchmark/src/test/java/io/fd/honeycomb/benchmark/memory/HoneycombFootprintTest.java [new file with mode: 0644]
infra/it/pom.xml

diff --git a/infra/it/management/asciidoc/Readme.adoc b/infra/it/management/asciidoc/Readme.adoc
new file mode 100644 (file)
index 0000000..89bbf65
--- /dev/null
@@ -0,0 +1,35 @@
+= management
+
+This modules is used to enable JMX monitoring on honeycomb Instance.
+
+= Tutorial
+== Configure
+To build honeycomb with management module incldued
+
+ mvn clean install -DskipTests -Pmanagement
+
+After this management module must be included to honeycomb module configuration.
+In /minimal-distribution/modules , just include fully qualified name of management module like so
+
+ io.fd.honeycomb.management.jmx.HoneycombManagementModule
+
+This will start all necessary beans to allow jmx connections to honeycomb instance.
+Also in logs , you will see all available JMX beans
+
+== Use
+
+To get any available JMX bean,
+use interface *JMXBeanProvider* that defines utility method to get *JMXConnector*
+
+ // get configured instance of jxm connection url according to HoneycombManagementConfig
+ @Inject JMXServiceUrl url;
+
+ // creates JMX connector
+ final JMXConnector connector = getConnector(url);
+ // to get any available bean
+ final String beanType = "java.lang:type=Memory";
+ final String beanName = "HeapMemoryUsage";
+ final Object jmxBean = getJMXAttribute(connector, beanType, beanName);
+
+
+
diff --git a/infra/it/management/pom.xml b/infra/it/management/pom.xml
new file mode 100644 (file)
index 0000000..0a8e972
--- /dev/null
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>io.fd.honeycomb.common</groupId>
+        <artifactId>honeycomb-parent</artifactId>
+        <version>1.17.04-SNAPSHOT</version>
+        <relativePath>../../../common/honeycomb-parent</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <properties>
+        <jetty-jmx.version>9.3.11.v20160721</jetty-jmx.version>
+    </properties>
+
+    <groupId>io.fd.honeycomb.it</groupId>
+    <artifactId>management</artifactId>
+    <version>1.17.04-SNAPSHOT</version>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-jmx</artifactId>
+            <version>${jetty-jmx.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>io.fd.honeycomb</groupId>
+            <artifactId>minimal-distribution</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file
diff --git a/infra/it/management/src/main/java/io/fd/honeycomb/management/jmx/ConnectorServerProvider.java b/infra/it/management/src/main/java/io/fd/honeycomb/management/jmx/ConnectorServerProvider.java
new file mode 100644 (file)
index 0000000..625c63c
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * 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.honeycomb.management.jmx;
+
+import com.google.inject.Inject;
+import io.fd.honeycomb.infra.distro.ProviderTrait;
+import org.eclipse.jetty.jmx.ConnectorServer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.management.remote.JMXServiceURL;
+
+/**
+ * Provides and start JMX connector server
+ * */
+public class ConnectorServerProvider extends ProviderTrait<ConnectorServer> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ConnectorServerProvider.class);
+
+    @Inject
+    private HoneycombManagementConfig config;
+
+    @Inject
+    private JMXServiceURL jmxServiceUrl;
+
+    @Override
+    protected ConnectorServer create() {
+        try {
+            final ConnectorServer connectorServer = new ConnectorServer(jmxServiceUrl,
+                    "org.eclipse.jetty.jmx:name="+HoneycombManagementConfig.JXM_CONNECTOR_SERVER_NAME);
+
+            LOG.info("Starting connector server {}", connectorServer);
+            connectorServer.doStart();
+
+            return connectorServer;
+        } catch (Exception e) {
+            throw new IllegalStateException("Unable to create jmx connector server", e);
+        }
+    }
+}
diff --git a/infra/it/management/src/main/java/io/fd/honeycomb/management/jmx/HoneycombManagementConfig.java b/infra/it/management/src/main/java/io/fd/honeycomb/management/jmx/HoneycombManagementConfig.java
new file mode 100644 (file)
index 0000000..2362b6f
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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.honeycomb.management.jmx;
+
+
+import net.jmob.guice.conf.core.BindConfig;
+import net.jmob.guice.conf.core.InjectConfig;
+import net.jmob.guice.conf.core.Syntax;
+
+import java.util.Optional;
+
+@BindConfig(value = "management", syntax = Syntax.JSON)
+public class HoneycombManagementConfig {
+
+    public static final String JMX_PROTOCOL = "rmi";
+    public static final String JXM_CONNECTOR_SERVER_NAME = "rmi";
+
+    public static final String PROP_JMX_HOST = "jetty.jmxrmihost";
+    public static final String PROP_JMX_PORT = "jetty.jmxrmiport";
+
+
+    @InjectConfig(PROP_JMX_HOST)
+    private String jmxHost;
+
+    @InjectConfig(PROP_JMX_PORT)
+    private String jmxPort;
+
+    public String getJmxHost() {
+        return Optional.ofNullable(jmxHost).orElse("localhost");
+    }
+
+    public int getJmxPort() {
+        return Integer.parseInt(Optional.ofNullable(jmxPort).orElse("1099"));
+    }
+}
diff --git a/infra/it/management/src/main/java/io/fd/honeycomb/management/jmx/HoneycombManagementModule.java b/infra/it/management/src/main/java/io/fd/honeycomb/management/jmx/HoneycombManagementModule.java
new file mode 100644 (file)
index 0000000..bc75cd0
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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.honeycomb.management.jmx;
+
+
+import com.google.inject.AbstractModule;
+import net.jmob.guice.conf.core.ConfigurationModule;
+import org.eclipse.jetty.jmx.ConnectorServer;
+import org.eclipse.jetty.jmx.MBeanContainer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.management.ObjectInstance;
+import javax.management.remote.JMXServiceURL;
+import java.lang.management.ManagementFactory;
+
+public class HoneycombManagementModule extends AbstractModule {
+
+    private static final Logger LOG = LoggerFactory.getLogger(HoneycombManagementModule.class);
+
+    @Override
+    protected void configure() {
+        install(ConfigurationModule.create());
+        requestInjection(HoneycombManagementConfig.class);
+        bind(MBeanContainer.class).toInstance(new MBeanContainer(ManagementFactory.getPlatformMBeanServer()));
+        bind(JMXServiceURL.class).toProvider(JMXServiceUrlProvider.class);
+        // .asEagerSingleton(); will cause also start defined in provider
+        bind(ConnectorServer.class).toProvider(ConnectorServerProvider.class).asEagerSingleton();
+
+        showAvailableBeans();
+    }
+
+    /**
+     * Prints all available JMX beans
+     */
+    protected static void showAvailableBeans() {
+        for (final ObjectInstance instance : ManagementFactory.getPlatformMBeanServer().queryMBeans(null, null)) {
+            LOG.info("MBean Found:");
+            LOG.info("Class Name:{}", instance.getClassName());
+            LOG.info("Object Name:{}", instance.getObjectName());
+            LOG.info("****************************************");
+        }
+    }
+}
diff --git a/infra/it/management/src/main/java/io/fd/honeycomb/management/jmx/JMXBeanProvider.java b/infra/it/management/src/main/java/io/fd/honeycomb/management/jmx/JMXBeanProvider.java
new file mode 100644 (file)
index 0000000..557acb4
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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.honeycomb.management.jmx;
+
+import javax.annotation.Nonnull;
+import javax.management.ObjectName;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXServiceURL;
+import java.io.IOException;
+
+public interface JMXBeanProvider {
+
+    /**
+     * Provides JMX connector to specified url
+     */
+    default JMXConnector getConnector(@Nonnull final JMXServiceURL url) {
+        try {
+            return JMXConnectorFactory.connect(url);
+        } catch (IOException e) {
+            throw new IllegalStateException("Unable to create JMX connector", e);
+        }
+    }
+
+    /**
+     * Requests specified jxm bean from provided connector
+     */
+    default Object getJMXAttribute(@Nonnull final JMXConnector connector, @Nonnull final String beanType,
+                                   @Nonnull final String beanName) {
+        try {
+            return connector.getMBeanServerConnection().getAttribute(new ObjectName(beanType), beanName);
+        } catch (Exception e) {
+            throw new IllegalStateException(
+                    String.format("Unable to query mbean of type %s, name %s", beanType, beanName), e);
+        }
+    }
+}
diff --git a/infra/it/management/src/main/java/io/fd/honeycomb/management/jmx/JMXServiceUrlProvider.java b/infra/it/management/src/main/java/io/fd/honeycomb/management/jmx/JMXServiceUrlProvider.java
new file mode 100644 (file)
index 0000000..1b91365
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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.honeycomb.management.jmx;
+
+import com.google.inject.Inject;
+import io.fd.honeycomb.infra.distro.ProviderTrait;
+
+import javax.management.remote.JMXServiceURL;
+import java.net.MalformedURLException;
+
+/**
+ * Provides properly binded {@link JMXServiceURL}
+ */
+public class JMXServiceUrlProvider extends ProviderTrait<JMXServiceURL> {
+
+    @Inject
+    private HoneycombManagementConfig config;
+
+    @Override
+    protected JMXServiceURL create() {
+        try {
+            return new JMXServiceURL(
+                    HoneycombManagementConfig.JMX_PROTOCOL,
+                    config.getJmxHost(),
+                    config.getJmxPort(),
+                    "/jndi/rmi://" + config.getJmxHost() + ":" + config.getJmxPort() + "/jmxrmi");
+        } catch (MalformedURLException e) {
+            throw new IllegalStateException("Unable to create JXM Service url", e);
+        }
+    }
+}
diff --git a/infra/it/management/src/main/resources/management.json b/infra/it/management/src/main/resources/management.json
new file mode 100644 (file)
index 0000000..7a73a41
--- /dev/null
@@ -0,0 +1,2 @@
+{
+}
\ No newline at end of file
diff --git a/infra/it/memory-benchmark-api/asciidoc/Readme.adoc b/infra/it/memory-benchmark-api/asciidoc/Readme.adoc
new file mode 100644 (file)
index 0000000..c630736
--- /dev/null
@@ -0,0 +1,5 @@
+= memory-benchmark-api
+
+Overview of memory-benchmark-api
+
+Provides test models for honeycomb memory benchmark.
\ No newline at end of file
diff --git a/infra/it/memory-benchmark-api/pom.xml b/infra/it/memory-benchmark-api/pom.xml
new file mode 100644 (file)
index 0000000..8b92303
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>api-parent</artifactId>
+        <groupId>io.fd.honeycomb.common</groupId>
+        <version>1.17.04-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>io.fd.honeycomb.it</groupId>
+    <artifactId>memory-benchmark-api</artifactId>
+    <version>1.17.04-SNAPSHOT</version>
+</project>
\ No newline at end of file
diff --git a/infra/it/memory-benchmark-api/src/main/yang/memory-benchmark.yang b/infra/it/memory-benchmark-api/src/main/yang/memory-benchmark.yang
new file mode 100644 (file)
index 0000000..e015506
--- /dev/null
@@ -0,0 +1,19 @@
+module memory-benchmark {
+
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:memory:benchmark";
+    prefix "mm-bench";
+
+    revision "2016-12-04" {
+      description "Memory benchmark test api";
+    }
+
+    container config-data {
+        list config-list {
+            key name;
+            leaf name {
+                type string;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/infra/it/memory-benchmark-scripts/pom.xml b/infra/it/memory-benchmark-scripts/pom.xml
new file mode 100644 (file)
index 0000000..b6b29e5
--- /dev/null
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <!-- have to basically duplicate common-scripts, it cannot be used as parent because of jar packaging -->
+
+    <properties>
+        <!-- groovy -->
+        <maven.groovy.version>2.0</maven.groovy.version>
+        <groovy.version>2.4.7</groovy.version>
+        <groovy.eclipse.compiler.version>2.9.2-01</groovy.eclipse.compiler.version>
+        <groovy.eclipse.batch.version>2.4.3-01</groovy.eclipse.batch.version>
+    </properties>
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>io.fd.honeycomb.it</groupId>
+    <artifactId>benchmark-scripts</artifactId>
+    <version>1.17.04-SNAPSHOT</version>
+    <packaging>jar</packaging>
+
+    <build>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-site-plugin</artifactId>
+                    <configuration>
+                        <skip>true</skip>
+                        <skipDeploy>true</skipDeploy>
+                    </configuration>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.groovy</groupId>
+                <artifactId>groovy-eclipse-compiler</artifactId>
+                <version>${groovy.eclipse.compiler.version}</version>
+                <extensions>true</extensions>
+            </plugin>
+            <plugin>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <!-- 2.8.0-01 and later require maven-compiler-plugin 3.1 or higher -->
+                <configuration>
+                    <compilerId>groovy-eclipse-compiler</compilerId>
+                </configuration>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.codehaus.groovy</groupId>
+                        <artifactId>groovy-eclipse-compiler</artifactId>
+                        <version>${groovy.eclipse.compiler.version}</version>
+                    </dependency>
+                    <!-- for 2.8.0-01 and later you must have an explicit dependency on groovy-eclipse-batch -->
+                    <dependency>
+                        <groupId>org.codehaus.groovy</groupId>
+                        <artifactId>groovy-eclipse-batch</artifactId>
+                        <version>${groovy.eclipse.batch.version}</version>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.codehaus.groovy</groupId>
+            <artifactId>groovy-all</artifactId>
+            <version>${groovy.version}</version>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file
diff --git a/infra/it/memory-benchmark-scripts/src/main/groovy/io/fd/honeycomb/benchmark/script/MemoryBenchmarkStartupScriptGenerator.groovy b/infra/it/memory-benchmark-scripts/src/main/groovy/io/fd/honeycomb/benchmark/script/MemoryBenchmarkStartupScriptGenerator.groovy
new file mode 100644 (file)
index 0000000..1db656a
--- /dev/null
@@ -0,0 +1,38 @@
+package io.fd.honeycomb.benchmark.script
+
+import groovy.text.SimpleTemplateEngine
+
+import java.nio.file.Files
+import java.nio.file.Paths
+
+class MemoryBenchmarkStartupScriptGenerator {
+
+    static final def STARTUP_SCRIPT_ON_REST_TEMPLATE = MemoryBenchmarkStartupScriptGenerator.getResource("/memoryBenchmarkScript")
+    static final def STARTUP_SCRIPT_NAME_BASE = "honeycomb-memory-footprint-benchmark-"
+
+    static final def FOOTPRINT_TEST_CLASS = "io.fd.honeycomb.benchmark.memory.HoneycombFootprintTest"
+
+    static final def OUTPUT_PATH_PARAM = "-DoutPath=\$(dirname \$0)/"
+    static final def SAMPLE_SIZE_PARAM = "-DsampleSize="
+
+    /**
+     * Generate script to run io.fd.honeycomb.benchmark.memory.HoneycombWithDataTest with provided params
+     * */
+    public static void generateWithDataScript(project, log, String outputFileName, dataSampleSize) {
+        log.info "Binding execution script for with-data benchmark[output=${outputFileName},sampleSize=${dataSampleSize}]"
+        def scriptContent = new SimpleTemplateEngine().createTemplate(STARTUP_SCRIPT_ON_REST_TEMPLATE).make(
+                [
+                        "testParams"             : "${OUTPUT_PATH_PARAM}${outputFileName}-${dataSampleSize} ${SAMPLE_SIZE_PARAM}${dataSampleSize}",
+                        "testClass"              : FOOTPRINT_TEST_CLASS
+                ]).toString()
+        flushScript(Paths.get(project.build.directory, "${STARTUP_SCRIPT_NAME_BASE}${dataSampleSize}"), scriptContent, log)
+    }
+
+    private static flushScript(filePath, content,log) {
+        log.info "Saving script to path ${filePath}"
+        def file = Files.createFile(filePath).toFile()
+
+        file.text = content
+        file.setExecutable(true)
+    }
+}
diff --git a/infra/it/memory-benchmark-scripts/src/main/resources/memoryBenchmarkScript b/infra/it/memory-benchmark-scripts/src/main/resources/memoryBenchmarkScript
new file mode 100644 (file)
index 0000000..120cb00
--- /dev/null
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+java -cp .:memory-benchmark-1.0.0-with-tests.jar ${testParams} org.junit.runner.JUnitCore ${testClass}
\ No newline at end of file
diff --git a/infra/it/memory-benchmark/asciidoc/Readme.adoc b/infra/it/memory-benchmark/asciidoc/Readme.adoc
new file mode 100644 (file)
index 0000000..80e2ffb
--- /dev/null
@@ -0,0 +1,68 @@
+= memory-benchmark
+
+Overview of memory-benchmark
+
+= Tutorial
+= Configure
+
+To run honeycomb memory benchmark, use maven profile *memory-benchmark* like so
+
+ mvn clean install -DskipTests -Pmemory-benchmark
+
+This will add following modules to build
+
+* _management_ - Enable JMX for honeycomb
+* _memory-benchmark-scripts_ - Script generation for benchmarks
+* _memory-benchmark-api_ - Test models for benchmark
+* _memory-benchmark_ - Benchmark itself
+
+By default, 3 versions of run scripts are produces in project build folder
+
+* _honeycomb-memory-footprint-benchmark-0_ - Tests honeycomb memory footprint on rest without any config/context data
+* _honeycomb-memory-footprint-benchmark-1000_ - Tests honeycomb memory footprint while 1000 data nodes present in config data
+* _honeycomb-memory-footprint-benchmark-10000_ - Tests honeycomb memory footprint while 10000 data nodes present in config data
+
+Any other data sample size can be tested by modifying script parameter *-DsampleSize*
+
+== Run
+
+To run benchmark
+
+ ./honeycomb-memory-footprint-benchmark-0
+
+This will produce two output files.
+
+* memory-benchmark-on-rest-out-0-HeapMemoryUsage.csv
+* memory-benchmark-on-rest-out-0-NonHeapMemoryUsage.csv
+
+For further explanation look at
+
+ https://docs.oracle.com/javase/7/docs/api/java/lang/management/MemoryMXBean.html
+
+
+Each of these files contains values in following format
+
+ committed,init,max,used
+ 132644864,109051904,1525153792,12577144
+
+These values stands for
+
+
+* init - Represents the initial amount of memory (in bytes) that the Java virtual machine requests from the operating system for memory management during startup.
+The Java virtual machine may request additional memory from the operating system and may also release memory to the system over time.
+The value of init may be undefined(-1).
+* used - Represents the amount of memory currently used (in bytes).
+* committed    - Represents the amount of memory (in bytes) that is guaranteed to be available for use by the Java virtual machine.
+The amount of committed memory may change over time (increase or decrease). The Java virtual machine may release memory to the system and committed could be less than init.
+Committed will always be greater than or equal to used.
+* max - Represents the maximum amount of memory (in bytes) that can be used for memory management. Its value may be undefined(-1).
+ The maximum amount of memory may change over time if defined.
+ The amount of used and committed memory will always be less than or equal to max if max is defined.
+ A memory allocation may fail if it attempts to increase the used memory
+ such that used > committed even if used <= max would still be true (for example, when the system is low on virtual memory).
+
+
+
+
+
+
diff --git a/infra/it/memory-benchmark/pom.xml b/infra/it/memory-benchmark/pom.xml
new file mode 100644 (file)
index 0000000..8c93c0b
--- /dev/null
@@ -0,0 +1,184 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright (c) 2016 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <!-- Parent set as common script to use all groovy dependency versions, etc-->
+    <parent>
+        <groupId>io.fd.honeycomb.common</groupId>
+        <artifactId>honeycomb-parent</artifactId>
+        <version>1.17.04-SNAPSHOT</version>
+        <relativePath>../../../common/honeycomb-parent</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>io.fd.honeycomb.it</groupId>
+    <artifactId>memory-benchmark</artifactId>
+    <!-- Static version, we don't want it to be deployed anyway-->
+    <version>1.0.0</version>
+    <properties>
+        <commons-csv.version>1.4</commons-csv.version>
+        <honeycomb.version>1.17.04-SNAPSHOT</honeycomb.version>
+        <maven.groovy.version>2.0</maven.groovy.version>
+        <groovy.version>2.4.7</groovy.version>
+        <groovy.eclipse.compiler.version>2.9.2-01</groovy.eclipse.compiler.version>
+        <groovy.eclipse.batch.version>2.4.3-01</groovy.eclipse.batch.version>
+    </properties>
+    <!-- to be runnable from command line -->
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>io.fd.honeycomb.it</groupId>
+            <artifactId>memory-benchmark-api</artifactId>
+            <version>${honeycomb.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>io.fd.honeycomb</groupId>
+            <artifactId>minimal-distribution</artifactId>
+            <version>${honeycomb.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>io.fd.honeycomb.it</groupId>
+            <artifactId>management</artifactId>
+            <version>${honeycomb.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-csv</artifactId>
+            <version>${commons-csv.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.codehaus.groovy</groupId>
+            <artifactId>groovy-all</artifactId>
+            <version>${groovy.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+
+            <!-- Skip deploy -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
+
+            <!-- skips test by default but compile them -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <version>2.19.1</version>
+                <configuration>
+                    <skipTests>true</skipTests>
+                </configuration>
+            </plugin>
+
+            <!-- assemble jar with all dependencies and test classes -->
+            <plugin>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <version>2.3</version>
+                <configuration>
+                    <descriptor>src/main/assembly/assembly.xml</descriptor>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>make-assembly</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <!-- generate scripts for benchmarks -->
+            <plugin>
+                <groupId>org.codehaus.gmaven</groupId>
+                <artifactId>groovy-maven-plugin</artifactId>
+                <executions>
+                    <!-- script for on-rest memory benchmark -->
+                    <execution>
+                        <id>generate-on-rest-benchmark-script</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>execute</goal>
+                        </goals>
+                        <!-- 0 data samples == empty config file, therefore same as honeycomb on rest -->
+                        <configuration>
+                            <source>
+                            io.fd.honeycomb.benchmark.script.MemoryBenchmarkStartupScriptGenerator.generateWithDataScript(project, log, "memory-benchmark-on-rest-out", 0)
+                            </source>
+                        </configuration>
+                    </execution>
+                    <!-- script for memory benchmark with 1000 nodes in config data-->
+                    <execution>
+                        <id>generate-with-data-1000-benchmark-script</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>execute</goal>
+                        </goals>
+                        <configuration>
+                            <source>
+                            io.fd.honeycomb.benchmark.script.MemoryBenchmarkStartupScriptGenerator.generateWithDataScript(project, log, "memory-benchmark-with-data-out", 1000)
+                            </source>
+                        </configuration>
+                    </execution>
+                    <!-- script for memory benchmark with 10000 nodes in config data-->
+                    <execution>
+                        <id>generate-with-data-10000-benchmark-script</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>execute</goal>
+                        </goals>
+                        <configuration>
+                            <source>
+                            io.fd.honeycomb.benchmark.script.MemoryBenchmarkStartupScriptGenerator.generateWithDataScript(project, log, "memory-benchmark-with-data-out", 10000)
+                            </source>
+                        </configuration>
+                    </execution>
+                </executions>
+                <dependencies>
+                    <dependency>
+                        <groupId>io.fd.honeycomb.it</groupId>
+                        <artifactId>benchmark-scripts</artifactId>
+                        <version>1.17.04-SNAPSHOT</version>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/infra/it/memory-benchmark/src/main/assembly/assembly.xml b/infra/it/memory-benchmark/src/main/assembly/assembly.xml
new file mode 100644 (file)
index 0000000..385d0dc
--- /dev/null
@@ -0,0 +1,30 @@
+<assembly
+        xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
+    <id>with-tests</id>
+    <formats>
+        <format>jar</format>
+    </formats>
+    <includeBaseDirectory>false</includeBaseDirectory>
+    <dependencySets>
+        <dependencySet>
+            <outputDirectory>/</outputDirectory>
+            <useProjectArtifact>true</useProjectArtifact>
+            <!-- Will include junit-->
+            <useProjectAttachments>true</useProjectAttachments>
+            <unpack>true</unpack>
+            <scope>test</scope>
+        </dependencySet>
+    </dependencySets>
+    <fileSets>
+        <fileSet>
+            <directory>${project.build.directory}/test-classes</directory>
+            <outputDirectory>/</outputDirectory>
+            <includes>
+                <include>**/*.class</include>
+            </includes>
+            <useDefaultExcludes>true</useDefaultExcludes>
+        </fileSet>
+    </fileSets>
+</assembly>
\ No newline at end of file
diff --git a/infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/BenchmarkFilesProvider.java b/infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/BenchmarkFilesProvider.java
new file mode 100644 (file)
index 0000000..c7717d5
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 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.honeycomb.benchmark.memory;
+
+
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVPrinter;
+import org.slf4j.Logger;
+
+import javax.annotation.Nonnull;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.function.Supplier;
+
+public interface BenchmarkFilesProvider {
+
+    default void outputBenchmarkResult(@Nonnull final MemoryInfo benchmarkResult,
+                                       @Nonnull final String outputPath,
+                                       @Nonnull final Supplier<Logger> loggerSupplier) {
+        // specifies output file in form specified_name-memory_info_type.csv
+        final Path outPath = Paths.get(outputPath + "-" + benchmarkResult.getMemoryInfoTypeName() + ".csv");
+        final CSVFormat csvFormat = CSVFormat.RFC4180.withHeader(MemoryInfo.COMMITTED, MemoryInfo.INIT, MemoryInfo.MAX, MemoryInfo.USED);
+
+        try (final CSVPrinter csvPrinter = new CSVPrinter(new StringBuilder(), csvFormat)) {
+            // prints values in same order that header is
+            csvPrinter.printRecord(benchmarkResult.getCommitted(), benchmarkResult.getInit(), benchmarkResult.getMax(), benchmarkResult.getUsed());
+
+            loggerSupplier.get().info("Creating output file {}", outPath);
+            // writes output to separate file
+            Files.write(Files.createFile(outPath), Collections.singleton(csvPrinter.getOut().toString()));
+        } catch (IOException e) {
+            throw new IllegalStateException("Unable to output results of benchmark", e);
+        }
+    }
+
+
+    default String generateEmptyJsonFile(final String fileName) {
+        try {
+            Path tempFilePath = Files.createTempFile(fileName, ".json");
+
+            Files.write(tempFilePath, Arrays.asList("{}"));
+
+            return tempFilePath.normalize().toString();
+        } catch (IOException e) {
+            throw new IllegalStateException("Unable to create temp config data file");
+        }
+    }
+
+    /**
+     * Generate dummy data file to be provided for honeycomb as config data
+     */
+    default String generateNonEmptyConfigDataFile(final String fileName, final int dataSampleSize) {
+        try {
+            Path tempFilePath = Files.createTempFile(fileName, ".json");
+
+            StringBuilder dataBuilder = new StringBuilder();
+
+            dataBuilder.append("{\"mm-bench:config-data\":{\"config-list\":[");
+
+            for (int i = 0; i < dataSampleSize; i++) {
+                dataBuilder.append("{\"name\":\"")
+                        .append(String.valueOf(i))
+                        .append("\"}");
+                if (i != dataSampleSize - 1) {
+                    dataBuilder.append(",");
+                }
+            }
+
+            dataBuilder.append("]}}");
+
+            Files.write(tempFilePath, Arrays.asList(dataBuilder.toString()));
+
+            return tempFilePath.normalize().toString();
+        } catch (IOException e) {
+            throw new IllegalStateException("Unable to create temp config data file");
+        }
+    }
+}
diff --git a/infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/MemoryFootprintBenchmark.java b/infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/MemoryFootprintBenchmark.java
new file mode 100644 (file)
index 0000000..48d8059
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * 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.honeycomb.benchmark.memory;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Injector;
+import com.google.inject.Module;
+import io.fd.honeycomb.benchmark.memory.config.BindableCfgAttrsModule;
+import io.fd.honeycomb.benchmark.memory.config.StaticHoneycombManagementModule;
+import io.fd.honeycomb.benchmark.memory.write.NoopWritersModule;
+import io.fd.honeycomb.infra.distro.Main;
+import io.fd.honeycomb.infra.distro.cfgattrs.HoneycombConfiguration;
+import io.fd.honeycomb.infra.distro.data.ConfigAndOperationalPipelineModule;
+import io.fd.honeycomb.infra.distro.data.context.ContextPipelineModule;
+import io.fd.honeycomb.infra.distro.initializer.InitializerPipelineModule;
+import io.fd.honeycomb.infra.distro.netconf.NetconfModule;
+import io.fd.honeycomb.infra.distro.netconf.NetconfReadersModule;
+import io.fd.honeycomb.infra.distro.restconf.RestconfModule;
+import io.fd.honeycomb.infra.distro.schema.SchemaModule;
+import io.fd.honeycomb.infra.distro.schema.YangBindingProviderModule;
+import io.fd.honeycomb.management.jmx.JMXBeanProvider;
+import org.eclipse.jetty.server.Server;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.Nonnull;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXServiceURL;
+import java.util.Set;
+
+/**
+ * Measure memory consumption of config data storage
+ */
+public class MemoryFootprintBenchmark implements JMXBeanProvider, BenchmarkFilesProvider {
+
+    private static final Logger LOG = LoggerFactory.getLogger(MemoryFootprintBenchmark.class);
+
+    /**
+     * All modules from infra to load.Not static to not persist state
+     */
+    private final Set<Module> BASE_MODULES = ImmutableSet.of(
+            new YangBindingProviderModule(),
+            new SchemaModule(),
+            new ConfigAndOperationalPipelineModule(),
+            new ContextPipelineModule(),
+            new InitializerPipelineModule(),
+            new NetconfModule(),
+            new NetconfReadersModule(),
+            new RestconfModule(),
+            // to enable jmx
+            new StaticHoneycombManagementModule(),
+            //adds noop writers
+            new NoopWritersModule());
+
+    // configuration class used to run benchmark, allows us to switch between honeycomb with data, or on rest
+    private final HoneycombConfiguration configuration;
+
+    // output file path
+    private final String outputPath;
+
+    public MemoryFootprintBenchmark(@Nonnull final HoneycombConfiguration configuration, @Nonnull final String outputPath) {
+        this.configuration = configuration;
+        this.outputPath = outputPath;
+    }
+
+    public void run() throws Exception {
+        // start honeycomb with configuration of BASE_MODULES + configuration class
+        final Injector injector = startHoneycomb();
+
+        // query memory beans with JMX and output results on output path
+        queryMemoryBeans(injector.getInstance(JMXServiceURL.class))
+                .forEach(memoryInfo -> outputBenchmarkResult(memoryInfo, outputPath, () -> LOG));
+        // shutdowns server instance
+        injector.getInstance(Server.class).stop();
+    }
+
+    /**
+     * start honeycomb with basic modules + provided static configuration
+     */
+    private Injector startHoneycomb() {
+        LOG.info("Starting embedded server with configuration {}", configuration);
+        return Main.init(ImmutableSet.<Module>builder()
+                .add(new BindableCfgAttrsModule(configuration))
+                .addAll(BASE_MODULES).build());
+    }
+
+    /**
+     * Queries heap and non-heap memory usage
+     */
+    private Set<MemoryInfo> queryMemoryBeans(final JMXServiceURL url) {
+        LOG.info("Requesting memory bean on url {}", url);
+
+        try (final JMXConnector connector = getConnector(url)) {
+            MemoryInfo heapMemoryInfo = new MemoryInfo(
+                    (CompositeDataSupport) getJMXAttribute(connector, MemoryInfo.MEMORY_MBEAN_TYPE,
+                            MemoryInfo.HEAP_MEMORY), MemoryInfo.HEAP_MEMORY);
+            LOG.info("Heap memory usage {}", heapMemoryInfo);
+
+            MemoryInfo nonHeapMemoryInfo = new MemoryInfo(
+                    (CompositeDataSupport) getJMXAttribute(connector, MemoryInfo.MEMORY_MBEAN_TYPE,
+                            MemoryInfo.NON_HEAP_MEMORY), MemoryInfo.NON_HEAP_MEMORY);
+            LOG.info("NonHeap memory usage {}", nonHeapMemoryInfo);
+            return ImmutableSet.of(heapMemoryInfo, nonHeapMemoryInfo);
+        } catch (Exception e) {
+            throw new IllegalStateException("Unable to query memory beans", e);
+        }
+    }
+
+}
+
diff --git a/infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/MemoryInfo.java b/infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/MemoryInfo.java
new file mode 100644 (file)
index 0000000..f79006f
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * 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.honeycomb.benchmark.memory;
+
+import javax.annotation.Nonnull;
+import javax.management.openmbean.CompositeDataSupport;
+import java.util.Arrays;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * Wrapped from data extracted from JMX beans of type Memory
+ * */
+public final class MemoryInfo {
+
+    public static final String MEMORY_MBEAN_TYPE = "java.lang:type=Memory";
+    public static final String HEAP_MEMORY = "HeapMemoryUsage";
+    public static final String NON_HEAP_MEMORY = "NonHeapMemoryUsage";
+
+    public static final String COMMITTED = "committed";
+    public static final String INIT = "init";
+    public static final String MAX = "max";
+    public static final String USED = "used";
+
+    private final String memoryInfoTypeName;
+    private final long committed, init, max, used;
+
+    public MemoryInfo(@Nonnull final CompositeDataSupport compositeData, @Nonnull final String memoryInfoTypeName) {
+        checkArgument(compositeData.getCompositeType().keySet().containsAll(Arrays.asList(COMMITTED, INIT, MAX, USED)),
+                "Submitted composite data %s does not contains necessary attributes", compositeData);
+        this.memoryInfoTypeName = memoryInfoTypeName;
+        this.committed = compositeDataAttributeValue(compositeData.get(COMMITTED));
+        this.init = compositeDataAttributeValue(compositeData.get(INIT));
+        this.max = compositeDataAttributeValue(compositeData.get(MAX));
+        this.used = compositeDataAttributeValue(compositeData.get(USED));
+
+    }
+
+    public String getMemoryInfoTypeName() {
+        return memoryInfoTypeName;
+    }
+
+    public long getCommitted() {
+        return committed;
+    }
+
+    public long getInit() {
+        return init;
+    }
+
+    public long getMax() {
+        return max;
+    }
+
+    public long getUsed() {
+        return used;
+    }
+
+    @Override
+    public String toString() {
+        return memoryInfoTypeName + "[" +
+                "committed=" + committed +
+                ",init=" + init +
+                ",max=" + max +
+                ",used=" + used +
+                ']';
+    }
+
+    private static Long compositeDataAttributeValue(final Object commited) {
+        checkArgument(commited instanceof Long, "Unsupported memory attribute value %s", commited.getClass());
+        return Long.class.cast(commited);
+    }
+}
diff --git a/infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/config/BindableCfgAttrsModule.java b/infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/config/BindableCfgAttrsModule.java
new file mode 100644 (file)
index 0000000..03e3774
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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.honeycomb.benchmark.memory.config;
+
+
+import com.google.inject.AbstractModule;
+import io.fd.honeycomb.infra.distro.cfgattrs.HoneycombConfiguration;
+
+/**
+ * Provides ability to bind specific instance of static configuration
+ * */
+public class BindableCfgAttrsModule extends AbstractModule {
+
+    private final HoneycombConfiguration configToBind;
+
+    public BindableCfgAttrsModule(HoneycombConfiguration configToBind) {
+        this.configToBind = configToBind;
+    }
+
+    @Override
+    protected void configure() {
+        // Inject non-dependency configuration
+        bind(HoneycombConfiguration.class).toInstance(configToBind);
+    }
+}
diff --git a/infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/config/StaticHoneycombConfiguration.java b/infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/config/StaticHoneycombConfiguration.java
new file mode 100644 (file)
index 0000000..6bcf7ef
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * 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.honeycomb.benchmark.memory.config;
+
+import io.fd.honeycomb.infra.distro.cfgattrs.HoneycombConfiguration;
+
+import javax.annotation.Nonnull;
+import java.io.Closeable;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Optional;
+
+/**
+ * Static configuration to prevent injecting of properties from json fles
+ */
+public class StaticHoneycombConfiguration extends HoneycombConfiguration implements Closeable {
+
+    public StaticHoneycombConfiguration(@Nonnull final String persistConfigPath, @Nonnull final String persistContextPath) {
+        this.peristConfigPath = persistConfigPath;
+        this.peristContextPath = persistContextPath;
+
+        this.username = "admin";
+        this.password = "admin";
+        this.notificationServiceQueueDepth = 1;
+        this.restconfBindingAddress = Optional.of("/restconf");
+        this.restconfPort = Optional.of(8187);
+        this.restconfBindingAddress = Optional.of("127.0.0.1");
+        this.persistedConfigRestorationType = "Merge";
+        this.persistedContextRestorationType = "Merge";
+        this.restconfWebsocketPort = Optional.of(7890);
+    }
+
+    @Override
+    public boolean isConfigPersistenceEnabled() {
+        return false;
+    }
+
+    @Override
+    public boolean isRestconfHttpsEnabled() {
+        return false;
+    }
+
+    @Override
+    public boolean isRestconfHttpEnabled() {
+        return true;
+    }
+
+    @Override
+    public boolean isRestconfEnabled() {
+        return true;
+    }
+
+    @Override
+    public boolean isNetconfTcpEnabled() {
+        return false;
+    }
+
+    @Override
+    public boolean isContextPersistenceEnabled() {
+        return false;
+    }
+
+    @Override
+    public boolean isNetconfEnabled() {
+        return false;
+    }
+
+    @Override
+    public boolean isNetconfSshEnabled() {
+        return false;
+    }
+
+    @Override
+    public void close() throws IOException {
+        if (Files.exists(Paths.get(peristConfigPath))) {
+            Files.delete(Paths.get(peristConfigPath));
+        }
+
+        if (Files.exists(Paths.get(peristContextPath))) {
+            Files.delete(Paths.get(peristContextPath));
+        }
+    }
+}
diff --git a/infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/config/StaticHoneycombManagementModule.java b/infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/config/StaticHoneycombManagementModule.java
new file mode 100644 (file)
index 0000000..a91d6ba
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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.honeycomb.benchmark.memory.config;
+
+import io.fd.honeycomb.management.jmx.ConnectorServerProvider;
+import io.fd.honeycomb.management.jmx.HoneycombManagementConfig;
+import io.fd.honeycomb.management.jmx.HoneycombManagementModule;
+import io.fd.honeycomb.management.jmx.JMXServiceUrlProvider;
+import org.eclipse.jetty.jmx.ConnectorServer;
+import org.eclipse.jetty.jmx.MBeanContainer;
+
+import javax.management.remote.JMXServiceURL;
+import java.lang.management.ManagementFactory;
+
+/**
+ * In this case we need to override Honeycomb config, but if standard management module is active,
+ * configuration module injection will cause attempt to inject attributes in HoneycombConfiguration,
+ * even if static instance is provider. Therefore here we need to override configure to also provide
+ * static instance for HoneycombManagementConfig
+ */
+public class StaticHoneycombManagementModule extends HoneycombManagementModule {
+
+    @Override
+    protected void configure() {
+        // all values are wrapped in Optionals with default values
+        bind(HoneycombManagementConfig.class).toInstance(new HoneycombManagementConfig());
+        bind(MBeanContainer.class).toInstance(new MBeanContainer(ManagementFactory.getPlatformMBeanServer()));
+        bind(JMXServiceURL.class).toProvider(JMXServiceUrlProvider.class);
+        bind(ConnectorServer.class).toProvider(ConnectorServerProvider.class).asEagerSingleton();
+
+        showAvailableBeans();
+    }
+}
diff --git a/infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/write/NoopWriter.java b/infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/write/NoopWriter.java
new file mode 100644 (file)
index 0000000..000a176
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * 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.honeycomb.benchmark.memory.write;
+
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.honeycomb.translate.write.Writer;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+public final class NoopWriter<T extends DataObject> implements Writer<T> {
+
+    private final InstanceIdentifier<T> id;
+
+    public NoopWriter(final InstanceIdentifier<T> id) {
+        this.id = id;
+    }
+
+    @Override
+    public void update(@Nonnull final InstanceIdentifier<? extends DataObject> id,
+                       @Nullable final DataObject dataBefore,
+                       @Nullable final DataObject dataAfter,
+                       @Nonnull final WriteContext ctx) throws WriteFailedException {
+        // NOOP
+    }
+
+    @Nonnull
+    @Override
+    public InstanceIdentifier<T> getManagedDataObjectType() {
+        return id;
+    }
+
+    @Override
+    public String toString() {
+        return "NoopWriter{" +
+                id.getTargetType().getSimpleName() + '}';
+    }
+}
\ No newline at end of file
diff --git a/infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/write/NoopWritersModule.java b/infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/write/NoopWritersModule.java
new file mode 100644 (file)
index 0000000..a88c514
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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.honeycomb.benchmark.memory.write;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.multibindings.Multibinder;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.memory.benchmark.rev161204.ConfigData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.memory.benchmark.rev161204.config.data.ConfigList;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class NoopWritersModule extends AbstractModule {
+    @Override
+    protected void configure() {
+
+        final Multibinder<WriterFactory> writeBinder = Multibinder.newSetBinder(binder(), WriterFactory.class);
+        writeBinder.addBinding().toInstance(registry -> {
+            // Add noop writers for all data written in this benchmark
+
+            registry.add(new NoopWriter<>(InstanceIdentifier.create(ConfigData.class)));
+            registry.add(new NoopWriter<>(InstanceIdentifier.create(ConfigData.class).child(ConfigList.class)));
+        });
+    }
+
+}
diff --git a/infra/it/memory-benchmark/src/test/java/io/fd/honeycomb/benchmark/memory/HoneycombFootprintTest.java b/infra/it/memory-benchmark/src/test/java/io/fd/honeycomb/benchmark/memory/HoneycombFootprintTest.java
new file mode 100644 (file)
index 0000000..b8817f8
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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.honeycomb.benchmark.memory;
+
+import io.fd.honeycomb.benchmark.memory.config.StaticHoneycombConfiguration;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * Test honeycomb memory footprint while containing amount of nodes specified by
+ * parameter sampleSize.<br>
+ * Test must be triggered by separated scripts, not by Parametrized runner,<br>
+ * because of classes like WebSocketServer that is internally a singleton, therefore it holds static reference<br>
+ * on itself and would fail on second run on precondition, because junit kills threads, but does not unload classes
+ */
+public class HoneycombFootprintTest implements BenchmarkFilesProvider {
+
+    private static final String SAMPLE_SIZE_PROP = "sampleSize";
+    private static final String OUTPUT_PROP = "outPath";
+
+    private StaticHoneycombConfiguration staticHoneycombConfiguration;
+    private String outputPath;
+
+    @Before
+    public void init() {
+        outputPath = Objects.requireNonNull(System.getProperty(OUTPUT_PROP),
+                "No output file path specified, make sure you've specified -D" + OUTPUT_PROP + " parameter");
+    }
+
+    @Test
+    public void testHoneycombMemoryFootprintWithData() throws Exception {
+        final int dataSampleSize = Integer.valueOf(Objects.requireNonNull(System.getProperty(SAMPLE_SIZE_PROP),
+                "No sample data size defined, make sure you've specified -D" + SAMPLE_SIZE_PROP + " parameter"));
+
+        staticHoneycombConfiguration = new StaticHoneycombConfiguration(
+                generateNonEmptyConfigDataFile("temp-config", dataSampleSize),
+                generateEmptyJsonFile("temp-empty-context"));
+
+        new MemoryFootprintBenchmark(staticHoneycombConfiguration, outputPath).run();
+    }
+
+    @After
+    public void destroyTest() throws IOException {
+        // removes temp files,etc
+        staticHoneycombConfiguration.close();
+    }
+}
index da6e3c2..cbf8eae 100644 (file)
     <module>it-test</module>
   </modules>
 
-
-  <!-- Activate from command line with mvn <goals> -Pbenchmark -->
   <profiles>
+    <!-- Activate from command line with mvn <goals> -Pbenchmark -->
     <profile>
       <id>benchmark</id>
       <modules>
         <module>benchmark</module>
       </modules>
     </profile>
+
+    <!-- Activate management module -->
+    <profile>
+      <id>management</id>
+      <modules>
+        <module>management</module>
+      </modules>
+    </profile>
+
+    <!-- Activate memory benchmarking modules -->
+    <profile>
+      <id>memory-benchmark</id>
+      <modules>
+        <module>management</module>
+        <module>memory-benchmark-scripts</module>
+        <module>memory-benchmark</module>
+        <module>memory-benchmark-api</module>
+      </modules>
+    </profile>
   </profiles>
 
   <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->