From e0e1cb6ee9a6be95c11c156089a2e5e2807806e6 Mon Sep 17 00:00:00 2001 From: Nikolay Baraboshkin Date: Wed, 4 Dec 2024 21:54:09 +0400 Subject: [PATCH 1/2] improve the performance of RollingWindow.GetEnumerator Closes #8443 --- Common/Indicators/RollingWindow.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Common/Indicators/RollingWindow.cs b/Common/Indicators/RollingWindow.cs index d2f7ed526813..605f13ad2397 100644 --- a/Common/Indicators/RollingWindow.cs +++ b/Common/Indicators/RollingWindow.cs @@ -244,18 +244,20 @@ public bool IsReady /// 1 public IEnumerator GetEnumerator() { - // we make a copy on purpose so the enumerator isn't tied - // to a mutable object, well it is still mutable but out of scope - var temp = new List(_list.Count); try { _listLock.EnterReadLock(); - for (int i = 0; i < _list.Count; i++) + // we make a copy on purpose so the enumerator isn't tied + // to a mutable object, well it is still mutable but out of scope + var count = _list.Count; + var temp = new T[count]; + for (int i = count - 1; i >= 0; i--) { - temp.Add(this[i]); + temp[count - 1 - i] = _list[(_tail + i) % count]; } - return temp.GetEnumerator(); + + return ((IEnumerable) temp).GetEnumerator(); } finally { From 1dbc2b379fa96896b1ab50e73645bdddffe3bbd9 Mon Sep 17 00:00:00 2001 From: Nikolay Baraboshkin Date: Thu, 5 Dec 2024 22:51:02 +0400 Subject: [PATCH 2/2] address review comments --- Common/Indicators/RollingWindow.cs | 15 +++++++++++---- Tests/Indicators/RollingWindowTests.cs | 6 ++++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Common/Indicators/RollingWindow.cs b/Common/Indicators/RollingWindow.cs index 605f13ad2397..b1172752499f 100644 --- a/Common/Indicators/RollingWindow.cs +++ b/Common/Indicators/RollingWindow.cs @@ -16,6 +16,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Runtime.CompilerServices; using System.Threading; namespace QuantConnect.Indicators @@ -174,7 +175,7 @@ public T this [int i] return default; } - return _list[(_list.Count + _tail - i - 1) % _list.Count]; + return _list[GetListIndex(i, _list.Count, _tail)]; } finally { @@ -206,7 +207,7 @@ public T this [int i] } } - _list[(_list.Count + _tail - i - 1) % _list.Count] = value; + _list[GetListIndex(i, _list.Count, _tail)] = value; } finally { @@ -252,9 +253,9 @@ public IEnumerator GetEnumerator() // to a mutable object, well it is still mutable but out of scope var count = _list.Count; var temp = new T[count]; - for (int i = count - 1; i >= 0; i--) + for (int i = 0; i < count; i++) { - temp[count - 1 - i] = _list[(_tail + i) % count]; + temp[i] = _list[GetListIndex(i, count, _tail)]; } return ((IEnumerable) temp).GetEnumerator(); @@ -327,6 +328,12 @@ public void Reset() } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int GetListIndex(int index, int listCount, int tail) + { + return (listCount + tail - index - 1) % listCount; + } + private void Resize(int size) { try diff --git a/Tests/Indicators/RollingWindowTests.cs b/Tests/Indicators/RollingWindowTests.cs index c451e8838b71..5c7001c50c6f 100644 --- a/Tests/Indicators/RollingWindowTests.cs +++ b/Tests/Indicators/RollingWindowTests.cs @@ -114,6 +114,12 @@ public void EnumeratesAsExpected() Assert.AreEqual(2, inOrder[0]); Assert.AreEqual(1, inOrder[1]); Assert.AreEqual(0, inOrder[2]); + + window.Add(3); + var inOrder2 = window.ToList(); + Assert.AreEqual(3, inOrder2[0]); + Assert.AreEqual(2, inOrder2[1]); + Assert.AreEqual(1, inOrder2[2]); } [Test]