From c94f9fae5c5bb3db2d20548429bf9844fe646bac Mon Sep 17 00:00:00 2001 From: Wraiyth Date: Sat, 30 Mar 2019 16:22:37 +1100 Subject: [PATCH 1/2] Performance improvements to Queue.Enqueue and Stack.Push --- .../src/System/Collections/Generic/Queue.cs | 33 +++++++++++++++---- .../src/System/Collections/Generic/Stack.cs | 1 + 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/System.Collections/src/System/Collections/Generic/Queue.cs b/src/System.Collections/src/System/Collections/Generic/Queue.cs index 14b165dec2c5..5ba6a584788a 100644 --- a/src/System.Collections/src/System/Collections/Generic/Queue.cs +++ b/src/System.Collections/src/System/Collections/Generic/Queue.cs @@ -181,17 +181,36 @@ void ICollection.CopyTo(Array array, int index) } // Adds item to the tail of the queue. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Enqueue(T item) { - if (_size == _array.Length) + int size = _size; + T[] array = _array; + + if ((uint)size < (uint)array.Length) { - int newcapacity = (int)((long)_array.Length * (long)GrowFactor / 100); - if (newcapacity < _array.Length + MinimumGrow) - { - newcapacity = _array.Length + MinimumGrow; - } - SetCapacity(newcapacity); + _array[_tail] = item; + MoveNext(ref _tail); + _size++; + _version++; + } + else + { + EnqueueWithResize(item); } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private void EnqueueWithResize(T item) + { + int newCapacity = _array.Length * 2; + + if (newCapacity < _array.Length + MinimumGrow) + { + newCapacity = _array.Length + MinimumGrow; + } + + SetCapacity(newCapacity); _array[_tail] = item; MoveNext(ref _tail); diff --git a/src/System.Collections/src/System/Collections/Generic/Stack.cs b/src/System.Collections/src/System/Collections/Generic/Stack.cs index 2baeaff8e19b..0d1ecbb07239 100644 --- a/src/System.Collections/src/System/Collections/Generic/Stack.cs +++ b/src/System.Collections/src/System/Collections/Generic/Stack.cs @@ -262,6 +262,7 @@ public bool TryPop(out T result) } // Pushes an item to the top of the stack. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Push(T item) { int size = _size; From da0088461eba7edddda3dc9172b9c51feefeeec6 Mon Sep 17 00:00:00 2001 From: Wraiyth Date: Sun, 31 Mar 2019 09:17:10 +1100 Subject: [PATCH 2/2] Changes based on PR Feedback Removed unused GrowFactor member Removed Aggressive Inlining Other minor improvements --- .../src/System/Collections/Generic/Queue.cs | 25 ++++++++----------- .../src/System/Collections/Generic/Stack.cs | 1 - 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/System.Collections/src/System/Collections/Generic/Queue.cs b/src/System.Collections/src/System/Collections/Generic/Queue.cs index 5ba6a584788a..5c3d2d18c2a5 100644 --- a/src/System.Collections/src/System/Collections/Generic/Queue.cs +++ b/src/System.Collections/src/System/Collections/Generic/Queue.cs @@ -33,7 +33,6 @@ public class Queue : IEnumerable, private int _version; private const int MinimumGrow = 4; - private const int GrowFactor = 200; // double each time // Creates a queue with room for capacity objects. The default initial // capacity and grow factor are used. @@ -181,17 +180,18 @@ void ICollection.CopyTo(Array array, int index) } // Adds item to the tail of the queue. - [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Enqueue(T item) { + int tail = _tail; int size = _size; T[] array = _array; - if ((uint)size < (uint)array.Length) + if ((uint)size < (uint)array.Length && (uint)tail < (uint)array.Length) { - _array[_tail] = item; - MoveNext(ref _tail); - _size++; + array[tail] = item; + MoveNext(ref tail, array); + _tail = tail; + _size = size + 1; _version++; } else @@ -203,12 +203,8 @@ public void Enqueue(T item) [MethodImpl(MethodImplOptions.NoInlining)] private void EnqueueWithResize(T item) { - int newCapacity = _array.Length * 2; - - if (newCapacity < _array.Length + MinimumGrow) - { - newCapacity = _array.Length + MinimumGrow; - } + int length = _array.Length; + int newCapacity = Math.Max(length * 2, length + MinimumGrow); SetCapacity(newCapacity); @@ -376,15 +372,16 @@ private void SetCapacity(int capacity) _tail = (_size == capacity) ? 0 : _size; _version++; } + private void MoveNext(ref int index) => MoveNext(ref index, _array); // Increments the index wrapping it if necessary. - private void MoveNext(ref int index) + private void MoveNext(ref int index, T[] array) { // It is tempting to use the remainder operator here but it is actually much slower // than a simple comparison and a rarely taken branch. // JIT produces better code than with ternary operator ?: int tmp = index + 1; - if (tmp == _array.Length) + if (tmp == array.Length) { tmp = 0; } diff --git a/src/System.Collections/src/System/Collections/Generic/Stack.cs b/src/System.Collections/src/System/Collections/Generic/Stack.cs index 0d1ecbb07239..2baeaff8e19b 100644 --- a/src/System.Collections/src/System/Collections/Generic/Stack.cs +++ b/src/System.Collections/src/System/Collections/Generic/Stack.cs @@ -262,7 +262,6 @@ public bool TryPop(out T result) } // Pushes an item to the top of the stack. - [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Push(T item) { int size = _size;