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 {
60059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe        private final static int ALLOC_SIZE = 1024;
61059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe
62f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        @Override
63f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public boolean perform() {
64f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            try {
65f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                List<byte[]> l = new ArrayList<byte[]>();
66f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                while (true) {
67059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe                    l.add(new byte[ALLOC_SIZE]);
68f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                }
69f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            } catch (OutOfMemoryError e) {
70f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
71f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            return true;
72f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
73f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
74f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
75f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static class SigQuit extends Operation {
76f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        private final static int sigquit;
77f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        private final static Method kill;
78f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        private final static int pid;
79f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
80f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        static {
81f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            int pidTemp = -1;
82f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            int sigquitTemp = -1;
83f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            Method killTemp = null;
84f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
85f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            try {
86f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                Class<?> osClass = Class.forName("android.system.Os");
87f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                Method getpid = osClass.getDeclaredMethod("getpid");
88f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                pidTemp = (Integer)getpid.invoke(null);
89f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
90f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                Class<?> osConstants = Class.forName("android.system.OsConstants");
91f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                Field sigquitField = osConstants.getDeclaredField("SIGQUIT");
92f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                sigquitTemp = (Integer)sigquitField.get(null);
93f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
94f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                killTemp = osClass.getDeclaredMethod("kill", int.class, int.class);
95f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            } catch (Exception e) {
96f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                if (!e.getClass().getName().equals("ErrnoException")) {
97f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    e.printStackTrace(System.out);
98f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                }
99f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
100f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
101f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            pid = pidTemp;
102f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            sigquit = sigquitTemp;
103f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            kill = killTemp;
104f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
105f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
106f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        @Override
107f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public boolean perform() {
108f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            try {
109f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                kill.invoke(null, pid, sigquit);
110f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            } catch (Exception e) {
111f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                if (!e.getClass().getName().equals("ErrnoException")) {
112f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    e.printStackTrace(System.out);
113f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                }
114f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
115f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            return true;
116f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
117f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
118f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
119f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static class Alloc extends Operation {
120059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe        private final static int ALLOC_SIZE = 1024;  // Needs to be small enough to not be in LOS.
121059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe        private final static int ALLOC_COUNT = 1024;
122059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe
123059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe        @Override
124059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe        public boolean perform() {
125059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe            try {
126059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe                List<byte[]> l = new ArrayList<byte[]>();
127059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe                for (int i = 0; i < ALLOC_COUNT; i++) {
128059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe                    l.add(new byte[ALLOC_SIZE]);
129059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe                }
130059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe            } catch (OutOfMemoryError e) {
131059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe            }
132059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe            return true;
133059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe        }
134059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe    }
135059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe
136059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe    private final static class LargeAlloc extends Operation {
137059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe        private final static int PAGE_SIZE = 4096;
138059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe        private final static int PAGE_SIZE_MODIFIER = 10;  // Needs to be large enough for LOS.
139059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe        private final static int ALLOC_COUNT = 100;
140059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe
141f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        @Override
142f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public boolean perform() {
143f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            try {
144f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                List<byte[]> l = new ArrayList<byte[]>();
145059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe                for (int i = 0; i < ALLOC_COUNT; i++) {
146059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe                    l.add(new byte[PAGE_SIZE_MODIFIER * PAGE_SIZE]);
147f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                }
148f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            } catch (OutOfMemoryError e) {
149f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
150f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            return true;
151f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
152f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
153f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
154f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static class StackTrace extends Operation {
155f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        @Override
156f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public boolean perform() {
157f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            Thread.currentThread().getStackTrace();
158f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            return true;
159f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
160f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
161f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
162f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static class Exit extends Operation {
163f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        @Override
164f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public boolean perform() {
165f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            return false;
166f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
167f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
168f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
169f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static class Sleep extends Operation {
170059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe        private final static int SLEEP_TIME = 100;
171059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe
172f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        @Override
173f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public boolean perform() {
174f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            try {
175059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe                Thread.sleep(SLEEP_TIME);
176f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            } catch (InterruptedException ignored) {
177f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
178f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            return true;
179f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
180f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
1814cd121ef0cb35fced70c7d9de378277be7a727d9Elliott Hughes
182f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static class TimedWait extends Operation {
183059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe        private final static int SLEEP_TIME = 100;
184059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe
185f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        private final Object lock;
1867c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
187f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public TimedWait(Object lock) {
188f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            this.lock = lock;
189f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
190f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
191f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        @Override
192f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public boolean perform() {
193f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            synchronized (lock) {
194f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                try {
195059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe                    lock.wait(SLEEP_TIME, 0);
196f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                } catch (InterruptedException ignored) {
197f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                }
198f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
199f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            return true;
2007c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        }
2017c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom    }
2027c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
203f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static class Wait extends Operation {
204f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        private final Object lock;
205f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
206f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public Wait(Object lock) {
207f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            this.lock = lock;
208f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
209f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
210f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        @Override
211f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public boolean perform() {
212f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            synchronized (lock) {
213f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                try {
214f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    lock.wait();
215f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                } catch (InterruptedException ignored) {
216f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                }
217f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
218f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            return true;
219f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
220f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
221f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
222f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static class SyncAndWork extends Operation {
223f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        private final Object lock;
224f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
225f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public SyncAndWork(Object lock) {
226f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            this.lock = lock;
227f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
228f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
229f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        @Override
230f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public boolean perform() {
231f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            synchronized (lock) {
232f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                try {
233f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    Thread.sleep((int)(Math.random()*10));
234f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                } catch (InterruptedException ignored) {
235f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                }
236f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
237f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            return true;
238f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
239f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
240f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
241f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static Map<Operation, Double> createDefaultFrequencyMap(Object lock) {
242f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        Map<Operation, Double> frequencyMap = new HashMap<Operation, Double>();
243f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        frequencyMap.put(new OOM(), 0.005);             //  1/200
244f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        frequencyMap.put(new SigQuit(), 0.095);         // 19/200
245059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe        frequencyMap.put(new Alloc(), 0.25);            // 50/200
246059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe        frequencyMap.put(new LargeAlloc(), 0.05);       // 10/200
247f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        frequencyMap.put(new StackTrace(), 0.1);        // 20/200
248f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        frequencyMap.put(new Exit(), 0.25);             // 50/200
249f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        frequencyMap.put(new Sleep(), 0.125);           // 25/200
250f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        frequencyMap.put(new TimedWait(lock), 0.05);    // 10/200
251f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        frequencyMap.put(new Wait(lock), 0.075);        // 15/200
252f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
253f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        return frequencyMap;
254f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
255f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
256f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static Map<Operation, Double> createLockFrequencyMap(Object lock) {
257f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe      Map<Operation, Double> frequencyMap = new HashMap<Operation, Double>();
258f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe      frequencyMap.put(new Sleep(), 0.2);
259f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe      frequencyMap.put(new TimedWait(lock), 0.2);
260f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe      frequencyMap.put(new Wait(lock), 0.2);
261f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe      frequencyMap.put(new SyncAndWork(lock), 0.4);
262f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
263f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe      return frequencyMap;
264f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
265f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
2667c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom    public static void main(String[] args) throws Exception {
267f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        parseAndRun(args);
268f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
2697c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
270f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private static Map<Operation, Double> updateFrequencyMap(Map<Operation, Double> in,
271f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            Object lock, String arg) {
272f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        String split[] = arg.split(":");
273f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (split.length != 2) {
274f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            throw new IllegalArgumentException("Can't split argument " + arg);
275f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
276f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        double d;
277f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        try {
278f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            d = Double.parseDouble(split[1]);
279f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        } catch (Exception e) {
280f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            throw new IllegalArgumentException(e);
281f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
282f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (d < 0) {
283f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            throw new IllegalArgumentException(arg + ": value must be >= 0.");
284f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
285f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        Operation op = null;
286f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (split[0].equals("-oom")) {
287f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            op = new OOM();
288f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        } else if (split[0].equals("-sigquit")) {
289f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            op = new SigQuit();
290f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        } else if (split[0].equals("-alloc")) {
291f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            op = new Alloc();
292059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe        } else if (split[0].equals("-largealloc")) {
293059e62711093bbc115e1d6ca56573e2df3ebdff8Andreas Gampe            op = new LargeAlloc();
294f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        } else if (split[0].equals("-stacktrace")) {
295f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            op = new StackTrace();
296f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        } else if (split[0].equals("-exit")) {
297f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            op = new Exit();
298f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        } else if (split[0].equals("-sleep")) {
299f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            op = new Sleep();
300f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        } else if (split[0].equals("-wait")) {
301f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            op = new Wait(lock);
302f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        } else if (split[0].equals("-timedwait")) {
303f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            op = new TimedWait(lock);
304f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        } else {
305f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            throw new IllegalArgumentException("Unknown arg " + arg);
306f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
307f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
308f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (in == null) {
309f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            in = new HashMap<Operation, Double>();
310f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
311f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        in.put(op, d);
3127c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
313f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        return in;
314f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
315f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
316f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private static void normalize(Map<Operation, Double> map) {
317f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        double sum = 0;
318f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        for (Double d : map.values()) {
319f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            sum += d;
320f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
321f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (sum == 0) {
322f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            throw new RuntimeException("No elements!");
323f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
324f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (sum != 1.0) {
325f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            // Avoid ConcurrentModificationException.
326f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            Set<Operation> tmp = new HashSet<>(map.keySet());
327f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            for (Operation op : tmp) {
328f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                map.put(op, map.get(op) / sum);
329f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
330f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
331f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
332f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
333f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    public static void parseAndRun(String[] args) throws Exception {
334f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        int numberOfThreads = -1;
335def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        int numberOfDaemons = -1;
336f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        int totalOperations = -1;
337f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        int operationsPerThread = -1;
338f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        Object lock = new Object();
339f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        Map<Operation, Double> frequencyMap = null;
340f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        boolean dumpMap = false;
341f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
342f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (args != null) {
343031768a340634e2dbdec1aebb2bb3fe509b2f1f6Mathieu Chartier            // args[0] is libarttest
344031768a340634e2dbdec1aebb2bb3fe509b2f1f6Mathieu Chartier            for (int i = 1; i < args.length; i++) {
345f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                if (args[i].equals("-n")) {
346f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    i++;
347f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    numberOfThreads = Integer.parseInt(args[i]);
348def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                } else if (args[i].equals("-d")) {
349def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                    i++;
350def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                    numberOfDaemons = Integer.parseInt(args[i]);
351f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                } else if (args[i].equals("-o")) {
352f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    i++;
353f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    totalOperations = Integer.parseInt(args[i]);
354f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                } else if (args[i].equals("-t")) {
355f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    i++;
356f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    operationsPerThread = Integer.parseInt(args[i]);
357f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                } else if (args[i].equals("--locks-only")) {
358f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    lock = new Object();
359f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    frequencyMap = createLockFrequencyMap(lock);
360f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                } else if (args[i].equals("--dumpmap")) {
361f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    dumpMap = true;
362f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                } else {
363f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    frequencyMap = updateFrequencyMap(frequencyMap, lock, args[i]);
364f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                }
365f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
366f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
3677c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
368f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (totalOperations != -1 && operationsPerThread != -1) {
369f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            throw new IllegalArgumentException(
370f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    "Specified both totalOperations and operationsPerThread");
371f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
372f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
373f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (numberOfThreads == -1) {
374f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            numberOfThreads = 5;
375f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
376f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
377def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        if (numberOfDaemons == -1) {
378def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao            numberOfDaemons = 3;
379def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        }
380def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao
381f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (totalOperations == -1) {
382f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            totalOperations = 1000;
383f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
384f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
385f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (operationsPerThread == -1) {
386f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            operationsPerThread = totalOperations/numberOfThreads;
387f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
388f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
389f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (frequencyMap == null) {
390f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            frequencyMap = createDefaultFrequencyMap(lock);
391f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
392f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        normalize(frequencyMap);
393f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
394f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (dumpMap) {
395f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            System.out.println(frequencyMap);
396f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
397f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
398def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        runTest(numberOfThreads, numberOfDaemons, operationsPerThread, lock, frequencyMap);
399f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
400f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
401def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao    public static void runTest(final int numberOfThreads, final int numberOfDaemons,
402def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                               final int operationsPerThread, final Object lock,
403def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                               Map<Operation, Double> frequencyMap) throws Exception {
404def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        // Each normal thread is going to do operationsPerThread
405def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        // operations. Each daemon thread will loop over all
406def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        // the operations and will not stop.
407def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        // The distribution of operations is determined by
4087c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // the Operation.frequency values. We fill out an Operation[]
4097c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // for each thread with the operations it is to perform. The
4107c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // Operation[] is shuffled so that there is more random
4117c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // interactions between the threads.
4127c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
4137c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // Fill in the Operation[] array for each thread by laying
4147c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // down references to operation according to their desired
4157c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // frequency.
416def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        // The first numberOfThreads elements are normal threads, the last
417def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        // numberOfDaemons elements are daemon threads.
418def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        final Main[] threadStresses = new Main[numberOfThreads + numberOfDaemons];
4197c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        for (int t = 0; t < threadStresses.length; t++) {
4207c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            Operation[] operations = new Operation[operationsPerThread];
4217c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            int o = 0;
4227c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            LOOP:
4237c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            while (true) {
424f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                for (Operation op : frequencyMap.keySet()) {
425f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    int freq = (int)(frequencyMap.get(op) * operationsPerThread);
426f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    for (int f = 0; f < freq; f++) {
4277c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                        if (o == operations.length) {
4287c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                            break LOOP;
4297c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                        }
4307c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                        operations[o] = op;
4317c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                        o++;
4327c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    }
4337c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                }
4347c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            }
435def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao            // Randomize the operation order
4367c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            Collections.shuffle(Arrays.asList(operations));
437def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao            threadStresses[t] = t < numberOfThreads ? new Main(lock, t, operations) :
438def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                                                      new Daemon(lock, t, operations);
4397c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        }
4407c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
441f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        // Enable to dump operation counts per thread to make sure its
4427c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // sane compared to Operation.frequency
4437c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        if (DEBUG) {
4447c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            for (int t = 0; t < threadStresses.length; t++) {
445f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                Operation[] operations = threadStresses[t].operations;
4467c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                Map<Operation, Integer> distribution = new HashMap<Operation, Integer>();
4477c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                for (Operation operation : operations) {
4487c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    Integer ops = distribution.get(operation);
4497c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    if (ops == null) {
4507c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                        ops = 1;
4517c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    } else {
4527c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                        ops++;
4537c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    }
4547c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    distribution.put(operation, ops);
4557c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                }
4567c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                System.out.println("Distribution for " + t);
457f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                for (Operation op : frequencyMap.keySet()) {
4587c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    System.out.println(op + " = " + distribution.get(op));
4597c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                }
4607c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            }
4617c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        }
4627c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
4637c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // Create the runners for each thread. The runner Thread
4647c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // ensures that thread that exit due to Operation.EXIT will be
4657c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // restarted until they reach their desired
4667c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // operationsPerThread.
4677c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        Thread[] runners = new Thread[numberOfThreads];
4687c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        for (int r = 0; r < runners.length; r++) {
4691c83cbc4a817acbd7f9abb5b29a2d418a958e6a1Andreas Gampe            final Main ts = threadStresses[r];
4705f51d4b80058236759fea1d932470a57f348c199Mathieu Chartier            runners[r] = new Thread("Runner thread " + r) {
4711c83cbc4a817acbd7f9abb5b29a2d418a958e6a1Andreas Gampe                final Main threadStress = ts;
4727c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                public void run() {
4737c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    int id = threadStress.id;
4745f51d4b80058236759fea1d932470a57f348c199Mathieu Chartier                    System.out.println("Starting worker for " + id);
4757c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    while (threadStress.nextOperation < operationsPerThread) {
4769d3c3fc49dc904ddd393f8d24ed062a42c68939aMathieu Chartier                        try {
47772e36d84d8c6eb4a0396ce7e4de8f696ad3d2a7fMathieu Chartier                            Thread thread = new Thread(ts, "Worker thread " + id);
47872e36d84d8c6eb4a0396ce7e4de8f696ad3d2a7fMathieu Chartier                            thread.start();
47972e36d84d8c6eb4a0396ce7e4de8f696ad3d2a7fMathieu Chartier                            try {
48072e36d84d8c6eb4a0396ce7e4de8f696ad3d2a7fMathieu Chartier                                thread.join();
48172e36d84d8c6eb4a0396ce7e4de8f696ad3d2a7fMathieu Chartier                            } catch (InterruptedException e) {
48272e36d84d8c6eb4a0396ce7e4de8f696ad3d2a7fMathieu Chartier                            }
48372e36d84d8c6eb4a0396ce7e4de8f696ad3d2a7fMathieu Chartier
4849d3c3fc49dc904ddd393f8d24ed062a42c68939aMathieu Chartier                            System.out.println("Thread exited for " + id + " with "
4859d3c3fc49dc904ddd393f8d24ed062a42c68939aMathieu Chartier                                               + (operationsPerThread - threadStress.nextOperation)
4869d3c3fc49dc904ddd393f8d24ed062a42c68939aMathieu Chartier                                               + " operations remaining.");
4879d3c3fc49dc904ddd393f8d24ed062a42c68939aMathieu Chartier                        } catch (OutOfMemoryError e) {
4889d3c3fc49dc904ddd393f8d24ed062a42c68939aMathieu Chartier                            // Ignore OOME since we need to print "Finishing worker" for the test
4899d3c3fc49dc904ddd393f8d24ed062a42c68939aMathieu Chartier                            // to pass.
4909d3c3fc49dc904ddd393f8d24ed062a42c68939aMathieu Chartier                        }
4917c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    }
49272e36d84d8c6eb4a0396ce7e4de8f696ad3d2a7fMathieu Chartier                    // Keep trying to print "Finishing worker" until it succeeds.
49372e36d84d8c6eb4a0396ce7e4de8f696ad3d2a7fMathieu Chartier                    while (true) {
49472e36d84d8c6eb4a0396ce7e4de8f696ad3d2a7fMathieu Chartier                        try {
49572e36d84d8c6eb4a0396ce7e4de8f696ad3d2a7fMathieu Chartier                            System.out.println("Finishing worker");
49672e36d84d8c6eb4a0396ce7e4de8f696ad3d2a7fMathieu Chartier                            break;
49772e36d84d8c6eb4a0396ce7e4de8f696ad3d2a7fMathieu Chartier                        } catch (OutOfMemoryError e) {
49872e36d84d8c6eb4a0396ce7e4de8f696ad3d2a7fMathieu Chartier                        }
49972e36d84d8c6eb4a0396ce7e4de8f696ad3d2a7fMathieu Chartier                    }
5007c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                }
5017c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            };
5027c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        }
5037c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
5047c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // The notifier thread is a daemon just loops forever to wake
5057c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // up threads in Operation.WAIT
506f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (lock != null) {
507f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            Thread notifier = new Thread("Notifier") {
508f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                public void run() {
509f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    while (true) {
510f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                        synchronized (lock) {
511f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                            lock.notifyAll();
512f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                        }
5137c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    }
5147c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                }
515f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            };
516f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            notifier.setDaemon(true);
517f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            notifier.start();
518f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
5197c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
520def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        // Create and start the daemon threads.
521def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        for (int r = 0; r < numberOfDaemons; r++) {
522def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao            Main daemon = threadStresses[numberOfThreads + r];
523def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao            Thread t = new Thread(daemon, "Daemon thread " + daemon.id);
524def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao            t.setDaemon(true);
525def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao            t.start();
526def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        }
527def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao
5287c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        for (int r = 0; r < runners.length; r++) {
5297c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            runners[r].start();
5307c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        }
5317c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        for (int r = 0; r < runners.length; r++) {
5327c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            runners[r].join();
5337c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        }
5347c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom    }
5357c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
536def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao    protected final Operation[] operations;
5377c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom    private final Object lock;
538def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao    protected final int id;
5397c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
5407c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom    private int nextOperation;
5417c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
5421c83cbc4a817acbd7f9abb5b29a2d418a958e6a1Andreas Gampe    private Main(Object lock, int id, Operation[] operations) {
5437c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        this.lock = lock;
5447c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        this.id = id;
5457c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        this.operations = operations;
5467c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom    }
5477c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
5487c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom    public void run() {
5497c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        try {
5507c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            if (DEBUG) {
5517c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                System.out.println("Starting ThreadStress " + id);
5527c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            }
5537c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            while (nextOperation < operations.length) {
5547c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                Operation operation = operations[nextOperation];
5557c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                if (DEBUG) {
5567c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    System.out.println("ThreadStress " + id
5577c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                                       + " operation " + nextOperation
5587c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                                       + " is " + operation);
5597c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                }
5607c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                nextOperation++;
561f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                if (!operation.perform()) {
562f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    return;
5637c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                }
5647c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            }
5654514d3c0e69a49f5dbe19138330a2bb2aee36d63Brian Carlstrom        } finally {
5667c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            if (DEBUG) {
5677c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                System.out.println("Finishing ThreadStress for " + id);
5687c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            }
5697c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        }
5707c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom    }
5711c83cbc4a817acbd7f9abb5b29a2d418a958e6a1Andreas Gampe
572def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao    private static class Daemon extends Main {
573def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        private Daemon(Object lock, int id, Operation[] operations) {
574def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao            super(lock, id, operations);
575def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        }
576def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao
577def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        public void run() {
578def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao            try {
579def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                if (DEBUG) {
580def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                    System.out.println("Starting ThreadStress Daemon " + id);
581def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                }
582def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                int i = 0;
583def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                while (true) {
584def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                    Operation operation = operations[i];
585def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                    if (DEBUG) {
586def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                        System.out.println("ThreadStress Daemon " + id
587def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                                           + " operation " + i
588def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                                           + " is " + operation);
589def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                    }
590def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                    operation.perform();
591def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                    i = (i + 1) % operations.length;
592def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                }
593bf81547a47c46a8853092432635bfec6167a2388Mathieu Chartier            } catch (OutOfMemoryError e) {
594bf81547a47c46a8853092432635bfec6167a2388Mathieu Chartier                // Catch OutOfMemoryErrors since these can cause the test to fail it they print
595bf81547a47c46a8853092432635bfec6167a2388Mathieu Chartier                // the stack trace after "Finishing worker".
596def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao            } finally {
597def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                if (DEBUG) {
598def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                    System.out.println("Finishing ThreadStress Daemon for " + id);
599def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao                }
600def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao            }
601def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao        }
602def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao    }
603def3fcdbc5e9ef21c16047caac53ab53fb02de0cMan Cao
6047c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom}
605