/////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // Note: Perform short (bvt) and long running stress of multiprocessor // sensitive areas of the system. Used MonitorTest.cs as an // application template // using System; using System.Threading; using Microsoft.Singularity.UnitTest; using Microsoft.Singularity.Channels; using Microsoft.Contracts; using Microsoft.SingSharp.Reflection; using Microsoft.Singularity.Applications; using Microsoft.Singularity.Io; using Microsoft.Singularity.Configuration; [assembly: Transform(typeof(ApplicationResourceTransform))] namespace Microsoft.Singularity.Applications { [ConsoleCategory(DefaultAction=true)] internal class Parameters { [InputEndpoint("data")] public readonly TRef Stdin; [OutputEndpoint("data")] public readonly TRef Stdout; [LongParameter("cpucount", Default=2, HelpMessage="CPU Count for test")] internal long cpuCount; [LongParameter("passcount", Default=10, HelpMessage="Pass Count for test")] internal long passCount; reflective internal Parameters(); internal int AppMain() { return MpStress.AppMain(this); } } public class MpStress { internal static int AppMain(Parameters! config) { int result; Console.WriteLine("Running MpStress for CPU Count {0}", config.cpuCount); ThreadTest tt = new ThreadTest(); result = tt.RunTest(config.cpuCount, config.passCount); if (result != 0) { return result; } return 0; } } public class ThreadTest { public int RunTest(long cpuCount, long passCount) { // Start the thread create/destroy test //ThreadTestsThread threadTests = new ThreadTestsThread(cpuCount); // Run pulse tests PulseTestsThread pulseTests = new PulseTestsThread(cpuCount, passCount); pulseTests.RunThread(); // Start the background threads //threadTests.RunThread(); // Wait for pulse tests to complete ((!)pulseTests.Thread).Join(); return 0; } } // // Implementation classes represent different thread creation // parameters, and actions // public class PrintThread : ThreadRunner { private long argValue; public PrintThread(long arg) : base() { argValue = arg; } public override void ThreadMain() { //System.Console.WriteLine("PrintThread: Thread {0}, ThreadIndex {1}\n", Thread.CurrentThread.GetThreadId(), argValue); // Call some additional "interesting" system calls here in order to disturb // the system state, cause lock contention, flesh out races and unprotected code // regions, etc. // // This exits the thread //Console.Write("-"); return; } } public class ThreadTestsThread : ThreadRunner { private long cpuCount; public ThreadTestsThread(long cpuCount) : base() { this.cpuCount = cpuCount; } public override void ThreadMain() { const long Timeout = 1000 * 10; // 10 seconds long threadCount = 0; PrintThread[] threads; threadCount = cpuCount * 2; // // Run forever, process will exit when the ApMain thread // is done with the test sequence // for (;;) { //Console.Write("."); threads = new PrintThread[threadCount]; if (threads == null) { System.Console.WriteLine("Error allocating Thread[]"); return; } for (int i = 0; i < threadCount; i++) { threads[i] = new PrintThread(i); if (threads[i] == null) { System.Console.WriteLine("Error creating thread"); return; } } // Start them running for (int i = 0; i < threadCount; i++) { ((!)threads[i]).RunThread(); } TimeSpan timeout = TimeSpan.FromMilliseconds(Timeout); for (int i = 0; i < threadCount; i++) { if (!((!)(((!)threads[i]).Thread)).Join(timeout)) { Console.WriteLine("Timeout waiting for thread exit"); return; } //Console.Write("+"); } } } } public class PulseTestsThread : ThreadRunner { private long cpuCount; private long passes; private int threadCount; private int maxThreadCount; private const int threadsPerCpu = 64; public PulseTestsThread(long cpuCount, long passes) : base() { this.cpuCount = cpuCount; this.passes = passes; maxThreadCount = threadsPerCpu * (int)cpuCount; // Limit max threads, otherwise we will overflow the kernel's thread table if (maxThreadCount > 512) { maxThreadCount = 512; } } public override void ThreadMain() { System.Console.WriteLine("Running PulseTests: Thread {0}\n", Thread.CurrentThread.GetThreadId()); Console.Write("passes={0}", passes); Console.WriteLine(" cpuCount={0}", cpuCount); for (int pass = 0; pass < passes; pass++) { Console.WriteLine("pass={0}", pass); UnitTest.Clear(); threadCount = 0; for (int i = 0; i < cpuCount; i++) { // 50 threads if (!CheckMaxThreads(50)) { UnitTest.Add("Many Threads PulseAll", new UnitTest.TestDelegate(PulseAllTest.ManyThreadsTest)); } // 8 threads if (!CheckMaxThreads(8)) { UnitTest.Add("Few Threads PulseAll", new UnitTest.TestDelegate(PulseAllTest.FewThreadsTest)); } // 17 threads if (!CheckMaxThreads(17)) { UnitTest.Add("Low-density Pulse", new UnitTest.TestDelegate(PulseTest.LowDensityTest)); } // 32 threads if (!CheckMaxThreads(32)) { UnitTest.Add("Medium-density Pulse", new UnitTest.TestDelegate(PulseTest.MediumDensityTest)); } // 128 threads if (!CheckMaxThreads(128)) { UnitTest.Add("High-density Pulse", new UnitTest.TestDelegate(PulseTest.HighDensityTest)); } } Console.WriteLine("{0} PulseThreads", threadCount); // Wait for the sub-threads to run if (UnitTest.Run(true) != UnitTest.Result.Passed) { Console.WriteLine("PulseTest failed!\n"); } } // This exits the thread return; } // We must keep total thread count at a reasonable level // otherwise we overflow the kernel thread table that is // hardcoded at 1024. We will set 512 max threads for now. private bool CheckMaxThreads(int count) { if ((count + threadCount) <= maxThreadCount) { threadCount += count; return false; } return true; } } // Generic class that creates the thread public class ThreadRunner { private Thread thread; public ThreadRunner() { } public Thread Thread { get { return thread; } } // Creates thread, returns with it running public Thread RunThread() { thread = new Thread(new ThreadStart(ThreadMain)); thread.Start(); return thread; } public virtual void ThreadMain() { // This exits the thread return; } } }