001: /*
002: * The Apache Software License, Version 1.1
003: *
004: *
005: * Copyright (c) 2002 The Apache Software Foundation. All rights
006: * reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: *
012: * 1. Redistributions of source code must retain the above copyright
013: * notice, this list of conditions and the following disclaimer.
014: *
015: * 2. Redistributions in binary form must reproduce the above copyright
016: * notice, this list of conditions and the following disclaimer in
017: * the documentation and/or other materials provided with the
018: * distribution.
019: *
020: * 3. The end-user documentation included with the redistribution,
021: * if any, must include the following acknowledgment:
022: * "This product includes software developed by the
023: * Apache Software Foundation (http://www.apache.org/)."
024: * Alternately, this acknowledgment may appear in the software itself,
025: * if and wherever such third-party acknowledgments normally appear.
026: *
027: * 4. The names "WSIF" and "Apache Software Foundation" must
028: * not be used to endorse or promote products derived from this
029: * software without prior written permission. For written
030: * permission, please contact apache@apache.org.
031: *
032: * 5. Products derived from this software may not be called "Apache",
033: * nor may "Apache" appear in their name, without prior written
034: * permission of the Apache Software Foundation.
035: *
036: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
037: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
038: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
039: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
040: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
041: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
042: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
043: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
044: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
045: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
046: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
047: * SUCH DAMAGE.
048: * ====================================================================
049: *
050: * This software consists of voluntary contributions made by many
051: * individuals on behalf of the Apache Software Foundation and was
052: * originally based on software copyright (c) 2001, 2002, International
053: * Business Machines, Inc., http://www.apache.org. For more
054: * information on the Apache Software Foundation, please see
055: * <http://www.apache.org/>.
056: */
057: package performance;
058:
059: import java.io.File;
060: import java.io.FileInputStream;
061: import java.io.FileOutputStream;
062: import java.util.Enumeration;
063: import java.util.HashMap;
064: import java.util.Iterator;
065: import java.util.Properties;
066:
067: import junit.framework.Test;
068: import junit.framework.TestCase;
069: import junit.framework.TestSuite;
070:
071: import org.apache.wsif.WSIFMessage;
072: import org.apache.wsif.WSIFOperation;
073: import org.apache.wsif.WSIFPort;
074: import org.apache.wsif.WSIFService;
075: import org.apache.wsif.WSIFServiceFactory;
076: import org.apache.wsif.base.WSIFServiceImpl;
077: import org.apache.wsif.providers.soap.apacheaxis.WSIFDynamicProvider_ApacheAxis;
078: import org.apache.wsif.util.WSIFPluggableProviders;
079:
080: import util.TestUtilities;
081:
082: import addressbook.wsiftypes.Address;
083: import addressbook.wsiftypes.Phone;
084:
085: /**
086: * Junit test to measure some simple performance statistics.
087: * It times a number of iterations of getPort, createOperation,
088: * and executeRequestResponseOperation for each provider. The
089: * results are stored in a properties file to allow each run
090: * to test if the performance has changed since the last run.
091: *
092: * The number of iterations to do is determined by the time
093: * each test takes and the TIME_PER_TEST constant. You need
094: * to run it atleast 3 times to get the iterations calculation
095: * to settle on a good value; The MARGIN_OF_ERROR constant
096: * defines how mush variation between run times is ignored
097: * when determining if the performance has changed.
098: *
099: * You may need to change the TIME_PER_TEST and MARGIN_OF_ERROR
100: * constants for your machine speed.
101: *
102: * For testing you can add futher timing points to the internal
103: * WSIF classes which this test will then monitor and report on.
104: *
105: * For example, to time the axis provider invoke method, at the
106: * start of the invoke method add:
107: * Monitor.start( "axisInvoke" );
108: * followed by a stop call at the end of the invoke method:
109: * Monitor.stop( "axisInvoke" );
110: *
111: * Monitor points can be paused around unwanted code. For example
112: * with the above monitors in the invoke method, you could exclude
113: * the SOAP call time with:
114: * Monitor.pause( "axisInvoke" );
115: * resp = call.invoke(locationUri, getSoapActionURI());
116: * Monitor.resume( "axisInvoke" );
117: *
118: * @author <a href="mailto:antelder@apache.org">Ant Elder</a>
119: */
120: public class SpeedTest extends TestCase {
121:
122: // This defines how long each test should be run for.
123: // There are 3 tests per provider; getPort, createOperation
124: // and executeOperation, so the total runnning time will be
125: // 3 times this value, times the number of providers tested.
126: static final float TIME_PER_TEST = 20000.0F; // 1 minute
127:
128: // This defines the time variation between runs before a
129: // result is considered a significant performance change.
130: // System.currentTimeMillis() is only acurate to 10msecs
131: // so for this to work you need to run enough iterations
132: static final float MARGIN_OF_ERROR = 0.1F; // tenth of a millisecond
133:
134: // defines if this run will overwrite existing statistics
135: static final boolean UPDATE_STATS = true;
136:
137: // delete this file to reset the previous statistics
138: static final File propFile = new File("wsifPerformanceStats.txt");
139:
140: static final int DEFAULT_ITERATIONS = 500;
141:
142: static final boolean TEST_GETPORT = true;
143: static final boolean TEST_CREATEOP = true;
144: static final boolean TEST_EXECOP = true;
145:
146: static Properties stats, newStats;
147:
148: static final String wsdlLocation = TestUtilities
149: .getWsdlPath("java\\test\\addressbook\\wsifservice")
150: + "AddressBook.wsdl";
151:
152: public SpeedTest(String name) {
153: super (name);
154: }
155:
156: public static void main(String[] args) {
157: TestUtilities.startListeners();
158: junit.textui.TestRunner.run(suite());
159: TestUtilities.stopListeners();
160: }
161:
162: public static Test suite() {
163: TestSuite suite = new TestSuite("Speed Tests");
164: suite.addTest(new TestSuite(SpeedTest.class));
165: //suite.addTest(new TestSuite(SpeedTest.class) );
166: //suite.addTest(new TestSuite(SpeedTest.class) );
167: return suite;
168: }
169:
170: public void setUp() {
171: TestUtilities.setUpExtensionsAndProviders();
172: newStats = new Properties();
173: Monitor.clear();
174: }
175:
176: public void testJava() {
177: doit("JavaPort", "java");
178: }
179:
180: /*
181: public void testJava() {
182: doit("JavaPort", "java");
183: }
184: public void testAxis() {
185: doit("SOAPPort", "axis");
186: }
187: JMS seems to slow for most runs
188: public void testSoapJms() {
189: doit("SOAPJMSPort", "soap");
190: }
191: public void testAxisJms() {
192: doit("SOAPJMSPort", "axis");
193: }
194: public void testNativeJms() {
195: doit("NativeJmsPort", "njms" );
196: }
197: //public void testEJB() {
198: //}
199: */
200:
201: private void doit(String portName, String protocol) {
202: int iterations;
203: String testName;
204: String testNamePrefix = protocol + "." + portName;
205:
206: if (portName.toUpperCase().indexOf("JMS") != -1
207: && !TestUtilities.areWeTesting("jms"))
208: return;
209:
210: TestUtilities.setProviderForProtocol(protocol);
211:
212: try {
213: WSIFServiceFactory factory = WSIFServiceFactory
214: .newInstance();
215: WSIFService service = factory.getService(wsdlLocation,
216: null, // serviceNS
217: null, // serviceName
218: "http://wsifservice.addressbook/", // portTypeNS
219: "AddressBook"); // portTypeName
220:
221: service.mapType(new javax.xml.namespace.QName(
222: "http://wsiftypes.addressbook/", "address"), Class
223: .forName("addressbook.wsiftypes.Address"));
224:
225: service.mapType(new javax.xml.namespace.QName(
226: "http://wsiftypes.addressbook/", "phone"), Class
227: .forName("addressbook.wsiftypes.Phone"));
228:
229: WSIFPort port = null;
230:
231: port = service.getPort(portName);
232:
233: /*
234: * Run iterations of getPort
235: */
236: testName = testNamePrefix + ".getPort";
237: iterations = (TEST_GETPORT) ? getIterations(testName) : 1;
238: System.out.println("running " + iterations + " " + testName
239: + " iterations...");
240: for (int i = 0; i < iterations; i++) {
241: Monitor.start(testName);
242: port = service.getPort(portName);
243: Monitor.stop(testName);
244: }
245:
246: WSIFOperation operation = port.createOperation("addEntry",
247: "AddEntryWholeNameRequest", null);
248:
249: WSIFMessage inputMessage = operation.createInputMessage();
250: WSIFMessage outputMessage = operation.createOutputMessage();
251: WSIFMessage faultMessage = operation.createFaultMessage();
252:
253: // Create a name and address to add to the addressbook
254: String nameToAdd = "Chris P. Bacon";
255: Address addressToAdd = new Address(1, "The Waterfront",
256: "Some City", "NY", 47907, new Phone(765, "494",
257: "4900"));
258:
259: // Add the name and address to the input message
260: inputMessage.setObjectPart("name", nameToAdd);
261: inputMessage.setObjectPart("address", addressToAdd);
262:
263: // Execute the operation, obtaining a flag to indicate its success
264: boolean ok = operation.executeRequestResponseOperation(
265: inputMessage, outputMessage, faultMessage);
266:
267: assertTrue("failed to add name and address!!", ok);
268:
269: /*
270: * Run iterations of createOperation
271: */
272: testName = testNamePrefix + ".createOperation";
273: iterations = (TEST_CREATEOP) ? getIterations(testName) : 1;
274: System.out.println("running " + iterations + " " + testName
275: + " iterations...");
276: for (int i = 0; i < iterations; i++) {
277: Monitor.start(testName);
278: operation = port.createOperation("getAddressFromName");
279: Monitor.stop(testName);
280: }
281:
282: /*
283: * Run iterations of executeRequestResponseOperation
284: */
285: testName = testNamePrefix + ".executeOperation";
286: iterations = (TEST_EXECOP) ? getIterations(testName) : 1;
287: System.out.println("running " + iterations + " " + testName
288: + " iterations...");
289: for (int i = 0; i < iterations; i++) {
290: operation = port.createOperation("getAddressFromName");
291: inputMessage = operation.createInputMessage();
292: outputMessage = operation.createOutputMessage();
293: faultMessage = operation.createFaultMessage();
294:
295: inputMessage.setObjectPart("name", nameToAdd);
296:
297: Monitor.start(testName);
298: boolean operationSucceeded = operation
299: .executeRequestResponseOperation(inputMessage,
300: outputMessage, faultMessage);
301: Monitor.stop(testName);
302: if (!operationSucceeded) {
303: System.out
304: .println("Failed to lookup name in addressbook");
305: assertTrue("executing op returned false!!", false);
306: }
307: }
308:
309: // make sure it all worked
310: Address addressFound = (Address) outputMessage
311: .getObjectPart("address");
312: assertTrue("returned address not correct!!", addressToAdd
313: .equals(addressFound));
314:
315: Monitor.printResults();
316:
317: // test is theres a performance change
318: boolean worse = testResults();
319: setIterations(testNamePrefix);
320: mergeNewStats();
321: if (UPDATE_STATS) {
322: saveStatsToFile();
323: }
324:
325: assertTrue("performance is worse than before!!", !worse);
326:
327: } catch (Exception ex) {
328: ex.printStackTrace();
329: assertTrue("exception executing op!!", false);
330: }
331: }
332:
333: private boolean testResults() {
334: float diff;
335: String s1, s2;
336: boolean worse = false;
337:
338: HashMap results = Monitor.getAvgResults();
339: String testName;
340: float duration, oldDuration;
341: for (Iterator i = results.keySet().iterator(); i.hasNext();) {
342: testName = (String) i.next();
343: duration = ((Float) results.get(testName)).floatValue();
344: duration = ((float) Math.round(duration * 1000) / 1000);
345: oldDuration = getfloatStat(testName);
346: newStats.setProperty(testName, "" + duration);
347: diff = duration - oldDuration;
348: if (Math.abs(diff) - MARGIN_OF_ERROR > 0) {
349: worse = diff > 0;
350: System.err.println(testName + " significantly "
351: + (worse ? "worse" : "better") + " by " + diff
352: + " msecs, time = " + duration + " msecs");
353: }
354: }
355:
356: return worse;
357: }
358:
359: private int getIterations(String testName) {
360: int i;
361: i = getintStat(testName + ".Iterations");
362: if (i == 0) {
363: i = DEFAULT_ITERATIONS;
364: }
365: return i;
366: }
367:
368: private void setIterations(String prefix) {
369: String s;
370: int iterations;
371: float duration, createDuration;
372: HashMap results = Monitor.getAvgResults();
373:
374: s = prefix + ".getPort";
375: duration = ((Float) results.get(s)).floatValue();
376: iterations = (duration == 0) ? DEFAULT_ITERATIONS
377: : (int) ((TIME_PER_TEST * 100) / (duration * 100));
378: newStats.setProperty(s + ".Iterations", "" + iterations);
379:
380: s = prefix + ".createOperation";
381: duration = ((Float) results.get(s)).floatValue();
382: iterations = (duration == 0) ? DEFAULT_ITERATIONS
383: : (int) ((TIME_PER_TEST * 100) / (duration * 100));
384: newStats.setProperty(s + ".Iterations", "" + iterations);
385: createDuration = duration;
386:
387: s = prefix + ".executeOperation";
388: duration = ((Float) results.get(s)).floatValue();
389: iterations = (duration == 0) ? DEFAULT_ITERATIONS
390: : (int) ((TIME_PER_TEST * 100) / ((duration + createDuration) * 100));
391: newStats.setProperty(s + ".Iterations", "" + iterations);
392:
393: }
394:
395: private int getintStat(String name) {
396: int i;
397: Properties stats = getStats();
398: try {
399: i = Integer.parseInt(stats.getProperty(name));
400: } catch (Exception ex) {
401: i = 0;
402: }
403: return i;
404: }
405:
406: private float getfloatStat(String name) {
407: float f;
408: Properties stats = getStats();
409: try {
410: f = Float.parseFloat(stats.getProperty(name));
411: } catch (Exception ex) {
412: f = 0;
413: }
414: return f;
415: }
416:
417: private static Properties getStats() {
418: if (stats == null) {
419: loadStatsFromFile();
420: }
421: return stats;
422: }
423:
424: private static void mergeNewStats() {
425: Properties stats = getStats();
426: String testName;
427: String value;
428: int iterations;
429: for (Enumeration i = newStats.keys(); i.hasMoreElements();) {
430: testName = (String) i.nextElement();
431: value = (String) newStats.get(testName);
432: stats.setProperty(testName, value);
433: }
434: }
435:
436: private static void loadStatsFromFile() {
437: try {
438: FileInputStream fis = new FileInputStream(propFile);
439: stats = new Properties();
440: stats.load(fis);
441: } catch (Exception ex) {
442: stats = new Properties();
443: }
444: }
445:
446: private static void saveStatsToFile() {
447: try {
448: FileOutputStream fos = new FileOutputStream(propFile);
449: stats.store(fos, "WSIF Performance stats");
450: } catch (Exception ex) {
451: ex.printStackTrace();
452: }
453: }
454:
455: }
|