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.regression;
026:
027: import java.sql.Connection;
028: import java.sql.PreparedStatement;
029: import java.sql.ResultSet;
030: import java.sql.SQLException;
031: import java.sql.Statement;
032: import java.sql.Timestamp;
033: import java.util.ArrayList;
034: import java.util.Collections;
035: import java.util.Date;
036: import java.util.List;
037: import java.util.Properties;
038:
039: import testsuite.BaseTestCase;
040:
041: /**
042: * Tests for multi-thread stress regressions.
043: *
044: * @author Mark Matthews
045: * @version $Id: StressRegressionTest.java,v 1.1.2.1 2005/05/13 18:58:38
046: * mmatthews Exp $
047: */
048: public class StressRegressionTest extends BaseTestCase {
049: private int numThreadsStarted;
050:
051: /**
052: * Creates a new StressRegressionTest
053: *
054: * @param name
055: * the name of the test.
056: */
057: public StressRegressionTest(String name) {
058: super (name);
059:
060: // TODO Auto-generated constructor stub
061: }
062:
063: /**
064: * Runs all test cases in this test suite
065: *
066: * @param args
067: */
068: public static void main(String[] args) {
069: junit.textui.TestRunner.run(StressRegressionTest.class);
070: }
071:
072: /**
073: *
074: *
075: * @throws Exception
076: * ...
077: */
078: public synchronized void testContention() throws Exception {
079: if (false) {
080: System.out.println("Calculating baseline elapsed time...");
081:
082: long start = System.currentTimeMillis();
083:
084: contentiousWork(this .conn, this .stmt, 0);
085:
086: long singleThreadElapsedTimeMillis = System
087: .currentTimeMillis()
088: - start;
089:
090: System.out.println("Single threaded execution took "
091: + singleThreadElapsedTimeMillis + " ms.");
092:
093: int numThreadsToStart = 95;
094:
095: System.out.println("\nStarting " + numThreadsToStart
096: + " threads.");
097:
098: this .numThreadsStarted = numThreadsToStart;
099:
100: ContentionThread[] threads = new ContentionThread[this .numThreadsStarted];
101:
102: for (int i = 0; i < numThreadsToStart; i++) {
103: threads[i] = new ContentionThread(i);
104: threads[i].start();
105: }
106:
107: for (;;) {
108: try {
109: wait();
110:
111: if (this .numThreadsStarted == 0) {
112: break;
113: }
114: } catch (InterruptedException ie) {
115: // ignore
116: }
117: }
118:
119: // Collect statistics...
120: System.out.println("Done!");
121:
122: double avgElapsedTimeMillis = 0;
123:
124: List elapsedTimes = new ArrayList();
125:
126: for (int i = 0; i < numThreadsToStart; i++) {
127: elapsedTimes
128: .add(new Long(threads[i].elapsedTimeMillis));
129:
130: avgElapsedTimeMillis += ((double) threads[i].elapsedTimeMillis / numThreadsToStart);
131: }
132:
133: Collections.sort(elapsedTimes);
134:
135: System.out.println("Average elapsed time per-thread was "
136: + avgElapsedTimeMillis + " ms.");
137: System.out.println("Median elapsed time per-thread was "
138: + elapsedTimes.get(elapsedTimes.size() / 2)
139: + " ms.");
140: System.out.println("Minimum elapsed time per-thread was "
141: + elapsedTimes.get(0) + " ms.");
142: System.out.println("Maximum elapsed time per-thread was "
143: + elapsedTimes.get(elapsedTimes.size() - 1)
144: + " ms.");
145: }
146: }
147:
148: /**
149: *
150: *
151: * @throws Exception
152: * ...
153: */
154: public void testCreateConnections() throws Exception {
155: new CreateThread().start();
156: }
157:
158: /**
159: *
160: *
161: * @throws Exception
162: * ...
163: */
164: public void testCreateConnectionsUnderLoad() throws Exception {
165: new CreateThread(new BusyThread()).start();
166: }
167:
168: void contentiousWork(Connection threadConn, Statement threadStmt,
169: int threadNumber) {
170: Date now = new Date();
171:
172: try {
173: for (int i = 0; i < 1000; i++) {
174: ResultSet threadRs = threadStmt
175: .executeQuery("SELECT 1, 2");
176:
177: while (threadRs.next()) {
178: threadRs.getString(1);
179: threadRs.getString(2);
180: }
181:
182: threadRs.close();
183:
184: PreparedStatement pStmt = threadConn
185: .prepareStatement("SELECT ?");
186: pStmt.setTimestamp(1, new Timestamp(now.getTime()));
187:
188: threadRs = pStmt.executeQuery();
189:
190: while (threadRs.next()) {
191: threadRs.getTimestamp(1);
192: }
193:
194: threadRs.close();
195: pStmt.close();
196: }
197: } catch (Exception ex) {
198: throw new RuntimeException(ex.toString());
199: }
200: }
201:
202: synchronized void reportDone() {
203: this .numThreadsStarted--;
204: notify();
205: }
206:
207: public class BusyThread extends Thread {
208: boolean stop = false;
209:
210: public void run() {
211: while (!this .stop) {
212: }
213: }
214: }
215:
216: class ContentionThread extends Thread {
217: Connection threadConn;
218:
219: Statement threadStmt;
220:
221: int threadNumber;
222:
223: long elapsedTimeMillis;
224:
225: public ContentionThread(int num) throws SQLException {
226: this .threadNumber = num;
227: this .threadConn = getConnectionWithProps(new Properties());
228: this .threadStmt = this .threadConn.createStatement();
229:
230: System.out.println(this .threadConn);
231: }
232:
233: public void run() {
234: long start = System.currentTimeMillis();
235:
236: try {
237: contentiousWork(this .threadConn, this .threadStmt,
238: this .threadNumber);
239: this .elapsedTimeMillis = System.currentTimeMillis()
240: - start;
241:
242: System.out.println("Thread " + this .threadNumber
243: + " finished.");
244: } finally {
245: if (this .elapsedTimeMillis == 0) {
246: this .elapsedTimeMillis = System.currentTimeMillis()
247: - start;
248: }
249:
250: reportDone();
251:
252: try {
253: this .threadStmt.close();
254: this .threadConn.close();
255: } catch (SQLException ex) {
256: // ignore
257: }
258: }
259: }
260: }
261:
262: class CreateThread extends Thread {
263: BusyThread busyThread;
264:
265: int numConnections = 15;
266:
267: public CreateThread() {
268: }
269:
270: public CreateThread(BusyThread toStop) {
271: this .busyThread = toStop;
272: }
273:
274: public CreateThread(int numConns) {
275: this .numConnections = numConns;
276: }
277:
278: public void run() {
279: try {
280: Connection[] connList = new Connection[this .numConnections];
281:
282: long maxConnTime = Long.MIN_VALUE;
283: long minConnTime = Long.MAX_VALUE;
284: double averageTime = 0;
285:
286: Properties nullProps = new Properties();
287:
288: for (int i = 0; i < this .numConnections; i++) {
289: long startTime = System.currentTimeMillis();
290: connList[i] = getConnectionWithProps(nullProps);
291:
292: long endTime = System.currentTimeMillis();
293: long ellapsedTime = endTime - startTime;
294:
295: if (ellapsedTime < minConnTime) {
296: minConnTime = ellapsedTime;
297: }
298:
299: if (ellapsedTime > maxConnTime) {
300: maxConnTime = ellapsedTime;
301: }
302:
303: averageTime += ((double) ellapsedTime / this .numConnections);
304: }
305:
306: if (this .busyThread != null) {
307: this .busyThread.stop = true;
308: }
309:
310: for (int i = 0; i < this .numConnections; i++) {
311: connList[i].close();
312: }
313:
314: System.out.println(minConnTime + "/" + maxConnTime
315: + "/" + averageTime);
316: } catch (Exception ex) {
317: throw new RuntimeException(ex);
318: }
319: }
320: }
321: }
|