2 using System.Collections.Generic;
3 using System.Threading;
4 using System.Diagnostics;
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.
21 Remoting / Transparent Proxies
29 static bool stop_please;
30 const int TEST_DURATION = 1000;
32 static object very_contended_object = new object ();
34 static bool Ok (ref int loops) {
43 static void MonitorEnterInALoop (int loops)
45 while (Ok (ref loops)) {
46 if (Monitor.TryEnter (very_contended_object, 100)) {
48 Monitor.Exit (very_contended_object);
53 static void AllocObjectInALoop (int loops) {
54 while (Ok (ref loops)) {
55 var a = new object ();
56 var b = new byte [100];
60 static void AllocDomainInALoop (int loops) {
62 while (Ok (ref loops)) {
63 var a = AppDomain.CreateDomain ("test_domain_" + ++count);
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);
77 static void Timer_Elapsed(object sender, EventArgs e)
79 HashSet<string> h = new HashSet<string>();
80 for (int j = 0; j < 500; j++)
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;
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 ());
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"),
114 static void GcPump (int timeInMillis)
116 var sw = Stopwatch.StartNew ();
120 } while (sw.ElapsedMilliseconds < timeInMillis);
124 const int minTpSteps = 1;
125 const int maxTpSteps = 30;
127 static void QueueStuffUsingTpl (int threadCount) {
129 int maxPending = threadCount * 2;
130 int generatorIdx = 0;
131 Random rand = new Random (0);
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 (_ => {
139 Interlocked.Decrement (ref pendingJobs);
141 Interlocked.Increment (ref pendingJobs);
145 while (pendingJobs > 0)
149 static void DynamicLoadGenerator (int threadCount, int timeInMillis) {
150 var t = new Thread (() => QueueStuffUsingTpl (threadCount));
153 GcPump (timeInMillis);
158 static void StaticLoadGenerator (int threadCount, int testIndex, int timeInMillis) {
159 List<Thread> threads = new List<Thread> ();
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));
168 GcPump (timeInMillis);
170 foreach (var t in threads)
174 static int ParseTestName (string name) {
175 for (int i = 0; i < available_tests.Length; ++i) {
176 if (available_tests[i].Item2 == name)
179 Console.WriteLine ("Invalid test name {0}", name);
180 Environment.Exit (2);
184 static int Main (string[] args) {
185 int threadCount = Environment.ProcessorCount - 1;
186 int timeInMillis = TEST_DURATION;
188 bool tpLoadGenerator = false;
189 string testName = "static";
192 for (int j = 0; j < args.Length;) {
193 if ((args [j] == "--duration") || (args [j] == "-d")) {
194 timeInMillis = Int32.Parse (args [j + 1]);
196 } else if ((args [j] == "--test") || (args [j] == "-t")) {
197 if (args [j + 1] == "static")
199 else if (args [j + 1] == "tp")
200 tpLoadGenerator = true;
202 testIndex = ParseTestName (testName = args [j + 1]);
204 } else if ((args [j] == "--thread-count") || (args [j] == "-tc")) {
205 threadCount = Int32.Parse (args [j + 1]);
208 Console.WriteLine ("Unknown argument: " + args [j]);
213 if (tpLoadGenerator) {
214 Console.WriteLine ("tp window {0} duration {1}", threadCount, timeInMillis);
215 DynamicLoadGenerator (threadCount, timeInMillis);
217 Console.WriteLine ("thread count {0} duration {1} test {2}", threadCount, timeInMillis, testName);
218 StaticLoadGenerator (threadCount, testIndex, timeInMillis);