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
        }
Пример #2
0
        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();
        }