[threadpool] Fix race on runtime shutdown (#4263)
[mono-project.git] / acceptance-tests / profiler-stress / runner.cs
blob5ef4ab02a2eb198eeb669e3a1fed781af3376828
1 using System;
2 using System.Collections.Generic;
3 using System.Diagnostics;
4 using System.Globalization;
5 using System.IO;
6 using System.Linq;
7 using System.Text;
8 using System.Text.RegularExpressions;
9 using System.Threading;
10 using System.Xml;
11 using Mono.Unix.Native;
12 using Newtonsoft.Json;
14 // Shut up CLS compliance warnings from Json.NET.
15 [assembly: CLSCompliant (true)]
17 namespace Mono.Profiling.Tests.Stress {
19 // https://github.com/xamarin/benchmarker/blob/master/tools/libdbmodel/Benchmark.cs
20 sealed class Benchmark {
22 public string Name { get; set; }
23 public string TestDirectory { get; set; }
24 public bool OnlyExplicit { get; set; }
25 public string[] CommandLine { get; set; }
26 public string[] ClientCommandLine { get; set; }
27 public string[] AOTAssemblies { get; set; }
29 public static Benchmark Load (string file)
31 return JsonConvert.DeserializeObject<Benchmark> (File.ReadAllText (file));
35 sealed class TestResult {
37 public Benchmark Benchmark { get; set; }
38 public ProcessStartInfo StartInfo { get; set; }
39 public Stopwatch Stopwatch { get; set; } = new Stopwatch ();
40 public int? ExitCode { get; set; }
41 public StringBuilder StandardOutput { get; set; } = new StringBuilder ();
42 public StringBuilder StandardError { get; set; } = new StringBuilder ();
45 static class Program {
47 static readonly TimeSpan _timeout = TimeSpan.FromHours (6);
49 static string FilterInvalidXmlChars (string text) {
50 return Regex.Replace (text, @"[^\x09\x0A\x0D\x20-\uD7FF\uE000-\uFFFD\u10000-\u10FFFF]", string.Empty);
53 static int Main ()
55 var depDir = Path.Combine ("..", "external", "benchmarker");
56 var benchDir = Path.Combine (depDir, "benchmarks");
57 var testDir = Path.Combine (depDir, "tests");
59 var benchmarks = Directory.EnumerateFiles (benchDir, "*.benchmark")
60 .Select (Benchmark.Load)
61 .Where (b => !b.OnlyExplicit && b.ClientCommandLine == null)
62 .OrderBy (b => b.Name)
63 .ToArray ();
65 var monoPath = Path.GetFullPath (Path.Combine ("..", "..", "runtime", "mono-wrapper"));
66 var classDir = Path.GetFullPath (Path.Combine ("..", "..", "mcs", "class", "lib", "net_4_x"));
68 var rand = new Random ();
69 var cpus = Environment.ProcessorCount;
71 var results = new List<TestResult> (benchmarks.Length);
73 var sw = Stopwatch.StartNew ();
75 for (var i = 0; i < benchmarks.Length; i++) {
76 var bench = benchmarks [i];
78 var sampleFreq = rand.Next (0, 1001);
79 var sampleMode = rand.Next (0, 2) == 1 ? "real" : "process";
80 var maxSamples = rand.Next (0, cpus * 2000 + 1);
81 var heapShotFreq = rand.Next (0, 11);
82 var maxFrames = rand.Next (0, 33);
83 var allocMode = rand.Next (0, 2) == 1 ? "alloc" : "noalloc";
85 var profOptions = $"sample=cycles/{sampleFreq},sampling-{sampleMode},maxsamples={maxSamples},heapshot={heapShotFreq}gc,maxframes={maxFrames},{allocMode},output=/dev/null";
87 var info = new ProcessStartInfo {
88 UseShellExecute = false,
89 WorkingDirectory = Path.Combine (testDir, bench.TestDirectory),
90 FileName = monoPath,
91 Arguments = $"--debug --profile=log:{profOptions} " + string.Join (" ", bench.CommandLine),
92 RedirectStandardOutput = true,
93 RedirectStandardError = true,
96 info.EnvironmentVariables.Clear ();
97 info.EnvironmentVariables.Add ("MONO_PATH", classDir);
99 var progress = $"({i + 1}/{benchmarks.Length})";
101 Console.ForegroundColor = ConsoleColor.Blue;
102 Console.WriteLine ($"[{sw.Elapsed.ToString ("G")}] {progress} Running {bench.Name} with profiler options: {profOptions}");
103 Console.ResetColor ();
105 var result = new TestResult {
106 Benchmark = bench,
107 StartInfo = info,
110 using (var proc = new Process ()) {
111 proc.StartInfo = info;
113 proc.OutputDataReceived += (sender, args) => {
114 if (args.Data != null)
115 result.StandardOutput.AppendLine (args.Data);
118 proc.ErrorDataReceived += (sender, args) => {
119 if (args.Data != null)
120 result.StandardError.AppendLine (args.Data);
123 result.Stopwatch.Start ();
125 proc.Start ();
127 proc.BeginOutputReadLine ();
128 proc.BeginErrorReadLine ();
130 if (!proc.WaitForExit ((int) _timeout.TotalMilliseconds)) {
131 // Force a thread dump.
132 Syscall.kill (proc.Id, Signum.SIGQUIT);
133 Thread.Sleep (1000);
135 try {
136 proc.Kill ();
137 } catch (Exception) {
139 } else
140 result.ExitCode = proc.ExitCode;
142 result.Stopwatch.Stop ();
145 var resultStr = result.ExitCode == null ? "timed out" : $"exited with code: {result.ExitCode}";
147 Console.ForegroundColor = result.ExitCode != 0 ? ConsoleColor.Red : ConsoleColor.Green;
148 Console.WriteLine ($"[{sw.Elapsed.ToString ("G")}] {progress} {bench.Name} took {result.Stopwatch.Elapsed.ToString ("G")} and {resultStr}");
149 Console.ResetColor ();
151 if (result.ExitCode != 0) {
152 Console.ForegroundColor = ConsoleColor.Red;
153 Console.WriteLine ("===== stdout =====");
154 Console.ResetColor ();
156 Console.WriteLine (result.StandardOutput.ToString ());
158 Console.ForegroundColor = ConsoleColor.Red;
159 Console.WriteLine ("===== stderr =====");
160 Console.ResetColor ();
162 Console.WriteLine (result.StandardError.ToString ());
165 results.Add (result);
168 sw.Stop ();
170 var successes = results.Count (r => r.ExitCode == 0);
171 var failures = results.Count (r => r.ExitCode != null && r.ExitCode != 0);
172 var timeouts = results.Count (r => r.ExitCode == null);
174 var settings = new XmlWriterSettings {
175 NewLineOnAttributes = true,
176 Indent = true,
179 using (var writer = XmlWriter.Create ("TestResult-profiler-stress.xml", settings)) {
180 writer.WriteStartDocument ();
181 writer.WriteComment ("This file represents the results of running a test suite");
183 writer.WriteStartElement ("test-results");
184 writer.WriteAttributeString ("name", "profiler-stress-tests.dummy");
185 writer.WriteAttributeString ("total", results.Count.ToString ());
186 writer.WriteAttributeString ("failures", failures.ToString ());
187 writer.WriteAttributeString ("not-run", "0");
188 writer.WriteAttributeString ("date", DateTime.Now.ToString ("yyyy-MM-dd"));
189 writer.WriteAttributeString ("time", DateTime.Now.ToString ("HH:mm:ss"));
191 writer.WriteStartElement ("environment");
192 writer.WriteAttributeString ("nunit-version", "2.4.8.0");
193 writer.WriteAttributeString ("clr-version", Environment.Version.ToString ());
194 writer.WriteAttributeString ("os-version", Environment.OSVersion.ToString ());
195 writer.WriteAttributeString ("platform", Environment.OSVersion.Platform.ToString ());
196 writer.WriteAttributeString ("cwd", Environment.CurrentDirectory);
197 writer.WriteAttributeString ("machine-name", Environment.MachineName);
198 writer.WriteAttributeString ("user", Environment.UserName);
199 writer.WriteAttributeString ("user-domain", Environment.UserDomainName);
200 writer.WriteEndElement ();
202 writer.WriteStartElement ("culture-info");
203 writer.WriteAttributeString ("current-culture", CultureInfo.CurrentCulture.Name);
204 writer.WriteAttributeString ("current-uiculture", CultureInfo.CurrentUICulture.Name);
205 writer.WriteEndElement ();
207 writer.WriteStartElement ("test-suite");
208 writer.WriteAttributeString ("name", "profiler-stress-tests.dummy");
209 writer.WriteAttributeString ("success", (failures + timeouts == 0).ToString ());
210 writer.WriteAttributeString ("time", ((int) sw.Elapsed.TotalSeconds).ToString ());
211 writer.WriteAttributeString ("asserts", (failures + timeouts).ToString ());
212 writer.WriteStartElement ("results");
214 writer.WriteStartElement ("test-suite");
215 writer.WriteAttributeString ("name", "MonoTests");
216 writer.WriteAttributeString ("success", (failures + timeouts == 0).ToString ());
217 writer.WriteAttributeString ("time", ((int) sw.Elapsed.TotalSeconds).ToString ());
218 writer.WriteAttributeString ("asserts", (failures + timeouts).ToString ());
219 writer.WriteStartElement ("results");
221 writer.WriteStartElement ("test-suite");
222 writer.WriteAttributeString ("name", "profiler-stress");
223 writer.WriteAttributeString ("success", (failures + timeouts == 0).ToString ());
224 writer.WriteAttributeString ("time", ((int) sw.Elapsed.TotalSeconds).ToString ());
225 writer.WriteAttributeString ("asserts", (failures + timeouts).ToString ());
226 writer.WriteStartElement ("results");
228 foreach (var result in results) {
229 var timeoutStr = result.ExitCode == null ? "_timeout" : string.Empty;
231 writer.WriteStartElement ("test-case");
232 writer.WriteAttributeString ("name", $"MonoTests.profiler-stress.{result.Benchmark.Name}{timeoutStr}");
233 writer.WriteAttributeString ("executed", "True");
234 writer.WriteAttributeString ("success", (result.ExitCode == 0).ToString ());
235 writer.WriteAttributeString ("time", ((int) result.Stopwatch.Elapsed.TotalSeconds).ToString ());
236 writer.WriteAttributeString ("asserts", result.ExitCode == 0 ? "0" : "1");
238 if (result.ExitCode != 0) {
239 writer.WriteStartElement ("failure");
241 writer.WriteStartElement ("message");
242 writer.WriteCData (FilterInvalidXmlChars (result.StandardOutput.ToString ()));
243 writer.WriteEndElement ();
245 writer.WriteStartElement ("stack-trace");
246 writer.WriteCData (FilterInvalidXmlChars (result.StandardError.ToString ()));
247 writer.WriteEndElement ();
249 writer.WriteEndElement ();
252 writer.WriteEndElement ();
255 writer.WriteEndElement ();
256 writer.WriteEndElement ();
258 writer.WriteEndElement ();
259 writer.WriteEndElement ();
261 writer.WriteEndElement ();
262 writer.WriteEndElement ();
264 writer.WriteEndElement ();
266 writer.WriteEndDocument ();
269 var failureStr = failures + timeouts != 0 ? $" ({failures} failures, {timeouts} timeouts)" : string.Empty;
271 Console.ForegroundColor = failures + timeouts != 0 ? ConsoleColor.Red : ConsoleColor.Green;
272 Console.WriteLine ($"[{sw.Elapsed.ToString ("G")}] Finished with {successes}/{results.Count} passing tests{failureStr}");
273 Console.ResetColor ();
275 return failures + timeouts;