295 lines
9.0 KiB
C#
295 lines
9.0 KiB
C#
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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<UnicodePipeContract.Exp:READY> Stdin;
|
|
|
|
[OutputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Imp:READY> 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;
|
|
}
|
|
}
|
|
}
|