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
35f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe//    -o X ............ number of overall operations
36f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe//    -t X ............ number of operations per thread
37f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe//    --dumpmap ....... print the frequency map
38f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe//    -oom:X .......... frequency of OOM (double)
39f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe//    -alloc:X ........ frequency of Alloc
40f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe//    -stacktrace:X ... frequency of StackTrace
41f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe//    -exit:X ......... frequency of Exit
42f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe//    -sleep:X ........ frequency of Sleep
43f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe//    -wait:X ......... frequency of Wait
44f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe//    -timedwait:X .... frequency of TimedWait
45f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
461c83cbc4a817acbd7f9abb5b29a2d418a958e6a1Andreas Gampepublic class Main implements Runnable {
477c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
484514d3c0e69a49f5dbe19138330a2bb2aee36d63Brian Carlstrom    public static final boolean DEBUG = false;
497c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
50f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private static abstract class Operation {
51f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        /**
52f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe         * Perform the action represented by this operation. Returns true if the thread should
53f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe         * continue.
54f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe         */
55f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public abstract boolean perform();
56f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
57f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
58f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static class OOM extends Operation {
59f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        @Override
60f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public boolean perform() {
61f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            try {
62f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                List<byte[]> l = new ArrayList<byte[]>();
63f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                while (true) {
64f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    l.add(new byte[1024]);
65f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                }
66f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            } catch (OutOfMemoryError e) {
67f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
68f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            return true;
69f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
70f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
71f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
72f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static class SigQuit extends Operation {
73f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        private final static int sigquit;
74f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        private final static Method kill;
75f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        private final static int pid;
76f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
77f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        static {
78f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            int pidTemp = -1;
79f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            int sigquitTemp = -1;
80f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            Method killTemp = null;
81f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
82f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            try {
83f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                Class<?> osClass = Class.forName("android.system.Os");
84f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                Method getpid = osClass.getDeclaredMethod("getpid");
85f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                pidTemp = (Integer)getpid.invoke(null);
86f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
87f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                Class<?> osConstants = Class.forName("android.system.OsConstants");
88f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                Field sigquitField = osConstants.getDeclaredField("SIGQUIT");
89f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                sigquitTemp = (Integer)sigquitField.get(null);
90f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
91f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                killTemp = osClass.getDeclaredMethod("kill", int.class, int.class);
92f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            } catch (Exception e) {
93f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                if (!e.getClass().getName().equals("ErrnoException")) {
94f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    e.printStackTrace(System.out);
95f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                }
96f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
97f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
98f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            pid = pidTemp;
99f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            sigquit = sigquitTemp;
100f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            kill = killTemp;
101f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
102f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
103f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        @Override
104f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public boolean perform() {
105f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            try {
106f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                kill.invoke(null, pid, sigquit);
107f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            } catch (Exception e) {
108f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                if (!e.getClass().getName().equals("ErrnoException")) {
109f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    e.printStackTrace(System.out);
110f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                }
111f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
112f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            return true;
113f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
114f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
115f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
116f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static class Alloc extends Operation {
117f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        @Override
118f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public boolean perform() {
119f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            try {
120f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                List<byte[]> l = new ArrayList<byte[]>();
121f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                for (int i = 0; i < 1024; i++) {
122f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    l.add(new byte[1024]);
123f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                }
124f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            } catch (OutOfMemoryError e) {
125f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
126f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            return true;
127f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
128f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
129f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
130f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static class StackTrace extends Operation {
131f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        @Override
132f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public boolean perform() {
133f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            Thread.currentThread().getStackTrace();
134f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            return true;
135f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
136f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
137f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
138f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static class Exit extends Operation {
139f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        @Override
140f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public boolean perform() {
141f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            return false;
142f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
143f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
144f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
145f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static class Sleep extends Operation {
146f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        @Override
147f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public boolean perform() {
148f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            try {
149f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                Thread.sleep(100);
150f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            } catch (InterruptedException ignored) {
151f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
152f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            return true;
153f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
154f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
1554cd121ef0cb35fced70c7d9de378277be7a727d9Elliott Hughes
156f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static class TimedWait extends Operation {
157f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        private final Object lock;
1587c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
159f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public TimedWait(Object lock) {
160f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            this.lock = lock;
161f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
162f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
163f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        @Override
164f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public boolean perform() {
165f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            synchronized (lock) {
166f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                try {
167f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    lock.wait(100, 0);
168f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                } catch (InterruptedException ignored) {
169f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                }
170f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
171f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            return true;
1727c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        }
1737c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom    }
1747c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
175f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static class Wait extends Operation {
176f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        private final Object lock;
177f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
178f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public Wait(Object lock) {
179f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            this.lock = lock;
180f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
181f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
182f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        @Override
183f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public boolean perform() {
184f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            synchronized (lock) {
185f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                try {
186f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    lock.wait();
187f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                } catch (InterruptedException ignored) {
188f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                }
189f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
190f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            return true;
191f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
192f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
193f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
194f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static class SyncAndWork extends Operation {
195f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        private final Object lock;
196f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
197f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public SyncAndWork(Object lock) {
198f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            this.lock = lock;
199f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
200f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
201f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        @Override
202f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        public boolean perform() {
203f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            synchronized (lock) {
204f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                try {
205f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    Thread.sleep((int)(Math.random()*10));
206f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                } catch (InterruptedException ignored) {
207f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                }
208f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
209f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            return true;
210f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
211f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
212f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
213f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static Map<Operation, Double> createDefaultFrequencyMap(Object lock) {
214f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        Map<Operation, Double> frequencyMap = new HashMap<Operation, Double>();
215f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        frequencyMap.put(new OOM(), 0.005);             //  1/200
216f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        frequencyMap.put(new SigQuit(), 0.095);         // 19/200
217f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        frequencyMap.put(new Alloc(), 0.3);             // 60/200
218f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        frequencyMap.put(new StackTrace(), 0.1);        // 20/200
219f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        frequencyMap.put(new Exit(), 0.25);             // 50/200
220f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        frequencyMap.put(new Sleep(), 0.125);           // 25/200
221f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        frequencyMap.put(new TimedWait(lock), 0.05);    // 10/200
222f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        frequencyMap.put(new Wait(lock), 0.075);        // 15/200
223f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
224f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        return frequencyMap;
225f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
226f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
227f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private final static Map<Operation, Double> createLockFrequencyMap(Object lock) {
228f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe      Map<Operation, Double> frequencyMap = new HashMap<Operation, Double>();
229f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe      frequencyMap.put(new Sleep(), 0.2);
230f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe      frequencyMap.put(new TimedWait(lock), 0.2);
231f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe      frequencyMap.put(new Wait(lock), 0.2);
232f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe      frequencyMap.put(new SyncAndWork(lock), 0.4);
233f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
234f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe      return frequencyMap;
235f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
236f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
2377c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom    public static void main(String[] args) throws Exception {
238f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        parseAndRun(args);
239f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
2407c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
241f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private static Map<Operation, Double> updateFrequencyMap(Map<Operation, Double> in,
242f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            Object lock, String arg) {
243f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        String split[] = arg.split(":");
244f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (split.length != 2) {
245f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            throw new IllegalArgumentException("Can't split argument " + arg);
246f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
247f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        double d;
248f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        try {
249f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            d = Double.parseDouble(split[1]);
250f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        } catch (Exception e) {
251f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            throw new IllegalArgumentException(e);
252f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
253f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (d < 0) {
254f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            throw new IllegalArgumentException(arg + ": value must be >= 0.");
255f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
256f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        Operation op = null;
257f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (split[0].equals("-oom")) {
258f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            op = new OOM();
259f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        } else if (split[0].equals("-sigquit")) {
260f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            op = new SigQuit();
261f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        } else if (split[0].equals("-alloc")) {
262f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            op = new Alloc();
263f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        } else if (split[0].equals("-stacktrace")) {
264f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            op = new StackTrace();
265f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        } else if (split[0].equals("-exit")) {
266f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            op = new Exit();
267f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        } else if (split[0].equals("-sleep")) {
268f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            op = new Sleep();
269f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        } else if (split[0].equals("-wait")) {
270f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            op = new Wait(lock);
271f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        } else if (split[0].equals("-timedwait")) {
272f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            op = new TimedWait(lock);
273f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        } else {
274f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            throw new IllegalArgumentException("Unknown arg " + arg);
275f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
276f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
277f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (in == null) {
278f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            in = new HashMap<Operation, Double>();
279f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
280f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        in.put(op, d);
2817c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
282f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        return in;
283f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
284f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
285f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    private static void normalize(Map<Operation, Double> map) {
286f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        double sum = 0;
287f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        for (Double d : map.values()) {
288f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            sum += d;
289f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
290f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (sum == 0) {
291f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            throw new RuntimeException("No elements!");
292f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
293f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (sum != 1.0) {
294f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            // Avoid ConcurrentModificationException.
295f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            Set<Operation> tmp = new HashSet<>(map.keySet());
296f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            for (Operation op : tmp) {
297f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                map.put(op, map.get(op) / sum);
298f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
299f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
300f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
301f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
302f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    public static void parseAndRun(String[] args) throws Exception {
303f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        int numberOfThreads = -1;
304f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        int totalOperations = -1;
305f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        int operationsPerThread = -1;
306f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        Object lock = new Object();
307f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        Map<Operation, Double> frequencyMap = null;
308f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        boolean dumpMap = false;
309f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
310f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (args != null) {
311f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            for (int i = 0; i < args.length; i++) {
312f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                if (args[i].equals("-n")) {
313f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    i++;
314f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    numberOfThreads = Integer.parseInt(args[i]);
315f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                } else if (args[i].equals("-o")) {
316f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    i++;
317f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    totalOperations = Integer.parseInt(args[i]);
318f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                } else if (args[i].equals("-t")) {
319f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    i++;
320f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    operationsPerThread = Integer.parseInt(args[i]);
321f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                } else if (args[i].equals("--locks-only")) {
322f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    lock = new Object();
323f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    frequencyMap = createLockFrequencyMap(lock);
324f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                } else if (args[i].equals("--dumpmap")) {
325f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    dumpMap = true;
326f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                } else {
327f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    frequencyMap = updateFrequencyMap(frequencyMap, lock, args[i]);
328f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                }
329f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            }
330f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
3317c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
332f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (totalOperations != -1 && operationsPerThread != -1) {
333f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            throw new IllegalArgumentException(
334f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    "Specified both totalOperations and operationsPerThread");
335f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
336f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
337f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (numberOfThreads == -1) {
338f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            numberOfThreads = 5;
339f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
340f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
341f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (totalOperations == -1) {
342f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            totalOperations = 1000;
343f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
344f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
345f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (operationsPerThread == -1) {
346f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            operationsPerThread = totalOperations/numberOfThreads;
347f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
348f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
349f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (frequencyMap == null) {
350f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            frequencyMap = createDefaultFrequencyMap(lock);
351f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
352f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        normalize(frequencyMap);
353f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
354f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (dumpMap) {
355f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            System.out.println(frequencyMap);
356f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
357f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
358f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        runTest(numberOfThreads, operationsPerThread, lock, frequencyMap);
359f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    }
360f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe
361f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe    public static void runTest(final int numberOfThreads, final int operationsPerThread,
362f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                               final Object lock, Map<Operation, Double> frequencyMap)
363f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                                   throws Exception {
3647c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // Each thread is going to do operationsPerThread
3657c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // operations. The distribution of operations is determined by
3667c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // the Operation.frequency values. We fill out an Operation[]
3677c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // for each thread with the operations it is to perform. The
3687c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // Operation[] is shuffled so that there is more random
3697c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // interactions between the threads.
3707c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
3717c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // Fill in the Operation[] array for each thread by laying
3727c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // down references to operation according to their desired
3737c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // frequency.
3741c83cbc4a817acbd7f9abb5b29a2d418a958e6a1Andreas Gampe        final Main[] threadStresses = new Main[numberOfThreads];
3757c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        for (int t = 0; t < threadStresses.length; t++) {
3767c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            Operation[] operations = new Operation[operationsPerThread];
3777c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            int o = 0;
3787c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            LOOP:
3797c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            while (true) {
380f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                for (Operation op : frequencyMap.keySet()) {
381f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    int freq = (int)(frequencyMap.get(op) * operationsPerThread);
382f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    for (int f = 0; f < freq; f++) {
3837c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                        if (o == operations.length) {
3847c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                            break LOOP;
3857c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                        }
3867c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                        operations[o] = op;
3877c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                        o++;
3887c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    }
3897c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                }
3907c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            }
3917c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            // Randomize the oepration order
3927c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            Collections.shuffle(Arrays.asList(operations));
3931c83cbc4a817acbd7f9abb5b29a2d418a958e6a1Andreas Gampe            threadStresses[t] = new Main(lock, t, operations);
3947c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        }
3957c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
396f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        // Enable to dump operation counts per thread to make sure its
3977c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // sane compared to Operation.frequency
3987c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        if (DEBUG) {
3997c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            for (int t = 0; t < threadStresses.length; t++) {
400f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                Operation[] operations = threadStresses[t].operations;
4017c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                Map<Operation, Integer> distribution = new HashMap<Operation, Integer>();
4027c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                for (Operation operation : operations) {
4037c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    Integer ops = distribution.get(operation);
4047c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    if (ops == null) {
4057c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                        ops = 1;
4067c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    } else {
4077c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                        ops++;
4087c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    }
4097c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    distribution.put(operation, ops);
4107c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                }
4117c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                System.out.println("Distribution for " + t);
412f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                for (Operation op : frequencyMap.keySet()) {
4137c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    System.out.println(op + " = " + distribution.get(op));
4147c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                }
4157c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            }
4167c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        }
4177c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
4187c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // Create the runners for each thread. The runner Thread
4197c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // ensures that thread that exit due to Operation.EXIT will be
4207c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // restarted until they reach their desired
4217c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // operationsPerThread.
4227c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        Thread[] runners = new Thread[numberOfThreads];
4237c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        for (int r = 0; r < runners.length; r++) {
4241c83cbc4a817acbd7f9abb5b29a2d418a958e6a1Andreas Gampe            final Main ts = threadStresses[r];
4255f51d4b80058236759fea1d932470a57f348c199Mathieu Chartier            runners[r] = new Thread("Runner thread " + r) {
4261c83cbc4a817acbd7f9abb5b29a2d418a958e6a1Andreas Gampe                final Main threadStress = ts;
4277c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                public void run() {
4287c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    int id = threadStress.id;
4295f51d4b80058236759fea1d932470a57f348c199Mathieu Chartier                    System.out.println("Starting worker for " + id);
4307c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    while (threadStress.nextOperation < operationsPerThread) {
4315f51d4b80058236759fea1d932470a57f348c199Mathieu Chartier                        Thread thread = new Thread(ts, "Worker thread " + id);
4327c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                        thread.start();
4337c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                        try {
4347c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                            thread.join();
4357c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                        } catch (InterruptedException e) {
4367c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                        }
4377c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                        System.out.println("Thread exited for " + id + " with "
4387c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                                           + (operationsPerThread - threadStress.nextOperation)
4397c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                                           + " operations remaining.");
4407c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    }
4411c83cbc4a817acbd7f9abb5b29a2d418a958e6a1Andreas Gampe                    System.out.println("Finishing worker");
4427c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                }
4437c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            };
4447c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        }
4457c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
4467c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // The notifier thread is a daemon just loops forever to wake
4477c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        // up threads in Operation.WAIT
448f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        if (lock != null) {
449f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            Thread notifier = new Thread("Notifier") {
450f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                public void run() {
451f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    while (true) {
452f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                        synchronized (lock) {
453f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                            lock.notifyAll();
454f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                        }
4557c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    }
4567c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                }
457f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            };
458f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            notifier.setDaemon(true);
459f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe            notifier.start();
460f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe        }
4617c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
4627c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        for (int r = 0; r < runners.length; r++) {
4637c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            runners[r].start();
4647c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        }
4657c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        for (int r = 0; r < runners.length; r++) {
4667c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            runners[r].join();
4677c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        }
4687c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom    }
4697c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
4707c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom    private final Operation[] operations;
4717c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom    private final Object lock;
4727c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom    private final int id;
4737c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
4747c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom    private int nextOperation;
4757c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
4761c83cbc4a817acbd7f9abb5b29a2d418a958e6a1Andreas Gampe    private Main(Object lock, int id, Operation[] operations) {
4777c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        this.lock = lock;
4787c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        this.id = id;
4797c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        this.operations = operations;
4807c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom    }
4817c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom
4827c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom    public void run() {
4837c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        try {
4847c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            if (DEBUG) {
4857c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                System.out.println("Starting ThreadStress " + id);
4867c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            }
4877c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            while (nextOperation < operations.length) {
4887c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                Operation operation = operations[nextOperation];
4897c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                if (DEBUG) {
4907c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                    System.out.println("ThreadStress " + id
4917c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                                       + " operation " + nextOperation
4927c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                                       + " is " + operation);
4937c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                }
4947c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                nextOperation++;
495f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                if (!operation.perform()) {
496f2fdc7368c5fd5d9cbb4bd1d962b887e87f0654cAndreas Gampe                    return;
4977c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                }
4987c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            }
4994514d3c0e69a49f5dbe19138330a2bb2aee36d63Brian Carlstrom        } finally {
5007c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            if (DEBUG) {
5017c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom                System.out.println("Finishing ThreadStress for " + id);
5027c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom            }
5037c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom        }
5047c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom    }
5051c83cbc4a817acbd7f9abb5b29a2d418a958e6a1Andreas Gampe
5067c6deaa3382f1f4fb0f591af206f03045c6e9004Brian Carlstrom}
507