/// <summary> /// Get textual statistics about the buffer pool. /// </summary> public static string GetStatistics(bool showEmptyBuffers = true) { rwLock.EnterReadLock(); try { statiscticsBuilder.Length = 0; statiscticsBuilder.AppendFormat("Pooled array reused count: {0:N0}\n", GetBuffers); statiscticsBuilder.AppendFormat("Release call count: {0:N0}\n", ReleaseBuffers); statiscticsBuilder.AppendFormat("PoolSize: {0:N0}\n", PoolSize); statiscticsBuilder.AppendFormat("Buffers: {0}\n", FreeBuffers.Count); for (int i = 0; i < FreeBuffers.Count; ++i) { BufferStore store = FreeBuffers[i]; List <BufferDesc> buffers = store.buffers; if (showEmptyBuffers || buffers.Count > 0) { statiscticsBuilder.AppendFormat("- Size: {0:N0} Count: {1:N0}\n", store.Size, buffers.Count); } } return(statiscticsBuilder.ToString()); } finally { rwLock.ExitReadLock(); } }
/// <summary> /// Internal function called by the plugin to remove old, non-used buffers. /// </summary> internal static void Maintain() { DateTime now = DateTime.UtcNow; if (!_isEnabled || lastMaintenance + RunMaintenanceEvery > now) { return; } lastMaintenance = now; //if (HTTPManager.Logger.Level == Logger.Loglevels.All) // HTTPManager.Logger.Information("VariableSizedBufferPool", "Before Maintain: " + GetStatistics()); DateTime olderThan = now - RemoveOlderThan; rwLock.EnterWriteLock(); try { for (int i = 0; i < FreeBuffers.Count; ++i) { BufferStore store = FreeBuffers[i]; List <BufferDesc> buffers = store.buffers; for (int cv = buffers.Count - 1; cv >= 0; cv--) { BufferDesc desc = buffers[cv]; if (desc.released < olderThan) { // buffers stores available buffers ascending by age. So, when we find an old enough, we can // delete all entries in the [0..cv] range. int removeCount = cv + 1; buffers.RemoveRange(0, removeCount); PoolSize -= (int)(removeCount * store.Size); break; } } if (RemoveEmptyLists && buffers.Count == 0) { FreeBuffers.RemoveAt(i--); } } } finally { rwLock.ExitWriteLock(); } //if (HTTPManager.Logger.Level == Logger.Loglevels.All) // HTTPManager.Logger.Information("VariableSizedBufferPool", "After Maintain: " + GetStatistics()); }
private static void AddFreeBuffer(byte[] buffer) { int bufferLength = buffer.Length; for (int i = 0; i < FreeBuffers.Count; ++i) { BufferStore store = FreeBuffers[i]; if (store.Size == bufferLength) { // We highly assume here that every buffer will be released only once. // Checking for double-release would mean that we have to do another O(n) operation, where n is the // count of the store's elements. if (IsDoubleReleaseCheckEnabled) { for (int cv = 0; cv < store.buffers.Count; ++cv) { var entry = store.buffers[cv]; if (ReferenceEquals(entry.buffer, buffer)) { HTTPManager.Logger.Error("VariableSizedBufferPool", "Buffer already added to the pool!"); return; } } } store.buffers.Add(new BufferDesc(buffer)); return; } if (store.Size > bufferLength) { FreeBuffers.Insert(i, new BufferStore(bufferLength, buffer)); return; } } // When we reach this point, there's no same sized or larger BufferStore present, so we have to add a new one // to the end of our list. FreeBuffers.Add(new BufferStore(bufferLength, buffer)); }
private static BufferDesc FindFreeBuffer(long size, bool canBeLarger) { rwLock.EnterUpgradeableReadLock(); try { for (int i = 0; i < FreeBuffers.Count; ++i) { BufferStore store = FreeBuffers[i]; if (store.buffers.Count > 0 && (store.Size == size || (canBeLarger && store.Size > size))) { // Getting the last one has two desired effect: // 1.) RemoveAt should be quicker as it don't have to move all the remaining entries // 2.) Old, non-used buffers will age. Getting a buffer and putting it back will not keep buffers fresh. BufferDesc lastFree = store.buffers[store.buffers.Count - 1]; rwLock.EnterWriteLock(); try { store.buffers.RemoveAt(store.buffers.Count - 1); } finally { rwLock.ExitWriteLock(); } return(lastFree); } } } finally { rwLock.ExitUpgradeableReadLock(); } return(BufferDesc.Empty); }
/// <summary> /// Get textual statistics about the buffer pool. /// </summary> public static string GetStatistics(bool showEmptyBuffers = true) { rwLock.EnterReadLock(); try { statiscticsBuilder.Length = 0; statiscticsBuilder.AppendFormat("Pooled array reused count: {0:N0}\n", GetBuffers); statiscticsBuilder.AppendFormat("Release call count: {0:N0}\n", ReleaseBuffers); statiscticsBuilder.AppendFormat("PoolSize: {0:N0}\n", PoolSize); statiscticsBuilder.AppendFormat("Buffers: {0}\n", FreeBuffers.Count); for (int i = 0; i < FreeBuffers.Count; ++i) { BufferStore store = FreeBuffers[i]; List <BufferDesc> buffers = store.buffers; if (showEmptyBuffers || buffers.Count > 0) { statiscticsBuilder.AppendFormat("- Size: {0:N0} Count: {1:N0}\n", store.Size, buffers.Count); } } #if UNITY_EDITOR if (EnableDebugStackTraceCollection) { lock (getStackStats) { int sum = 0; foreach (var kvp in getStackStats) { sum += kvp.Value; } statiscticsBuilder.AppendFormat("Get stacks: {0:N0}\n", sum); foreach (var kvp in getStackStats) { statiscticsBuilder.AppendFormat("- {0:N0}: {1}\n", kvp.Value, kvp.Key); } } lock (releaseStackStats) { int sum = 0; foreach (var kvp in releaseStackStats) { sum += kvp.Value; } statiscticsBuilder.AppendFormat("Release stacks: {0:N0}\n", sum); foreach (var kvp in releaseStackStats) { statiscticsBuilder.AppendFormat("- {0:N0}: {1}\n", kvp.Value, kvp.Key); } } } #endif return(statiscticsBuilder.ToString()); } finally { rwLock.ExitReadLock(); } }