<div dir="ltr">I'm not keen on introducing yield calls all over the place in the runtime to work around bad test-environment combinations.<div><br></div><div>Adding them to the test suite it fine though.</div><div><br></div><div>Maybe the 200ms timeout is too low to deal with overloaded systems and must be increased. The goal is to</div><div>detect bugs in the suspend code.</div><div><br></div><div>It would be much easier if unix had a way to transfer the quantum in a yield call instead of just giving up on it.</div><div>We can definitely increase the timeout if that would help or make it optional guarded behind an env var.<br></div><div><br></div><div>Does changing the timeout to infinite fix those crashes?</div><div><br><div class="gmail_extra"><br><div class="gmail_quote">On Thu, May 21, 2015 at 4:20 PM, Neale Ferguson <span dir="ltr"><<a href="mailto:neale@sinenomine.net" target="_blank">neale@sinenomine.net</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi,<br>
I have been experiencing some failures with the tests in mono/tests,<br>
particularly in a single core configuration.<br>
<br>
Firstly, the sleep test: when the delegated thread is started, the main<br>
thread goes to call the StopWatch start method which requires JITting.<br>
This involves gc interaction as objects are allocated. However, the<br>
delegated thread gets up and starts issuing GC.Collection() calls which<br>
end up occurring every 50 microseconds. This means the main thread never<br>
gets a chance to get out of the allocation phase so never gets to execute<br>
the stopwatch start, thread sleep etc. so the thread never ends. In a<br>
multi-core configuration this is not a problem and the test passes. I<br>
found by inserting a Thread.Yield() as the first method called in the<br>
delegated thread eliminates the problem [1].<br>
<br>
Secondly, the xxxxx-exit (e.g. thread-exit) tests will occasionally fail<br>
with an abort due to "suspend_thread suspend took xxx ms, which is more<br>
than the allowed 200 ms” where xxx exceeds 200. This seems to be due to<br>
the exiting thread sometimes not getting to the stage of setting the<br>
thread->state to ThreadState_Stopped in the<br>
ves_icall_System_Environment_Exit() processing within the 200ms time<br>
period. Again, with multiple cores this is not a problem (or the problem<br>
is much rarer). I found by inserting a mono_thread_info_yield() prior to<br>
the suspend_internal_thread() in mono_thread_suspend_all_other_threads()<br>
fixes the problem [2]. I am not sure this is the best option and it’s<br>
still theoretically possible for the problem to still occur depending on<br>
how heavily the system is loaded. I was wondering if the setting of the<br>
state to ThreadState_stopped could be moved earlier in the process rather<br>
than in thread_cleanup() or if there’s another alternative.<br>
<br>
While the occasional failure has been experienced with some of the more<br>
pathological tests, the trouble is they happen nearly 100% of the time on<br>
a single core virtual machine, less often on a 2 core but in a virtual<br>
machine environment where there may be 100s of virtual machines competing<br>
for the real cores the probability of failure increases. In addition tests<br>
in the main test suite also have failed for the same reason as described<br>
in the second case.<br>
<br>
Neale<br>
<br>
[1] Circumvention for case 1 -<br>
<br>
--- a/mono/tests/sleep.cs<br>
+++ b/mono/tests/sleep.cs<br>
@@ -13,6 +13,7 @@ public class Tests<br>
        public static int test_0_time_drift () {<br>
                // Test the Thread.Sleep () is able to deal with time<br>
drifting due to interrupts<br>
                Thread t = new Thread (delegate () {<br>
+                               Thread.Yield();<br>
                                while (!finished)<br>
                                        GC.Collect ();<br>
                        });<br>
<br>
[2] Circumvention for case 2 -<br>
<br>
--- a/mono/metadata/threads.c<br>
+++ b/mono/metadata/threads.c<br>
<br>
@@ -3132,6 +3147,8 @@ void mono_thread_suspend_all_other_threads (void)<br>
<br>
                        UNLOCK_THREAD (thread);<br>
<br>
+                       mono_thread_info_yield ();<br>
+<br>
                        /* Signal the thread to suspend */<br>
                        suspend_thread_internal (thre<br>
<br>
_______________________________________________<br>
Mono-devel-list mailing list<br>
<a href="mailto:Mono-devel-list@lists.ximian.com">Mono-devel-list@lists.ximian.com</a><br>
<a href="http://lists.ximian.com/mailman/listinfo/mono-devel-list" target="_blank">http://lists.ximian.com/mailman/listinfo/mono-devel-list</a><br>
</blockquote></div><br></div></div></div>