private static ConsoleLogMuxer CreateMuxer(ConsoleLogGlobalSettings settings) { var consoleFeaturesDetector = new ConsoleFeaturesDetector(); var consoleWriterFactory = new ConsoleWriterFactory(consoleFeaturesDetector, settings.OutputBufferSize); var consoleWriter = consoleWriterFactory.CreateWriter(); var eventsBatcher = new EventsBatcher(consoleFeaturesDetector); var eventsWriter = new EventsWriter(eventsBatcher, consoleWriter, consoleFeaturesDetector); return(new ConsoleLogMuxer(eventsWriter, settings.EventsQueueCapacity, settings.EventsTemporaryBufferCapacity)); }
/// <summary> /// Initializes the memory manager with the given block requiredSize. /// </summary> /// <param name="blockSize">Size of each block that is pooled. Must be > 0.</param> /// <param name="largeBufferMultiple">Each large buffer will be a multiple/exponential of this value.</param> /// <param name="maximumBufferSize">Buffers larger than this are not pooled</param> /// <param name="useExponentialLargeBuffer">Switch to exponential large buffer allocation strategy</param> /// <exception cref="ArgumentOutOfRangeException"> /// blockSize is not a positive number, or largeBufferMultiple is not a /// positive number, or maximumBufferSize is less than blockSize. /// </exception> /// <exception cref="ArgumentException">maximumBufferSize is not a multiple/exponential of largeBufferMultiple</exception> public RecyclableMemoryStreamManager(int blockSize, int largeBufferMultiple, int maximumBufferSize, bool useExponentialLargeBuffer) { if (blockSize <= 0) { throw new ArgumentOutOfRangeException(nameof(blockSize), blockSize, "blockSize must be a positive number"); } if (largeBufferMultiple <= 0) { throw new ArgumentOutOfRangeException(nameof(largeBufferMultiple), "largeBufferMultiple must be a positive number"); } if (maximumBufferSize < blockSize) { throw new ArgumentOutOfRangeException(nameof(maximumBufferSize), "maximumBufferSize must be at least blockSize"); } BlockSize = blockSize; LargeBufferMultiple = largeBufferMultiple; MaximumBufferSize = maximumBufferSize; UseExponentialLargeBuffer = useExponentialLargeBuffer; if (!IsLargeBufferSize(maximumBufferSize)) { throw new ArgumentException(string.Format("maximumBufferSize is not {0} of largeBufferMultiple", UseExponentialLargeBuffer ? "an exponential" : "a multiple"), nameof(maximumBufferSize)); } _smallPool = new ConcurrentStack <byte[]>(); var numLargePools = useExponentialLargeBuffer // ReSharper disable once PossibleLossOfFraction // Not our code assume loss is intentional ? (int)Math.Log(maximumBufferSize / largeBufferMultiple, 2) + 1 : maximumBufferSize / largeBufferMultiple; // +1 to store size of bytes in use that are too large to be pooled _largeBufferInUseSize = new long[numLargePools + 1]; _largeBufferFreeSize = new long[numLargePools]; _largePools = new ConcurrentStack <byte[]> [numLargePools]; for (var i = 0; i < _largePools.Length; ++i) { _largePools[i] = new ConcurrentStack <byte[]>(); } Counter = new Counters(this); EventsWriter.MemoryStreamManagerInitialized(blockSize, largeBufferMultiple, maximumBufferSize); }
/// <summary> /// Returns the buffer to the large pool /// </summary> /// <param name="buffer">The buffer to return.</param> /// <param name="tag">The tag of the stream returning this buffer, for logging if necessary.</param> /// <exception cref="ArgumentNullException">buffer is null</exception> /// <exception cref="ArgumentException"> /// buffer.Length is not a multiple/exponential of LargeBufferMultiple (it did not /// originate from this pool) /// </exception> internal void ReturnLargeBuffer(byte[] buffer, string tag) { if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } if (!IsLargeBufferSize(buffer.Length)) { throw new ArgumentException( string.Format("buffer did not originate from this memory manager. The size is not {0} of ", UseExponentialLargeBuffer ? "an exponential" : "a multiple") + LargeBufferMultiple); } var poolIndex = GetPoolIndex(buffer.Length); if (poolIndex < _largePools.Length) { if ((_largePools[poolIndex].Count + 1) * buffer.Length <= MaximumFreeLargePoolBytes || MaximumFreeLargePoolBytes == 0) { _largePools[poolIndex].Push(buffer); Interlocked.Add(ref _largeBufferFreeSize[poolIndex], buffer.Length); } else { EventsWriter.MemoryStreamDiscardBuffer(Events.MemoryStreamBufferType.Large, tag, Events.MemoryStreamDiscardReason.EnoughFree); ReportLargeBufferDiscarded(Events.MemoryStreamDiscardReason.EnoughFree); } } else { // This is a non-poolable buffer, but we still want to track its size for inuse // analysis. We have space in the inuse array for this. poolIndex = _largeBufferInUseSize.Length - 1; EventsWriter.MemoryStreamDiscardBuffer(Events.MemoryStreamBufferType.Large, tag, Events.MemoryStreamDiscardReason.TooLarge); ReportLargeBufferDiscarded(Events.MemoryStreamDiscardReason.TooLarge); } Interlocked.Add(ref _largeBufferInUseSize[poolIndex], -buffer.Length); ReportUsageReport(_smallPoolInUseSize, _smallPoolFreeSize, LargePoolInUseSize, LargePoolFreeSize); }
public void TestSetup() { batcher = Substitute.For <IEventsBatcher>(); batcher.BatchEvents(Arg.Any <LogEventInfo[]>(), Arg.Any <int>()).Returns(MakeBatch); consoleWriter = Substitute.For <IConsoleWriter>(); colorReleaser = Substitute.For <IDisposable>(); consoleWriter.ChangeColor(Arg.Any <ConsoleColor>()).Returns(_ => colorReleaser); var featuresDetector = Substitute.For <IConsoleFeaturesDetector>(); featuresDetector.AreColorsSupported.Returns(true); writer = new EventsWriter(batcher, consoleWriter, featuresDetector); }
/// <summary> /// Returns a buffer of arbitrary size from the large buffer pool. This buffer /// will be at least the requiredSize and always be a multiple/exponential of largeBufferMultiple. /// </summary> /// <param name="requiredSize">The minimum length of the buffer</param> /// <param name="tag">The tag of the stream returning this buffer, for logging if necessary.</param> /// <returns>A buffer of at least the required size.</returns> internal byte[] GetLargeBuffer(int requiredSize, string tag) { requiredSize = RoundToLargeBufferSize(requiredSize); var poolIndex = GetPoolIndex(requiredSize); byte[] buffer; if (poolIndex < _largePools.Length) { if (!_largePools[poolIndex].TryPop(out buffer)) { buffer = new byte[requiredSize]; EventsWriter.MemoryStreamNewLargeBufferCreated(requiredSize, LargePoolInUseSize); ReportLargeBufferCreated(); } else { Interlocked.Add(ref _largeBufferFreeSize[poolIndex], -buffer.Length); } } else { // Buffer is too large to pool. They get a new buffer. // We still want to track the size, though, and we've reserved a slot // in the end of the inuse array for nonpooled bytes in use. poolIndex = _largeBufferInUseSize.Length - 1; // We still want to round up to reduce heap fragmentation. buffer = new byte[requiredSize]; string callStack = null; if (GenerateCallStacks) { // Grab the stack -- we want to know who requires such large buffers callStack = Environment.StackTrace; } EventsWriter.MemoryStreamNonPooledLargeBufferCreated(requiredSize, tag, callStack); ReportLargeBufferCreated(); } Interlocked.Add(ref _largeBufferInUseSize[poolIndex], buffer.Length); return(buffer); }
/// <summary> /// Removes and returns a single block from the pool. /// </summary> /// <returns>A byte[] array</returns> internal byte[] GetBlock() { byte[] block; if (!_smallPool.TryPop(out block)) { // We'll add this back to the pool when the stream is disposed // (unless our free pool is too large) block = new byte[BlockSize]; EventsWriter.MemoryStreamNewBlockCreated(_smallPoolInUseSize); ReportBlockCreated(); } else { Interlocked.Add(ref _smallPoolFreeSize, -BlockSize); } Interlocked.Add(ref _smallPoolInUseSize, BlockSize); return(block); }
/// <summary> /// Returns the blocks to the pool /// </summary> /// <param name="blocks">Collection of blocks to return to the pool</param> /// <param name="tag">The tag of the stream returning these blocks, for logging if necessary.</param> /// <exception cref="ArgumentNullException">blocks is null</exception> /// <exception cref="ArgumentException">blocks contains buffers that are the wrong size (or null) for this memory manager</exception> internal void ReturnBlocks(ICollection <byte[]> blocks, string tag) { if (blocks == null) { throw new ArgumentNullException(nameof(blocks)); } var bytesToReturn = blocks.Count * BlockSize; Interlocked.Add(ref _smallPoolInUseSize, -bytesToReturn); foreach (var block in blocks) { if (block == null || block.Length != BlockSize) { throw new ArgumentException("blocks contains buffers that are not BlockSize in length"); } } foreach (var block in blocks) { if (MaximumFreeSmallPoolBytes == 0 || SmallPoolFreeSize < MaximumFreeSmallPoolBytes) { Interlocked.Add(ref _smallPoolFreeSize, BlockSize); _smallPool.Push(block); } else { EventsWriter.MemoryStreamDiscardBuffer(Events.MemoryStreamBufferType.Small, tag, Events.MemoryStreamDiscardReason.EnoughFree); ReportBlockDiscarded(); break; } } ReportUsageReport(_smallPoolInUseSize, _smallPoolFreeSize, LargePoolInUseSize, LargePoolFreeSize); }
/// <summary> /// Initializes a new instance of the <see cref="EventManager"/> class. /// </summary> /// <param name="logWriter">Used to receive loggings.</param> /// <param name="writer">Used to receive unparsed event messages.</param> public EventManager(LogWriterHandler logWriter, EventsWriter writer) { _logWriter = logWriter ?? NullWriter.Write; _socket = new EventSocket(_logWriter); _writer = writer; }