diff options
Diffstat (limited to 'infra/it/memory-benchmark/src/main/java/io')
8 files changed, 580 insertions, 0 deletions
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 index 000000000..c7717d593 --- /dev/null +++ b/infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/BenchmarkFilesProvider.java @@ -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 index 000000000..48d805975 --- /dev/null +++ b/infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/MemoryFootprintBenchmark.java @@ -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 index 000000000..f79006f78 --- /dev/null +++ b/infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/MemoryInfo.java @@ -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 index 000000000..03e3774db --- /dev/null +++ b/infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/config/BindableCfgAttrsModule.java @@ -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 index 000000000..6bcf7ef68 --- /dev/null +++ b/infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/config/StaticHoneycombConfiguration.java @@ -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 index 000000000..a91d6ba84 --- /dev/null +++ b/infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/config/StaticHoneycombManagementModule.java @@ -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 index 000000000..000a176df --- /dev/null +++ b/infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/write/NoopWriter.java @@ -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 index 000000000..a88c514c4 --- /dev/null +++ b/infra/it/memory-benchmark/src/main/java/io/fd/honeycomb/benchmark/memory/write/NoopWritersModule.java @@ -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))); + }); + } + +} |