5892314a451d1972f98aa8cc24eb598530f3e3c9
[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 class Driver {
9         static bool stop_please;
10         const int TEST_DURATION = 1000;
11
12         static object very_contended_object = new object ();
13
14         static bool Ok (ref int loops) {
15                 if (loops == -1)
16                         return !stop_please;
17                 if (loops == 0)
18                         return false;
19                 loops--;
20                 return true;
21
22         }
23         static void MonitorEnterInALoop (int loops)
24         {
25                 while (Ok (ref loops)) {
26                         if (Monitor.TryEnter (very_contended_object, 100)) {
27                                 Thread.Sleep (30);
28                                 Monitor.Exit (very_contended_object);
29                         }
30                 }
31         }
32
33         static void AllocObjectInALoop (int loops) {
34                 while (Ok (ref loops)) {
35                         var a = new object ();
36                         var b = new byte [100];
37                 }
38         }
39
40         static void AllocDomainInALoop (int loops) {
41                 int count = 0;
42                 while (Ok (ref loops)) {
43                         var a = AppDomain.CreateDomain ("test_domain_" + ++count);
44                         AppDomain.Unload (a);
45                 }
46         }
47
48         static void FileIO (int loops) {
49                 while (Ok (ref loops)) {
50                         var dir = Path.GetTempFileName () + "_" + Thread.CurrentThread.ManagedThreadId;
51                         Directory.CreateDirectory (dir);
52                         Directory.Delete (dir);
53                         
54                 }
55         }
56
57     static void Timer_Elapsed(object sender, EventArgs e)
58     {
59         HashSet<string> h = new HashSet<string>();
60         for (int j = 0; j < 500; j++)
61         {
62             h.Add(""+j+""+j);
63         }
64     }
65
66         //From sgen-new-threads-dont-join-stw
67         static void TimerStress (int loops) {
68                 while (Ok (ref loops)) {
69                         System.Timers.Timer timer = new System.Timers.Timer();
70             timer.Elapsed += Timer_Elapsed;
71             timer.AutoReset = false;
72             timer.Interval = 500;
73             timer.Start ();
74                 }
75         }
76
77         //from sgen-weakref-stress
78         static void WeakRefStress (int loops) {
79                 while (Ok (ref loops)) {
80                    for (int j = 0; j < 500; ++j) {
81                        new WeakReference (new object ());
82                    }
83                 }
84         }
85         static Tuple<Action<int>,string>[] available_tests = new [] {
86                 Tuple.Create (new Action<int> (MonitorEnterInALoop), "monitor"),
87                 Tuple.Create (new Action<int> (AllocObjectInALoop), "alloc"),
88                 Tuple.Create (new Action<int> (AllocDomainInALoop), "appdomain"),
89                 Tuple.Create (new Action<int> (FileIO), "file-io"),
90                 Tuple.Create (new Action<int> (TimerStress), "timers"),
91                 Tuple.Create (new Action<int> (WeakRefStress), "weakref"),
92         };
93
94         static void GcPump (int timeInMillis)
95         {
96                 var sw = Stopwatch.StartNew ();
97                 do {
98                         GC.Collect ();
99                         Thread.Sleep (1);
100                 } while (sw.ElapsedMilliseconds < timeInMillis);
101                 stop_please = true;
102         }
103
104         const int minTpSteps = 1;
105         const int maxTpSteps = 30;
106
107         static void QueueStuffUsingTpl (int threadCount) {
108                 int pendingJobs = 0;
109                 int maxPending = threadCount * 2;
110                 int generatorIdx = 0;
111                 Random rand = new Random (0);
112
113                 while (!stop_please) {
114                         while (pendingJobs < maxPending) {
115                                 var task = available_tests [generatorIdx++ % available_tests.Length].Item1;
116                                 int steps = rand.Next(minTpSteps, maxTpSteps);
117                                 ThreadPool.QueueUserWorkItem (_ => {
118                                         task (steps);
119                                         Interlocked.Decrement (ref pendingJobs);
120                                 });
121                                 Interlocked.Increment (ref pendingJobs);
122                         }
123                         Thread.Sleep (1);
124                 }
125                 while (pendingJobs > 0)
126                         Thread.Sleep (1);
127         }
128
129         static void DynamicLoadGenerator (int threadCount, int timeInMillis) {
130                 var t = new Thread (() => QueueStuffUsingTpl (threadCount));
131                 t.Start ();
132
133                 GcPump (timeInMillis);
134
135                 t.Join ();
136         }
137
138         static void StaticLoadGenerator (int threadCount, int testIndex, int timeInMillis) {
139                 List<Thread> threads = new List<Thread> ();
140
141                 for (int i = 0; i < threadCount; ++i) {
142                         var dele = (testIndex >= 0 ? available_tests [testIndex] : available_tests [i % available_tests.Length]).Item1;
143                         var t = new Thread (() => dele (-1));
144                         t.Start ();
145                         threads.Add (t);
146                 }
147
148                 GcPump (timeInMillis);
149
150                 foreach (var t in threads)
151                         t.Join ();
152         }
153         
154         static int ParseTestName (string name) {
155                 for (int i = 0; i < available_tests.Length; ++i) {
156                         if (available_tests[i].Item2 == name)
157                                 return i;
158                 }
159                 Console.WriteLine ("Invalid test name {0}", name);
160                 Environment.Exit (2);
161                 return -1;
162         }
163
164         static int Main (string[] args) {
165                 int threadCount = Environment.ProcessorCount - 1;
166                 int timeInMillis = TEST_DURATION;
167                 int testIndex = -1;
168                 bool tpLoadGenerator = false;
169                 string testName = "static";
170                 
171
172                 for (int j = 0; j < args.Length;) {
173                         if ((args [j] == "--duration") || (args [j] == "-d")) {
174                                 timeInMillis = Int32.Parse (args [j + 1]);
175                                 j += 2;
176                         } else if ((args [j] == "--test") || (args [j] == "-t")) {
177                                 if (args [j + 1] == "static")
178                                         testIndex = -1;
179                                 else if (args [j + 1] == "tp")
180                                         tpLoadGenerator = true;
181                                 else
182                                         testIndex = ParseTestName (testName = args [j + 1]);
183                                 j += 2;
184                         } else  if ((args [j] == "--thread-count") || (args [j] == "-tc")) {
185                                 threadCount = Int32.Parse (args [j + 1]);
186                                 j += 2;
187                         }else {
188                                 Console.WriteLine ("Unknown argument: " + args [j]);
189                                 return 1;
190                         }
191         }
192
193                 if (tpLoadGenerator) {
194                         Console.WriteLine ("tp window {0} duration {1}", threadCount, timeInMillis);
195                         DynamicLoadGenerator (threadCount, timeInMillis);
196                 } else {
197                         Console.WriteLine ("thread count {0} duration {1} test {2}", threadCount, timeInMillis, testName);
198                         StaticLoadGenerator (threadCount, testIndex, timeInMillis);
199                 }
200
201                 return 0;
202         }
203 }