001: /*
002: * All content copyright (c) 2003-2007 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tctest;
006:
007: import EDU.oswego.cs.dl.util.concurrent.CyclicBarrier;
008:
009: import com.tc.config.schema.setup.TestTVSConfigurationSetupManagerFactory;
010: import com.tc.object.config.ConfigVisitor;
011: import com.tc.object.config.DSOClientConfigHelper;
012: import com.tc.object.config.TransparencyClassSpec;
013: import com.tc.object.config.spec.CyclicBarrierSpec;
014: import com.tc.simulator.app.ApplicationConfig;
015: import com.tc.simulator.listener.ListenerProvider;
016: import com.tc.util.concurrent.ThreadUtil;
017: import com.tctest.runner.AbstractErrorCatchingTransparentApp;
018: import com.terracottatech.config.PersistenceMode;
019:
020: import java.util.HashMap;
021: import java.util.Map;
022: import java.util.Random;
023:
024: public class ArrayGCTest extends GCTestBase {
025:
026: protected Class getApplicationClass() {
027: return App.class;
028: }
029:
030: protected boolean useExternalProcess() {
031: return true;
032: }
033:
034: protected void setupConfig(
035: TestTVSConfigurationSetupManagerFactory configFactory) {
036: super .setupConfig(configFactory);
037: configFactory
038: .setPersistenceMode(PersistenceMode.PERMANENT_STORE);
039: }
040:
041: public static class App extends AbstractErrorCatchingTransparentApp {
042: private static long DURATION = 5 * 60 * 1000;
043: private static long END = System.currentTimeMillis() + DURATION;
044:
045: private static final String TYPE_NEW = "N";
046: private static final String TYPE_ELEMENT = "E";
047: private static final String TYPE_COPY = "C";
048:
049: private static final int NUM = 500;
050: private static final int LEN = 50;
051:
052: private final CyclicBarrier barrier;
053: private final Map root;
054: private final Random random;
055:
056: public App(String appId, ApplicationConfig cfg,
057: ListenerProvider listenerProvider) {
058: super (appId, cfg, listenerProvider);
059:
060: if (getParticipantCount() < 2) {
061: throw new AssertionError();
062: }
063:
064: barrier = new CyclicBarrier(getParticipantCount());
065: root = new HashMap();
066:
067: long seed = new Random().nextLong();
068: System.err.println("seed for " + getApplicationId()
069: + " is " + seed);
070: random = new Random(seed);
071: }
072:
073: protected void runTest() throws Throwable {
074: final int index = barrier.barrier();
075:
076: if (index == 0) {
077: populate();
078: }
079:
080: barrier.barrier();
081:
082: if ((index % 2) == 0) {
083: read();
084: } else {
085: createAndMutate();
086: }
087: }
088:
089: private void populate() {
090: for (int i = 0, n = NUM; i < n; i++) {
091: synchronized (root) {
092: root.put(TYPE_NEW + i, newArray());
093: root.put(TYPE_ELEMENT + i, newArray());
094: root.put(TYPE_COPY + i, newArray());
095: }
096: }
097: }
098:
099: private Object[] newArray() {
100: return newArray(random.nextInt(LEN));
101: }
102:
103: private Object[] newArray(int length) {
104: Object[] rv = new Object[length];
105: for (int i = 0, n = rv.length; i < n; i++) {
106: rv[i] = new Object();
107: }
108: return rv;
109: }
110:
111: private void read() {
112: final int h = hashCode();
113:
114: while (!shouldEnd()) {
115: Object[] array = getRandomArray();
116:
117: for (int i = 0, n = array.length; i < n; i++) {
118: synchronized (array) {
119: Object o = array[i]; // resolve array element
120:
121: // this bit of code should prevent any optimizer from removing the array access above
122: if (o.hashCode() == h) {
123: System.err.println("OK");
124: }
125: }
126: }
127: }
128: }
129:
130: private Object[] getRandomArray() {
131: return getArray(getRandomType(), getRandomNum());
132: }
133:
134: private int getRandomNum() {
135: return random.nextInt(NUM);
136: }
137:
138: private String getRandomType() {
139: switch (random.nextInt(3)) {
140: case 0: {
141: return TYPE_COPY;
142: }
143: case 1: {
144: return TYPE_ELEMENT;
145: }
146: case 2: {
147: return TYPE_NEW;
148: }
149: }
150:
151: throw new AssertionError();
152: }
153:
154: private Object[] getArray(String type, int num) {
155: synchronized (root) {
156: return (Object[]) root.get(type + num);
157: }
158: }
159:
160: public void createAndMutate() {
161: while (!shouldEnd()) {
162: String type = getRandomType();
163: int num = getRandomNum();
164:
165: if (TYPE_COPY.equals(type)) {
166: Object[] array = getArray(type, num);
167: Object[] newArray = newArray(array.length);
168: synchronized (array) {
169: System.arraycopy(newArray, 0, array, 0,
170: array.length);
171: }
172: } else if (TYPE_ELEMENT.equals(type)) {
173: Object[] array = getArray(type, num);
174: synchronized (array) {
175: for (int i = 0, n = array.length; i < n; i++) {
176: array[i] = new Object();
177: }
178: }
179: } else if (TYPE_NEW.equals(type)) {
180: synchronized (root) {
181: root.put(type + num, newArray());
182: }
183: } else {
184: throw new AssertionError(type);
185: }
186: }
187: }
188:
189: private static boolean shouldEnd() {
190: // slow down for the monkeys
191: ThreadUtil.reallySleep(10);
192:
193: return System.currentTimeMillis() > END;
194: }
195:
196: public static void visitL1DSOConfig(ConfigVisitor visitor,
197: DSOClientConfigHelper config) {
198: new CyclicBarrierSpec().visit(visitor, config);
199:
200: String testClassName = App.class.getName();
201: TransparencyClassSpec spec = config
202: .getOrCreateSpec(testClassName);
203: spec.addRoot("root", "root");
204: spec.addRoot("barrier", "barrier");
205:
206: config.addReadAutolock("* " + testClassName
207: + ".getArray(..)");
208: config.addReadAutolock("* " + testClassName + ".read()");
209:
210: config.addWriteAutolock("* " + testClassName
211: + ".populate()");
212: config.addWriteAutolock("* " + testClassName
213: + ".createAndMutate()");
214:
215: }
216:
217: }
218:
219: }
|