singrdk/base/Kernel/Bartok/GCs/CollectorStatistics.cs

263 lines
8.9 KiB
C#

/*******************************************************************/
/* WARNING */
/* This file should be identical in the Bartok and Singularity */
/* depots. Master copy resides in Bartok Depot. Changes should be */
/* made to Bartok Depot and propagated to Singularity Depot. */
/*******************************************************************/
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
#define ENABLED
namespace System.GCs {
using System;
using System.Threading;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
#if SINGULARITY
using Microsoft.Singularity;
#if SINGULARITY_PROCESS
using Microsoft.Singularity.V1.Services;
#endif
#endif
/// <summary>
/// Enumeration of Event Types.
/// </summary>
public enum GCEvent: int {
CreateHeap,
DestroyHeap,
StopTheWorld,
StopThread,
ResumeTheWorld,
ComputeRootSet,
TraceStart,
TraceSpecial,
SweepStart,
SweepSpecial,
SweepPreCommit,
CollectionComplete,
RootSetComputed,
StackScanStart,
StackScanComplete
}
/// <summary>
/// Manages statistics from the collector. Intended for communication
/// with the scheduler.
/// </summary>
internal class CollectorStatistics {
[Inline]
private static string EventToString(GCEvent ev) {
switch (ev) {
case GCEvent.CreateHeap: return "CreateHeap ";
case GCEvent.DestroyHeap: return "DestroyHeap ";
case GCEvent.StopTheWorld: return "StopTheWorld ";
case GCEvent.StopThread: return "StopThread ";
case GCEvent.ResumeTheWorld: return "ResumeTheWorld ";
case GCEvent.ComputeRootSet: return "ComputeRootSet ";
case GCEvent.TraceStart: return "TraceStart ";
case GCEvent.TraceSpecial: return "TraceSpecial ";
case GCEvent.SweepStart: return "SweepStart ";
case GCEvent.SweepSpecial: return "SweepSpecial ";
case GCEvent.SweepPreCommit: return "SweepPreCommit ";
case GCEvent.CollectionComplete: return "CollectionComplete";
case GCEvent.RootSetComputed: return "RootSetComputed ";
case GCEvent.StackScanStart: return "StackScanStart ";
case GCEvent.StackScanComplete: return "StackScanComplete ";
default: return "Unknown! ";
}
}
[Inline]
private static string EventToFormatString(GCEvent ev) {
switch (ev) {
case GCEvent.CreateHeap: return "CreateHeap";
case GCEvent.DestroyHeap: return "DestroyHeap";
case GCEvent.StopTheWorld: return "StopTheWorld";
case GCEvent.StopThread: return "StopThread, thread {0}";
case GCEvent.ResumeTheWorld: return "ResumeTheWorld";
case GCEvent.ComputeRootSet: return "ComputeRootSet";
case GCEvent.TraceStart: return "TraceStart";
case GCEvent.TraceSpecial: return "TraceSpecial";
case GCEvent.SweepStart: return "SweepStart";
case GCEvent.SweepSpecial: return "SweepSpecial";
case GCEvent.SweepPreCommit: return "SweepPreCommit";
case GCEvent.CollectionComplete: return "CollectionComplete";
case GCEvent.RootSetComputed: return "RootSetComputed";
case GCEvent.StackScanStart: return "StackScanStart, thread {0}";
case GCEvent.StackScanComplete: return "StackScanComplete, thread {0}";
default: return "Unknown!";
}
}
/// <summary>
/// The current value of the counter.
/// </summary>
public static long PerformanceCounter {
[Inline]
get {
long val;
bool ok = QueryPerformanceCounter(out val);
VTable.Assert(ok);
return val;
}
}
public static long ThreadTime {
[Inline]
get {
#if SINGULARITY
return 0;
#else
long creationTime, exitTime, kernelTime, userTime;
UIntPtr handle = Thread.CurrentThread.asmWin32ThreadHandle;
bool ok = GetThreadTimes(handle,
out creationTime,
out exitTime,
out kernelTime,
out userTime);
VTable.Assert(ok);
return kernelTime + userTime;
#endif
}
}
#if SINGULARITY_KERNEL
public static bool QueryPerformanceCounter(out long lpPerformanceCount)
{
lpPerformanceCount = unchecked((long)Processor.CycleCount);
return true;
}
public static bool QueryPerformanceFrequency(out long lpFrequency)
{
lpFrequency = unchecked((long)Processor.CyclesPerSecond);
return true;
}
#elif SINGULARITY_PROCESS
public static bool QueryPerformanceCounter(out long lpPerformanceCount)
{
lpPerformanceCount = unchecked((long)ProcessService.GetCycleCount());
return true;
}
public static bool QueryPerformanceFrequency(out long lpFrequency)
{
lpFrequency = unchecked((long)ProcessService.GetCyclesPerSecond());
return true;
}
#else // not SINGULARITY
[DllImport("BRT")]
[GCAnnotation(GCOption.NOGC)]
[StackBound(1024)]
public static extern bool QueryPerformanceCounter(
out long lpPerformanceCount);
[DllImport("BRT")]
[GCAnnotation(GCOption.NOGC)]
[StackBound(1024)]
public static extern bool QueryPerformanceFrequency(
out long lpFrequency);
[DllImport("BRT")]
[GCAnnotation(GCOption.NOGC)]
[StackBound(1024)]
public static extern bool GetThreadTimes(
UIntPtr hThread,
out long lpCreationTime,
out long lpExitTime,
out long lpKernelTime,
out long lpUserTime
);
#endif
/// <summary>
/// The number of counter values per microsecond.
/// </summary>
public static long CounterFrequency;
/// <summary>
/// The counter value at the initialization of statistics.
/// </summary>
public static long StartCount;
/// <summary>
/// Initialize the statistics information
/// </summary>
public static void Initialize() {
#if ENABLED
bool ok = QueryPerformanceFrequency(out CounterFrequency);
VTable.Assert(CounterFrequency > 0);
VTable.Assert(ok);
StartCount = PerformanceCounter;
#endif
}
/// <summary>
/// Print out a summary
/// </summary>
public static void Summary() {
}
/// <summary>
/// A GC event.
/// </summary>
[Inline]
public static void Event(GCEvent ev) {
Event(ev, -1);
}
/// <summary>
/// A GC event.
/// </summary>
[Inline]
public static void Event(GCEvent ev, long val) {
#if ENABLED
long time = ((PerformanceCounter - StartCount) * 1000000
/ CounterFrequency);
LogEntry le;
le.TimeStamp = time;
le.ThreadTime = 0;
le.Event = ev;
le.Data = val;
Log(le);
#endif
}
private static SpinLock hack;
private static void Log(LogEntry le) {
#if SINGULARITY
Tracing.Log(Tracing.Audit,
EventToFormatString(le.Event),
unchecked((UIntPtr)(uint)le.Data));
#endif
#if DONT
Thread t = Thread.CurrentThread;
VTable.DebugPrint("#GCEVENT Thread {0}: {1}, {2}, {3}\n",
__arglist(t.threadIndex,
EventToString(le.Event),
le.TimeStamp,
le.Data));
#endif
}
private struct LogEntry {
public GCEvent Event;
public long TimeStamp;
public long ThreadTime;
public long Data;
}
}
}