private void PerformCollection(int currentThreadIndex, int generation) { // Clear the GCRequest bit (if necessary) before doing // anything that could cause a state transition. if (Transitions.HasGCRequest(currentThreadIndex)) { Transitions.ClearGCRequest(currentThreadIndex); } int startTicks = 0; bool enableGCTiming = VTable.enableGCTiming; if (enableGCTiming || VTable.enableFinalGCTiming) { VTable.enableGCTiming = false; startTicks = Environment.TickCount; if (enableGCTiming) { VTable.DebugPrint("[GC start: {0} bytes]\n", __arglist(TotalMemory)); } } #if SINGULARITY Tracing.Log(Tracing.Debug, "GC start"); #endif CollectorStatistics.Event(GCEvent.StopTheWorld); CurrentPhase = StopTheWorldPhase.Synchronizing; StopTheWorld(); CurrentPhase = StopTheWorldPhase.SingleThreaded; StartGCCycle(); #if SINGULARITY long preGcMemoryUsage = GC.GetTotalMemory(false); #if SINGULARITY_KERNEL #if THREAD_TIME_ACCOUNTING TimeSpan ticks = Thread.CurrentThread.ExecutionTime; TimeSpan ticks2 = SystemClock.KernelUpTime; #else TimeSpan ticks = SystemClock.KernelUpTime; #endif #elif SINGULARITY_PROCESS #if THREAD_TIME_ACCOUNTING TimeSpan ticks = ProcessService.GetThreadTime(); TimeSpan ticks2 = ProcessService.GetUpTime(); #else TimeSpan ticks = ProcessService.GetUpTime(); #endif #endif #endif //singularity #if SINGULARITY_KERNEL bool iflag = Processor.DisableInterrupts(); // Disable interrupts on other CPU's MpExecution.StopProcessorsForGC(); #endif #if SINGULARITY ulong beg = Isa.GetCycleCount(); #endif // Preparation GC.allocationGCInhibitCount++; // Verify the heap before GC if (VTable.enableGCVerify) { this.VerifyHeap(true); } // Invoke the chosen collector #if SINGULARITY Monitoring.Log(Monitoring.Provider.GC, (ushort)GarbageCollectorEvent.StartCollection); #endif this.CollectStopped(collectorThreadIndex, generation); #if SINGULARITY Monitoring.Log(Monitoring.Provider.GC, (ushort)GarbageCollectorEvent.EndCollection); #endif // Verify the heap after GC if (VTable.enableGCVerify) { this.VerifyHeap(false); } if (VTable.enableGCAccounting) { MemoryAccounting.Report(GC.gcType); } // Cleanup CollectorStatistics.Event(GCEvent.ResumeTheWorld); GC.allocationGCInhibitCount--; CurrentPhase = StopTheWorldPhase.Idle; #if SINGULARITY long postGcMemoryUsage = GC.GetTotalMemory(false); #endif if (enableGCTiming || VTable.enableFinalGCTiming) { int elapsedTicks = Environment.TickCount - startTicks; BaseCollector.RegisterPause(elapsedTicks); if (enableGCTiming) { VTable.DebugPrint("[GC end : {0} bytes, {1} ms]\n", __arglist(TotalMemory, elapsedTicks)); VTable.enableGCTiming = true; } } if (VTable.enableGCProfiling) { ulong totalMemory = (ulong)GC.GetTotalMemory(false); this.RegisterHeapSize(totalMemory); } ResumeTheWorld(); collectorThreadIndex = -1; #if SINGULARITY Tracing.Log(Tracing.Debug, "GC stop"); long pagesCollected = preGcMemoryUsage - postGcMemoryUsage; #if SINGULARITY_KERNEL #if THREAD_TIME_ACCOUNTING int procId = Thread.CurrentProcess.ProcessId; ticks = Thread.CurrentThread.ExecutionTime - ticks; ticks2 = SystemClock.KernelUpTime - ticks2; Process.kernelProcess.SetGcPerformanceCounters(ticks, (long)pagesCollected); #else ticks = SystemClock.KernelUpTime - ticks; #endif Thread.CurrentProcess.SetGcPerformanceCounters(ticks, (long)pagesCollected); #elif SINGULARITY_PROCESS #if THREAD_TIME_ACCOUNTING ushort procId = ProcessService.GetCurrentProcessId(); ticks = ProcessService.GetThreadTime() - ticks; ticks2 = ProcessService.GetUpTime() - ticks2; #else ticks = ProcessService.GetUpTime() - ticks; #endif ProcessService.SetGcPerformanceCounters(ticks, (long)pagesCollected); #endif #if DEBUG #if THREAD_TIME_ACCOUNTING DebugStub.WriteLine("~~~~~ StopTheWorld [collected pages={0:x8}, pid={1:x3}, ms(Thread)={2:d6}, ms(System)={3:d6}, procId={4}, tid={5}]", __arglist(pagesCollected, PageTable.processTag >> 16, ticks.Milliseconds, ticks2.Milliseconds, procId, Thread.GetCurrentThreadIndex() )); #endif #endif #endif #if SINGULARITY DebugStub.AddToPerfCounter(GC.perfCounter, Isa.GetCycleCount() - beg); #endif #if SINGULARITY_KERNEL // Resume interrupts on other CPU's MpExecution.ResumeProcessorsAfterGC(); Processor.RestoreInterrupts(iflag); #endif }
public unsafe void DispatchInterrupt(InterruptContext *context) { Processor p = Processor.CurrentProcessor; int interrupt = context->ExceptionId; // Indicate that we are in an interrupt context. Thread target = null; Thread current = Processor.GetCurrentThread(); Kernel.Waypoint(801); // Don't generate loads of output for debugger-related interrupts #if DEBUG_INTERRUPTS DebugStub.WriteLine("Int{0:x2}", __arglist(interrupt)); context->Display(); #endif if (Processor.IsSamplingEnabled) { if (p.nextSampleIdle == false) { p.Profiler.LogStackTrace(context->InstructionPointer, context->StackPointer); } p.nextSampleIdle = false; } if (halted) { p.clock.CpuResumeFromHaltEvent(); halted = false; } unchecked { if (interrupt != p.clockInterrupt && interrupt != p.timerInterrupt) { // We don't log the clockInterrupt because of all the spew. Tracing.Log(Tracing.Debug, "Interrupt 0x{0:x}, count={1:x}, eip={2:x} [CC={3:x8}]", (UIntPtr)(uint)interrupt, (UIntPtr)p.interruptCounts[interrupt], (UIntPtr)context->InstructionPointer, (UIntPtr)(uint)Processor.CycleCount); } } Monitoring.Log(Monitoring.Provider.Processor, (ushort)ProcessorEvent.Interrupt, 0, (uint)interrupt, 0, 0, 0, 0); if (interrupt == Kernel.HalIpiInterrupt) { #if DEBUG_IPI DebugStub.WriteLine("IPI received 0x{0:x2} on processor {1}", __arglist(interrupt, p.Id)); #endif // DEBUG_DISPATCH_TIMER Platform.ClearFixedIPI(interrupt); //p.dispatcher.HandlePreemptionReschedule(); } else if (interrupt == p.timerInterrupt) { // Polling on every timer interrupt is EXCEEDINGLY costly p.timer.ClearInterrupt(); p.dispatcher.HandlePreemptionReschedule(p.timer); } else if (interrupt == p.clockInterrupt) { p.clock.ClearInterrupt(); #if DEBUG // Check for a debug break. if (DebugStub.PollForBreak()) { DebugStub.WriteLine("Debugger ctrl-break after interrupt 0x{0:x2}", __arglist(interrupt)); DebugStub.Break(); } #endif // DEBUG } #if ISA_IX else if (interrupt == EVectors.GCSynchronization) { Platform.ClearFixedIPI(interrupt); MpExecution.GCSynchronizationInterrupt(); } else if (interrupt == EVectors.SpuriousInterrupt) { // FIXME: identify the source of these isolated interrupts after the // warmboot. Ignore them for now. DebugStub.WriteLine("Spurious interrupt"); } #endif // ISA_IX else { if (!Platform.InternalInterrupt((byte)interrupt)) { HalPic pic = p.GetPic(); DebugStub.Assert(pic != null); pic.ClearInterrupt((byte)interrupt); IoIrq.SignalInterrupt(pic.InterruptToIrq((byte)interrupt)); #if DEBUG_DISPATCH_IO DebugStub.WriteLine("++DispatchInterruptEvent Irq={0:x2}, Thread={1:x8}", __arglist(pic.InterruptToIrq((byte)interrupt), Kernel.AddressOf(target))); #endif // DEBUG_DISPATCH_IO p.dispatcher.HandleIOReschedule(); } else { // Potentially missed interrupt DebugStub.Break(); } } #if DEBUG_INTERRUPTS DebugStub.WriteLine("(2nd)Int{0:x2}", __arglist(interrupt)); context->Display(); if (!Processor.InterruptsDisabled()) { DebugStub.WriteLine(" interrupts enabled!!!!!!!"); DebugStub.Break(); } #if DEBUG_DEEPER DebugStub.WriteLine("Int{0:x2}", __arglist(interrupt)); Thread.DisplayAbbrev(ref context, " int end"); #endif #endif // Now swap in the resulting current thread. (Note that this call will not return.) Isa.GetCurrentThread()->spill.Resume(); }