File: System\Caching\MemoryMonitor.cs
Project: ndp\fx\src\Caching\System.Runtime.Caching.csproj (System.Runtime.Caching)
// <copyright file="MemoryMonitor.cs" company="Microsoft">
//   Copyright (c) 2009 Microsoft Corporation.  All rights reserved.
// </copyright>
 
using System;
using System.Collections.Specialized;
using System.Security;
 
namespace System.Runtime.Caching {
    // MemoryMonitor is the base class for memory monitors.  The MemoryCache has two
    // types of monitors:  PhysicalMemoryMonitor and CacheMemoryMonitor.  The first monitors
    // the amount of physical memory used on the machine, and helps determine when we should
    // drop cache entries to avoid paging.  The second monitors the amount of memory used by
    // the cache itself, and helps determine when we should drop cache entries to avoid 
    // exceeding the cache's memory limit.  Both are configurable (see ConfigUtil.cs).
    internal abstract class MemoryMonitor {
        protected const int TERABYTE_SHIFT = 40;
        protected const long TERABYTE = 1L << TERABYTE_SHIFT;
 
        protected const int GIGABYTE_SHIFT = 30;
        protected const long GIGABYTE = 1L << GIGABYTE_SHIFT;
 
        protected const int MEGABYTE_SHIFT = 20;
        protected const long MEGABYTE = 1L << MEGABYTE_SHIFT; // 1048576
 
        protected const int KILOBYTE_SHIFT = 10;
        protected const long KILOBYTE = 1L << KILOBYTE_SHIFT; // 1024
 
        protected const int HISTORY_COUNT = 6;
 
        protected int _pressureHigh;      // high pressure level
        protected int _pressureLow;       // low pressure level - slow growth here
 
        protected int _i0;
        protected int[] _pressureHist;
        protected int _pressureTotal;
 
        private static long s_totalPhysical;
        private static long s_totalVirtual;
 
        [SecuritySafeCritical]
        static MemoryMonitor() {
            MEMORYSTATUSEX memoryStatusEx = new MEMORYSTATUSEX();
            memoryStatusEx.Init();
            if (UnsafeNativeMethods.GlobalMemoryStatusEx(ref memoryStatusEx) != 0) {
                s_totalPhysical = memoryStatusEx.ullTotalPhys;
                s_totalVirtual = memoryStatusEx.ullTotalVirtual;
            }
        }
 
        internal static long TotalPhysical { get { return s_totalPhysical; } }
        internal static long TotalVirtual { get { return s_totalVirtual; } }
 
        internal int PressureLast { get { return _pressureHist[_i0]; } }
        internal int PressureHigh { get { return _pressureHigh; } }
        internal int PressureLow { get { return _pressureLow; } }
 
        internal bool IsAboveHighPressure() {
            return PressureLast >= PressureHigh;
        }
 
        protected abstract int GetCurrentPressure();
 
        internal abstract int GetPercentToTrim(DateTime lastTrimTime, int lastTrimPercent);
 
        protected void InitHistory() {
            Dbg.Assert(_pressureHigh > 0, "_pressureHigh > 0");
            Dbg.Assert(_pressureLow > 0, "_pressureLow > 0");
            Dbg.Assert(_pressureLow <= _pressureHigh, "_pressureLow <= _pressureHigh");
 
            int pressure = GetCurrentPressure();
 
            _pressureHist = new int[HISTORY_COUNT];
            for (int i = 0; i < HISTORY_COUNT; i++) {
                _pressureHist[i] = pressure;
                _pressureTotal += pressure;
            }
        }
 
        // Get current pressure and update history
        internal void Update() {
            int pressure = GetCurrentPressure();
 
            _i0 = (_i0 + 1) % HISTORY_COUNT;
            _pressureTotal -= _pressureHist[_i0];
            _pressureTotal += pressure;
            _pressureHist[_i0] = pressure;
 
#if DBG
            Dbg.Trace("MemoryCacheStats", this.GetType().Name + ".Update: last=" + pressure
                        + ",high=" + PressureHigh
                        + ",low=" + PressureLow
                        + " " + Dbg.FormatLocalDate(DateTime.Now));
#endif
        }
    }
}