Main.java revision bf81547a47c46a8853092432635bfec6167a2388
17c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom/*
27c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom * Copyright (C) 2011 The Android Open Source Project
37c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom *
47c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom * Licensed under the Apache License, Version 2.0 (the "License");
57c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom * you may not use this file except in compliance with the License.
67c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom * You may obtain a copy of the License at
77c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom *
87c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom *      http://www.apache.org/licenses/LICENSE-2.0
97c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom *
107c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom * Unless required by applicable law or agreed to in writing, software
117c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom * distributed under the License is distributed on an "AS IS" BASIS,
127c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom * See the License for the specific language governing permissions and
147c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom * limitations under the License.
157c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom */
167c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
171c83cbc4a817acbd7f9abb5b29a2d418a958e6a1Andreas Gampeimport java.lang.reflect.*;
187c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstromimport java.util.ArrayList;
197c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstromimport java.util.Arrays;
207c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstromimport java.util.Collections;
217c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstromimport java.util.HashMap;
22f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampeimport java.util.HashSet;
237c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstromimport java.util.List;
247c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstromimport java.util.Map;
25f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampeimport java.util.Set;
267c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
277c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom// Run on host with:
287c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom//   javac ThreadTest.java && java ThreadStress && rm *.class
29f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe// Through run-test:
30f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe//   test/run-test {run-test-args} 004-ThreadStress [Main {ThreadStress-args}]
31f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe//   (It is important to pass Main if you want to give parameters...)
32f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe//
33f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe// ThreadStress command line parameters:
34f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe//    -n X ............ number of threads
35def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao//    -d X ............ number of daemon threads
36f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe//    -o X ............ number of overall operations
37f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe//    -t X ............ number of operations per thread
38f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe//    --dumpmap ....... print the frequency map
39f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe//    -oom:X .......... frequency of OOM (double)
40f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe//    -alloc:X ........ frequency of Alloc
41f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe//    -stacktrace:X ... frequency of StackTrace
42f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe//    -exit:X ......... frequency of Exit
43f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe//    -sleep:X ........ frequency of Sleep
44f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe//    -wait:X ......... frequency of Wait
45f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe//    -timedwait:X .... frequency of TimedWait
46f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
471c83cbc4a817acbd7f9abb5b29a2d418a958e6a1Andreas Gampepublic class Main implements Runnable {
487c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
494514d3c0e69a49f5dbe19138330a2bb2aee36d63Brian Carlstrom    public static final boolean DEBUG = false;
507c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
51f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private static abstract class Operation {
52f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        /**
53f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe         * Perform the action represented by this operation. Returns true if the thread should
54f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe         * continue.
55f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe         */
56f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public abstract boolean perform();
57f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
58f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
59f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static class OOM extends Operation {
60f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        @Override
61f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public boolean perform() {
62f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            try {
63f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                List<byte[]> l = new ArrayList<byte[]>();
64f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                while (true) {
65f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    l.add(new byte[1024]);
66f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                }
67f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            } catch (OutOfMemoryError e) {
68f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
69f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            return true;
70f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
71f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
72f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
73f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static class SigQuit extends Operation {
74f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        private final static int sigquit;
75f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        private final static Method kill;
76f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        private final static int pid;
77f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
78f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        static {
79f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            int pidTemp = -1;
80f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            int sigquitTemp = -1;
81f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            Method killTemp = null;
82f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
83f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            try {
84f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                Class<?> osClass = Class.forName("android.system.Os");
85f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                Method getpid = osClass.getDeclaredMethod("getpid");
86f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                pidTemp = (Integer)getpid.invoke(null);
87f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
88f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                Class<?> osConstants = Class.forName("android.system.OsConstants");
89f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                Field sigquitField = osConstants.getDeclaredField("SIGQUIT");
90f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                sigquitTemp = (Integer)sigquitField.get(null);
91f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
92f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                killTemp = osClass.getDeclaredMethod("kill", int.class, int.class);
93f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            } catch (Exception e) {
94f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                if (!e.getClass().getName().equals("ErrnoException")) {
95f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    e.printStackTrace(System.out);
96f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                }
97f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
98f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
99f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            pid = pidTemp;
100f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            sigquit = sigquitTemp;
101f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            kill = killTemp;
102f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
103f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
104f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        @Override
105f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public boolean perform() {
106f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            try {
107f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                kill.invoke(null, pid, sigquit);
108f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            } catch (Exception e) {
109f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                if (!e.getClass().getName().equals("ErrnoException")) {
110f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    e.printStackTrace(System.out);
111f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                }
112f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
113f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            return true;
114f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
115f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
116f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
117f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static class Alloc extends Operation {
118f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        @Override
119f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public boolean perform() {
120f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            try {
121f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                List<byte[]> l = new ArrayList<byte[]>();
122f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                for (int i = 0; i < 1024; i++) {
123f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    l.add(new byte[1024]);
124f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                }
125f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            } catch (OutOfMemoryError e) {
126f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
127f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            return true;
128f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
129f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
130f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
131f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static class StackTrace extends Operation {
132f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        @Override
133f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public boolean perform() {
134f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            Thread.currentThread().getStackTrace();
135f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            return true;
136f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
137f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
138f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
139f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static class Exit extends Operation {
140f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        @Override
141f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public boolean perform() {
142f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            return false;
143f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
144f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
145f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
146f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static class Sleep extends Operation {
147f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        @Override
148f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public boolean perform() {
149f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            try {
150f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                Thread.sleep(100);
151f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            } catch (InterruptedException ignored) {
152f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
153f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            return true;
154f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
155f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
1564cd121ef0cb35fced70c7d9de378277be7a727d9Elliott Hughes
157f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static class TimedWait extends Operation {
158f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        private final Object lock;
1597c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
160f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public TimedWait(Object lock) {
161f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            this.lock = lock;
162f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
163f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
164f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        @Override
165f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public boolean perform() {
166f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            synchronized (lock) {
167f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                try {
168f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    lock.wait(100, 0);
169f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                } catch (InterruptedException ignored) {
170f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                }
171f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
172f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            return true;
1737c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        }
1747c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom    }
1757c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
176f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static class Wait extends Operation {
177f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        private final Object lock;
178f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
179f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public Wait(Object lock) {
180f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            this.lock = lock;
181f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
182f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
183f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        @Override
184f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public boolean perform() {
185f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            synchronized (lock) {
186f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                try {
187f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    lock.wait();
188f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                } catch (InterruptedException ignored) {
189f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                }
190f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
191f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            return true;
192f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
193f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
194f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
195f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static class SyncAndWork extends Operation {
196f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        private final Object lock;
197f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
198f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public SyncAndWork(Object lock) {
199f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            this.lock = lock;
200f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
201f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
202f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        @Override
203f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public boolean perform() {
204f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            synchronized (lock) {
205f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                try {
206f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    Thread.sleep((int)(Math.random()*10));
207f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                } catch (InterruptedException ignored) {
208f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                }
209f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
210f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            return true;
211f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
212f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
213f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
214f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static Map<Operation, Double> createDefaultFrequencyMap(Object lock) {
215f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        Map<Operation, Double> frequencyMap = new HashMap<Operation, Double>();
216f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        frequencyMap.put(new OOM(), 0.005);             //  1/200
217f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        frequencyMap.put(new SigQuit(), 0.095);         // 19/200
218f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        frequencyMap.put(new Alloc(), 0.3);             // 60/200
219f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        frequencyMap.put(new StackTrace(), 0.1);        // 20/200
220f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        frequencyMap.put(new Exit(), 0.25);             // 50/200
221f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        frequencyMap.put(new Sleep(), 0.125);           // 25/200
222f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        frequencyMap.put(new TimedWait(lock), 0.05);    // 10/200
223f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        frequencyMap.put(new Wait(lock), 0.075);        // 15/200
224f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
225f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        return frequencyMap;
226f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
227f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
228f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static Map<Operation, Double> createLockFrequencyMap(Object lock) {
229f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe      Map<Operation, Double> frequencyMap = new HashMap<Operation, Double>();
230f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe      frequencyMap.put(new Sleep(), 0.2);
231f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe      frequencyMap.put(new TimedWait(lock), 0.2);
232f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe      frequencyMap.put(new Wait(lock), 0.2);
233f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe      frequencyMap.put(new SyncAndWork(lock), 0.4);
234f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
235f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe      return frequencyMap;
236f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
237f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
2387c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom    public static void main(String[] args) throws Exception {
239f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        parseAndRun(args);
240f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
2417c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
242f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private static Map<Operation, Double> updateFrequencyMap(Map<Operation, Double> in,
243f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            Object lock, String arg) {
244f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        String split[] = arg.split(":");
245f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (split.length != 2) {
246f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            throw new IllegalArgumentException("Can't split argument " + arg);
247f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
248f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        double d;
249f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        try {
250f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            d = Double.parseDouble(split[1]);
251f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        } catch (Exception e) {
252f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            throw new IllegalArgumentException(e);
253f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
254f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (d < 0) {
255f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            throw new IllegalArgumentException(arg + ": value must be >= 0.");
256f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
257f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        Operation op = null;
258f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (split[0].equals("-oom")) {
259f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            op = new OOM();
260f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        } else if (split[0].equals("-sigquit")) {
261f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            op = new SigQuit();
262f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        } else if (split[0].equals("-alloc")) {
263f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            op = new Alloc();
264f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        } else if (split[0].equals("-stacktrace")) {
265f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            op = new StackTrace();
266f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        } else if (split[0].equals("-exit")) {
267f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            op = new Exit();
268f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        } else if (split[0].equals("-sleep")) {
269f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            op = new Sleep();
270f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        } else if (split[0].equals("-wait")) {
271f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            op = new Wait(lock);
272f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        } else if (split[0].equals("-timedwait")) {
273f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            op = new TimedWait(lock);
274f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        } else {
275f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            throw new IllegalArgumentException("Unknown arg " + arg);
276f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
277f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
278f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (in == null) {
279f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            in = new HashMap<Operation, Double>();
280f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
281f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        in.put(op, d);
2827c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
283f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        return in;
284f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
285f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
286f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private static void normalize(Map<Operation, Double> map) {
287f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        double sum = 0;
288f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        for (Double d : map.values()) {
289f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            sum += d;
290f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
291f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (sum == 0) {
292f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            throw new RuntimeException("No elements!");
293f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
294f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (sum != 1.0) {
295f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            // Avoid ConcurrentModificationException.
296f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            Set<Operation> tmp = new HashSet<>(map.keySet());
297f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            for (Operation op : tmp) {
298f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                map.put(op, map.get(op) / sum);
299f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
300f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
301f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
302f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
303f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    public static void parseAndRun(String[] args) throws Exception {
304f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        int numberOfThreads = -1;
305def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        int numberOfDaemons = -1;
306f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        int totalOperations = -1;
307f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        int operationsPerThread = -1;
308f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        Object lock = new Object();
309f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        Map<Operation, Double> frequencyMap = null;
310f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        boolean dumpMap = false;
311f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
312f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (args != null) {
313f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            for (int i = 0; i < args.length; i++) {
314f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                if (args[i].equals("-n")) {
315f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    i++;
316f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    numberOfThreads = Integer.parseInt(args[i]);
317def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                } else if (args[i].equals("-d")) {
318def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                    i++;
319def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                    numberOfDaemons = Integer.parseInt(args[i]);
320f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                } else if (args[i].equals("-o")) {
321f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    i++;
322f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    totalOperations = Integer.parseInt(args[i]);
323f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                } else if (args[i].equals("-t")) {
324f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    i++;
325f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    operationsPerThread = Integer.parseInt(args[i]);
326f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                } else if (args[i].equals("--locks-only")) {
327f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    lock = new Object();
328f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    frequencyMap = createLockFrequencyMap(lock);
329f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                } else if (args[i].equals("--dumpmap")) {
330f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    dumpMap = true;
331f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                } else {
332f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    frequencyMap = updateFrequencyMap(frequencyMap, lock, args[i]);
333f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                }
334f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
335f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
3367c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
337f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (totalOperations != -1 && operationsPerThread != -1) {
338f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            throw new IllegalArgumentException(
339f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    "Specified both totalOperations and operationsPerThread");
340f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
341f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
342f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (numberOfThreads == -1) {
343f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            numberOfThreads = 5;
344f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
345f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
346def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        if (numberOfDaemons == -1) {
347def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao            numberOfDaemons = 3;
348def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        }
349def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao
350f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (totalOperations == -1) {
351f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            totalOperations = 1000;
352f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
353f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
354f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (operationsPerThread == -1) {
355f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            operationsPerThread = totalOperations/numberOfThreads;
356f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
357f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
358f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (frequencyMap == null) {
359f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            frequencyMap = createDefaultFrequencyMap(lock);
360f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
361f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        normalize(frequencyMap);
362f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
363f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (dumpMap) {
364f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            System.out.println(frequencyMap);
365f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
366f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
367def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        runTest(numberOfThreads, numberOfDaemons, operationsPerThread, lock, frequencyMap);
368f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
369f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
370def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao    public static void runTest(final int numberOfThreads, final int numberOfDaemons,
371def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                               final int operationsPerThread, final Object lock,
372def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                               Map<Operation, Double> frequencyMap) throws Exception {
373def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        // Each normal thread is going to do operationsPerThread
374def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        // operations. Each daemon thread will loop over all
375def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        // the operations and will not stop.
376def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        // The distribution of operations is determined by
3777c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // the Operation.frequency values. We fill out an Operation[]
3787c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // for each thread with the operations it is to perform. The
3797c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // Operation[] is shuffled so that there is more random
3807c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // interactions between the threads.
3817c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
3827c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // Fill in the Operation[] array for each thread by laying
3837c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // down references to operation according to their desired
3847c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // frequency.
385def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        // The first numberOfThreads elements are normal threads, the last
386def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        // numberOfDaemons elements are daemon threads.
387def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        final Main[] threadStresses = new Main[numberOfThreads + numberOfDaemons];
3887c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        for (int t = 0; t < threadStresses.length; t++) {
3897c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            Operation[] operations = new Operation[operationsPerThread];
3907c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            int o = 0;
3917c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            LOOP:
3927c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            while (true) {
393f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                for (Operation op : frequencyMap.keySet()) {
394f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    int freq = (int)(frequencyMap.get(op) * operationsPerThread);
395f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    for (int f = 0; f < freq; f++) {
3967c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                        if (o == operations.length) {
3977c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                            break LOOP;
3987c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                        }
3997c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                        operations[o] = op;
4007c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                        o++;
4017c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    }
4027c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                }
4037c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            }
404def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao            // Randomize the operation order
4057c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            Collections.shuffle(Arrays.asList(operations));
406def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao            threadStresses[t] = t < numberOfThreads ? new Main(lock, t, operations) :
407def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                                                      new Daemon(lock, t, operations);
4087c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        }
4097c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
410f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        // Enable to dump operation counts per thread to make sure its
4117c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // sane compared to Operation.frequency
4127c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        if (DEBUG) {
4137c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            for (int t = 0; t < threadStresses.length; t++) {
414f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                Operation[] operations = threadStresses[t].operations;
4157c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                Map<Operation, Integer> distribution = new HashMap<Operation, Integer>();
4167c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                for (Operation operation : operations) {
4177c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    Integer ops = distribution.get(operation);
4187c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    if (ops == null) {
4197c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                        ops = 1;
4207c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    } else {
4217c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                        ops++;
4227c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    }
4237c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    distribution.put(operation, ops);
4247c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                }
4257c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                System.out.println("Distribution for " + t);
426f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                for (Operation op : frequencyMap.keySet()) {
4277c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    System.out.println(op + " = " + distribution.get(op));
4287c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                }
4297c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            }
4307c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        }
4317c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
4327c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // Create the runners for each thread. The runner Thread
4337c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // ensures that thread that exit due to Operation.EXIT will be
4347c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // restarted until they reach their desired
4357c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // operationsPerThread.
4367c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        Thread[] runners = new Thread[numberOfThreads];
4377c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        for (int r = 0; r < runners.length; r++) {
4381c83cbc4a817acbd7f9abb5b29a2d418a958e6a1Andreas Gampe            final Main ts = threadStresses[r];
4395f51d4b80058236759fea1d932470a57f348c199Mathieu Chartier            runners[r] = new Thread("Runner thread " + r) {
4401c83cbc4a817acbd7f9abb5b29a2d418a958e6a1Andreas Gampe                final Main threadStress = ts;
4417c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                public void run() {
4427c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    int id = threadStress.id;
4435f51d4b80058236759fea1d932470a57f348c199Mathieu Chartier                    System.out.println("Starting worker for " + id);
4447c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    while (threadStress.nextOperation < operationsPerThread) {
4455f51d4b80058236759fea1d932470a57f348c199Mathieu Chartier                        Thread thread = new Thread(ts, "Worker thread " + id);
4467c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                        thread.start();
4477c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                        try {
4487c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                            thread.join();
4497c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                        } catch (InterruptedException e) {
4507c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                        }
4517c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                        System.out.println("Thread exited for " + id + " with "
4527c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                                           + (operationsPerThread - threadStress.nextOperation)
4537c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                                           + " operations remaining.");
4547c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    }
4551c83cbc4a817acbd7f9abb5b29a2d418a958e6a1Andreas Gampe                    System.out.println("Finishing worker");
4567c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                }
4577c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            };
4587c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        }
4597c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
4607c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // The notifier thread is a daemon just loops forever to wake
4617c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // up threads in Operation.WAIT
462f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (lock != null) {
463f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            Thread notifier = new Thread("Notifier") {
464f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                public void run() {
465f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    while (true) {
466f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                        synchronized (lock) {
467f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                            lock.notifyAll();
468f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                        }
4697c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    }
4707c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                }
471f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            };
472f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            notifier.setDaemon(true);
473f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            notifier.start();
474f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
4757c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
476def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        // Create and start the daemon threads.
477def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        for (int r = 0; r < numberOfDaemons; r++) {
478def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao            Main daemon = threadStresses[numberOfThreads + r];
479def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao            Thread t = new Thread(daemon, "Daemon thread " + daemon.id);
480def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao            t.setDaemon(true);
481def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao            t.start();
482def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        }
483def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao
4847c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        for (int r = 0; r < runners.length; r++) {
4857c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            runners[r].start();
4867c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        }
4877c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        for (int r = 0; r < runners.length; r++) {
4887c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            runners[r].join();
4897c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        }
4907c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom    }
4917c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
492def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao    protected final Operation[] operations;
4937c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom    private final Object lock;
494def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao    protected final int id;
4957c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
4967c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom    private int nextOperation;
4977c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
4981c83cbc4a817acbd7f9abb5b29a2d418a958e6a1Andreas Gampe    private Main(Object lock, int id, Operation[] operations) {
4997c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        this.lock = lock;
5007c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        this.id = id;
5017c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        this.operations = operations;
5027c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom    }
5037c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
5047c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom    public void run() {
5057c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        try {
5067c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            if (DEBUG) {
5077c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                System.out.println("Starting ThreadStress " + id);
5087c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            }
5097c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            while (nextOperation < operations.length) {
5107c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                Operation operation = operations[nextOperation];
5117c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                if (DEBUG) {
5127c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    System.out.println("ThreadStress " + id
5137c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                                       + " operation " + nextOperation
5147c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                                       + " is " + operation);
5157c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                }
5167c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                nextOperation++;
517f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                if (!operation.perform()) {
518f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    return;
5197c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                }
5207c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            }
5214514d3c0e69a49f5dbe19138330a2bb2aee36d63Brian Carlstrom        } finally {
5227c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            if (DEBUG) {
5237c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                System.out.println("Finishing ThreadStress for " + id);
5247c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            }
5257c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        }
5267c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom    }
5271c83cbc4a817acbd7f9abb5b29a2d418a958e6a1Andreas Gampe
528def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao    private static class Daemon extends Main {
529def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        private Daemon(Object lock, int id, Operation[] operations) {
530def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao            super(lock, id, operations);
531def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        }
532def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao
533def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        public void run() {
534def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao            try {
535def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                if (DEBUG) {
536def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                    System.out.println("Starting ThreadStress Daemon " + id);
537def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                }
538def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                int i = 0;
539def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                while (true) {
540def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                    Operation operation = operations[i];
541def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                    if (DEBUG) {
542def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                        System.out.println("ThreadStress Daemon " + id
543def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                                           + " operation " + i
544def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                                           + " is " + operation);
545def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                    }
546def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                    operation.perform();
547def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                    i = (i + 1) % operations.length;
548def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                }
549bf81547a47c46a8853092432635bfec6167a2388Mathieu Chartier            } catch (OutOfMemoryError e) {
550bf81547a47c46a8853092432635bfec6167a2388Mathieu Chartier                // Catch OutOfMemoryErrors since these can cause the test to fail it they print
551bf81547a47c46a8853092432635bfec6167a2388Mathieu Chartier                // the stack trace after "Finishing worker".
552def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao            } finally {
553def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                if (DEBUG) {
554def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                    System.out.println("Finishing ThreadStress Daemon for " + id);
555def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                }
556def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao            }
557def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        }
558def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao    }
559def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao
5607c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom}
561