/* | |
* 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.tuscany.sca.test.performance; | |
import static org.junit.Assert.assertEquals; | |
import static org.junit.Assert.assertNotNull; | |
import static org.junit.Assert.fail; | |
import java.io.BufferedWriter; | |
import java.io.File; | |
import java.io.FileWriter; | |
import java.lang.management.ManagementFactory; | |
import java.lang.management.MemoryMXBean; | |
import java.lang.management.OperatingSystemMXBean; | |
import java.lang.ref.WeakReference; | |
import javax.management.MBeanServer; | |
import org.apache.tuscany.sca.Node; | |
import org.apache.tuscany.sca.TuscanyRuntime; | |
import org.apache.tuscany.sca.core.ExtensionPointRegistry; | |
import org.apache.tuscany.sca.core.FactoryExtensionPoint; | |
import org.apache.tuscany.sca.core.UtilityExtensionPoint; | |
import org.apache.tuscany.sca.databinding.jaxb.JAXBContextHelper; | |
import org.apache.tuscany.sca.impl.NodeImpl; | |
import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; | |
import org.apache.tuscany.sca.interfacedef.java.impl.JavaInterfaceFactoryImpl; | |
import org.apache.tuscany.sca.test.performance.client.BeanA; | |
import org.apache.tuscany.sca.test.performance.client.Helloworld; | |
import org.junit.AfterClass; | |
import org.junit.Assert; | |
import org.junit.BeforeClass; | |
import org.junit.Test; | |
import com.sun.management.HotSpotDiagnosticMXBean; | |
/* | |
* A test looking at memory and runtime performance. | |
* TODO - only a couple of memory tests to start with | |
*/ | |
public class PerformanceTestCase { | |
public boolean writeHeapDump = true; | |
private static BufferedWriter resultsFile = null; | |
private TuscanyRuntime runtime; | |
private Node node; | |
private ExtensionPointRegistry extensionPointRegistry; | |
private long lastTotal = 0; | |
private long lastFree = 0; | |
private long lastUsed = 0; | |
@BeforeClass | |
public static void setUp() throws Exception { | |
FileWriter fileWriter = new FileWriter("out.txt"); | |
resultsFile = new BufferedWriter(fileWriter); | |
} | |
@AfterClass | |
public static void tearDown() throws Exception { | |
resultsFile.flush(); | |
resultsFile.close(); | |
} | |
@Test | |
public void testNodeStartStop() { | |
dumpHeapStart("testInstallUninstall"); | |
printRuntimeStats("createRuntime"); | |
createRuntime(); | |
callNodeStartStopRepeatedly(100); | |
waitForInput(); | |
dumpHeapEnd("testInstallUninstall_postNodeStop"); | |
printRuntimeStats("stopRuntime"); | |
stopRuntime(); | |
printRuntimeStats("destroyRuntime"); | |
destroyRuntime(); | |
printRuntimeStats("End"); | |
dumpHeapEnd("testInstallUninstall_postStop"); | |
} | |
@Test | |
public void testInstallUninstall() { | |
dumpHeapStart("testInstallUninstall"); | |
printRuntimeStats("createRuntime"); | |
createRuntime(); | |
printRuntimeStats("createNode"); | |
createNode(); | |
callInstallUninstallRepeatedly(100); | |
dumpHeapEnd("testInstallUninstall_postUninstall"); | |
checkCacheStatus(); | |
printRuntimeStats("stopNode"); | |
stopNode(); | |
printRuntimeStats("destroyNode"); | |
destroyNode(); | |
printRuntimeStats("stopRuntime"); | |
stopRuntime(); | |
printRuntimeStats("destroyRuntime"); | |
destroyRuntime(); | |
printRuntimeStats("End"); | |
dumpHeapEnd("testInstallUninstall_postStop"); | |
} | |
@Test | |
public void testCall() { | |
dumpHeapStart("TestCall"); | |
printRuntimeStats("createRuntime"); | |
createRuntime(); | |
printRuntimeStats("createNode"); | |
createNode(); | |
printRuntimeStats("installContribution"); | |
installContribution(); | |
printRuntimeStats("startNode"); | |
startComposite(); | |
printRuntimeStats("callServiceRepeatedly 10000 times"); | |
callServiceRepeatedly(10000); | |
printRuntimeStats("stopCompositeAndUninstallUnused"); | |
stopCompositeAndUninstallUnused(); | |
//printRuntimeStats("uninstallContribution"); | |
//uninstallContribution(); | |
dumpHeapEnd("TestCall_postUninstall"); | |
printRuntimeStats("stopNode"); | |
stopNode(); | |
printRuntimeStats("destroyNode"); | |
destroyNode(); | |
printRuntimeStats("stopRuntime"); | |
stopRuntime(); | |
printRuntimeStats("destroyRuntime"); | |
destroyRuntime(); | |
printRuntimeStats("End"); | |
dumpHeapEnd("TestCall_postStop"); | |
} | |
public void checkCacheStatus(){ | |
UtilityExtensionPoint utilityExtensionPoint = extensionPointRegistry.getExtensionPoint(UtilityExtensionPoint.class); | |
JAXBContextHelper jaxbContextHelper = utilityExtensionPoint.getUtility(JAXBContextHelper.class); | |
Assert.assertEquals("JAXBContextCache > 1", 1, jaxbContextHelper.getJAXBContextCache().getCache().keySet().size()); | |
FactoryExtensionPoint factoryExtensionPoint = extensionPointRegistry.getExtensionPoint(FactoryExtensionPoint.class); | |
JavaInterfaceFactory javaInterfaceFactory = factoryExtensionPoint.getFactory(JavaInterfaceFactory.class); | |
Assert.assertEquals("JavaInterfaceFactoryImpl.normalCache > 1", 1, ((JavaInterfaceFactoryImpl)javaInterfaceFactory).getNormalCache().keySet().size()); | |
} | |
// ============================================================ | |
public void callNodeStartStopRepeatedly(int repeatCount) { | |
for (int i =0; i < repeatCount; i++){ | |
printRuntimeStats("createNode"); | |
createNode(); | |
callInstallUninstallRepeatedly(1); | |
printRuntimeStats("stopNode"); | |
stopNode(); | |
printRuntimeStats("destroyNode"); | |
destroyNode(); | |
} | |
} | |
public void callInstallUninstallRepeatedly(int repeatCount) { | |
for (int i =0; i < repeatCount; i++){ | |
printRuntimeStats("install/unistall contribution"); | |
installContribution(); | |
startComposite(); | |
callService(); | |
stopCompositeAndUninstallUnused(); | |
//uninstallContribution(); | |
} | |
} | |
public void callServiceRepeatedly(int repeatCount) { | |
for (int i =0; i < repeatCount; i++){ | |
callService(); | |
} | |
} | |
// ============================================================ | |
public void dumpHeapStart(String name){ | |
if (writeHeapDump){ | |
dumpHeap("heap_start_" + name + ".bin"); | |
} | |
} | |
public void dumpHeapEnd(String name){ | |
if (writeHeapDump){ | |
dumpHeap("heap_stop_" + name + ".bin"); | |
System.out.println("You can watch a JVM run using \n" + | |
" jconsole \n" + | |
"You can manually dump the heap using \n" + | |
" jmap -dump:file=heap_stop_" + name + ".bin 345" + | |
"Where 345 is the process id from jconsole \n" + | |
"The program dumps the heap at the start and end. You can look at them using \n" + | |
" jhat -J-Xmx512m heap_start.bin\n" + | |
" jhat -J-Xmx512m heap_stop_" + name + ".bin\n" + | |
"Then point your browser at\n" + | |
" http://localhost:7000/"); | |
} else { | |
System.out.println("NO HEAP DUMPS WRITTEN"); | |
} | |
} | |
public void createRuntime() { | |
runtime = TuscanyRuntime.newInstance(); | |
} | |
public void createNode() { | |
node = runtime.createNode("default"); | |
extensionPointRegistry = ((NodeImpl)node).getExtensionPointRegistry(); | |
} | |
public void installContribution() { | |
try { | |
node.installContribution("performance", "../performance-contribution1/target/itest-performance-contribution1-2.5-SNAPSHOT.jar", null, null); | |
} catch (Exception ex){ | |
ex.printStackTrace(); | |
} | |
} | |
public void startComposite() { | |
try { | |
node.startComposite("performance", "PerformanceTest.composite"); | |
} catch (Exception ex){ | |
ex.printStackTrace(); | |
} | |
} | |
public void stopCompositeAndUninstallUnused(){ | |
try { | |
node.stopCompositeAndUninstallUnused("performance", "PerformanceTest.composite"); | |
} catch (Exception ex){ | |
ex.printStackTrace(); | |
} | |
} | |
public void uninstallContribution(){ | |
try { | |
node.installContribution("performance"); | |
} catch (Exception ex){ | |
ex.printStackTrace(); | |
} | |
} | |
public void stopNode(){ | |
node.stop(); | |
} | |
public void destroyNode() { | |
node = null; | |
} | |
public void stopRuntime() { | |
runtime.stop(); | |
} | |
public void destroyRuntime() { | |
runtime = null; | |
} | |
public void callService() { | |
try { | |
Helloworld helloWorldClient = node.getService(Helloworld.class, "HelloWorldClientComponent"); | |
assertNotNull(helloWorldClient); | |
BeanA beanA = new BeanA(); | |
beanA.setField1("Smith"); | |
beanA.setField2(13); | |
assertEquals("Hello Hello Jane Smith", helloWorldClient.sayHello("Jane", beanA)); | |
} catch (Exception ex) { | |
fail(ex.toString()); | |
} | |
} | |
public void printRuntimeStats(String step){ | |
tryToGC(); | |
Runtime runtime = Runtime.getRuntime(); | |
long used = runtime.totalMemory() - runtime.freeMemory(); | |
long free = runtime.freeMemory(); | |
long total = runtime.totalMemory(); | |
String stats = "U " + used + "[" + (used - lastUsed ) + "] \t" + | |
"F " + free + "[" + (free - lastFree ) + "] \t" + | |
"T " + total + "[" + (total - lastTotal) + "] \t" + | |
step + "\n"; | |
try { | |
resultsFile.write(stats); | |
} catch (Exception ex) { | |
ex.printStackTrace(); | |
} | |
System.out.print(stats); | |
lastTotal = total; | |
lastFree = free; | |
lastUsed = used; | |
} | |
/** | |
* We can't rely on GC doing anything sensible | |
* but I'm just playing here to see if I can | |
* force it to GC | |
*/ | |
public void tryToGC(){ | |
Runtime runtime = Runtime.getRuntime(); | |
/* | |
// force OOME | |
StringBuffer sb = new StringBuffer(); | |
try { | |
while(true) | |
{ | |
sb.append("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); | |
} | |
} catch (OutOfMemoryError ex){ | |
// we are going to GC now | |
System.out.println("OOME"); | |
} | |
sb = null; | |
for (int i = 0; i < 10; i++){ | |
Object obj = new Object(); | |
WeakReference ref = new WeakReference<Object>(obj); | |
obj = null; | |
while(ref.get() != null) { | |
runtime.runFinalization(); | |
runtime.gc(); | |
try { | |
Thread.sleep(100); | |
} catch (InterruptedException e) { | |
// Do nothing | |
} | |
} | |
} | |
*/ | |
} | |
public void dumpHeap(String heapName){ | |
String vendor = System.getProperty("java.vendor"); | |
if (vendor.contains("Sun")){ | |
dumpHeapSun(heapName); | |
} | |
} | |
public void dumpHeapSun(String heapName){ | |
final MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean(); | |
final OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean(); | |
final MBeanServer platformBean = ManagementFactory.getPlatformMBeanServer(); | |
HotSpotDiagnosticMXBean bean = null; | |
try { | |
bean = ManagementFactory.newPlatformMXBeanProxy(platformBean, | |
"com.sun.management:type=HotSpotDiagnostic", | |
HotSpotDiagnosticMXBean.class); | |
deleteFile(heapName); | |
bean.dumpHeap(heapName, false); | |
} catch(Exception ex){ | |
ex.printStackTrace(); | |
} | |
} | |
public void dumpHeapIBM(){ | |
} | |
public void deleteFile(String filename){ | |
File theFile = new File(filename); | |
theFile.delete(); | |
} | |
public void waitForInput() { | |
System.out.println("Press a key to end"); | |
try { | |
System.in.read(); | |
} catch (Exception ex) { | |
} | |
System.out.println("Continuing"); | |
} | |
// final MemoryMXBean mb = ManagementFactory.getMemoryMXBean(); | |
// com.sun.management.OperatingSystemMXBean if java.lang.management.OperationSystemMXBean | |
} |