001: /*
002: Copyright (C) 2002-2004 MySQL AB
003:
004: This program is free software; you can redistribute it and/or modify
005: it under the terms of version 2 of the GNU General Public License as
006: published by the Free Software Foundation.
007:
008: There are special exceptions to the terms and conditions of the GPL
009: as it is applied to this software. View the full text of the
010: exception in file EXCEPTIONS-CONNECTOR-J in the directory of this
011: software distribution.
012:
013: This program is distributed in the hope that it will be useful,
014: but WITHOUT ANY WARRANTY; without even the implied warranty of
015: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: GNU General Public License for more details.
017:
018: You should have received a copy of the GNU General Public License
019: along with this program; if not, write to the Free Software
020: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
021:
022:
023:
024: */
025: package testsuite.perf;
026:
027: import testsuite.BaseTestCase;
028:
029: import java.text.NumberFormat;
030:
031: import java.util.ArrayList;
032: import java.util.List;
033:
034: /**
035: * Base class for performance test cases. Handles statistics.
036: *
037: * @author Mark Matthews
038: */
039: public abstract class BasePerfTest extends BaseTestCase {
040: // ~ Static fields/initializers
041: // ---------------------------------------------
042:
043: /**
044: * Confidence interval lookup table, indexed by degrees of freedom at 95%.
045: */
046: private static final double[] T95 = { 12.706, 4.303, 3.182, 2.776,
047: 2.571, 2.447, 2.365, 2.306, 2.262, 2.228, 2.201, 2.179,
048: 2.160, 2.145, 2.131, 2.120, 2.110, 2.101, 2.093, 2.086,
049: 2.080, 2.074, 2.069, 2.064, 2.060, 2.056, 2.052, 2.048,
050: 2.045, 2.042 };
051:
052: /**
053: * Confidence interval lookup table, indexed by degrees of freedom at 99%.
054: */
055: private static final double[] T99 = { 63.657, 9.925, 5.841, 4.604,
056: 4.032, 3.707, 3.499, 3.355, 3.250, 3.169, 3.106, 3.055,
057: 3.012, 2.977, 2.947, 2.921, 2.898, 2.878, 2.861, 2.845,
058: 2.831, 2.819, 2.807, 2.797, 2.787, 2.779, 2.771, 2.763,
059: 2.756, 2.750 };
060:
061: static NumberFormat numberFormatter = NumberFormat.getInstance();
062:
063: static {
064: numberFormatter.setMaximumFractionDigits(4);
065: numberFormatter.setMinimumFractionDigits(4);
066: }
067:
068: // ~ Instance fields
069: // --------------------------------------------------------
070:
071: /**
072: * List of values for each iteration
073: */
074: private List testValuesList = new ArrayList();
075:
076: private double confidenceLevel = 95; // 95% by default
077:
078: private double confidenceValue = 0;
079:
080: private double intervalWidth = 0.1;
081:
082: private double meanValue = 0;
083:
084: private double squareSumValue = 0;
085:
086: private double sumValue = 0;
087:
088: private double variationValue = 0;
089:
090: /**
091: * The number of iterations that we have performed
092: */
093: private int numIterations = 0;
094:
095: // ~ Constructors
096: // -----------------------------------------------------------
097:
098: /**
099: * Creates a new BasePerfTest object.
100: *
101: * @param name
102: * the testcase name to perform.
103: */
104: public BasePerfTest(String name) {
105: super (name);
106: }
107:
108: // ~ Methods
109: // ----------------------------------------------------------------
110:
111: /**
112: * Returns the meanValue.
113: *
114: * @return double
115: */
116: public double getMeanValue() {
117: return this .meanValue;
118: }
119:
120: /**
121: * Sub-classes should override this to perform the operation to be measured.
122: *
123: * @throws Exception
124: * if an error occurs.
125: */
126: protected abstract void doOneIteration() throws Exception;
127:
128: /**
129: * Returns the current confidence level.
130: *
131: * @return the current confindence level.
132: */
133: protected double getCurrentConfidence() {
134: return (this .intervalWidth - this .confidenceValue) * 100;
135: }
136:
137: /**
138: * Returns the current margin of error.
139: *
140: * @return the current margin of error.
141: */
142: protected double getMarginOfError() {
143: return getConfidenceLookup()
144: * (getStandardDeviationP() / Math
145: .sqrt(this .numIterations));
146: }
147:
148: /**
149: * Returns the current STDDEV.
150: *
151: * @return the current STDDEV
152: */
153: protected double getStandardDeviationP() {
154: if (this .numIterations < 1) {
155: return 0;
156: }
157:
158: return Math
159: .sqrt(((this .numIterations * this .squareSumValue) - (this .sumValue * this .sumValue))
160: / (this .numIterations * this .numIterations));
161: }
162:
163: /**
164: * Adds one test result to the statistics.
165: *
166: * @param value
167: * a single result representing the value being measured in the
168: * test.
169: */
170: protected void addResult(double value) {
171: this .numIterations++;
172: this .testValuesList.add(new Double(value));
173:
174: this .sumValue += value;
175: this .squareSumValue += (value * value);
176: this .meanValue = this .sumValue / this .numIterations;
177: this .variationValue = (this .squareSumValue / this .numIterations)
178: - (this .meanValue * this .meanValue);
179:
180: // Can only have confidence when more than one test
181: // has been completed
182: if (this .numIterations > 1) {
183: this .confidenceValue = this .intervalWidth
184: - ((2.0 * getConfidenceLookup() * Math
185: .sqrt(this .variationValue
186: / (this .numIterations - 1.0))) / this .meanValue);
187: }
188: }
189:
190: /**
191: * Calls doIteration() the <code>numIterations</code> times, displaying
192: * the mean, std, margin of error and confidence level.
193: *
194: * @param numIterations
195: * the number of iterations to perform ( < 30)
196: * @throws Exception
197: * if an error occurs.
198: */
199: protected void doIterations(int numIterations) throws Exception {
200: for (int i = 0; i < numIterations; i++) {
201: doOneIteration();
202: }
203: }
204:
205: /**
206: * Reports the current results to STDOUT, preceeded by
207: * <code>additionalMessage</code> if not null.
208: *
209: * @param additionalMessage
210: * the additional message to print, or null if no message.
211: */
212: protected synchronized void reportResults(String additionalMessage) {
213: StringBuffer messageBuf = new StringBuffer();
214:
215: if (additionalMessage != null) {
216: messageBuf.append(additionalMessage);
217: messageBuf.append(": ");
218: }
219:
220: messageBuf.append(" mean: ");
221: messageBuf.append(numberFormatter.format(this .meanValue));
222: messageBuf.append(" stdevp: ");
223: messageBuf.append(numberFormatter
224: .format(getStandardDeviationP()));
225: messageBuf.append(" m-o-e: ");
226: messageBuf.append(numberFormatter.format(getMarginOfError()));
227:
228: System.out.println(messageBuf.toString());
229: }
230:
231: private double getConfidenceLookup() {
232: if (this .confidenceLevel == 95) {
233: return T95[this .numIterations - 1];
234: } else if (this .confidenceLevel == 99) {
235: return T99[this .numIterations - 1];
236: } else {
237: throw new IllegalArgumentException(
238: "Confidence level must be 95 or 99");
239: }
240: }
241: }
|