singrdk/base/Applications/Benchmarks/diskrwnull/diskrw.sg

343 lines
12 KiB
Plaintext
Raw Normal View History

2008-03-05 09:52:00 -05:00
////////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Note:
//
using System;
using System.Runtime.CompilerServices;
using Microsoft.Singularity;
using Microsoft.Singularity.Directory;
using Microsoft.Singularity.V1.Services;
using Microsoft.Singularity.Io;
using Microsoft.Singularity.Channels;
using System.Threading;
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.Benchmarks.DiskRWNull
{
[ConsoleCategory(HelpMessage="Null Disk r/w performance test", DefaultAction=true)]
internal class Parameters
{
[InputEndpoint("data")]
public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
[OutputEndpoint("data")]
public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
[StringParameter( "device", Mandatory=true, Position=0 , HelpMessage="Device to read/write")]
internal string deviceName;
[LongParameter( "b", Default=0, HelpMessage="Set block size to <n> bytes.")]
internal long blockBytes;
[LongParameter( "g", Default=1, HelpMessage="Repeat test n times.")]
internal long repeatCount;
[LongParameter( "l", Default=0, HelpMessage="Fix disk size limit at <n> megabytes.")]
internal long diskLimitMB;
[LongParameter( "m", Default=0, HelpMessage="Perform test with <n> megabytes of data.")]
internal long dataMB;
[LongParameter( "n", Default=0, HelpMessage="Perform test with <n> blocks of data.")]
internal long blockCount;
[LongParameter( "p", Default=0, HelpMessage="Pause <n> seconds between iterations")]
internal long pauseSecs;
[BoolParameter( "r", Default=false, HelpMessage="Perform disk read test.")]
internal bool doRead ;
[BoolParameter( "w", Default=false, HelpMessage="Perform disk write test.")]
internal bool doWrite;
[BoolParameter( "x", Default=false, HelpMessage="Perform test with random I/O offsets.")]
internal bool randomIO;
reflective internal Parameters();
internal int AppMain() {
return DiskBenchmark.AppMain(this);
}
}
contract Hack
{
message Hak();
state HACK : one { Hak? -> Hak! -> HACK; }
}
public class DiskBenchmark
{
static TRef<Hack.Imp:HACK> himp;
static TRef<Hack.Exp:HACK> hexp;
private const uint BytesPerSector = 512;
private const uint SectorsPerMB = 1024 * 1024 / BytesPerSector;
private static ulong GetRandomOffset(SRandom! rng,
ulong diskSectorCount,
ulong blockBytes)
{
ulong maxBlock = diskSectorCount * 512 / blockBytes;
ulong offset = 0;
2008-11-17 18:29:00 -05:00
for (int i = 0; i < 64; i += 30) {
2008-03-05 09:52:00 -05:00
offset ^= (ulong)(rng.Next() << i);
}
offset &= 0x7fffffffffffffff;
offset %= maxBlock;
return offset * blockBytes;
}
private static void DisplayPerf(bool didRead,
bool didRandom,
TimeSpan elapsed,
ulong blockCount,
ulong blockBytes,
ulong nextOffset)
{
double delta = (double)elapsed.Ticks / TimeSpan.TicksPerSecond;
double ops = (double)blockCount / delta;
Console.Write("{0}{1}.{2} ",
didRandom ? "R" : "S",
didRead ? "R" : "W",
blockBytes);
Console.WriteLine("Ops/s: {0:f2} MB/s: {1:f2} Elapsed: {2:f2} Check: {3:x}",
ops, ops * blockBytes / (1024.0 * 1024.0),
delta, nextOffset);
}
public static int DoDevice(string! deviceName,
int runNumber,
ulong blockCount,
ulong blockBytes,
ulong diskLimitMB,
bool doRandom,
bool doRead)
{
2008-11-17 18:29:00 -05:00
for (int i = 0; i < 4000; i++) {
2008-03-05 09:52:00 -05:00
Hack.Imp! imp;
Hack.Exp! exp;
Hack.NewChannel(out imp, out exp);
delete imp;
delete exp;
}
ulong diskSectorCount = 4000000;
// Constrain disk size if user requested
if (diskLimitMB != 0 &&
diskSectorCount > diskLimitMB * SectorsPerMB)
{
diskSectorCount = diskLimitMB * SectorsPerMB;
}
diskLimitMB = diskSectorCount / SectorsPerMB;
// Constrain block count if it overflows available blocks
2008-11-17 18:29:00 -05:00
if (blockCount * blockBytes > diskSectorCount * BytesPerSector) {
2008-03-05 09:52:00 -05:00
blockCount = diskSectorCount * BytesPerSector / blockBytes;
}
2008-11-17 18:29:00 -05:00
if (runNumber == 0) {
2008-03-05 09:52:00 -05:00
Console.WriteLine("# Type: {0} {1}",
doRandom ? "Random" : "Sequential",
doRead ? "Read" : "Write");
Console.WriteLine("# Disk: {0} MB",
diskSectorCount / SectorsPerMB);
Console.WriteLine("# Limit: {0} MB", diskLimitMB);
Console.WriteLine("# Work: {0:f2} MB",
blockCount * blockBytes / (1024.0 * 1024.0));
Console.WriteLine("# Ops: {0}", blockCount);
}
byte[] in ExHeap buffer = new [ExHeap] byte [blockBytes];
SRandom rng = new SRandom();
ulong diskPos = 0;
2008-11-17 18:29:00 -05:00
if (doRandom) {
2008-03-05 09:52:00 -05:00
diskPos = GetRandomOffset(rng, diskSectorCount, blockBytes);
}
long startIrqCount = ProcessService.GetKernelInterruptCount();
long startSwitchCount = ProcessService.GetContextSwitchCount();
long startKernelGcCount = ProcessService.GetKernelGcCount();
int startGcCount;
long startGcMillis;
long startGcBytes;
GC.PerformanceCounters(out startGcCount,
out startGcMillis,
out startGcBytes);
Hack.Imp! imph = himp.Acquire();
Hack.Exp! exph = hexp.Acquire();
2008-11-17 18:29:00 -05:00
///
2008-03-05 09:52:00 -05:00
ESet<Hack.Exp:HACK> eset = new ESet<Hack.Exp:HACK>();
eset.Add(exph);
2008-11-17 18:29:00 -05:00
///
2008-03-05 09:52:00 -05:00
TimeSpan startTime = ProcessService.GetUpTime();
2008-11-17 18:29:00 -05:00
for (ulong i = 0; i < blockCount; i++) {
2008-03-05 09:52:00 -05:00
byte[]! in ExHeap outBuffer;
2008-11-17 18:29:00 -05:00
if (doRead) {
2008-03-05 09:52:00 -05:00
//ProcessService.GetUpTime();
//imph.SendHak();
//switch receive { case exph.Hak(): exph.SendHak(); break; case unsatisfiable: throw new System.Exception(); }
//imph.RecvHak();
2008-11-17 18:29:00 -05:00
///
2008-03-05 09:52:00 -05:00
imph.SendHak();
2008-11-17 18:29:00 -05:00
switch receive {
case ep.Hak() in eset: ep.SendHak(); eset.Add(ep); break; case unsatisfiable: throw new System.Exception();
}
2008-03-05 09:52:00 -05:00
imph.RecvHak();
2008-11-17 18:29:00 -05:00
///
2008-03-05 09:52:00 -05:00
//imph.SendHak(); exph.RecvHak(); exph.SendHak(); imph.RecvHak();
outBuffer = buffer;
}
2008-11-17 18:29:00 -05:00
else {
2008-03-05 09:52:00 -05:00
outBuffer = buffer;
}
buffer = outBuffer;
2008-11-17 18:29:00 -05:00
if (doRandom) {
2008-03-05 09:52:00 -05:00
diskPos =
GetRandomOffset(rng, diskSectorCount, blockBytes);
}
2008-11-17 18:29:00 -05:00
else {
2008-03-05 09:52:00 -05:00
diskPos += blockBytes;
}
}
TimeSpan endTime = ProcessService.GetUpTime();
2008-11-17 18:29:00 -05:00
///
2008-03-05 09:52:00 -05:00
imph.SendHak();
2008-11-17 18:29:00 -05:00
switch receive {
case ep.Hak() in eset: ep.SendHak(); hexp.Release(ep); break; case unsatisfiable: throw new System.Exception();
}
2008-03-05 09:52:00 -05:00
imph.RecvHak();
himp.Release(imph);
eset.Dispose();
2008-11-17 18:29:00 -05:00
///
2008-03-05 09:52:00 -05:00
//hexp.Release(exph);
//himp.Release(imph);
delete buffer;
DisplayPerf(doRead, doRandom, endTime - startTime,
blockCount, blockBytes, diskPos);
int endGcCount;
long endGcMillis;
long endGcBytes;
GC.PerformanceCounters(out endGcCount,
out endGcMillis,
out endGcBytes);
Console.WriteLine("[AppGC :- cnt {0} bytes {1} Kern: ints {2} swi {3} gcs {4}/{5}]",
endGcCount - startGcCount,
endGcBytes - startGcBytes,
ProcessService.GetKernelInterruptCount() - startIrqCount,
ProcessService.GetContextSwitchCount() - startSwitchCount,
ProcessService.GetKernelGcCount() - startKernelGcCount,
ProcessService.GetKernelGcCount());
return 0;
}
public static bool ParseNumber(string! arg,
string! name,
out ulong value)
{
// arg should look like "[-/][A-z]:[0-9]"
2008-11-17 18:29:00 -05:00
if (arg.Length >= 4) {
try {
2008-03-05 09:52:00 -05:00
value = UInt64.Parse(arg.Substring(3));
return true;
}
2008-11-17 18:29:00 -05:00
catch (FormatException) {
}
catch (OverflowException) {
}
2008-03-05 09:52:00 -05:00
}
Console.WriteLine("Could not parse {0}", name);
value = 0;
return false;
}
internal static int AppMain(Parameters! config)
{
string deviceName = config.deviceName;
ulong blockBytes = (ulong) config.blockBytes;
ulong blockCount = (ulong) config.blockCount;
ulong diskLimitMB = (ulong) config.diskLimitMB;
ulong repeatCount = (ulong) config.repeatCount;
ulong pauseSecs = (ulong) config.pauseSecs;
ulong dataMB = (ulong) config.dataMB;
bool doWrite = config.doRead;
bool doRead = config.doWrite;
bool randomIO = config.randomIO;
bool diskReadTest = false;
Hack.Imp! imp;
Hack.Exp! exp;
Hack.NewChannel(out imp, out exp);
himp = new TRef<Hack.Imp:HACK>(imp);
hexp = new TRef<Hack.Exp:HACK>(exp);
2008-11-17 18:29:00 -05:00
if (blockBytes < 512 || (blockBytes & (blockBytes - 1)) != 0) {
2008-03-05 09:52:00 -05:00
Console.WriteLine("Block size must be a power of two greater than or equal to 512.");
return -1;
}
2008-11-17 18:29:00 -05:00
if (doRead == doWrite) {
2008-03-05 09:52:00 -05:00
Console.WriteLine("Need to specify either read or write test.");
return -1;
}
2008-11-17 18:29:00 -05:00
else if (doRead) {
2008-03-05 09:52:00 -05:00
diskReadTest = true;
}
2008-11-17 18:29:00 -05:00
if (dataMB != 0) {
2008-03-05 09:52:00 -05:00
blockCount = dataMB * 1024 * 1024 / blockBytes;
}
2008-11-17 18:29:00 -05:00
for (int run = 0; run < (int)repeatCount; run++) {
2008-03-05 09:52:00 -05:00
if (run != 0)
System.Threading.Thread.Sleep(1000 * (int)pauseSecs);
Tracing.Log(Tracing.Debug, "Starting diskrw run {0}",
(UIntPtr) run);
if (DoDevice(deviceName, run, blockCount, blockBytes,
diskLimitMB, randomIO, diskReadTest) != 0)
{
return -1;
}
Tracing.Log(Tracing.Debug, "Ending diskrw run {0}",
(UIntPtr) run);
}
return 0;
}
}
}