432 lines
17 KiB
C#
432 lines
17 KiB
C#
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Microsoft Research Singularity
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
// File: CreateProcess.cs
|
||
|
//
|
||
|
// 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) {
|
||
|
disabled = Processor.DisableInterrupts();
|
||
|
}
|
||
|
|
||
|
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);
|
||
|
} else {
|
||
|
// 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) {
|
||
|
Processor.RestoreInterrupts(disabled);
|
||
|
}
|
||
|
|
||
|
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)));
|
||
|
} else {
|
||
|
// 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];
|
||
|
arguments[0] = "testpe.x86";
|
||
|
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();
|
||
|
}
|
||
|
}
|
||
|
}
|