singrdk/base/Applications/Benchmarks/CreateProcess/CreateProcess.cs

432 lines
17 KiB
C#
Raw Normal View History

2008-03-05 09:52:00 -05:00
///////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Note: Singularity micro-benchmark program.
//
using Microsoft.Singularity;
using Microsoft.Singularity.V1.Services;
using Microsoft.Singularity.V1.Threads;
using System;
using System.Runtime.CompilerServices;
using System.Diagnostics;
using System.Threading;
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(HelpMessage="CreateProcess benchmark test", DefaultAction=true)]
internal class Parameters
{
[InputEndpoint("data")]
public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
[OutputEndpoint("data")]
public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
[BoolParameter( "q", Default=false, HelpMessage="Quiet Mode.")]
internal bool quietMode;
[LongParameter( "r", Default=1, HelpMessage="Repetition count.")]
internal long repetitions;
reflective internal Parameters();
internal int AppMain() {
return CreateProcessTest.AppMain(this);
}
}
//
// The goal of this test is to time how long it takes to
// create a process.
//
public class CreateProcessTest
{
private static bool AtRing3;
#if x64_PERF
[CLSCompliant(false)]
public struct PerfEvtSel
{
// Bits and Flags
public const uint CNT_MASK = 0xff000000;
public const uint INV = 0x00800000;
public const uint EN = 0x00400000;
public const uint INT = 0x00100000;
public const uint PC = 0x00080000;
public const uint E = 0x00040000;
public const uint OS = 0x00020000;
public const uint USR = 0x00010000;
public const uint UNIT_MASK = 0x0000ff00;
public const uint SELECTOR = 0x000000ff;
// Common setting: Count all, but don't interrupt,
public const uint COUNT = (EN | PC | OS | USR);
// Selector values.
public const uint DtlbL1MissL2Hit = 0x45; // Speculative
public const uint DtlbL1MissL2Miss = 0x46; // Speculative
public const uint CyclesNotHalted = 0x76;
public const uint RequestsToL2Cache = 0x7d;
public const uint ItlbL1MissL2Hit = 0x84;
public const uint ItlbL1MissL2Miss = 0x85;
public const uint RetiredInstructions = 0xc0;
public const uint RetiredBranchInstructions = 0xc2;
public const uint RetiredBranchesMispredicted = 0xc3;
public const uint RetiredBranchesTaken = 0xc4;
public const uint CyclesInterruptsMasked = 0xcd;
public const uint CyclesInterruptsBlocked = 0xce;
}
public static void Reset(uint pmc, ulong value)
{
// Clear the event selector.
Processor.WriteMsr(0xc0010000 + pmc, 0);
// Clear the performance counter.
Processor.WriteMsr(0xc0010004 + pmc, 0);
// Enable the event selector.
Processor.WriteMsr(0xc0010000 + pmc, value);
}
public static string EvtSelToString(ulong value)
{
switch (value & 0xff) {
case PerfEvtSel.DtlbL1MissL2Hit: return "DTLB_L2_Hit";
case PerfEvtSel.DtlbL1MissL2Miss: return "DTBL_L2_Miss";
case PerfEvtSel.CyclesNotHalted: return "CyclesNotHalted";
case PerfEvtSel.RequestsToL2Cache: return "TLB_L2_Requests";
case PerfEvtSel.ItlbL1MissL2Hit: return "ITLB_L2_Hit";
case PerfEvtSel.ItlbL1MissL2Miss: return "ITLB_L2_Miss";
case PerfEvtSel.RetiredInstructions: return "Retired_Inst.";
case PerfEvtSel.RetiredBranchInstructions: return "Branches";
case PerfEvtSel.RetiredBranchesMispredicted:return "Br_Mispredicted";
case PerfEvtSel.RetiredBranchesTaken: return "Br_Taken";
case PerfEvtSel.CyclesInterruptsMasked: return "Ints_Masked (cyc)";
case PerfEvtSel.CyclesInterruptsBlocked: return "Ints_Blocked (cyc)";
default:
return String.Format("{0:x16}", value);
}
}
private static ulong x64_i0, x64_p0;
private static ulong x64_i1, x64_p1;
private static ulong x64_i2, x64_p2;
private static ulong x64_i3, x64_p3;
#endif
private static void DualWriteLine(string message)
{
Console.WriteLine(message);
DebugStub.WriteLine(message);
}
public struct PerfSnap
{
private bool disabled;
private long begCycleCount;
private long endCycleCount;
private long begSwitchCount;
private long endSwitchCount;
private long begInterruptCount;
private long endInterruptCount;
private long begKernelGcCount;
private long endKernelGcCount;
private long begProcessGcCount;
private long endProcessGcCount;
private long iterations;
private ulong begAllocatedCount;
private ulong begAllocatedBytes;
private ulong begFreedCount;
private ulong begFreedBytes;
private ulong endAllocatedCount;
private ulong endAllocatedBytes;
private ulong endFreedCount;
private ulong endFreedBytes;
private ulong begStackGets;
private ulong begStackRets;
private ulong endStackGets;
private ulong endStackRets;
public long Cycles { get { return endCycleCount - begCycleCount; } }
public long Interrupts { get { return endInterruptCount - begInterruptCount; } }
public long Switches { get { return endSwitchCount - begSwitchCount; } }
public long KernelGCs { get { return endKernelGcCount - begKernelGcCount; } }
public long ProcessGCs { get { return endProcessGcCount - begProcessGcCount; } }
public ulong AllocatedCount { get { return endAllocatedCount-begAllocatedCount; } }
public ulong AllocatedBytes { get { return endAllocatedBytes-begAllocatedBytes; } }
public ulong FreedCount { get { return endFreedCount - begFreedCount; } }
public ulong FreedBytes { get { return endFreedBytes - begFreedBytes; } }
public ulong StackGets { get { return endStackGets - begStackGets; } }
public ulong StackRets { get { return endStackRets - begStackRets; } }
public void Start()
{
if (!AtRing3) {
2008-11-17 18:29:00 -05:00
disabled = Processor.DisableLocalPreemption();
2008-03-05 09:52:00 -05:00
}
int collectorCount;
long collectorMillis;
long collectorBytes;
GC.PerformanceCounters(out collectorCount,
out collectorMillis,
out collectorBytes);
ulong stackGets;
ulong stackRets;
StackService.GetUsageStatistics(out stackGets,
out stackRets);
begStackGets = stackGets;
begStackRets = stackRets;
ulong allocatedCount;
ulong allocatedBytes;
ulong freedCount;
ulong freedBytes;
PageTableService.GetUsageStatistics(out allocatedCount,
out allocatedBytes,
out freedCount,
out freedBytes);
begAllocatedCount = allocatedCount;
begAllocatedBytes = allocatedBytes;
begFreedCount = freedCount;
begFreedBytes = freedBytes;
begInterruptCount = ProcessService.GetKernelInterruptCount();
begSwitchCount = ProcessService.GetContextSwitchCount();
begKernelGcCount = ProcessService.GetKernelGcCount();
begProcessGcCount = collectorCount;
#if x64_PERF
// Set up for perf counting
if (!AtRing3) {
// Reset the performance counters to what we're interested in.
Reset(0, PerfEvtSel.COUNT | PerfEvtSel.CyclesNotHalted);
Reset(1, PerfEvtSel.COUNT | PerfEvtSel.RetiredInstructions);
Reset(2, PerfEvtSel.COUNT | PerfEvtSel.RetiredBranchInstructions);
Reset(3, PerfEvtSel.COUNT | PerfEvtSel.RequestsToL2Cache | 0x400);
2008-11-17 18:29:00 -05:00
}
else {
2008-03-05 09:52:00 -05:00
// We're not allowed to reset the perf counters, so take note
// of their current values; we will subtract from this later.
x64_i0 = Processor.ReadPmc(0);
x64_i1 = Processor.ReadPmc(1);
x64_i2 = Processor.ReadPmc(2);
x64_i3 = Processor.ReadPmc(3);
}
#endif
begCycleCount = unchecked((long)Processor.CycleCount);
}
public void Finish(long iterations)
{
endCycleCount = unchecked((long)Processor.CycleCount);
#if X64_PERF
x64_p0 = Processor.ReadPmc(0);
x64_p1 = Processor.ReadPmc(1);
x64_p2 = Processor.ReadPmc(2);
x64_p3 = Processor.ReadPmc(3);
#endif
endInterruptCount = ProcessService.GetKernelInterruptCount();
endSwitchCount = ProcessService.GetContextSwitchCount();
endKernelGcCount = ProcessService.GetKernelGcCount();
int collectorCount;
long collectorMillis;
long collectorBytes;
GC.PerformanceCounters(out collectorCount,
out collectorMillis,
out collectorBytes);
endProcessGcCount = collectorCount;
ulong allocatedCount;
ulong allocatedBytes;
ulong freedCount;
ulong freedBytes;
PageTableService.GetUsageStatistics(out allocatedCount,
out allocatedBytes,
out freedCount,
out freedBytes);
endAllocatedCount = allocatedCount;
endAllocatedBytes = allocatedBytes;
endFreedCount = freedCount;
endFreedBytes = freedBytes;
ulong stackGets;
ulong stackRets;
StackService.GetUsageStatistics(out stackGets,
out stackRets);
endStackGets = stackGets;
endStackRets = stackRets;
if (!AtRing3) {
2008-11-17 18:29:00 -05:00
Processor.RestoreLocalPreemption(disabled);
2008-03-05 09:52:00 -05:00
}
this.iterations = iterations;
}
public void Display(string name)
{
DualWriteLine(
String.Format("{0,-16} {1,6:d} x{2,8:d} ={3,12:d} " +
"[swi={4,6:d} int={5,3:d} gc={6:d}/{7:d}]",
name,
iterations,
Cycles / iterations,
Cycles,
Switches,
Interrupts,
KernelGCs,
ProcessGCs)
);
if (AllocatedCount != 0 || FreedCount != 0 || StackGets != 0) {
DualWriteLine(
string.Format(
" " +
"[alloc={0,4:d}/{1,8:x} free={2,4:d}/{3,8:x} " +
"stack={4,4:d}/{5,4:d}]",
AllocatedCount,
AllocatedBytes,
FreedCount,
FreedBytes,
StackGets,
StackRets)
);
}
#if x64_PERF
if (!AtRing3) {
// Read off the current MSR values and turn them
// into nice labels
ulong e0 = Processor.ReadMsr(0xc0010000);
ulong e1 = Processor.ReadMsr(0xc0010001);
ulong e2 = Processor.ReadMsr(0xc0010002);
ulong e3 = Processor.ReadMsr(0xc0010003);
DualWriteLine(
String.Format("evt: {0,16} {1,16} {2,16} {3,16}",
EvtSelToString(e0),
EvtSelToString(e1),
EvtSelToString(e2),
EvtSelToString(e3)));
2008-11-17 18:29:00 -05:00
}
else {
2008-03-05 09:52:00 -05:00
// Subtract from the initial perf-counter values to
// get the delta we want
x64_p0 -= x64_i0;
x64_p1 -= x64_i1;
x64_p2 -= x64_i2;
x64_p3 -= x64_i3;
}
DualWriteLine(
String.Format("pmc: {0:d16} {1:d16} {2:d16} {3:d16} {4:d16}\n\n",
Cycles, x64_p0, x64_p1, x64_p2, x64_p3));
#endif
}
}
internal static int AppMain(Parameters! config)
{
bool runQuiet = config.quietMode;
long repetitions = config.repetitions;
Console.Write("\nProcess creation test\n\n");
string [] arguments;
for (long i = 0; i < repetitions; i++) {
arguments = new string[2];
2008-11-17 18:29:00 -05:00
arguments[0] = "testpe";
2008-03-05 09:52:00 -05:00
arguments[1] = "!"; // Special flag to not notify debugger.
TimeProcess(arguments, runQuiet);
}
return 0;
}
public static void TimeProcess(String[]! args, bool runQuiet)
{
ulong baseline;
ulong created;
ulong started;
ulong exited;
Process process = null;
PerfSnap snap = new PerfSnap();
snap.Start();
try {
ProcessService.Waypoint0();
baseline = Processor.CycleCount;
//
// Time process creation.
//
ProcessService.Waypoint(1500);
process = new Process(args);
created = Processor.CycleCount;
//
// Time process start.
//
ProcessService.Waypoint(1501);
process.Start();
started = Processor.CycleCount;
ProcessService.Waypoint(1502);
//
// Time process execution.
//
process.Join();
ProcessService.Waypoint(1503);
exited = Processor.CycleCount;
}
finally {
snap.Finish(1);
}
snap.Display("CreateProc");
ProcessService.Waypoint(1504);
process.Dispose(true);
ProcessService.Waypoint(1505);
ProcessService.WaypointDump();
if (runQuiet) {
return;
}
//
// Tell the world.
//
Console.WriteLine();
Console.WriteLine("Tested process: {0}", args[0]);
Console.WriteLine("Create process: {0,15:d} cycles", created - baseline);
Console.WriteLine("Start process: {0,15:d} cycles", started - created);
Console.WriteLine("Run process: {0,15:d} cycles", exited - started);
Console.WriteLine("Total: {0,15:d} cycles", exited - baseline);
Console.WriteLine("Process.Create: {0,15:d} cycles", started - baseline);
Console.WriteLine();
Console.WriteLine();
}
}
}