Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.GaussianProcessTuning/ILNumerics.2.14.4735.573/Misc/ILMemoryPoolInternal.cs @ 9844

Last change on this file since 9844 was 9102, checked in by gkronber, 12 years ago

#1967: ILNumerics source for experimentation

File size: 30.6 KB
Line 
1///
2///    This file is part of ILNumerics Community Edition.
3///
4///    ILNumerics Community Edition - high performance computing for applications.
5///    Copyright (C) 2006 - 2012 Haymo Kutschbach, http://ilnumerics.net
6///
7///    ILNumerics Community Edition is free software: you can redistribute it and/or modify
8///    it under the terms of the GNU General Public License version 3 as published by
9///    the Free Software Foundation.
10///
11///    ILNumerics Community Edition is distributed in the hope that it will be useful,
12///    but WITHOUT ANY WARRANTY; without even the implied warranty of
13///    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14///    GNU General Public License for more details.
15///
16///    You should have received a copy of the GNU General Public License
17///    along with ILNumerics Community Edition. See the file License.txt in the root
18///    of your distribution package. If not, see <http://www.gnu.org/licenses/>.
19///
20///    In addition this software uses the following components and/or licenses:
21///
22///    =================================================================================
23///    The Open Toolkit Library License
24///   
25///    Copyright (c) 2006 - 2009 the Open Toolkit library.
26///   
27///    Permission is hereby granted, free of charge, to any person obtaining a copy
28///    of this software and associated documentation files (the "Software"), to deal
29///    in the Software without restriction, including without limitation the rights to
30///    use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
31///    the Software, and to permit persons to whom the Software is furnished to do
32///    so, subject to the following conditions:
33///
34///    The above copyright notice and this permission notice shall be included in all
35///    copies or substantial portions of the Software.
36///
37///    =================================================================================
38///   
39
40using System;
41using System.Collections;
42using System.Collections.Generic;
43using System.Text;
44using ILNumerics.Exceptions;
45using ILNumerics.Data;
46
47namespace ILNumerics.Misc {
48    /// <summary>
49    /// Memory pool serving as temporary storage for System.Array objects
50    /// </summary>
51    /// <remarks>The pool reduces the pressure on the systems memory caused by larger objects.
52    /// <para>Arrays created in ILNumerics will first try to reclaim their memory from this pool. If that
53    /// fails, the memory is allocated from the managed heap only.</para>
54    /// <para>Disposed array objects register their underlying System.Array in the pool for
55    /// later reusing. The process is triggered by the ILNumerics memory management automatically.</para></remarks>
56    internal partial class ILMemoryPoolInternal<T> : IILMemoryPool {
57
58        internal enum MemoryPoolShrinkStrategies {
59            Popularity,
60            Smallest
61        }
62
63        #region attributes
64        private Dictionary<long,Stack<T[]>> m_pool;
65        private Dictionary<long,int> m_requests;
66        private ILAVLTree m_lengths;
67        private Dictionary<long, string> m_profiler;
68        private long m_maxBytes;
69        private long m_curBytes;
70        private long m_minArrLength;
71        private long m_reclaimedBytesCount;
72        private long m_reclaimedObjectsCount;
73        private int m_catchedOOMs;
74        private bool[] m_rateHistVals = new bool[100];
75        private int m_rateHistPos = 0;
76        private int m_shrinksCount = 0; 
77        private int m_curObjectsCount = 0;
78        private double m_autoIncreaseNewRequests = 1.1;
79        private double m_maxRequestedLengthIncrease = 1.2;
80        private double m_maxBytesIncreaseRate = 1.02;
81        private double m_OOMdecreaseMaxBytesRate = 0.8;
82        private Comparer<KeyValuePair<long, int>> m_comparer = new ILRequestsValueComparer();
83        private static readonly int s_singleElementSize;
84        private static readonly double s_shrinkPercent = .5;
85        private static readonly double s_shrinkRequestLenghtIncreaseRate;
86        private static readonly string s_elementTypeName;
87        internal static ILMemoryPoolInternal<T> Pool;
88        internal static ILPerformanceCounter<T> s_performanceCounters = new ILPerformanceCounter<T>();
89#if VERBOSE
90        internal static string s_logfilename = String.Format("ILMemoryPool_VERBOSE_Log_{0}.log",typeof(T).Name);
91        internal static StringBuilder s_logBuilder = new StringBuilder("ILMemoryPoolInternal allocation history from " + DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString() + Environment.NewLine);
92#endif
93        #endregion
94
95        #region properties
96        /// <summary>
97        /// factor used, to allow returned arrays to exceed the requested array length
98        /// </summary>
99        public double MaxRequestedLengthIncrease {
100            get { return m_maxRequestedLengthIncrease; }
101            set {
102                m_maxRequestedLengthIncrease = value;
103                if (Settings.s_measurePerformanceAtRuntime)
104                    s_performanceCounters.PCAcceptLengthIncreaseSet((int)Math.Log10(m_maxRequestedLengthIncrease));
105            }
106        }
107        /// <summary>
108        /// minimum length of array objects for recognition in the pool (default: 80k)
109        /// </summary>
110        public long MinArrayLength {
111            get { return m_minArrLength; }
112            set { m_minArrLength = value; }
113        }
114        /// <summary>
115        /// maximum size of the pool configured in bytes
116        /// </summary>
117        public long MaxBytes {
118            get { return m_maxBytes; }
119            set {
120                m_maxBytes = value;
121                if (Settings.s_measurePerformanceAtRuntime)
122                    s_performanceCounters.PCmaximumPoolSizeSet(m_maxBytes);
123            }
124        }
125        /// <summary>
126        /// percentage of allocation requests which could be successfully be completed
127        /// </summary>
128        public double SuccessRate {
129            get  {
130                int succ = 0;
131                foreach (bool b in m_rateHistVals) {
132                    if (b) succ++;
133                }
134                return succ / (double)m_rateHistVals.Length * 100d;
135            }
136        }
137        /// <summary>
138        /// Number of reclaimed bytes since the pool exists
139        /// </summary>
140        /// <remarks>The counter will be reset by calls to <see cref="ILNumerics.Misc.ILMemoryPool.Reset(int, int)"/></remarks>
141        public long ReclaimedBytesCount {
142            get { return m_reclaimedBytesCount; }
143        }
144        /// <summary>
145        /// Number of reclaimed objects since the pool exists
146        /// </summary>
147        /// <remarks>The counter will be reset by calls to <see cref="ILNumerics.Misc.ILMemoryPool.Reset(int, int)"/></remarks>
148        public long ReclaimedObjectsCount {
149            get { return m_reclaimedObjectsCount; }
150        }
151        #endregion
152
153        #region constructors
154        private ILMemoryPoolInternal()
155            : this (getDefaultMinArrayLength(),200) {} // (int)(Environment.WorkingSet / 1024.0 / 1024 / 10)) { }
156
157        private ILMemoryPoolInternal(int MinArrayLength, int PoolSizeMB) {
158            m_maxBytes = PoolSizeMB * 1024 * 1024;
159            m_minArrLength = MinArrayLength;
160            m_requests = new Dictionary<long,int>();
161            m_pool = new Dictionary<long,Stack<T[]>>();
162            m_lengths = new ILAVLTree();
163            m_profiler = new Dictionary<long,string>();
164            MaxRequestedLengthIncrease = 1.2;
165            ILMemoryPool.Pools.Add(typeof(T),this);
166        }
167
168        static ILMemoryPoolInternal() {
169            if (typeof(T).IsValueType) {
170                T tmp = default(T);
171                s_singleElementSize = Math.Max(System.Runtime.InteropServices.Marshal.SizeOf(tmp), 1);
172            } else {
173                s_singleElementSize = 4;
174            }
175            Pool = new ILMemoryPoolInternal<T>();
176            s_elementTypeName = typeof(T).Name;
177
178#if DEBUG   
179            //System.Diagnostics.StackTrace.METHODS_TO_SKIP
180#endif
181
182#if VERBOSE
183            // manage log file
184            System.IO.File.Delete(s_logfilename);
185#endif
186        }
187
188        #endregion
189
190        #region public API
191        /// <summary>
192        /// Reset &amp; reconfigure the pool
193        /// </summary>
194        /// <param name="MinArrayLength">Minimum length for array object to be stored inside the pool</param>
195        /// <param name="PoolSizeMB">Overall size the memory pool consumes at most</param>
196        /// <remarks>Reset will dispose all objects currently hold in the pool!</remarks>
197        public void Reset ( long MinArrayLength, int PoolSizeMB ) {
198            lock (this) {
199                if (PoolSizeMB < 10)
200                    PoolSizeMB = 10;
201                m_maxBytes = PoolSizeMB * 1024 * 1024;
202                m_minArrLength = MinArrayLength;
203                DisposeContent();
204                m_reclaimedBytesCount = 0;
205                m_reclaimedObjectsCount = 0;
206            }
207        }
208        /// <summary>
209        /// Dispose all objects currently hold in the pool
210        /// </summary>
211        /// <remarks>The pool get cleared and continues working with the same parameters after the call has finished. </remarks>
212        public void DisposeContent() {
213            lock (this) {
214                //m_requests.Clear(); // lets keep the statistics
215                m_pool.Clear();
216                m_lengths.Clear();
217                m_requests.Clear();
218                m_curBytes = 0;
219                m_curObjectsCount = 0;
220
221                if (Settings.s_measurePerformanceAtRuntime) {
222                    s_performanceCounters.PCoverallSizeSet(0);
223                }
224            }
225        }
226        /// <summary>
227        /// Return or register an array object of value type in the pool that is not used anymore, i.e. free it
228        /// </summary>
229        /// <typeparam name="T">arbitrary element type</typeparam>
230        /// <param name="arr">array</param>
231        /// <remarks><para>In order to be stored in the pool, the array must meet the minimum array length and must fit into the global pool size.
232        /// Null objects or empty arrays or array not suitable for the pool will be silently ignored.</para>
233        /// <para>If the new array is too large to fit into the remaining pool space, the oldest objects in the pool will be released until the object can get registered.</para></remarks>
234        public void Free(T[] arr) {
235#if VERBOSE
236            //System.Diagnostics.Debug.WriteLine("ILMemoryPoolInternal registering array: {0}[] {1}",typeof(T).Name, arr.Length); 
237            Log(arr.Length,"REG");
238#endif
239            if (arr == null || arr.Length == 0 || arr.Length < m_minArrLength)
240                return;
241#if DEBUG
242                //System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace();
243                //DebuggerTraceHelper.Output.Append(String.Format("\r\n{0}[{1}]-{2}\r\n{3}\r\n======================================"
244                //    ,arr.ToString(), arr.Length, arr.GetHashCode() ,st.ToString()));
245                //DebuggerTraceHelper.Output.Append(String.Format("============================="));
246#endif
247            if (!String.IsNullOrEmpty(Settings.s_memoryPoolProfileFileName)) {
248                lock (m_profiler) {
249                    int key = arr.GetHashCode();
250                    if (m_profiler.ContainsKey(key))
251                        m_profiler.Remove(key);
252                }
253            }
254            // determine size of new array
255            long newSize = arr.Length * s_singleElementSize + 8; // up to .NET 4.0
256            if (newSize >= m_maxBytes) {
257                m_maxBytes = newSize+1;
258                return;
259            }
260            lock (this) {
261                if (m_curBytes + newSize > m_maxBytes)
262                    Shrink(newSize);
263                // add the array to the pool
264                Stack<T[]> inPool;
265                if (m_pool.TryGetValue(arr.Length, out inPool)) {
266                    // append to pool
267                    System.Diagnostics.Debug.Assert(!inPool.Contains(arr));
268                    inPool.Push(arr);
269                } else {
270                    // add new length to pool
271                    inPool = new Stack<T[]>();
272                    inPool.Push(arr);
273                    m_pool.Add(arr.Length,inPool);     
274                }
275                m_lengths.Add(arr.Length);
276                m_curObjectsCount++;
277                m_curBytes += newSize;
278                if (Settings.s_measurePerformanceAtRuntime) {
279                    s_performanceCounters.PCoverallSizeSet(m_curBytes);
280                    s_performanceCounters.PCcurObjectsCountSet(m_curObjectsCount);
281                }
282            }
283        }
284        /// <summary>
285        /// Request a System.Array instance, may not be cleared
286        /// </summary>
287        /// <typeparam name="T">value type</typeparam>
288        /// <param name="length"><b>minimum</b> length of array</param>
289        /// <returns>System.Array - either from the pool or a newly created array</returns>
290        /// <remarks><para>If a suitable System.Array was found in the pool, this object is returned.
291        /// Otherwise a new array is created.</para>
292        /// <para>There is no way of determining, if the array was reclaimed from pool or newly created!
293        /// If you must be sure, the element values are set to default(T), call the overloaded version
294        /// <see cref="ILNumerics.Misc.ILMemoryPool.New&lt;T&gt;(int, bool, out bool)"/> instead!</para>
295        /// <para>If a new array could not get created due to an OutOfMemoryException, a garbage collection
296        /// is triggered and the array is again requested from the pool. If this again fails, another attempt
297        /// to create the array is done. Exceptions may thrown from this last attempt are not catched and
298        /// therefore must be handled by the calling function.</para></remarks>
299        public T[] New(long length) {
300#if VERBOSE
301            //System.Diagnostics.Debug.WriteLine(String.Format("Pool<{0}>: requesting length: {1}", typeof(T).Name, length));
302            Log((int)length,"NEW");
303#endif
304            T[] ret = null;
305            lock (this) {
306                // try to find a suitable object in the pool first
307                if (length >= m_minArrLength && (ret = GetFromPool(length)) != null) {
308                    int oldRequestCount = 0;
309                    length = ret.Length;
310                    m_requests.TryGetValue(length, out oldRequestCount);
311                    m_requests[length] = ++oldRequestCount;
312                    return ret;
313                }
314            }
315            // must create a new one
316            try {
317                length = (long)(m_autoIncreaseNewRequests * length);
318                ret = new T[length];
319            } catch (OutOfMemoryException) {
320                m_catchedOOMs++;
321                m_maxBytes = (long) (m_maxBytes * m_OOMdecreaseMaxBytesRate);
322                if (Settings.s_measurePerformanceAtRuntime) {
323                    s_performanceCounters.PCOOMcatchedIncrement();
324                }
325                DisposeContent();
326            }
327            if (ret == null) {
328                ret = new T[length];
329            }
330            lock (this) {
331                int oldRequestCount = 0;
332                m_requests.TryGetValue(length, out oldRequestCount);
333                m_requests[length] = ++oldRequestCount;
334            }
335            return ret;
336        }
337        /// <summary>
338        /// Request a System.Array instance and optionally clear the array
339        /// </summary>
340        /// <typeparam name="T">value type</typeparam>
341        /// <param name="length">length of array</param>
342        /// <param name="clear">if true, the elements of the array returned are set to default(T).</param>
343        /// <param name="iscleared">out paramater determining if the array returned has been cleared</param>
344        /// <returns>System.Array - either from the pool or a newly created array</returns>
345        /// <remarks><para>If a suitable System.Array was found in the pool, this object is returned. Otherwise a new array is created.</para>
346        /// <para>If the <paramref name="clear">clear </paramref> parameter was set to false, the
347        /// <paramref name="iscleared">iscleared</paramref> parameter can be used to determine, if the object
348        /// was returnd from the pool and may need extra clearing.</para>
349        /// <para>If a new array could not get created due to an OutOfMemoryException, a garbage
350        /// collection is triggered and the array is again requested from the pool. If this again failes,
351        /// another attempt to create the array is done. Exceptions eventually thrown from this last
352        /// attempt are not catched and given back to the callee.</para></remarks>
353        public T[] New(long length, bool clear, out bool iscleared) {
354#if VERBOSE
355            //System.Diagnostics.Debug.Write(String.Format("Pool<{0}>: requesting length: {1}", typeof(T).Name, length));
356            Log(length,"NEW");
357#endif
358            T[] ret = null;
359            lock (this) {
360                // try to find a suitable object in the pool first
361                if (length >= m_minArrLength && (ret = GetFromPool(length)) != null) {
362                    int oldRequestCount = 0;
363                    length = ret.Length;
364                    m_requests.TryGetValue(length, out oldRequestCount);
365                    m_requests[length] = ++oldRequestCount;
366                    if (clear) {
367                        for (int i = 0; i < length; i++) {
368                            ret[i] = default(T);
369                        }
370                        iscleared = true;
371                    } else {
372                        iscleared = false;
373                    }
374                    return ret;
375                }
376            }
377            // must create a new one
378            try {
379                length = (int)(m_autoIncreaseNewRequests * length);
380                ret = new T[length];
381            } catch (OutOfMemoryException) {
382                DisposeContent();
383                m_maxBytes = (long)(m_maxBytes * m_OOMdecreaseMaxBytesRate);
384                m_catchedOOMs++;
385                if (Settings.s_measurePerformanceAtRuntime) {
386                    s_performanceCounters.PCOOMcatchedIncrement();
387                }
388            }
389            if (ret == null) {
390                ret = new T[length];
391            }
392            iscleared = true;
393            lock (this) {
394                int oldRequestCount = 0;
395                length = ret.Length;
396                m_requests.TryGetValue(length, out oldRequestCount);
397                m_requests[length] = ++oldRequestCount;
398            }
399            return ret;
400        }
401        /// <summary>
402        /// Give infos about pool state, optionally reset counters
403        /// </summary>
404        /// <param name="shortVersion">true: abbreviate infos to: current MB in Pool, reclaimed MB for livetime, reclaimed objects for livetime. False: give full info (see below)</param>
405        /// <param name="reset">true: reset internal counter for reclaimed objects/ - bytes</param>
406        /// <returns>infos about current pool state</returns>
407        public string Info(bool shortVersion, bool reset) {
408            if (shortVersion) {
409                string s = String.Format("CurMB: {0}| CurObj: {1}| ReclMB: {2}| ReclObj: {3}| Rate: {4:G6}",m_curBytes/1024/1024,countObj(),m_reclaimedBytesCount/1024/1024,m_reclaimedObjectsCount,SuccessRate);
410                if (reset) {
411                    m_reclaimedBytesCount = 0;
412                    m_reclaimedObjectsCount = 0;
413                }
414                return s;
415            } else {
416                StringBuilder sb = new StringBuilder();
417                sb.Append("ILMemoryPool - ");
418                sb.Append(DateTime.Now.ToLongTimeString() + Environment.NewLine);
419                string tmp;
420                lock (this) {
421                    sb.Append(String.Format("CurMB: {0}| CurObj: {1}| ReclMB: {2}| ReclObj: {3}| Rate: {4:G6}",m_curBytes/1024/1024,countObj(),m_reclaimedBytesCount/1024/1024,m_reclaimedObjectsCount,SuccessRate) + Environment.NewLine);
422                    sb.Append(String.Format("OOM: {0}| Shrink: {1:}| LFact: {2:G2}| MaxMB: {3}\r\n",m_catchedOOMs, m_shrinksCount, m_maxRequestedLengthIncrease, m_maxBytes/1024/1024));
423                    foreach (KeyValuePair<long,Stack<T[]>> item in m_pool) {
424                        sb.Append(item.Key + ": ");
425                        foreach(Array a in item.Value) {
426                            tmp = a.GetType().GetElementType().Name;
427                            if (char.IsNumber(tmp[tmp.Length-1])) {
428                                tmp = new String(new char[]{tmp[0], tmp[tmp.Length-1]});
429                            } else {
430                                tmp = tmp.Substring(0,2);
431                            }
432                            sb.Append(tmp);
433                            sb.Append(" ");
434                        }
435                        sb.Append(Environment.NewLine);
436                    }
437                    if (reset) {
438                        m_reclaimedBytesCount = 0;
439                        m_reclaimedObjectsCount = 0;
440                    }
441                }
442                return sb.ToString();
443            }
444        }
445        /// <summary>
446        /// Give extended infos about pool state
447        /// </summary>
448        /// <returns>Full info about current and reclaimed pool objects</returns>
449        /// <remarks>For short version infos use the overloaded version <see cref="ILNumerics.Misc.ILMemoryPool.Info(bool)"/></remarks>
450        public string Info() {
451            return Info(false, false);
452        }
453        /// <summary>
454        /// Give infos about pool state, optionally reset counters
455        /// </summary>
456        /// <param name="shortVersion">true: abbreviate infos to: current MB in Pool, reclaimed MB for livetime, reclaimed objects for livetime. False: give full info (see below)</param>
457        /// <returns>infos about current pool state</returns>
458        public string Info(bool shortVersion) {
459            return Info(shortVersion, false);
460        }
461        #endregion
462
463        #region private helper
464#if VERBOSE
465        private void Log( int length, string prefix ) {
466            lock (this) {
467                s_logBuilder.Append(
468                    String.Format("{0},\t{1},\t{2},\t{3}" + Environment.NewLine
469                                    , prefix
470                                    , System.DateTime.Now.ToShortDateString()
471                                    , System.DateTime.Now.ToLongTimeString() + "." + System.DateTime.Now.Millisecond.ToString()
472                                    , length));
473                if (s_logBuilder.Length > 10000) {
474                    System.IO.File.AppendAllText(s_logfilename, s_logBuilder.ToString());
475                    s_logBuilder.Clear();
476                }
477            }
478        }
479#endif
480        private T[] GetFromPool(long length) {
481            Stack<T[]> inPool;
482            T[] ret = null;
483            lock (this) {
484                if (m_pool.TryGetValue(length, out inPool)) {
485                    ret = inPool.Pop();
486                    long newSize = (ret.Length * s_singleElementSize + 8);
487                    m_curBytes -= newSize;
488                    m_curObjectsCount--;
489                    if (Settings.s_measurePerformanceAtRuntime) {
490                        s_performanceCounters.PCcurObjectsCountSet(m_curObjectsCount);
491                        s_performanceCounters.PCoverallSizeSet(m_curBytes);
492                        s_performanceCounters.PCsuccessRateIncrement();
493                        s_performanceCounters.PCsuccessRateBaseIncrement();
494                        s_performanceCounters.PCreclaimedObjectsCountIncrement();
495                    }
496                    if (inPool.Count == 0) {
497                        m_pool.Remove(length);
498                        m_lengths.Remove(length);
499                        m_requests.Remove(length);
500                    }
501                    m_reclaimedObjectsCount += 1;
502                    m_reclaimedBytesCount += newSize;
503                    m_rateHistVals[m_rateHistPos++] = true;
504                    if (m_rateHistPos >= m_rateHistVals.Length)
505                        m_rateHistPos = 0;
506                } else {
507                    // try to get next larger array
508                    long largerLength = m_lengths.Next(length);
509                    if (largerLength >= 0 && largerLength <= length * m_maxRequestedLengthIncrease) {
510                        return GetFromPool(largerLength);
511                    }
512                }
513            }
514            if (ret == null) {
515                m_rateHistVals[m_rateHistPos++] = false;
516                if (Settings.s_measurePerformanceAtRuntime) {
517                    s_performanceCounters.PCsuccessRateBaseIncrement();
518                }
519                if (m_rateHistPos >= m_rateHistVals.Length)
520                    m_rateHistPos = 0;
521            } else if (!String.IsNullOrEmpty(Settings.s_memoryPoolProfileFileName)) {
522                lock (m_profiler) {
523                    int key = ret.GetHashCode();
524                    m_profiler[key] = s_elementTypeName + "[" + length + "] - " + new System.Diagnostics.StackTrace(4).ToString();
525                    if (m_profiler.Count > 500) {
526                        //throw new Exception("The profiler status indicates the existence of a memory leak! Check the stack traces for common functions requesting an array which is never returnd to the pool!");
527                        System.IO.File.WriteAllText(Settings.s_memoryPoolProfileFileName,
528                                String.Join(Environment.NewLine, m_profiler.Values));
529                        m_profiler.Clear();
530                    }
531                }
532            }
533            return ret;
534        }
535        private int countObj() {
536            int ret = 0;
537            lock (this)
538            foreach (KeyValuePair<long,Stack<T[]>> item in m_pool) {
539                foreach(Array a in item.Value) {
540                    ret ++;
541                }
542            }
543            return ret;
544        }
545        private static int getDefaultMinArrayLength() {
546            T[] tmp = new T[0];
547            if (tmp is double[]) {
548                return 500;
549            } else {
550                return 70 * 1024 / s_singleElementSize;
551            }
552        }
553        /// <summary>
554        /// shrink the pool's content to SHRINK_PERCENT of the maximum pool size or at the size, suitable to store requestLen
555        /// </summary>
556        /// <param name="requestLen">minimum length to make available (bytes)</param>
557        private void Shrink(long requestLen) {
558            try {
559                long targetSize = Math.Min(m_maxBytes - requestLen, (long)(s_shrinkPercent * m_maxBytes));
560                if (m_curBytes <= targetSize)
561                    return;
562                if (Settings.s_measurePerformanceAtRuntime) {
563                    s_performanceCounters.PCshrinksCountIncrement();
564                } m_shrinksCount++;
565                // recalculate new parameters
566                m_maxBytes = (long)(m_maxBytesIncreaseRate * m_maxBytes);
567                if (m_pool.Count <= 1) {
568                    MaxRequestedLengthIncrease /= 1.02;
569                } else {
570                    MaxRequestedLengthIncrease *= 1.02;
571                }
572
573                // first clear all arrays in pool, which were not requested
574                List<int> keys4Remove = new List<int>();
575                foreach (int key in m_pool.Keys) {
576                    if (!m_requests.ContainsKey(key)) {
577                        keys4Remove.Add(key);
578                    }
579                }
580                foreach (int key in keys4Remove) {
581                    int size = key * s_singleElementSize + 8;
582                    Stack<T[]> arrays = m_pool[key];
583                    while (arrays.Count > 0) {
584                        arrays.Pop();
585                        m_curBytes -= size;
586                        m_curObjectsCount--;
587                        //if (m_curBytes < targetSize) return;
588                    }
589                    if (arrays.Count == 0) {
590                        m_requests.Remove(key);
591                        m_pool.Remove(key);
592                        m_lengths.Remove(key);
593                    }
594                }
595                if (m_curBytes < targetSize) {
596                    if (Settings.s_measurePerformanceAtRuntime) {
597                        s_performanceCounters.PCoverallSizeSet(m_curBytes);
598                        s_performanceCounters.PCcurObjectsCountSet(m_curObjectsCount);
599                    }
600                    return;
601                }
602                // sort requests statistics by its values
603
604                List<KeyValuePair<long, int>> sorted = new List<KeyValuePair<long, int>>(m_requests);
605                sorted.Sort(m_comparer);
606                foreach (KeyValuePair<long, int> item in sorted) {
607                    long curKey = item.Key;
608                    Stack<T[]> inPool;
609                    if (!m_pool.TryGetValue(curKey, out inPool)) {
610                        continue;
611                    }
612                    while (inPool.Count > 0 && m_curBytes > targetSize) {
613                        inPool.Pop();
614                        m_curBytes -= ((long)curKey * s_singleElementSize + 8);
615                        m_curObjectsCount--;
616                    }
617                    if (inPool.Count == 0) {
618                        m_lengths.Remove(curKey);
619                        m_pool.Remove(curKey);
620                        m_requests.Remove(curKey);
621                    }
622                    if (m_curBytes <= targetSize) {
623                        if (Settings.s_measurePerformanceAtRuntime) {
624                            s_performanceCounters.PCoverallSizeSet(m_curBytes);
625                            s_performanceCounters.PCcurObjectsCountSet(m_curObjectsCount);
626                        }
627                        return;
628                    }
629                }
630                if (Settings.s_measurePerformanceAtRuntime) {
631                    s_performanceCounters.PCoverallSizeSet(m_curBytes);
632                    s_performanceCounters.PCcurObjectsCountSet(m_curObjectsCount);
633                }
634            } finally {
635                m_requests.Clear();
636            }
637        }
638        #endregion
639
640    }
641}
642
Note: See TracBrowser for help on using the repository browser.