All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.jackrabbit.oak.benchmark.AbstractTest Maven / Gradle / Ivy

There is a newer version: 1.72.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.jackrabbit.oak.benchmark;

import java.io.PrintStream;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import javax.annotation.Nullable;
import javax.jcr.Credentials;
import javax.jcr.GuestCredentials;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;

import jline.internal.Log;

import org.apache.commons.math.stat.descriptive.DescriptiveStatistics;
import org.apache.commons.math.stat.descriptive.SynchronizedDescriptiveStatistics;
import org.apache.jackrabbit.oak.benchmark.util.Profiler;
import org.apache.jackrabbit.oak.fixture.RepositoryFixture;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Abstract base class for individual performance benchmarks.
 */
abstract class AbstractTest extends Benchmark implements CSVResultGenerator {

    /**
     * A random string to guarantee concurrently running tests don't overwrite
     * each others changes (for example in a cluster).
     * 

* The probability of duplicates, for 50 concurrent processes, is less than * 1 in 1 million. */ static final String TEST_ID = Integer.toHexString(new Random().nextInt()); static AtomicInteger nodeNameCounter = new AtomicInteger(); /** * A node name that is guarantee to be unique within the current JVM. */ static String nextNodeName() { return "n" + Integer.toHexString(nodeNameCounter.getAndIncrement()); } private static final Credentials CREDENTIALS = new SimpleCredentials("admin", "admin".toCharArray()); private static final long WARMUP = TimeUnit.SECONDS.toMillis(Long.getLong("warmup", 5)); private static final long RUNTIME = TimeUnit.SECONDS.toMillis(Long.getLong("runtime", 60)); private static final boolean PROFILE = Boolean.getBoolean("profile"); private static final Logger LOG = LoggerFactory.getLogger(AbstractTest.class); private Repository repository; private Credentials credentials; private List sessions; private List threads; private volatile boolean running; private Profiler profiler; private PrintStream out; /** *

* used to signal the {@link #runTest(int)} if stop running future test planned or not. If set * to true, it will exit the loop not performing any more tests. *

* *

* useful when the running of the benchmark makes sense for as long as other processes didn't * complete. *

* *

* Set this variable from within the benchmark itself by using {@link #issueHaltRequest(String)} *

* *

* it works only for concurrency level of 1 ({@code --concurrency 1} the * default) *

*/ private boolean haltRequested; /** * If concurrency level is 1 ({@code --concurrency 1}, the default) it will issue a request to * halt any future runs of a single benchmark. Useful when the benchmark makes sense only if run * in conjunction of any other parallel operations. * * @param message an optional message that can be provided. It will logged at info level. */ protected void issueHaltRequest(@Nullable final String message) { String m = message == null ? "" : message; LOG.info("halt requested. {}", m); haltRequested = true; } /** *

* this method will be called during the {@link #tearDown()} before the {@link #afterSuite()}. * Override it if you have background processes you wish to stop. *

*

* For example in case of big imports, the suite could be keep running for as long as the import * is running, even if the tests are actually no longer executed. *

*/ protected void issueHaltChildThreads() { } @Override public void setPrintStream(PrintStream out) { this.out = out; } protected static int getScale(int def) { int scale = Integer.getInteger("scale", 0); if (scale == 0) { scale = def; } return scale; } /** * Prepares this performance benchmark. * * @param repository the repository to use * @param credentials credentials of a user with write access * @throws Exception if the benchmark can not be prepared */ public void setUp(Repository repository, Credentials credentials) throws Exception { this.repository = repository; this.credentials = credentials; this.sessions = new LinkedList(); this.threads = new LinkedList(); this.running = true; haltRequested = false; beforeSuite(); if (PROFILE) { profiler = new Profiler().startCollecting(); } } @Override public void run(Iterable fixtures) { run(fixtures, null); } @Override public void run(Iterable fixtures, List concurrencyLevels) { System.out.format( "# %-26.26s C min 10%% 50%% 90%% max N%n", toString()); if (out != null) { out.format( "# %-26.26s, C, min, 10%%, 50%%, 90%%, max, N%n", toString()); } for (RepositoryFixture fixture : fixtures) { try { Repository[] cluster = createRepository(fixture); try { runTest(fixture, cluster[0], concurrencyLevels); } finally { fixture.tearDownCluster(); } } catch (Exception e) { e.printStackTrace(); } } } private void runTest(RepositoryFixture fixture, Repository repository, List concurrencyLevels) throws Exception { setUp(repository, CREDENTIALS); try { // Run a few iterations to warm up the system long warmupEnd = System.currentTimeMillis() + WARMUP; boolean stop = false; while (System.currentTimeMillis() < warmupEnd && !stop) { if (!stop) { // we want to execute this at lease once. after that we consider the // `haltRequested` flag. stop = haltRequested; } execute(); } if (concurrencyLevels == null || concurrencyLevels.isEmpty()) { concurrencyLevels = Arrays.asList(1); } for (Integer concurrency: concurrencyLevels) { // Run the test DescriptiveStatistics statistics = runTest(concurrency); if (statistics.getN() > 0) { System.out.format( "%-28.28s %6d %6.0f %6.0f %6.0f %6.0f %6.0f %6d%n", fixture.toString(), concurrency, statistics.getMin(), statistics.getPercentile(10.0), statistics.getPercentile(50.0), statistics.getPercentile(90.0), statistics.getMax(), statistics.getN()); if (out != null) { out.format( "%-28.28s, %6d, %6.0f, %6.0f, %6.0f, %6.0f, %6.0f, %6d%n", fixture.toString(), concurrency, statistics.getMin(), statistics.getPercentile(10.0), statistics.getPercentile(50.0), statistics.getPercentile(90.0), statistics.getMax(), statistics.getN()); } } } } finally { tearDown(); } } private class Executor extends Thread { private final SynchronizedDescriptiveStatistics statistics; private boolean running = true; private Executor(String name, SynchronizedDescriptiveStatistics statistics) { super(name); this.statistics = statistics; } @Override public void run() { T context = null; try { context = prepareThreadExecutionContext(); while (running) { statistics.addValue(execute(context)); } } catch (Exception e) { e.printStackTrace(); } finally { disposeThreadExecutionContext(context); } } } private DescriptiveStatistics runTest(int concurrencyLevel) throws Exception { final SynchronizedDescriptiveStatistics statistics = new SynchronizedDescriptiveStatistics(); if (concurrencyLevel == 1) { // Run test iterations, and capture the execution times long runtimeEnd = System.currentTimeMillis() + RUNTIME; boolean stop = false; while (System.currentTimeMillis() < runtimeEnd && !stop) { if (!stop) { // we want to execute this at lease once. after that we consider the // `haltRequested` flag. stop = haltRequested; } statistics.addValue(execute()); } } else { List threads = new LinkedList(); for (int n=0; n




© 2015 - 2025 Weber Informatics LLC | Privacy Policy