298 lines
11 KiB
Plaintext
298 lines
11 KiB
Plaintext
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Microsoft Research Singularity
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
// Note: Performance measurer for Singularity Benchmark
|
||
|
//
|
||
|
|
||
|
using System;
|
||
|
using Microsoft.Singularity.V1.Services;
|
||
|
|
||
|
namespace Microsoft.Singularity.Applications
|
||
|
{
|
||
|
public struct PerfSnap
|
||
|
{
|
||
|
// Global options for all instances
|
||
|
static bool xmlOutput = false;
|
||
|
static bool atRing3 = false;
|
||
|
|
||
|
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;
|
||
|
|
||
|
private long begTicks;
|
||
|
private long endTicks;
|
||
|
|
||
|
|
||
|
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 long ElapsedTicks { get { return endTicks - begTicks; } }
|
||
|
|
||
|
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;
|
||
|
|
||
|
begTicks = DateTime.Now.Ticks;
|
||
|
|
||
|
|
||
|
#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;
|
||
|
|
||
|
endTicks = DateTime.Now.Ticks;
|
||
|
|
||
|
if (!atRing3) {
|
||
|
// /ravi/07/14/07/ Processor.RestoreInterrupts(disabled);
|
||
|
}
|
||
|
|
||
|
this.iterations = iterations;
|
||
|
}
|
||
|
|
||
|
public void Display(string name)
|
||
|
{
|
||
|
if (xmlOutput) {
|
||
|
DisplayXml(name);
|
||
|
}
|
||
|
else {
|
||
|
DisplayText(name);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static void WriteXmlValue(string name, long value)
|
||
|
{
|
||
|
DualWriteLine(
|
||
|
String.Format(" <Measurement> <name> {0} </name> <value> {1:d} </value> </Measurement>", name, value)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
private static void WriteXmlValue(string name, ulong value)
|
||
|
{
|
||
|
DualWriteLine(
|
||
|
String.Format(" <Measurement> <name> {0} </name> <value> {1:d} </value> </Measurement>", name, value)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
private void DisplayXml(string name)
|
||
|
{
|
||
|
DualWriteLine(
|
||
|
String.Format("<Microbenchmark Name=\"{0}\">", name)
|
||
|
);
|
||
|
WriteXmlValue("CyclesPerIteration", Cycles / iterations);
|
||
|
WriteXmlValue("Cycles", Cycles);
|
||
|
WriteXmlValue("Iterations", iterations);
|
||
|
WriteXmlValue("Switches", Switches);
|
||
|
WriteXmlValue("Interrupts", Interrupts);
|
||
|
WriteXmlValue("KernelGCs", KernelGCs);
|
||
|
WriteXmlValue("ProcessGCs", ProcessGCs);
|
||
|
WriteXmlValue("AllocationCount", AllocatedCount);
|
||
|
WriteXmlValue("AllocationBytes", AllocatedBytes);
|
||
|
WriteXmlValue("FreedCount", FreedCount);
|
||
|
WriteXmlValue("FreedBytes", FreedBytes);
|
||
|
WriteXmlValue("StackGetCount", StackGets);
|
||
|
WriteXmlValue("StackReturnCount", StackRets);
|
||
|
WriteXmlValue("ElapsedTicks", ElapsedTicks);
|
||
|
DualWriteLine("</Microbenchmark>");
|
||
|
}
|
||
|
|
||
|
private void DisplayText(string name)
|
||
|
{
|
||
|
DualWriteLine(
|
||
|
String.Format("{0,-16} {1,6:d} x{2,8:d} {3,6:d} " +
|
||
|
"[swi={4,6:d} int={5,3:d} gc={6:d}/{7:d}]",
|
||
|
name,
|
||
|
iterations,
|
||
|
Cycles / iterations,
|
||
|
ElapsedTicks / iterations,
|
||
|
Switches,
|
||
|
Interrupts,
|
||
|
KernelGCs,
|
||
|
ProcessGCs)
|
||
|
);
|
||
|
|
||
|
if (AllocatedCount > 1 || FreedCount > 1 || StackGets > 1) {
|
||
|
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
|
||
|
}
|
||
|
|
||
|
private static void DualWriteLine(string message)
|
||
|
{
|
||
|
Console.WriteLine(message);
|
||
|
DebugStub.WriteLine(message);
|
||
|
}
|
||
|
|
||
|
public static void SetOptions(bool ring3, bool doXmlOutput)
|
||
|
{
|
||
|
PerfSnap.atRing3 = ring3;
|
||
|
PerfSnap.xmlOutput = doXmlOutput;
|
||
|
}
|
||
|
}
|
||
|
}
|