[runtime] Synthesize IList and IReadOnlyList for the element type of enum errays...
[mono.git] / mono / tests / suspend-stress-test.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Threading;
4 using System.Diagnostics;
5 using System.IO;
6
7 /*
8 TODO
9         Some tests are much more expensive than others (on cycles and synchronization), add a calibration step to figure out duration.
10         Some tests are more disrruptive than others, add weights to tests so some are picked more frequently.
11         The workload is too static, add some background generation noise tests.
12         The workload is too stable, add perturbance on the number of available tasks.
13         Fuse threadpool with non threadpool workloads by firing some tasks as separate threads.
14         Add an external watchdog so we can run the stress test in a loop for very long times and get results out of it.
15         We don't have enough tests, add one per locking operation we got in the runtime.
16
17 Missing tests:
18         Ephemerons
19         Dynamic methods
20         Regular SRE
21         Remoting / Transparent Proxies
22         Context locals
23         Thread locals
24         Finalizers
25         Async socket IO
26 */
27
28 class Driver {
29         static bool stop_please;
30         const int TEST_DURATION = 1000;
31
32         static object very_contended_object = new object ();
33
34         static bool Ok (ref int loops) {
35                 if (loops == -1)
36                         return !stop_please;
37                 if (loops == 0)
38                         return false;
39                 loops--;
40                 return true;
41
42         }
43         static void MonitorEnterInALoop (int loops)
44         {
45                 while (Ok (ref loops)) {
46                         if (Monitor.TryEnter (very_contended_object, 100)) {
47                                 Thread.Sleep (30);
48                                 Monitor.Exit (very_contended_object);
49                         }
50                 }
51         }
52
53         static void AllocObjectInALoop (int loops) {
54                 while (Ok (ref loops)) {
55                         var a = new object ();
56                         var b = new byte [100];
57                 }
58         }
59
60         static void AllocDomainInALoop (int loops) {
61                 int count = 0;
62                 while (Ok (ref loops)) {
63                         var a = AppDomain.CreateDomain ("test_domain_" + ++count);
64                         AppDomain.Unload (a);
65                 }
66         }
67
68         static void FileIO (int loops) {
69                 while (Ok (ref loops)) {
70                         var dir = Path.GetTempFileName () + "_" + Thread.CurrentThread.ManagedThreadId;
71                         Directory.CreateDirectory (dir);
72                         Directory.Delete (dir);
73                         
74                 }
75         }
76
77     static void Timer_Elapsed(object sender, EventArgs e)
78     {
79         HashSet<string> h = new HashSet<string>();
80         for (int j = 0; j < 500; j++)
81         {
82             h.Add(""+j+""+j);
83         }
84     }
85
86         //From sgen-new-threads-dont-join-stw
87         static void TimerStress (int loops) {
88                 while (Ok (ref loops)) {
89                         System.Timers.Timer timer = new System.Timers.Timer();
90             timer.Elapsed += Timer_Elapsed;
91             timer.AutoReset = false;
92             timer.Interval = 500;
93             timer.Start ();
94                 }
95         }
96
97         //from sgen-weakref-stress
98         static void WeakRefStress (int loops) {
99                 while (Ok (ref loops)) {
100                    for (int j = 0; j < 500; ++j) {
101                        new WeakReference (new object ());
102                    }
103                 }
104         }
105         static Tuple<Action<int>,string>[] available_tests = new [] {
106                 Tuple.Create (new Action<int> (MonitorEnterInALoop), "monitor"),
107                 Tuple.Create (new Action<int> (AllocObjectInALoop), "alloc"),
108                 Tuple.Create (new Action<int> (AllocDomainInALoop), "appdomain"),
109                 Tuple.Create (new Action<int> (FileIO), "file-io"),
110                 Tuple.Create (new Action<int> (TimerStress), "timers"),
111                 Tuple.Create (new Action<int> (WeakRefStress), "weakref"),
112         };
113
114         static void GcPump (int timeInMillis)
115         {
116                 var sw = Stopwatch.StartNew ();
117                 do {
118                         GC.Collect ();
119                         Thread.Sleep (1);
120                 } while (sw.ElapsedMilliseconds < timeInMillis);
121                 stop_please = true;
122         }
123
124         const int minTpSteps = 1;
125         const int maxTpSteps = 30;
126
127         static void QueueStuffUsingTpl (int threadCount) {
128                 int pendingJobs = 0;
129                 int maxPending = threadCount * 2;
130                 int generatorIdx = 0;
131                 Random rand = new Random (0);
132
133                 while (!stop_please) {
134                         while (pendingJobs < maxPending) {
135                                 var task = available_tests [generatorIdx++ % available_tests.Length].Item1;
136                                 int steps = rand.Next(minTpSteps, maxTpSteps);
137                                 ThreadPool.QueueUserWorkItem (_ => {
138                                         task (steps);
139                                         Interlocked.Decrement (ref pendingJobs);
140                                 });
141                                 Interlocked.Increment (ref pendingJobs);
142                         }
143                         Thread.Sleep (1);
144                 }
145                 while (pendingJobs > 0)
146                         Thread.Sleep (1);
147         }
148
149         static void DynamicLoadGenerator (int threadCount, int timeInMillis) {
150                 var t = new Thread (() => QueueStuffUsingTpl (threadCount));
151                 t.Start ();
152
153                 GcPump (timeInMillis);
154
155                 t.Join ();
156         }
157
158         static void StaticLoadGenerator (int threadCount, int testIndex, int timeInMillis) {
159                 List<Thread> threads = new List<Thread> ();
160
161                 for (int i = 0; i < threadCount; ++i) {
162                         var dele = (testIndex >= 0 ? available_tests [testIndex] : available_tests [i % available_tests.Length]).Item1;
163                         var t = new Thread (() => dele (-1));
164                         t.Start ();
165                         threads.Add (t);
166                 }
167
168                 GcPump (timeInMillis);
169
170                 foreach (var t in threads)
171                         t.Join ();
172         }
173         
174         static int ParseTestName (string name) {
175                 for (int i = 0; i < available_tests.Length; ++i) {
176                         if (available_tests[i].Item2 == name)
177                                 return i;
178                 }
179                 Console.WriteLine ("Invalid test name {0}", name);
180                 Environment.Exit (2);
181                 return -1;
182         }
183
184         static int Main (string[] args) {
185                 int threadCount = Environment.ProcessorCount - 1;
186                 int timeInMillis = TEST_DURATION;
187                 int testIndex = -1;
188                 bool tpLoadGenerator = false;
189                 string testName = "static";
190                 
191
192                 for (int j = 0; j < args.Length;) {
193                         if ((args [j] == "--duration") || (args [j] == "-d")) {
194                                 timeInMillis = Int32.Parse (args [j + 1]);
195                                 j += 2;
196                         } else if ((args [j] == "--test") || (args [j] == "-t")) {
197                                 if (args [j + 1] == "static")
198                                         testIndex = -1;
199                                 else if (args [j + 1] == "tp")
200                                         tpLoadGenerator = true;
201                                 else
202                                         testIndex = ParseTestName (testName = args [j + 1]);
203                                 j += 2;
204                         } else  if ((args [j] == "--thread-count") || (args [j] == "-tc")) {
205                                 threadCount = Int32.Parse (args [j + 1]);
206                                 j += 2;
207                         }else {
208                                 Console.WriteLine ("Unknown argument: " + args [j]);
209                                 return 1;
210                         }
211         }
212
213                 if (tpLoadGenerator) {
214                         Console.WriteLine ("tp window {0} duration {1}", threadCount, timeInMillis);
215                         DynamicLoadGenerator (threadCount, timeInMillis);
216                 } else {
217                         Console.WriteLine ("thread count {0} duration {1} test {2}", threadCount, timeInMillis, testName);
218                         StaticLoadGenerator (threadCount, testIndex, timeInMillis);
219                 }
220
221                 return 0;
222         }
223 }