You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by al...@apache.org on 2015/11/13 18:13:03 UTC
[1/3] incubator-brooklyn git commit: Improve performance tests
Repository: incubator-brooklyn
Updated Branches:
refs/heads/master ca89ed4f5 -> 2b23266eb
Improve performance tests
- Extracts code from AbstractPerformanceTest into PerformanceMeasurer,
making it more configurable and usable from more places.
- Adds a default persister to write files to ~/brooklyn-performance/
(while we figure out where to write those to in anger).
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/3384c7eb
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/3384c7eb
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/3384c7eb
Branch: refs/heads/master
Commit: 3384c7eb46694b56ce9f1269d253c5f7d21605a0
Parents: ca89ed4
Author: Aled Sage <al...@gmail.com>
Authored: Thu Nov 12 23:52:11 2015 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Fri Nov 13 14:54:06 2015 +0000
----------------------------------------------------------------------
.../qa/performance/AbstractPerformanceTest.java | 47 ++++-
.../qa/performance/EntityPerformanceTest.java | 84 +++++---
.../FilePersistencePerformanceTest.java | 146 +++++++++----
.../GroovyYardStickPerformanceTest.groovy | 7 +-
.../JavaYardStickPerformanceTest.java | 35 ++--
.../SubscriptionPerformanceTest.java | 58 ++----
.../qa/performance/TaskPerformanceTest.java | 63 ++----
.../BlobStorePersistencePerformanceTest.java | 39 ++--
.../brooklyn/test/PerformanceTestUtils.java | 82 +-------
.../test/performance/FilePersister.java | 85 ++++++++
.../brooklyn/test/performance/Histogram.java | 89 ++++++++
.../performance/MeasurementResultPersister.java | 29 +++
.../test/performance/PerformanceMeasurer.java | 156 ++++++++++++++
.../performance/PerformanceTestDescriptor.java | 208 +++++++++++++++++++
.../test/performance/PerformanceTestResult.java | 62 ++++++
.../test/performance/PerformanceTestUtils.java | 107 ++++++++++
16 files changed, 1041 insertions(+), 256 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3384c7eb/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/AbstractPerformanceTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/AbstractPerformanceTest.java b/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/AbstractPerformanceTest.java
index a5a3568..739877b 100644
--- a/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/AbstractPerformanceTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/AbstractPerformanceTest.java
@@ -20,6 +20,7 @@ package org.apache.brooklyn.core.test.qa.performance;
import static org.testng.Assert.assertTrue;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.apache.brooklyn.api.mgmt.ManagementContext;
@@ -27,6 +28,9 @@ import org.apache.brooklyn.core.entity.Entities;
import org.apache.brooklyn.core.entity.factory.ApplicationBuilder;
import org.apache.brooklyn.core.location.SimulatedLocation;
import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.test.performance.PerformanceTestDescriptor;
+import org.apache.brooklyn.test.performance.PerformanceTestResult;
+import org.apache.brooklyn.test.performance.PerformanceMeasurer;
import org.apache.brooklyn.util.internal.DoubleSystemProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -80,11 +84,42 @@ public class AbstractPerformanceTest {
public void tearDown() throws Exception {
if (app != null) Entities.destroyAll(app.getManagementContext());
}
-
+
+ protected PerformanceTestResult measure(PerformanceTestDescriptor options) {
+ PerformanceTestResult result = PerformanceMeasurer.run(options);
+ System.out.println("test="+options+"; result="+result);
+ return result;
+ }
+
+ /**
+ * @deprecated since 0.9.0; use {@link #measure(PerformanceTestDescriptor)}
+ */
+ @Deprecated
protected void measureAndAssert(String prefix, int numIterations, double minRatePerSec, Runnable r) {
- measureAndAssert(prefix, numIterations, minRatePerSec, r, null);
+ measure(PerformanceTestDescriptor.create()
+ .summary(prefix)
+ .iterations(numIterations)
+ .minAcceptablePerSecond(minRatePerSec)
+ .job(r));
+ }
+
+ /**
+ * @deprecated since 0.9.0; use {@link #measure(PerformanceTestDescriptor)}
+ */
+ @Deprecated
+ protected void measureAndAssert(String prefix, int numIterations, double minRatePerSec, Runnable r, CountDownLatch completionLatch) {
+ measure(PerformanceTestDescriptor.create()
+ .summary(prefix)
+ .iterations(numIterations)
+ .completionLatch(completionLatch)
+ .minAcceptablePerSecond(minRatePerSec)
+ .job(r));
}
+ /**
+ * @deprecated since 0.9.0; use {@link #measure(PerformanceTestDescriptor)}
+ */
+ @Deprecated
protected void measureAndAssert(String prefix, int numIterations, double minRatePerSec, Runnable r, Runnable postIterationPhase) {
long durationMillis = measure(prefix, numIterations, r);
long postIterationDurationMillis = (postIterationPhase != null) ? measure(postIterationPhase) : 0;
@@ -102,6 +137,10 @@ public class AbstractPerformanceTest {
assertTrue(numPerSecIncludingPostIteration >= minRatePerSec, msg1+msg2);
}
+ /**
+ * @deprecated since 0.9.0; use {@link #measure(PerformanceTestDescriptor)}
+ */
+ @Deprecated
protected long measure(String prefix, int numIterations, Runnable r) {
final int logInterval = 5*1000;
long nextLogTime = logInterval;
@@ -128,6 +167,10 @@ public class AbstractPerformanceTest {
return stopwatch.elapsed(TimeUnit.MILLISECONDS);
}
+ /**
+ * @deprecated since 0.9.0; use {@link #measure(PerformanceTestDescriptor)}
+ */
+ @Deprecated
protected long measure(Runnable r) {
Stopwatch stopwatch = Stopwatch.createStarted();
r.run();
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3384c7eb/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/EntityPerformanceTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/EntityPerformanceTest.java b/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/EntityPerformanceTest.java
index 16707d0..c73b344 100644
--- a/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/EntityPerformanceTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/EntityPerformanceTest.java
@@ -30,6 +30,7 @@ import org.apache.brooklyn.api.sensor.SensorEventListener;
import org.apache.brooklyn.core.entity.Entities;
import org.apache.brooklyn.core.test.entity.TestEntity;
import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.test.performance.PerformanceTestDescriptor;
import org.apache.brooklyn.util.collections.MutableMap;
import org.apache.brooklyn.util.exceptions.Exceptions;
import org.testng.annotations.BeforeMethod;
@@ -69,10 +70,14 @@ public class EntityPerformanceTest extends AbstractPerformanceTest {
double minRatePerSec = 1000 * PERFORMANCE_EXPECTATION;
final AtomicInteger i = new AtomicInteger();
- measureAndAssert("updateAttribute", numIterations, minRatePerSec, new Runnable() {
- public void run() {
- entity.sensors().set(TestEntity.SEQUENCE, i.getAndIncrement());
- }});
+ measure(PerformanceTestDescriptor.create()
+ .summary("EntityPerformanceTest.testUpdateAttributeWhenNoListeners")
+ .iterations(numIterations)
+ .minAcceptablePerSecond(minRatePerSec)
+ .job(new Runnable() {
+ public void run() {
+ entity.sensors().set(TestEntity.SEQUENCE, i.getAndIncrement());
+ }}));
}
@Test(groups={"Integration", "Acceptance"})
@@ -87,10 +92,14 @@ public class EntityPerformanceTest extends AbstractPerformanceTest {
lastVal.set(event.getValue());
}});
- measureAndAssert("updateAttributeWithListener", numIterations, minRatePerSec, new Runnable() {
- public void run() {
- entity.sensors().set(TestEntity.SEQUENCE, (i.getAndIncrement()));
- }});
+ measure(PerformanceTestDescriptor.create()
+ .summary("EntityPerformanceTest.testUpdateAttributeWithNoopListeners")
+ .iterations(numIterations)
+ .minAcceptablePerSecond(minRatePerSec)
+ .job(new Runnable() {
+ public void run() {
+ entity.sensors().set(TestEntity.SEQUENCE, (i.getAndIncrement()));
+ }}));
Asserts.succeedsEventually(MutableMap.of("timeout", TIMEOUT_MS), new Runnable() {
public void run() {
@@ -103,10 +112,14 @@ public class EntityPerformanceTest extends AbstractPerformanceTest {
int numIterations = numIterations();
double minRatePerSec = 1000 * PERFORMANCE_EXPECTATION;
- measureAndAssert("invokeEffector", numIterations, minRatePerSec, new Runnable() {
- public void run() {
- entity.myEffector();
- }});
+ measure(PerformanceTestDescriptor.create()
+ .summary("EntityPerformanceTest.testInvokeEffector")
+ .iterations(numIterations)
+ .minAcceptablePerSecond(minRatePerSec)
+ .job(new Runnable() {
+ public void run() {
+ entity.myEffector();
+ }}));
}
@Test(groups={"Integration", "Acceptance"})
@@ -114,31 +127,38 @@ public class EntityPerformanceTest extends AbstractPerformanceTest {
int numIterations = numIterations();
double minRatePerSec = 1000 * PERFORMANCE_EXPECTATION;
- measureAndAssert("invokeEffectorAsyncAndGet", numIterations, minRatePerSec, new Runnable() {
- public void run() {
- Task<?> task = entity.invoke(TestEntity.MY_EFFECTOR, MutableMap.<String,Object>of());
- try {
- task.get();
- } catch (Exception e) {
- throw Exceptions.propagate(e);
- }
- }});
+ measure(PerformanceTestDescriptor.create()
+ .summary("EntityPerformanceTest.testAsyncEffectorInvocation")
+ .iterations(numIterations)
+ .minAcceptablePerSecond(minRatePerSec)
+ .job(new Runnable() {
+ public void run() {
+ Task<?> task = entity.invoke(TestEntity.MY_EFFECTOR, MutableMap.<String,Object>of());
+ try {
+ task.get();
+ } catch (Exception e) {
+ throw Exceptions.propagate(e);
+ }
+ }}));
}
- // TODO but surely parallel should be much faster?!
@Test(groups={"Integration", "Acceptance"})
public void testMultiEntityConcurrentEffectorInvocation() {
int numIterations = numIterations();
- double minRatePerSec = 100 * PERFORMANCE_EXPECTATION; // i.e. 1000 invocations
+ double minRatePerSec = 100 * PERFORMANCE_EXPECTATION; // i.e. 1000 invocations (because 10 entities per time)
- measureAndAssert("invokeEffectorMultiEntityConcurrentAsyncAndGet", numIterations, minRatePerSec, new Runnable() {
- public void run() {
- Task<?> task = Entities.invokeEffector(app, entities, TestEntity.MY_EFFECTOR);
- try {
- task.get();
- } catch (Exception e) {
- throw Exceptions.propagate(e);
- }
- }});
+ measure(PerformanceTestDescriptor.create()
+ .summary("EntityPerformanceTest.testMultiEntityConcurrentEffectorInvocation")
+ .iterations(numIterations)
+ .minAcceptablePerSecond(minRatePerSec)
+ .job(new Runnable() {
+ public void run() {
+ Task<?> task = Entities.invokeEffector(app, entities, TestEntity.MY_EFFECTOR);
+ try {
+ task.get();
+ } catch (Exception e) {
+ throw Exceptions.propagate(e);
+ }
+ }}));
}
}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3384c7eb/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/FilePersistencePerformanceTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/FilePersistencePerformanceTest.java b/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/FilePersistencePerformanceTest.java
index 594b102..364a673 100644
--- a/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/FilePersistencePerformanceTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/FilePersistencePerformanceTest.java
@@ -24,10 +24,12 @@ import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.brooklyn.core.mgmt.persist.FileBasedStoreObjectAccessor;
+import org.apache.brooklyn.test.performance.PerformanceTestDescriptor;
import org.apache.brooklyn.util.collections.MutableList;
import org.apache.brooklyn.util.collections.MutableMap;
import org.apache.brooklyn.util.core.internal.ssh.process.ProcessTool;
import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.io.FileUtil;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
@@ -71,10 +73,14 @@ public class FilePersistencePerformanceTest extends AbstractPerformanceTest {
double minRatePerSec = 100 * PERFORMANCE_EXPECTATION;
final AtomicInteger i = new AtomicInteger();
- measureAndAssert("FileBasedStoreObjectAccessor.put", numIterations, minRatePerSec, new Runnable() {
- public void run() {
- fileAccessor.put(""+i.incrementAndGet());
- }});
+ measure(PerformanceTestDescriptor.create()
+ .summary("FilePersistencePerformanceTest.testFileBasedStoreObjectPuts")
+ .iterations(numIterations)
+ .minAcceptablePerSecond(minRatePerSec)
+ .job(new Runnable() {
+ public void run() {
+ fileAccessor.put(""+i.incrementAndGet());
+ }}));
}
@Test(groups={"Integration", "Acceptance"})
@@ -83,10 +89,14 @@ public class FilePersistencePerformanceTest extends AbstractPerformanceTest {
int numIterations = numIterations();
double minRatePerSec = 100 * PERFORMANCE_EXPECTATION;
- measureAndAssert("FileBasedStoreObjectAccessor.get", numIterations, minRatePerSec, new Runnable() {
- public void run() {
- fileAccessor.get();
- }});
+ measure(PerformanceTestDescriptor.create()
+ .summary("FilePersistencePerformanceTest.testFileBasedStoreObjectGet")
+ .iterations(numIterations)
+ .minAcceptablePerSecond(minRatePerSec)
+ .job(new Runnable() {
+ public void run() {
+ fileAccessor.get();
+ }}));
}
@Test(groups={"Integration", "Acceptance"})
@@ -105,12 +115,16 @@ public class FilePersistencePerformanceTest extends AbstractPerformanceTest {
final AtomicInteger i = new AtomicInteger();
try {
- measureAndAssert("FileBasedStoreObjectAccessor.delete", numIterations, minRatePerSec, new Runnable() {
- public void run() {
- File file = files.get(i.getAndIncrement());
- FileBasedStoreObjectAccessor fileAccessor = new FileBasedStoreObjectAccessor(file, "mytmpextension");
- fileAccessor.delete();
- }});
+ measure(PerformanceTestDescriptor.create()
+ .summary("FilePersistencePerformanceTest.testFileBasedStoreObjectDelete")
+ .iterations(numIterations)
+ .minAcceptablePerSecond(minRatePerSec)
+ .job(new Runnable() {
+ public void run() {
+ File file = files.get(i.getAndIncrement());
+ FileBasedStoreObjectAccessor fileAccessor = new FileBasedStoreObjectAccessor(file, "mytmpextension");
+ fileAccessor.delete();
+ }}));
} finally {
for (File file : files) {
if (file != null) file.delete();
@@ -118,17 +132,51 @@ public class FilePersistencePerformanceTest extends AbstractPerformanceTest {
}
}
+ @Test(groups={"Integration", "Acceptance"})
+ public void testFileUtilSetFilePermissions() throws IOException {
+ int numIterations = numIterations();
+ double minRatePerSec = 10 * PERFORMANCE_EXPECTATION;
+
+ final File file = File.createTempFile("filePermissions", ".txt");
+
+ try {
+ measure(PerformanceTestDescriptor.create()
+ .summary("FilePersistencePerformanceTest.testFileUtilSetFilePermissions")
+ .iterations(numIterations)
+ .minAcceptablePerSecond(minRatePerSec)
+ .job(new Runnable() {
+ int i = 0;
+ public void run() {
+ try {
+ if (i % 2 == 0) {
+ FileUtil.setFilePermissionsTo600(file);
+ } else {
+ FileUtil.setFilePermissionsTo700(file);
+ }
+ } catch (Exception e) {
+ throw Exceptions.propagate(e);
+ }
+ }}));
+ } finally {
+ file.delete();
+ }
+ }
+
// fileAccessor.put() is implemented with an execCommands("mv") so look at performance of just that piece
@Test(groups={"Integration", "Acceptance"})
public void testProcessToolExecCommand() {
int numIterations = numIterations();
double minRatePerSec = 10 * PERFORMANCE_EXPECTATION;
- measureAndAssert("ProcessTool.exec", numIterations, minRatePerSec, new Runnable() {
- public void run() {
- String cmd = "true";
- new ProcessTool().execCommands(MutableMap.<String,String>of(), MutableList.of(cmd), null);
- }});
+ measure(PerformanceTestDescriptor.create()
+ .summary("FilePersistencePerformanceTest.testProcessToolExecCommand")
+ .iterations(numIterations)
+ .minAcceptablePerSecond(minRatePerSec)
+ .job(new Runnable() {
+ public void run() {
+ String cmd = "true";
+ new ProcessTool().execCommands(MutableMap.<String,String>of(), MutableList.of(cmd), null);
+ }}));
}
@Test(groups={"Integration", "Acceptance"})
@@ -139,12 +187,16 @@ public class FilePersistencePerformanceTest extends AbstractPerformanceTest {
final File parentDir = file.getParentFile();
final AtomicInteger i = new AtomicInteger();
- measureAndAssert("java.util.File.rename", numIterations, minRatePerSec, new Runnable() {
- public void run() {
- File newFile = new File(parentDir, "fileRename-"+i.incrementAndGet()+".txt");
- file.renameTo(newFile);
- file = newFile;
- }});
+ measure(PerformanceTestDescriptor.create()
+ .summary("FilePersistencePerformanceTest.testJavaUtilFileRenames")
+ .iterations(numIterations)
+ .minAcceptablePerSecond(minRatePerSec)
+ .job(new Runnable() {
+ public void run() {
+ File newFile = new File(parentDir, "fileRename-"+i.incrementAndGet()+".txt");
+ file.renameTo(newFile);
+ file = newFile;
+ }}));
}
@Test(groups={"Integration", "Acceptance"})
@@ -154,14 +206,18 @@ public class FilePersistencePerformanceTest extends AbstractPerformanceTest {
final AtomicInteger i = new AtomicInteger();
- measureAndAssert("guava.Files.write", numIterations, minRatePerSec, new Runnable() {
- public void run() {
- try {
- Files.write(""+i.incrementAndGet(), file, Charsets.UTF_8);
- } catch (IOException e) {
- throw Exceptions.propagate(e);
- }
- }});
+ measure(PerformanceTestDescriptor.create()
+ .summary("FilePersistencePerformanceTest.testGuavaFileWrites")
+ .iterations(numIterations)
+ .minAcceptablePerSecond(minRatePerSec)
+ .job(new Runnable() {
+ public void run() {
+ try {
+ Files.write(""+i.incrementAndGet(), file, Charsets.UTF_8);
+ } catch (IOException e) {
+ throw Exceptions.propagate(e);
+ }
+ }}));
}
@Test(groups={"Integration", "Acceptance"})
@@ -172,15 +228,19 @@ public class FilePersistencePerformanceTest extends AbstractPerformanceTest {
final File parentDir = file.getParentFile();
final AtomicInteger i = new AtomicInteger();
- measureAndAssert("guava.Files.move", numIterations, minRatePerSec, new Runnable() {
- public void run() {
- File newFile = new File(parentDir, "fileRename-"+i.incrementAndGet()+".txt");
- try {
- Files.move(file, newFile);
- } catch (IOException e) {
- throw Exceptions.propagate(e);
- }
- file = newFile;
- }});
+ measure(PerformanceTestDescriptor.create()
+ .summary("FilePersistencePerformanceTest.testGuavaFileMoves")
+ .iterations(numIterations)
+ .minAcceptablePerSecond(minRatePerSec)
+ .job(new Runnable() {
+ public void run() {
+ File newFile = new File(parentDir, "fileRename-"+i.incrementAndGet()+".txt");
+ try {
+ Files.move(file, newFile);
+ } catch (IOException e) {
+ throw Exceptions.propagate(e);
+ }
+ file = newFile;
+ }}));
}
}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3384c7eb/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/GroovyYardStickPerformanceTest.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/GroovyYardStickPerformanceTest.groovy b/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/GroovyYardStickPerformanceTest.groovy
index c269816..3940b49 100644
--- a/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/GroovyYardStickPerformanceTest.groovy
+++ b/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/GroovyYardStickPerformanceTest.groovy
@@ -24,6 +24,7 @@ import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.concurrent.atomic.AtomicInteger
+import org.apache.brooklyn.test.performance.PerformanceTestDescriptor;
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.testng.annotations.AfterMethod
@@ -56,7 +57,11 @@ public class GroovyYardStickPerformanceTest extends AbstractPerformanceTest {
double minRatePerSec = 1000000 * PERFORMANCE_EXPECTATION;
AtomicInteger i = new AtomicInteger();
- measureAndAssert("noop-groovy", numIterations, minRatePerSec, { i.incrementAndGet() });
+ measure(MeasurementOptions.create()
+ .summary("GroovyYardStickPerformanceTest.noop")
+ .iterations(numIterations)
+ .minAcceptablePerSecond(minRatePerSec)
+ .job({ i.incrementAndGet() }));
assertTrue(i.get() >= numIterations, "i="+i);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3384c7eb/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/JavaYardStickPerformanceTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/JavaYardStickPerformanceTest.java b/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/JavaYardStickPerformanceTest.java
index e5d4807..84c60ca 100644
--- a/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/JavaYardStickPerformanceTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/JavaYardStickPerformanceTest.java
@@ -24,6 +24,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
+import org.apache.brooklyn.test.performance.PerformanceTestDescriptor;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
@@ -53,10 +54,14 @@ public class JavaYardStickPerformanceTest extends AbstractPerformanceTest {
int numIterations = 1000000;
double minRatePerSec = 1000000 * PERFORMANCE_EXPECTATION;
final int[] i = {0};
- measureAndAssert("noop-java", numIterations, minRatePerSec, new Runnable() {
- @Override public void run() {
- i[0] = i[0] + 1;
- }});
+ measure(PerformanceTestDescriptor.create()
+ .summary("JavaYardStickPerformanceTest.noop")
+ .iterations(numIterations)
+ .minAcceptablePerSecond(minRatePerSec)
+ .job(new Runnable() {
+ @Override public void run() {
+ i[0] = i[0] + 1;
+ }}));
assertTrue(i[0] >= numIterations, "i="+i);
}
@@ -66,15 +71,19 @@ public class JavaYardStickPerformanceTest extends AbstractPerformanceTest {
int numIterations = 100000;
double minRatePerSec = 100000 * PERFORMANCE_EXPECTATION;
final int[] i = {0};
- measureAndAssert("scheduleExecuteAndGet-java", numIterations, minRatePerSec, new Runnable() {
- @Override public void run() {
- Future<?> future = executor.submit(new Runnable() { public void run() { i[0] = i[0] + 1; }});
- try {
- future.get();
- } catch (Exception e) {
- throw Throwables.propagate(e);
- }
- }});
+ measure(PerformanceTestDescriptor.create()
+ .summary("JavaYardStickPerformanceTest.scheduleExecuteAndGet")
+ .iterations(numIterations)
+ .minAcceptablePerSecond(minRatePerSec)
+ .job(new Runnable() {
+ @Override public void run() {
+ Future<?> future = executor.submit(new Runnable() { public void run() { i[0] = i[0] + 1; }});
+ try {
+ future.get();
+ } catch (Exception e) {
+ throw Throwables.propagate(e);
+ }
+ }}));
assertTrue(i[0] >= numIterations, "i="+i);
}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3384c7eb/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/SubscriptionPerformanceTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/SubscriptionPerformanceTest.java b/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/SubscriptionPerformanceTest.java
index 154c0e6..6f66f20 100644
--- a/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/SubscriptionPerformanceTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/SubscriptionPerformanceTest.java
@@ -18,11 +18,8 @@
*/
package org.apache.brooklyn.core.test.qa.performance;
-import static org.testng.Assert.assertTrue;
-
import java.util.List;
import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
@@ -31,8 +28,8 @@ import org.apache.brooklyn.api.mgmt.SubscriptionManager;
import org.apache.brooklyn.api.sensor.SensorEvent;
import org.apache.brooklyn.api.sensor.SensorEventListener;
import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.test.performance.PerformanceTestDescriptor;
import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.exceptions.Exceptions;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
@@ -41,7 +38,6 @@ import com.google.common.collect.Lists;
public class SubscriptionPerformanceTest extends AbstractPerformanceTest {
- private static final long LONG_TIMEOUT_MS = 30*1000;
private static final int NUM_ITERATIONS = 10000;
TestEntity entity;
@@ -81,22 +77,15 @@ public class SubscriptionPerformanceTest extends AbstractPerformanceTest {
}});
}
- measureAndAssert("updateAttributeWithManyPublishedOneSubscriber", numIterations, minRatePerSec,
- new Runnable() {
+ measure(PerformanceTestDescriptor.create()
+ .summary("SubscriptionPerformanceTest.testManyPublishedOneSubscriber")
+ .iterations(numIterations)
+ .minAcceptablePerSecond(minRatePerSec)
+ .job(new Runnable() {
public void run() {
entity.sensors().set(TestEntity.SEQUENCE, (iter.getAndIncrement()));
- }
- },
- new Runnable() {
- public void run() {
- try {
- completionLatch.await(LONG_TIMEOUT_MS, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {
- throw Exceptions.propagate(e);
- }
- assertTrue(completionLatch.getCount() <= 0);
- }
- });
+ }})
+ .completionLatch(completionLatch));
}
@Test(groups={"Integration", "Acceptance"})
@@ -118,20 +107,15 @@ public class SubscriptionPerformanceTest extends AbstractPerformanceTest {
}});
}
- measureAndAssert("updateAttributeWithManyListeners", numIterations, minRatePerSec,
- new Runnable() {
+ measure(PerformanceTestDescriptor.create()
+ .summary("SubscriptionPerformanceTest.testManyListenersForSensorEvent")
+ .iterations(numIterations)
+ .minAcceptablePerSecond(minRatePerSec)
+ .job(new Runnable() {
@Override public void run() {
entity.sensors().set(TestEntity.SEQUENCE, (iter.getAndIncrement()));
- }},
- new Runnable() {
- public void run() {
- try {
- completionLatch.await(LONG_TIMEOUT_MS, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {
- throw Exceptions.propagate(e);
- }
- assertTrue(completionLatch.getCount() <= 0);
- }});
+ }})
+ .completionLatch(completionLatch));
}
@Test(groups={"Integration", "Acceptance"})
@@ -155,10 +139,14 @@ public class SubscriptionPerformanceTest extends AbstractPerformanceTest {
}});
}
- measureAndAssert("updateAttributeWithUnrelatedListeners", numIterations, minRatePerSec, new Runnable() {
- @Override public void run() {
- entity.sensors().set(TestEntity.SEQUENCE, (iter.incrementAndGet()));
- }});
+ measure(PerformanceTestDescriptor.create()
+ .summary("SubscriptionPerformanceTest.testUpdateAttributeWithNoListenersButManyUnrelatedListeners")
+ .iterations(numIterations)
+ .minAcceptablePerSecond(minRatePerSec)
+ .job(new Runnable() {
+ @Override public void run() {
+ entity.sensors().set(TestEntity.SEQUENCE, (iter.incrementAndGet()));
+ }}));
if (exception.get() != null) {
throw exception.get();
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3384c7eb/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/TaskPerformanceTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/TaskPerformanceTest.java b/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/TaskPerformanceTest.java
index c80b27b..b0f9a07 100644
--- a/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/TaskPerformanceTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/test/qa/performance/TaskPerformanceTest.java
@@ -18,18 +18,18 @@
*/
package org.apache.brooklyn.core.test.qa.performance;
-import static org.testng.Assert.assertTrue;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.brooklyn.test.performance.PerformanceTestDescriptor;
import org.apache.brooklyn.util.collections.MutableMap;
import org.apache.brooklyn.util.core.task.BasicExecutionManager;
import org.apache.brooklyn.util.core.task.SingleThreadedScheduler;
import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.time.Duration;
import org.apache.brooklyn.util.time.Time;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -43,8 +43,6 @@ public class TaskPerformanceTest extends AbstractPerformanceTest {
private static final Logger LOG = LoggerFactory.getLogger(TaskPerformanceTest.class);
- private static final long LONG_TIMEOUT_MS = 30*1000;
-
BasicExecutionManager executionManager;
@BeforeMethod(alwaysRun=true)
@@ -71,20 +69,15 @@ public class TaskPerformanceTest extends AbstractPerformanceTest {
if (val >= numIterations) completionLatch.countDown();
}};
- measureAndAssert("executeSimplestRunnable", numIterations, minRatePerSec,
- new Runnable() {
+ measure(PerformanceTestDescriptor.create()
+ .summary("TaskPerformanceTest.testExecuteSimplestRunnable")
+ .iterations(numIterations)
+ .minAcceptablePerSecond(minRatePerSec)
+ .job(new Runnable() {
public void run() {
executionManager.submit(work);
- }},
- new Runnable() {
- public void run() {
- try {
- completionLatch.await(LONG_TIMEOUT_MS, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {
- throw Exceptions.propagate(e);
- }
- assertTrue(completionLatch.getCount() <= 0);
- }});
+ }})
+ .completionLatch(completionLatch));
}
@Test(groups={"Integration", "Acceptance"})
@@ -102,20 +95,15 @@ public class TaskPerformanceTest extends AbstractPerformanceTest {
final Map<String, ?> flags = MutableMap.of("tags", ImmutableList.of("a","b"));
- measureAndAssert("testExecuteRunnableWithTags", numIterations, minRatePerSec,
- new Runnable() {
+ measure(PerformanceTestDescriptor.create()
+ .summary("TaskPerformanceTest.testExecuteRunnableWithTags")
+ .iterations(numIterations)
+ .minAcceptablePerSecond(minRatePerSec)
+ .job(new Runnable() {
public void run() {
executionManager.submit(flags, work);
- }},
- new Runnable() {
- public void run() {
- try {
- completionLatch.await(LONG_TIMEOUT_MS, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {
- throw Exceptions.propagate(e);
- }
- assertTrue(completionLatch.getCount() <= 0);
- }});
+ }})
+ .completionLatch(completionLatch));
}
@Test(groups={"Integration", "Acceptance"})
@@ -146,8 +134,11 @@ public class TaskPerformanceTest extends AbstractPerformanceTest {
}
};
- measureAndAssert("testExecuteWithSingleThreadedScheduler", numIterations, minRatePerSec,
- new Runnable() {
+ measure(PerformanceTestDescriptor.create()
+ .summary("TaskPerformanceTest.testExecuteWithSingleThreadedScheduler")
+ .iterations(numIterations)
+ .minAcceptablePerSecond(minRatePerSec)
+ .job(new Runnable() {
public void run() {
while (submitCount.get() > counter.get() + 5000) {
LOG.info("delaying because "+submitCount.get()+" submitted and only "+counter.get()+" run");
@@ -155,16 +146,8 @@ public class TaskPerformanceTest extends AbstractPerformanceTest {
}
executionManager.submit(MutableMap.of("tags", ImmutableList.of("singlethreaded")), work);
submitCount.incrementAndGet();
- }},
- new Runnable() {
- public void run() {
- try {
- completionLatch.await(LONG_TIMEOUT_MS, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {
- throw Exceptions.propagate(e);
- }
- assertTrue(completionLatch.getCount() <= 0);
- }});
+ }})
+ .completionLatch(completionLatch));
if (exceptions.size() > 0) throw exceptions.get(0);
}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3384c7eb/locations/jclouds/src/test/java/org/apache/brooklyn/core/mgmt/persist/jclouds/BlobStorePersistencePerformanceTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/core/mgmt/persist/jclouds/BlobStorePersistencePerformanceTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/core/mgmt/persist/jclouds/BlobStorePersistencePerformanceTest.java
index 9690c00..bcba953 100644
--- a/locations/jclouds/src/test/java/org/apache/brooklyn/core/mgmt/persist/jclouds/BlobStorePersistencePerformanceTest.java
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/core/mgmt/persist/jclouds/BlobStorePersistencePerformanceTest.java
@@ -26,6 +26,7 @@ import org.apache.brooklyn.core.mgmt.persist.PersistMode;
import org.apache.brooklyn.core.mgmt.persist.PersistenceObjectStore.StoreObjectAccessor;
import org.apache.brooklyn.core.mgmt.persist.jclouds.JcloudsBlobStoreBasedObjectStore;
import org.apache.brooklyn.core.test.qa.performance.AbstractPerformanceTest;
+import org.apache.brooklyn.test.performance.PerformanceTestDescriptor;
import org.apache.brooklyn.util.text.Identifiers;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
@@ -75,10 +76,14 @@ public class BlobStorePersistencePerformanceTest extends AbstractPerformanceTest
double minRatePerSec = 10 * PERFORMANCE_EXPECTATION;
final AtomicInteger i = new AtomicInteger();
- measureAndAssert("StoreObjectAccessor.put", numIterations, minRatePerSec, new Runnable() {
- public void run() {
- blobstoreAccessor.put(""+i.incrementAndGet());
- }});
+ measure(PerformanceTestDescriptor.create()
+ .summary("StoreObjectAccessor.put")
+ .iterations(numIterations)
+ .minAcceptablePerSecond(minRatePerSec)
+ .job(new Runnable() {
+ public void run() {
+ blobstoreAccessor.put(""+i.incrementAndGet());
+ }}));
}
@Test(groups={"Live", "Acceptance"})
@@ -87,10 +92,14 @@ public class BlobStorePersistencePerformanceTest extends AbstractPerformanceTest
int numIterations = numIterations();
double minRatePerSec = 10 * PERFORMANCE_EXPECTATION;
- measureAndAssert("FileBasedStoreObjectAccessor.get", numIterations, minRatePerSec, new Runnable() {
- public void run() {
- blobstoreAccessor.get();
- }});
+ measure(PerformanceTestDescriptor.create()
+ .summary("FileBasedStoreObjectAccessor.get")
+ .iterations(numIterations)
+ .minAcceptablePerSecond(minRatePerSec)
+ .job(new Runnable() {
+ public void run() {
+ blobstoreAccessor.get();
+ }}));
}
@Test(groups={"Live", "Acceptance"})
@@ -107,11 +116,15 @@ public class BlobStorePersistencePerformanceTest extends AbstractPerformanceTest
final AtomicInteger i = new AtomicInteger();
try {
- measureAndAssert("FileBasedStoreObjectAccessor.delete", numIterations, minRatePerSec, new Runnable() {
- public void run() {
- StoreObjectAccessor blobstoreAccessor = blobstoreAccessors.get(i.getAndIncrement());
- blobstoreAccessor.delete();
- }});
+ measure(PerformanceTestDescriptor.create()
+ .summary("FileBasedStoreObjectAccessor.delete")
+ .iterations(numIterations)
+ .minAcceptablePerSecond(minRatePerSec)
+ .job(new Runnable() {
+ public void run() {
+ StoreObjectAccessor blobstoreAccessor = blobstoreAccessors.get(i.getAndIncrement());
+ blobstoreAccessor.delete();
+ }}));
} finally {
for (StoreObjectAccessor blobstoreAccessor : blobstoreAccessors) {
blobstoreAccessor.delete();
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3384c7eb/usage/test-support/src/main/java/org/apache/brooklyn/test/PerformanceTestUtils.java
----------------------------------------------------------------------
diff --git a/usage/test-support/src/main/java/org/apache/brooklyn/test/PerformanceTestUtils.java b/usage/test-support/src/main/java/org/apache/brooklyn/test/PerformanceTestUtils.java
index da38791..c0e9a71 100644
--- a/usage/test-support/src/main/java/org/apache/brooklyn/test/PerformanceTestUtils.java
+++ b/usage/test-support/src/main/java/org/apache/brooklyn/test/PerformanceTestUtils.java
@@ -18,81 +18,9 @@
*/
package org.apache.brooklyn.test;
-import java.lang.management.ManagementFactory;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.TimeUnit;
-
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
-
-import org.apache.brooklyn.util.time.Duration;
-import org.apache.brooklyn.util.time.Time;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Stopwatch;
-
-public class PerformanceTestUtils {
-
- private static final Logger LOG = LoggerFactory.getLogger(PerformanceTestUtils.class);
-
- private static boolean hasLoggedProcessCpuTimeUnavailable;
-
- public static long getProcessCpuTime() {
- try {
- MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
- ObjectName osMBeanName = ObjectName.getInstance(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME);
- return (Long) mbeanServer.getAttribute(osMBeanName, "ProcessCpuTime");
- } catch (Exception e) {
- if (!hasLoggedProcessCpuTimeUnavailable) {
- hasLoggedProcessCpuTimeUnavailable = true;
- LOG.warn("ProcessCPuTime not available in local JVM MXBean "+ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME+" (only available in sun JVM?)");
- }
- return -1;
- }
- }
-
- /**
- * Creates a background thread that will log.info the CPU fraction usage repeatedly, sampling at the given period.
- * Callers <em>must</em> cancel the returned future, e.g. {@code future.cancel(true)}, otherwise it will keep
- * logging until the JVM exits.
- */
- public static Future<?> sampleProcessCpuTime(final Duration period, final String loggingContext) {
- final ExecutorService executor = Executors.newSingleThreadExecutor(new ThreadFactory() {
- @Override public Thread newThread(Runnable r) {
- Thread thread = new Thread(r, "brooklyn-sampleProcessCpuTime-"+loggingContext);
- thread.setDaemon(true); // let the JVM exit
- return thread;
- }});
- Future<?> future = executor.submit(new Runnable() {
- @Override public void run() {
- try {
- long prevCpuTime = getProcessCpuTime();
- if (prevCpuTime == -1) {
- LOG.warn("ProcessCPuTime not available; cannot sample; aborting");
- return;
- }
- while (true) {
- Stopwatch stopwatch = Stopwatch.createStarted();
- Thread.sleep(period.toMilliseconds());
- long currentCpuTime = getProcessCpuTime();
-
- long elapsedTime = stopwatch.elapsed(TimeUnit.MILLISECONDS);
- double fractionCpu = (elapsedTime > 0) ? ((double)currentCpuTime-prevCpuTime) / TimeUnit.MILLISECONDS.toNanos(elapsedTime) : -1;
- prevCpuTime = currentCpuTime;
-
- LOG.info("CPU fraction over last {} was {} ({})", new Object[] {
- Time.makeTimeStringRounded(elapsedTime), fractionCpu, loggingContext});
- }
- } catch (InterruptedException e) {
- return; // graceful termination
- } finally {
- executor.shutdownNow();
- }
- }});
- return future;
- }
+/**
+ * @deprecated since 0.9.0; see {@link org.apache.brooklyn.test.performance.PerformanceTestUtils}.
+ */
+@Deprecated
+public class PerformanceTestUtils extends org.apache.brooklyn.test.performance.PerformanceTestUtils {
}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3384c7eb/usage/test-support/src/main/java/org/apache/brooklyn/test/performance/FilePersister.java
----------------------------------------------------------------------
diff --git a/usage/test-support/src/main/java/org/apache/brooklyn/test/performance/FilePersister.java b/usage/test-support/src/main/java/org/apache/brooklyn/test/performance/FilePersister.java
new file mode 100644
index 0000000..3d4eaf6
--- /dev/null
+++ b/usage/test-support/src/main/java/org/apache/brooklyn/test/performance/FilePersister.java
@@ -0,0 +1,85 @@
+/*
+ * 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.brooklyn.test.performance;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.apache.brooklyn.util.time.Time;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Charsets;
+import com.google.common.io.Files;
+
+@Beta
+public class FilePersister implements MeasurementResultPersister {
+
+ private static final Logger LOG = LoggerFactory.getLogger(PerformanceTestUtils.class);
+
+ private final File dir;
+
+ public FilePersister(File dir) {
+ this.dir = dir;
+ }
+
+ @Override
+ public void persist(Date date, PerformanceTestDescriptor options, PerformanceTestResult result) {
+ try {
+ String dateStr = new SimpleDateFormat(Time.DATE_FORMAT_PREFERRED).format(date);
+
+ dir.mkdirs();
+
+ File file = new File(dir, "auto-test-results.txt");
+ file.createNewFile();
+ Files.append("date="+dateStr+"; test="+options+"; result="+result+"\n", file, Charsets.UTF_8);
+
+ File summaryFile = new File(dir, "auto-test-summary.txt");
+ summaryFile.createNewFile();
+ Files.append(
+ dateStr
+ +"\t"+options.summary
+ +"\t"+roundToSignificantFigures(result.ratePerSecond, 6)
+ +"\t"+result.duration
+ +(result.cpuTotalFraction != null ? "\t"+"cpu="+roundToSignificantFigures(result.cpuTotalFraction, 3) : "")
+ +"\n",
+ summaryFile, Charsets.UTF_8);
+
+ } catch (IOException e) {
+ LOG.warn("Failed to persist performance results to "+dir+" (continuing)", e);
+ }
+ }
+
+ // Code copied from http://stackoverflow.com/questions/202302/rounding-to-an-arbitrary-number-of-significant-digits
+ private double roundToSignificantFigures(double num, int n) {
+ if(num == 0) {
+ return 0;
+ }
+
+ final double d = Math.ceil(Math.log10(num < 0 ? -num: num));
+ final int power = n - (int) d;
+
+ final double magnitude = Math.pow(10, power);
+ final long shifted = Math.round(num*magnitude);
+ return shifted/magnitude;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3384c7eb/usage/test-support/src/main/java/org/apache/brooklyn/test/performance/Histogram.java
----------------------------------------------------------------------
diff --git a/usage/test-support/src/main/java/org/apache/brooklyn/test/performance/Histogram.java b/usage/test-support/src/main/java/org/apache/brooklyn/test/performance/Histogram.java
new file mode 100644
index 0000000..9c60eb0
--- /dev/null
+++ b/usage/test-support/src/main/java/org/apache/brooklyn/test/performance/Histogram.java
@@ -0,0 +1,89 @@
+/*
+ * 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.brooklyn.test.performance;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.time.Duration;
+import org.apache.brooklyn.util.time.Time;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.Maps;
+
+/**
+ * A simplistic histogram to store times in a number of buckets.
+ * The buckets are in nanoseconds, increasing in size in powers of two.
+ */
+@Beta
+public class Histogram {
+
+ // TODO Currently just does toString to get the values back out.
+
+ private final Map<Integer, Integer> counts = Maps.newLinkedHashMap();
+
+ public void add(long val, TimeUnit unit) {
+ add(unit.toNanos(val));
+ }
+
+ public void add(Duration val) {
+ add(val.toNanoseconds());
+ }
+
+ protected void add(long val) {
+ if (val < 0) throw new UnsupportedOperationException("Negative numbers not accepted: "+val);
+ int pow = getPower(val);
+ Integer count = counts.get(pow);
+ counts.put(pow, (count == null) ? 1 : count+1);
+ }
+
+ protected int getPower(long val) {
+ for (int i = 0; i < 64; i++) {
+ if (val < Math.pow(2, i)) {
+ return i;
+ }
+ }
+ return 64;
+ }
+
+ @Override
+ public String toString() {
+ if (counts.isEmpty()) return "<empty>";
+
+ StringBuilder result = new StringBuilder("{");
+ List<Integer> sortedPows = MutableList.copyOf(counts.keySet());
+ Collections.sort(sortedPows);
+ int minPow = sortedPows.get(0);
+ int maxPow = sortedPows.get(sortedPows.size()-1);
+ for (int i = minPow; i <= maxPow; i++) {
+ if (i != minPow) result.append(", ");
+ long lower = i == 0 ? 0 : (long) Math.pow(2, i-1);
+ long upper = (long) Math.pow(2, i);
+ Integer count = counts.get(i);
+ result.append(Time.makeTimeStringRounded(lower, TimeUnit.NANOSECONDS)
+ + "-" + Time.makeTimeStringRounded(upper, TimeUnit.NANOSECONDS)
+ + ": " + (count == null ? 0 : count));
+ }
+ result.append("}");
+ return result.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3384c7eb/usage/test-support/src/main/java/org/apache/brooklyn/test/performance/MeasurementResultPersister.java
----------------------------------------------------------------------
diff --git a/usage/test-support/src/main/java/org/apache/brooklyn/test/performance/MeasurementResultPersister.java b/usage/test-support/src/main/java/org/apache/brooklyn/test/performance/MeasurementResultPersister.java
new file mode 100644
index 0000000..cdf00e8
--- /dev/null
+++ b/usage/test-support/src/main/java/org/apache/brooklyn/test/performance/MeasurementResultPersister.java
@@ -0,0 +1,29 @@
+/*
+ * 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.brooklyn.test.performance;
+
+import java.util.Date;
+
+import com.google.common.annotations.Beta;
+
+@Beta
+public interface MeasurementResultPersister {
+
+ void persist(Date time, PerformanceTestDescriptor options, PerformanceTestResult result);
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3384c7eb/usage/test-support/src/main/java/org/apache/brooklyn/test/performance/PerformanceMeasurer.java
----------------------------------------------------------------------
diff --git a/usage/test-support/src/main/java/org/apache/brooklyn/test/performance/PerformanceMeasurer.java b/usage/test-support/src/main/java/org/apache/brooklyn/test/performance/PerformanceMeasurer.java
new file mode 100644
index 0000000..31802db
--- /dev/null
+++ b/usage/test-support/src/main/java/org/apache/brooklyn/test/performance/PerformanceMeasurer.java
@@ -0,0 +1,156 @@
+/*
+ * 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.brooklyn.test.performance;
+
+import static org.testng.Assert.fail;
+
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.time.Duration;
+import org.apache.brooklyn.util.time.Time;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.Lists;
+
+/**
+ * For running simplistic performance tests, to measure the number of operations per second.
+ *
+ * With a short run, this is "good enough" for eye-balling performance, to spot if it goes
+ * horrendously wrong.
+ *
+ * However, good performance measurement involves much more warm up (e.g. to ensure java HotSpot
+ * optimisation have been applied), and running the test for a reasonable length of time.
+ *
+ * Longevity tests are also important for to check if object creation is going to kill
+ * performance in the long-term, etc.
+ */
+@Beta
+public class PerformanceMeasurer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(PerformanceMeasurer.class);
+
+ /**
+ * Runs a performance test. Repeatedly executes the given job. It measuring either the time it takes for
+ * many iterations, or the number of iterations it can execute in a fixed time.
+ */
+ public static PerformanceTestResult run(PerformanceTestDescriptor options) {
+ options.seal();
+ long nextLogTime = (options.logInterval == null) ? Long.MAX_VALUE : options.logInterval.toMilliseconds();
+
+ // Try to force garbage collection before the test, so it interferes less with the measurement.
+ System.gc(); System.gc();
+
+ // Run some warm-up cycles.
+ Stopwatch warmupWatch = Stopwatch.createStarted();
+ int warmupCounter = 0;
+
+ while ((options.warmup != null) ? options.warmup.isLongerThan(warmupWatch) : warmupCounter < options.warmupIterations) {
+ if (warmupWatch.elapsed(TimeUnit.MILLISECONDS) >= nextLogTime) {
+ LOG.info("Warm-up "+options.summary+" iteration="+warmupCounter+" at "+Time.makeTimeStringRounded(warmupWatch));
+ nextLogTime += options.logInterval.toMilliseconds();
+ }
+ options.job.run();
+ warmupCounter++;
+ }
+ warmupWatch.stop();
+
+ // Run the actual test (for the given duration / iterations); then wait for completionLatch (if supplied).
+ nextLogTime = (options.logInterval == null) ? Long.MAX_VALUE : options.logInterval.toMilliseconds();
+ int counter = 0;
+ Histogram histogram = new Histogram();
+ List<Double> cpuSampleFractions = Lists.newLinkedList();
+ Future<?> sampleCpuFuture = null;
+ if (options.sampleCpuInterval != null) {
+ sampleCpuFuture = PerformanceTestUtils.sampleProcessCpuTime(options.sampleCpuInterval, options.summary, cpuSampleFractions);
+ }
+
+ try {
+ long preCpuTime = PerformanceTestUtils.getProcessCpuTime();
+ Stopwatch watch = Stopwatch.createStarted();
+
+ while ((options.duration != null) ? options.duration.isLongerThan(watch) : counter < options.iterations) {
+ if (warmupWatch.elapsed(TimeUnit.MILLISECONDS) >= nextLogTime) {
+ LOG.info(options.summary+" iteration="+counter+" at "+Time.makeTimeStringRounded(watch));
+ nextLogTime += options.logInterval.toMilliseconds();
+ }
+ long before = watch.elapsed(TimeUnit.NANOSECONDS);
+ options.job.run();
+ if (options.histogram) {
+ histogram.add(watch.elapsed(TimeUnit.NANOSECONDS) - before, TimeUnit.NANOSECONDS);
+ }
+ counter++;
+ }
+
+ if (options.completionLatch != null) {
+ try {
+ boolean success = options.completionLatch.await(options.completionLatchTimeout.toMilliseconds(), TimeUnit.MILLISECONDS);
+ if (!success) {
+ fail("Timeout waiting for completionLatch: test="+options+"; counter="+counter);
+ }
+ } catch (InterruptedException e) {
+ throw Exceptions.propagate(e);
+ }
+ }
+ watch.stop();
+ long postCpuTime = PerformanceTestUtils.getProcessCpuTime();
+
+ // Generate the results
+ PerformanceTestResult result = new PerformanceTestResult();
+ result.warmup = Duration.of(warmupWatch);
+ result.warmupIterations = warmupCounter;
+ result.duration = Duration.of(watch);
+ result.iterations = counter;
+ result.ratePerSecond = (((double)counter) / watch.elapsed(TimeUnit.MILLISECONDS)) * 1000;
+ result.cpuTotalFraction = (watch.elapsed(TimeUnit.NANOSECONDS) > 0 && preCpuTime >= 0)
+ ? ((double)postCpuTime-preCpuTime) / watch.elapsed(TimeUnit.NANOSECONDS)
+ : -1;
+ if (options.histogram) {
+ result.histogram = histogram;
+ }
+ if (options.sampleCpuInterval != null) {
+ result.cpuSampleFractions = cpuSampleFractions;
+ }
+ result.minAcceptablePerSecond = options.minAcceptablePerSecond;
+
+ // Persist the results
+ if (options.persister != null) {
+ options.persister.persist(new Date(), options, result);
+ }
+
+ // Fail if we didn't meet the minimum performance requirements
+ if (options.minAcceptablePerSecond != null && options.minAcceptablePerSecond > result.ratePerSecond) {
+ fail("Performance too low: test="+options+"; result="+result);
+ }
+
+ return result;
+
+ } finally {
+ if (sampleCpuFuture != null) {
+ sampleCpuFuture.cancel(true);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3384c7eb/usage/test-support/src/main/java/org/apache/brooklyn/test/performance/PerformanceTestDescriptor.java
----------------------------------------------------------------------
diff --git a/usage/test-support/src/main/java/org/apache/brooklyn/test/performance/PerformanceTestDescriptor.java b/usage/test-support/src/main/java/org/apache/brooklyn/test/performance/PerformanceTestDescriptor.java
new file mode 100644
index 0000000..89225c9
--- /dev/null
+++ b/usage/test-support/src/main/java/org/apache/brooklyn/test/performance/PerformanceTestDescriptor.java
@@ -0,0 +1,208 @@
+/*
+ * 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.brooklyn.test.performance;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.io.File;
+import java.util.concurrent.CountDownLatch;
+
+import org.apache.brooklyn.util.time.Duration;
+import org.apache.commons.io.FileUtils;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
+
+/**
+ * For building up a description of what to measure.
+ * <p>
+ * Users are strongly encouraged to call the setter methods, rather than accessing the fields
+ * directly. The fields may be made protected in a future release.
+ * <p>
+ * The following fields are compulsory:
+ * <ul>
+ * <li>{@link #job(Runnable)}
+ * <li>Exactly one of {@link #duration(Duration)} or {@link #iterations(int)}
+ * </ul>
+ *
+ * See {@link PerformanceTestUtils#run(PerformanceTestDescriptor)}.
+ */
+@Beta
+public class PerformanceTestDescriptor {
+ public String summary;
+ public Duration warmup;
+ public Integer warmupIterations;
+ public Duration duration;
+ public Integer iterations;
+ public Runnable job;
+ public CountDownLatch completionLatch;
+ public Duration completionLatchTimeout = Duration.FIVE_MINUTES;
+ public Double minAcceptablePerSecond;
+ public Duration sampleCpuInterval = Duration.ONE_SECOND;
+ public Duration logInterval = Duration.FIVE_SECONDS;
+ public boolean histogram = true;
+ public MeasurementResultPersister persister = new FilePersister(new File(FileUtils.getUserDirectory(), "brooklyn-performance"));
+ public boolean sealed;
+
+ public static PerformanceTestDescriptor create() {
+ return new PerformanceTestDescriptor();
+ }
+
+ public static PerformanceTestDescriptor create(String summary) {
+ return create().summary(summary);
+ }
+
+ public PerformanceTestDescriptor summary(String val) {
+ if (sealed) throw new IllegalStateException("Should not modify after sealed (e.g. after use)");
+ this.summary = val; return this;
+ }
+
+ /**
+ * The length of time to repeatedly execute the job for, before doing the proper performance
+ * test. At most one of {@link #warmup(Duration)} or {@link #warmupIterations(int)} should be
+ * set - if neither is set, the warmup defaults to one tenth of the test duration.
+ */
+ public PerformanceTestDescriptor warmup(Duration val) {
+ if (sealed) throw new IllegalStateException("Should not modify after sealed (e.g. after use)");
+ this.warmup = val; return this;
+ }
+
+ /**
+ * See {@link #warmup(Duration)}.
+ */
+ public PerformanceTestDescriptor warmupIterations(int val) {
+ if (sealed) throw new IllegalStateException("Should not modify after sealed (e.g. after use)");
+ this.warmupIterations = val; return this;
+ }
+
+ /**
+ * The length of time to repeatedly execute the job for, when measuring the performance.
+ * Exactly one of {@link #duration(Duration)} or {@link #iterations(int)} should be
+ * set.
+ */
+ public PerformanceTestDescriptor duration(Duration val) {
+ if (sealed) throw new IllegalStateException("Should not modify after sealed (e.g. after use)");
+ this.duration = val; return this;
+ }
+
+ /**
+ * See {@link #duration(Duration)}.
+ */
+ public PerformanceTestDescriptor iterations(int val) {
+ if (sealed) throw new IllegalStateException("Should not modify after sealed (e.g. after use)");
+ this.iterations = val; return this;
+ }
+
+ /**
+ * The job to be repeatedly executed.
+ */
+ public PerformanceTestDescriptor job(Runnable val) {
+ if (sealed) throw new IllegalStateException("Should not modify after sealed (e.g. after use)");
+ this.job = val; return this;
+ }
+
+ /**
+ * If non-null, the performance test will wait for this latch before stopping the timer.
+ * This is useful for asynchronous work. For example, 1000 iterations of the job might
+ * be executed that each submits work asynchronously, and then the latch signals when all
+ * of those 1000 tasks have completed.
+ */
+ public PerformanceTestDescriptor completionLatch(CountDownLatch val) {
+ if (sealed) throw new IllegalStateException("Should not modify after sealed (e.g. after use)");
+ this.completionLatch = val; return this;
+ }
+
+ /**
+ * The maximum length of time to wait for the {@link #completionLatch(CountDownLatch)}, after
+ * executing the designated number of jobs. If the latch has not completed within this time,
+ * then the test will fail.
+ */
+ public PerformanceTestDescriptor completionLatchTimeout(Duration val) {
+ if (sealed) throw new IllegalStateException("Should not modify after sealed (e.g. after use)");
+ this.completionLatchTimeout = val; return this;
+ }
+
+ /**
+ * If non-null, the measured jobs-per-second will be compared against this number. If the
+ * jobs-per-second is not high enough, then the test wil fail.
+ */
+ public PerformanceTestDescriptor minAcceptablePerSecond(Double val) {
+ if (sealed) throw new IllegalStateException("Should not modify after sealed (e.g. after use)");
+ this.minAcceptablePerSecond = val; return this;
+ }
+
+ /**
+ * Whether to collect a histogram of the individual job times. This histogram stores the count
+ * in buckets (e.g. number of jobs that took 1-2ms, number that took 2-4ms, number that took
+ * 4-8ms, etc).
+ */
+ public PerformanceTestDescriptor histogram(boolean val) {
+ if (sealed) throw new IllegalStateException("Should not modify after sealed (e.g. after use)");
+ this.histogram = val; return this;
+ }
+
+ /**
+ * How often to log progress (e.g. number of iterations completed so far). If null, then no
+ * progress will be logged.
+ */
+ public PerformanceTestDescriptor logInterval(Duration val) {
+ if (sealed) throw new IllegalStateException("Should not modify after sealed (e.g. after use)");
+ this.logInterval = val; return this;
+ }
+
+ /**
+ * How often to calculate + record the fraction of CPU being used. If null, then CPU usage
+ * will not be recorded.
+ */
+ public PerformanceTestDescriptor sampleCpuInterval(Duration val) {
+ if (sealed) throw new IllegalStateException("Should not modify after sealed (e.g. after use)");
+ this.sampleCpuInterval = val; return this;
+ }
+
+ public void seal() {
+ sealed = true;
+ assertNotNull(job, "Job must be supplied: "+toString());
+ assertTrue(duration != null ^ iterations != null, "Exactly one of duration or iterations must be set: "+toString());
+ assertFalse(warmup != null && warmupIterations != null, "At most one of duration and iterations must be set: "+toString());
+ if (warmup == null && warmupIterations == null) {
+ if (duration != null) warmup = Duration.millis(duration.toMilliseconds() / 10);
+ if (iterations != null) warmupIterations = iterations / 10;
+ }
+ if (summary == null) {
+ summary = job.toString();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(this)
+ .omitNullValues()
+ .add("summary", summary)
+ .add("duration", duration)
+ .add("warmup", warmup)
+ .add("iterations", iterations)
+ .add("warmupIterations", warmupIterations)
+ .add("job", job)
+ .add("completionLatch", completionLatch)
+ .add("minAcceptablePerSecond", minAcceptablePerSecond)
+ .toString();
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3384c7eb/usage/test-support/src/main/java/org/apache/brooklyn/test/performance/PerformanceTestResult.java
----------------------------------------------------------------------
diff --git a/usage/test-support/src/main/java/org/apache/brooklyn/test/performance/PerformanceTestResult.java b/usage/test-support/src/main/java/org/apache/brooklyn/test/performance/PerformanceTestResult.java
new file mode 100644
index 0000000..ee7362e
--- /dev/null
+++ b/usage/test-support/src/main/java/org/apache/brooklyn/test/performance/PerformanceTestResult.java
@@ -0,0 +1,62 @@
+/*
+ * 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.brooklyn.test.performance;
+
+import java.util.List;
+
+import org.apache.brooklyn.util.time.Duration;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
+
+/**
+ * The results of a performance test.
+ *
+ * See {@link PerformanceTestUtils#run(MeasurementOptions)}.
+ */
+@Beta
+public class PerformanceTestResult {
+ public String summary;
+ public Duration warmup;
+ public int warmupIterations;
+ public Duration duration;
+ public int iterations;
+ public double ratePerSecond;
+ public Histogram histogram;
+ public Double minAcceptablePerSecond;
+ public Double cpuTotalFraction;
+ public List<Double> cpuSampleFractions;
+
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(this)
+ .omitNullValues()
+ .add("summary", summary)
+ .add("duration", duration)
+ .add("warmup", warmup)
+ .add("iterations", iterations)
+ .add("warmupIterations", warmupIterations)
+ .add("ratePerSecond", ratePerSecond)
+ .add("histogram", histogram)
+ .add("cpuTotalFraction", cpuTotalFraction)
+ .add("cpuSampleFractions", cpuSampleFractions)
+ .add("minAcceptablePerSecond", minAcceptablePerSecond)
+ .toString();
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3384c7eb/usage/test-support/src/main/java/org/apache/brooklyn/test/performance/PerformanceTestUtils.java
----------------------------------------------------------------------
diff --git a/usage/test-support/src/main/java/org/apache/brooklyn/test/performance/PerformanceTestUtils.java b/usage/test-support/src/main/java/org/apache/brooklyn/test/performance/PerformanceTestUtils.java
new file mode 100644
index 0000000..c747e8b
--- /dev/null
+++ b/usage/test-support/src/main/java/org/apache/brooklyn/test/performance/PerformanceTestUtils.java
@@ -0,0 +1,107 @@
+/*
+ * 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.brooklyn.test.performance;
+
+import java.lang.management.ManagementFactory;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.brooklyn.util.time.Duration;
+import org.apache.brooklyn.util.time.Time;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Stopwatch;
+
+public class PerformanceTestUtils {
+
+ private static final Logger LOG = LoggerFactory.getLogger(PerformanceTestUtils.class);
+
+ private static boolean hasLoggedProcessCpuTimeUnavailable;
+
+ public static long getProcessCpuTime() {
+ try {
+ MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
+ ObjectName osMBeanName = ObjectName.getInstance(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME);
+ return (Long) mbeanServer.getAttribute(osMBeanName, "ProcessCpuTime");
+ } catch (Exception e) {
+ if (!hasLoggedProcessCpuTimeUnavailable) {
+ hasLoggedProcessCpuTimeUnavailable = true;
+ LOG.warn("ProcessCPuTime not available in local JVM MXBean "+ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME+" (only available in sun JVM?)");
+ }
+ return -1;
+ }
+ }
+
+ /**
+ * Creates a background thread that will log.info the CPU fraction usage repeatedly, sampling at the given period.
+ * Callers <em>must</em> cancel the returned future, e.g. {@code future.cancel(true)}, otherwise it will keep
+ * logging until the JVM exits.
+ */
+ public static Future<?> sampleProcessCpuTime(final Duration period, final String loggingContext) {
+ return sampleProcessCpuTime(period, loggingContext, null);
+ }
+
+ public static Future<?> sampleProcessCpuTime(final Duration period, final String loggingContext, final List<Double> cpuFractions) {
+ final ExecutorService executor = Executors.newSingleThreadExecutor(new ThreadFactory() {
+ @Override public Thread newThread(Runnable r) {
+ Thread thread = new Thread(r, "brooklyn-sampleProcessCpuTime-"+loggingContext);
+ thread.setDaemon(true); // let the JVM exit
+ return thread;
+ }});
+ Future<?> future = executor.submit(new Runnable() {
+ @Override public void run() {
+ try {
+ long prevCpuTime = getProcessCpuTime();
+ if (prevCpuTime == -1) {
+ LOG.warn("ProcessCPuTime not available; cannot sample; aborting");
+ return;
+ }
+ while (true) {
+ Stopwatch stopwatch = Stopwatch.createStarted();
+ Thread.sleep(period.toMilliseconds());
+ long currentCpuTime = getProcessCpuTime();
+
+ long elapsedTime = stopwatch.elapsed(TimeUnit.MILLISECONDS);
+ double fractionCpu = (elapsedTime > 0) ? ((double)currentCpuTime-prevCpuTime) / TimeUnit.MILLISECONDS.toNanos(elapsedTime) : -1;
+ prevCpuTime = currentCpuTime;
+
+ LOG.info("CPU fraction over last {} was {} ({})", new Object[] {
+ Time.makeTimeStringRounded(elapsedTime), fractionCpu, loggingContext});
+
+ if (cpuFractions != null) {
+ cpuFractions.add(fractionCpu);
+ }
+ }
+ } catch (InterruptedException e) {
+ return; // graceful termination
+ } finally {
+ executor.shutdownNow();
+ }
+ }});
+ return future;
+ }
+}
[3/3] incubator-brooklyn git commit: This closes #1027
Posted by al...@apache.org.
This closes #1027
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/2b23266e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/2b23266e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/2b23266e
Branch: refs/heads/master
Commit: 2b23266eb2beb141fc09fadaa4e85d9571e98be5
Parents: ca89ed4 30d22d1
Author: Aled Sage <al...@gmail.com>
Authored: Fri Nov 13 17:10:42 2015 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Fri Nov 13 17:10:42 2015 +0000
----------------------------------------------------------------------
.../FileBasedStoreObjectAccessorWriterTest.java | 18 --
.../qa/performance/AbstractPerformanceTest.java | 47 ++++-
.../qa/performance/EntityPerformanceTest.java | 84 +++++---
.../FilePersistencePerformanceTest.java | 146 +++++++++----
.../GroovyYardStickPerformanceTest.groovy | 7 +-
.../JavaYardStickPerformanceTest.java | 35 ++--
.../SubscriptionPerformanceTest.java | 58 ++----
.../qa/performance/TaskPerformanceTest.java | 63 ++----
.../BlobStorePersistencePerformanceTest.java | 39 ++--
.../brooklyn/test/PerformanceTestUtils.java | 82 +-------
.../test/performance/FilePersister.java | 85 ++++++++
.../brooklyn/test/performance/Histogram.java | 89 ++++++++
.../performance/MeasurementResultPersister.java | 29 +++
.../test/performance/PerformanceMeasurer.java | 156 ++++++++++++++
.../performance/PerformanceTestDescriptor.java | 208 +++++++++++++++++++
.../test/performance/PerformanceTestResult.java | 62 ++++++
.../test/performance/PerformanceTestUtils.java | 107 ++++++++++
17 files changed, 1041 insertions(+), 274 deletions(-)
----------------------------------------------------------------------
[2/3] incubator-brooklyn git commit: Delete duplicate
testFilePermissionsPerformance
Posted by al...@apache.org.
Delete duplicate testFilePermissionsPerformance
This is already covered by
FilePersistencePerformanceTest.testFileBasedStoreObjectPuts
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/30d22d10
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/30d22d10
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/30d22d10
Branch: refs/heads/master
Commit: 30d22d100b431c2eb5acf01a7722ec92e089ba18
Parents: 3384c7e
Author: Aled Sage <al...@gmail.com>
Authored: Fri Nov 13 00:00:04 2015 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Fri Nov 13 14:55:15 2015 +0000
----------------------------------------------------------------------
.../FileBasedStoreObjectAccessorWriterTest.java | 18 ------------------
1 file changed, 18 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/30d22d10/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/FileBasedStoreObjectAccessorWriterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/FileBasedStoreObjectAccessorWriterTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/FileBasedStoreObjectAccessorWriterTest.java
index f6db2df..d131128 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/FileBasedStoreObjectAccessorWriterTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/FileBasedStoreObjectAccessorWriterTest.java
@@ -22,7 +22,6 @@ import static org.testng.Assert.assertEquals;
import java.io.File;
import java.io.IOException;
-import java.util.concurrent.TimeUnit;
import org.apache.brooklyn.core.mgmt.persist.PersistenceObjectStore.StoreObjectAccessorWithLock;
import org.apache.brooklyn.util.os.Os;
@@ -30,7 +29,6 @@ import org.apache.brooklyn.util.time.Duration;
import org.testng.annotations.Test;
import com.google.common.base.Charsets;
-import com.google.common.base.Stopwatch;
import com.google.common.collect.ImmutableList;
import com.google.common.io.Files;
@@ -89,20 +87,4 @@ public class FileBasedStoreObjectAccessorWriterTest extends PersistenceStoreObje
accessor.delete();
}
}
-
- @Test(groups={"Integration", "Acceptance"})
- public void testFilePermissionsPerformance() throws Exception {
- long interval = 10 * 1000; // millis
- long start = System.currentTimeMillis();
-
- int count = 0;
- Stopwatch stopwatch = Stopwatch.createStarted();
- while (System.currentTimeMillis() < start + interval) {
- accessor.put("abc" + count);
- count++;
- }
- stopwatch.stop();
- double writesPerSec = ((double)count) / stopwatch.elapsed(TimeUnit.MILLISECONDS) * 1000;
- System.out.println("writes per second: " + writesPerSec);
- }
}