From bfb46573ac6938ff06236663c27e331cf28382b8 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Thu, 12 Nov 2015 17:15:01 -0500 Subject: [PATCH] [test] Make sgen tests behave nicer on slower machines. * TestDriver.cs Add `TestTimeout` utility to check how much time CI allocated for the test. * sgen-domain-unload-2.cs print warning if running low on time. * sgen-new-threads-dont-join-stw.cs print progress dots and a warning when running low on time. --- mono/mini/TestDriver.cs | 62 ++++++++++++++++++++ mono/tests/sgen-domain-unload-2.cs | 15 ++++- mono/tests/sgen-new-threads-dont-join-stw.cs | 17 +++++- mono/tests/test-driver | 1 + mono/tests/test-runner.cs | 2 + 5 files changed, 92 insertions(+), 5 deletions(-) diff --git a/mono/mini/TestDriver.cs b/mono/mini/TestDriver.cs index 64372e06c24..c3bf999d272 100644 --- a/mono/mini/TestDriver.cs +++ b/mono/mini/TestDriver.cs @@ -133,3 +133,65 @@ public class TestDriver { } } +/// Provide tests with the ability to find out how much time they have to run before being timed out. +public class TestTimeout { + const string ENV_TIMEOUT = "TEST_DRIVER_TIMEOUT_SEC"; + private readonly TimeSpan availableTime; + private TimeSpan slack; + private DateTime startTime; + + /// + /// How much time the test runner provided for us or TimeSpan.Zero if there is no bound. + /// + public TimeSpan AvailableTime { get { return availableTime; } } + + public DateTime StartTime { get { return startTime; } } + + /// Extra time to add when deciding if there + /// is still time to run. Bigger slack means less + /// time left. + /// + public TimeSpan Slack { + get { return slack; } + set { slack = value; } + } + + public TestTimeout () { + availableTime = initializeAvailableTime (); + slack = defaultSlack (); + } + + /// + /// Consider the test started. + /// + public void Start () + { + startTime = DateTime.UtcNow; + } + + public bool HaveTimeLeft () + { + if (availableTime == TimeSpan.Zero) + return true; + var t = DateTime.UtcNow; + var finishTime = startTime + availableTime - slack; + return (t < finishTime); + } + + private TimeSpan defaultSlack () + { + return TimeSpan.FromSeconds (5); + } + + private TimeSpan initializeAvailableTime () + { + var e = System.Environment.GetEnvironmentVariable(ENV_TIMEOUT); + double d; + if (Double.TryParse(e, out d)) { + return TimeSpan.FromSeconds(d); + } else { + return TimeSpan.Zero; + } + } + +} diff --git a/mono/tests/sgen-domain-unload-2.cs b/mono/tests/sgen-domain-unload-2.cs index 6570842703c..f1f6c2f9320 100644 --- a/mono/tests/sgen-domain-unload-2.cs +++ b/mono/tests/sgen-domain-unload-2.cs @@ -9,7 +9,6 @@ This is a regression test for a crash in the domain object cleaner code that did stop-the-world before walking the heap. */ class Driver { - static void AllocStuff () { var x = new object (); @@ -24,6 +23,8 @@ class Driver { } static void Main () { + var testTimeout = new TestTimeout (); + testTimeout.Start (); for (int i = 0; i < Math.Max (1, Environment.ProcessorCount / 2); ++i) { // for (int i = 0; i < 4; ++i) { var t = new Thread (BackgroundNoise); @@ -31,13 +32,21 @@ class Driver { t.Start (); } - for (int i = 0; i < 100; ++i) { + const int TOTAL_ITERATIONS = 100; + for (int i = 0; i < TOTAL_ITERATIONS; ++i) { var ad = AppDomain.CreateDomain ("domain_" + i); ad.DoCallBack (new CrossAppDomainDelegate (AllocStuff)); AppDomain.Unload (ad); + Console.Write ("."); if (i > 0 && i % 20 == 0) Console.WriteLine (); + + if (!testTimeout.HaveTimeLeft ()) { + var finishTime = DateTime.UtcNow; + var ranFor = finishTime - testTimeout.StartTime; + Console.WriteLine ("Will run out of time soon. ran for {0}, finished {1}/{2} iterations", ranFor, i+1, TOTAL_ITERATIONS); + } } Console.WriteLine ("\ndone"); } -} \ No newline at end of file +} diff --git a/mono/tests/sgen-new-threads-dont-join-stw.cs b/mono/tests/sgen-new-threads-dont-join-stw.cs index b6d0a9b693b..966fff5d5b7 100644 --- a/mono/tests/sgen-new-threads-dont-join-stw.cs +++ b/mono/tests/sgen-new-threads-dont-join-stw.cs @@ -44,8 +44,11 @@ class T { } static void Main (string[] args) { - - for (int j = 0; j < 2; j++) + var testTimeout = new TestTimeout (); + testTimeout.Start (); + + const int TOTAL_ITERATIONS = 2; + for (int j = 0; j < TOTAL_ITERATIONS; j++) { count = 0; @@ -82,6 +85,7 @@ class T { { while (count < num_threads) { + Console.Write ("."); Monitor.Wait(count_lock); } } @@ -90,6 +94,15 @@ class T { { t.Join(); } + + Console.WriteLine (); + if (!testTimeout.HaveTimeLeft ()) { + var finishTime = DateTime.UtcNow; + var ranFor = finishTime - testTimeout.StartTime; + Console.WriteLine ("Will run out of time soon. ran for {0}, finished {1}/{2} iterations", ranFor, j+1, TOTAL_ITERATIONS); + } } + + Console.WriteLine ("done"); } } diff --git a/mono/tests/test-driver b/mono/tests/test-driver index b007040a62e..69be3d1396c 100755 --- a/mono/tests/test-driver +++ b/mono/tests/test-driver @@ -29,6 +29,7 @@ if ($test =~ /.*\|.*/) { #This is a silly workaround, but all tests that use extra parameters need a larger timeout. $timeout_in_minutes = 5; } +$ENV{'TEST_DRIVER_TIMEOUT_SEC'} = $timeout_in_minutes * 60; $| = 0; print "Testing $test... "; diff --git a/mono/tests/test-runner.cs b/mono/tests/test-runner.cs index 9c06bbf0668..e58e009a269 100644 --- a/mono/tests/test-runner.cs +++ b/mono/tests/test-runner.cs @@ -41,6 +41,7 @@ using System.Text.RegularExpressions; public class TestRunner { const string TEST_TIME_FORMAT = "mm\\:ss\\.fff"; + const string ENV_TIMEOUT = "TEST_DRIVER_TIMEOUT_SEC"; class ProcessData { public string test; @@ -220,6 +221,7 @@ public class TestRunner info.UseShellExecute = false; info.RedirectStandardOutput = true; info.RedirectStandardError = true; + info.EnvironmentVariables[ENV_TIMEOUT] = timeout.ToString(); Process p = new Process (); p.StartInfo = info; -- 2.25.1