/////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: PerfSnap.sg // // 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; 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) { if (xmlOutput) { DisplayXml(name); } else { DisplayText(name); } } private static void WriteXmlValue(string name, long value) { DualWriteLine( String.Format(" {0} {1:d} ", name, value) ); } private static void WriteXmlValue(string name, ulong value) { DualWriteLine( String.Format(" {0} {1:d} ", name, value) ); } private void DisplayXml(string name) { DualWriteLine( String.Format("", 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); DualWriteLine(""); } private void DisplayText(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 > 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; } } }