public void TestMoveFromLocalQueueToGlobal() { ThreadPoolQueueController q = new ThreadPoolQueueController(100, 50); ThreadPoolLocalQueue local = new ThreadPoolLocalQueue(); for (int i = 0; i < 100; i++) { q.Add(new TestThreadPoolItem(i), null); } Assert.AreEqual(100, q.GlobalQueue.OccupiedNodesCount); Assert.AreEqual(0, q.GlobalQueue.FreeNodesCount); for (int i = 100; i < 110; i++) { Assert.IsTrue(local.TryAddLocal(new TestThreadPoolItem(i))); } q.MoveItemsFromLocalQueueToGlobal(local); Assert.AreEqual(0, q.GlobalQueue.FreeNodesCount); Assert.AreEqual(110, q.GlobalQueue.OccupiedNodesCount); Assert.AreEqual(110, q.GlobalQueue.ExtendedCapacity); for (int i = 0; i < 110; i++) { Assert2.AreEqual(i, q.Take(null)); } Assert.AreEqual(100, q.GlobalQueue.FreeNodesCount); Assert.AreEqual(0, q.GlobalQueue.OccupiedNodesCount); Assert.AreEqual(100, q.GlobalQueue.ExtendedCapacity); }
public void TestLocalThreadQueuePrimaryScenario() { ThreadPoolLocalQueue q = new ThreadPoolLocalQueue(); RunLocalThreadQueuePrimaryScenario(q, int.MaxValue / 400 + 13, Environment.ProcessorCount, 32); RunLocalThreadQueuePrimaryScenario(q, int.MaxValue / 400 + 13, Environment.ProcessorCount, 32); }
//[TestMethod] //[Timeout(30 * 60 * 1000)] //[Ignore] public void TestLocalThreadQueuePrimaryScenarioManyRun() { ThreadPoolLocalQueue q = new ThreadPoolLocalQueue(); for (int i = 0; i < 200; i++) { RunLocalThreadQueuePrimaryScenario(q, int.MaxValue / 40 + 13, (i % Environment.ProcessorCount) + 1, 32); } }
//[TestMethod] //[Timeout(20 * 60 * 1000)] //[Ignore] public void TestAddStealManyElementsManyRun() { ThreadPoolLocalQueue q = new ThreadPoolLocalQueue(); for (int i = 0; i < 100; i++) { RunLocalThreadQueueAddStealTest(q, int.MaxValue / 20 + 13, 32); } }
public void TestSingleAddSteal() { ThreadPoolLocalQueue q = new ThreadPoolLocalQueue(); Assert.IsTrue(q.TryAddLocal(new TestThreadPoolItem(1))); ThreadPoolWorkItem item = null; Assert.IsTrue(q.TrySteal(out item)); Assert.IsNotNull(item); Assert2.AreEqual(1, item); }
public void TestStealingWakeUp() { ThreadPoolLocalQueue[] locQ = new ThreadPoolLocalQueue[] { new ThreadPoolLocalQueue(), new ThreadPoolLocalQueue(), new ThreadPoolLocalQueue(), new ThreadPoolLocalQueue(), }; ThreadPoolQueueController q = new ThreadPoolQueueController(100, 50); for (int i = 0; i < locQ.Length; i++) { q.AddLocalQueue(locQ[i]); } bool takeCompleted = false; List <int> takenItems = new List <int>(); Task.Run(() => { for (int i = 0; i < 100; i++) { takenItems.Add((TestThreadPoolItem)q.Take(locQ[0])); } takeCompleted = true; }); Thread.Sleep(1000); Assert.IsFalse(takeCompleted); for (int i = 0; i < 100; i++) { locQ[1 + (i % (locQ.Length - 1))].TryAddLocal(new TestThreadPoolItem(i)); Thread.Sleep(100); } Thread.Sleep(1000); Assert.IsTrue(takeCompleted); Assert.AreEqual(100, takenItems.Count); takenItems.Sort(); for (int i = 0; i < 100; i++) { Assert.AreEqual(i, takenItems[i]); } }
private void RunLocalThreadQueueAddStealTest(ThreadPoolLocalQueue q, int elemCount, int fillFactor) { Random rnd = new Random(); int addElem = 0; int takeElem = 0; List <int> takenIndexes = new List <int>(elemCount + 1); while (takeElem < elemCount) { int addCount = rnd.Next(fillFactor); for (int i = 0; i < addCount; i++) { if (addElem >= elemCount || !q.TryAddLocal(new TestThreadPoolItem(addElem))) { break; } addElem++; } int removeCount = rnd.Next(fillFactor); for (int i = 0; i < removeCount; i++) { ThreadPoolWorkItem tmp = null; if (!q.TrySteal(out tmp)) { break; } Assert.IsNotNull(tmp); takenIndexes.Add((TestThreadPoolItem)tmp); takeElem++; } } Assert.AreEqual(elemCount, takenIndexes.Count); takenIndexes.Sort(); for (int i = 0; i < elemCount; i++) { Assert.AreEqual(i, takenIndexes[i]); } }
public void TestItemStealingWork() { ThreadPoolLocalQueue[] locQ = new ThreadPoolLocalQueue[] { new ThreadPoolLocalQueue(), new ThreadPoolLocalQueue(), new ThreadPoolLocalQueue(), new ThreadPoolLocalQueue(), }; ThreadPoolQueueController q = new ThreadPoolQueueController(100, 1000); for (int i = 0; i < locQ.Length; i++) { q.AddLocalQueue(locQ[i]); } locQ[0].TryAddLocal(new TestThreadPoolItem(0)); locQ[1].TryAddLocal(new TestThreadPoolItem(1)); locQ[2].TryAddLocal(new TestThreadPoolItem(2)); locQ[3].TryAddLocal(new TestThreadPoolItem(3)); List <int> extractedItems = new List <int>(); for (int i = 0; i < 4; i++) { ThreadPoolWorkItem item = null; Assert.IsTrue(q.TryTake(locQ[0], out item, 0, CancellationToken.None, true)); extractedItems.Add((TestThreadPoolItem)item); } ThreadPoolWorkItem tmp = null; Assert.IsFalse(q.TryTake(locQ[0], out tmp, 0, CancellationToken.None, true)); extractedItems.Sort(); Assert.AreEqual(4, extractedItems.Count); for (int i = 0; i < extractedItems.Count; i++) { Assert.AreEqual(i, extractedItems[i]); } }
public void TestLocalThreadQueueUsage() { ThreadPoolLocalQueue local = new ThreadPoolLocalQueue(); ThreadPoolQueueController q = new ThreadPoolQueueController(100, 1000); q.AddLocalQueue(local); q.Add(new TestThreadPoolItem(1), local); ThreadPoolWorkItem item = null; Assert.IsTrue(local.TryTakeLocal(out item)); Assert2.AreEqual(1, item); local.TryAddLocal(new TestThreadPoolItem(1)); item = null; Assert.IsTrue(q.TryTake(local, out item, 0, CancellationToken.None, true)); Assert2.AreEqual(1, item); }
public void TestAddTakeUpToTheLimit() { ThreadPoolLocalQueue q = new ThreadPoolLocalQueue(); int index = 0; while (q.TryAddLocal(new TestThreadPoolItem(index))) { index++; Assert.IsTrue(index < int.MaxValue); } ThreadPoolWorkItem item = null; while (q.TryTakeLocal(out item)) { Assert.IsNotNull(item); Assert.IsTrue((TestThreadPoolItem)item == --index); } Assert.AreEqual(0, index); }
//private static void TestLocalThreadQueueAsQueue(ILocalThreadQueue q, int elemCount, int fillFactor) //{ // int trackElemCount = elemCount; // Stopwatch sw = Stopwatch.StartNew(); // while (trackElemCount > 0) // { // int initial = trackElemCount; // for (int i = 0; i < fillFactor; i++) // { // if (!q.TryAddGlobal(initial--)) // Console.WriteLine("11"); // } // initial = trackElemCount; // for (int i = 0; i < fillFactor; i++) // { // object tmp = null; // //q.TryRemove(out tmp); // if (!q.TryRemoveGlobal(out tmp)) // Console.WriteLine("22"); // if ((int)tmp != initial--) // Console.WriteLine("33"); // } // trackElemCount -= fillFactor; // } // sw.Stop(); // Console.WriteLine(q.GetType().Name + ". Element count = " + elemCount.ToString() + ", FillFactor = " + fillFactor.ToString() + ", Time = " + sw.ElapsedMilliseconds.ToString() + "ms"); // Console.WriteLine(); //} //private static void TestLocalThreadQueue2AsQueue(ILocalThreadQueue2 q, int elemCount, int fillFactor) //{ // int trackElemCount = elemCount; // Stopwatch sw = Stopwatch.StartNew(); // while (trackElemCount > 0) // { // int initial = trackElemCount; // for (int i = 0; i < fillFactor; i++) // { // if (!q.TryAddLocal(initial--)) // Console.WriteLine("11"); // } // initial = trackElemCount; // for (int i = 0; i < fillFactor; i++) // { // object tmp = null; // //q.TryRemove(out tmp); // if (!q.TryTakeLocal(out tmp)) // Console.WriteLine("22"); // if ((int)tmp != initial--) // Console.WriteLine("33"); // } // trackElemCount -= fillFactor; // } // sw.Stop(); // Console.WriteLine(q.GetType().Name + ". Element count = " + elemCount.ToString() + ", FillFactor = " + fillFactor.ToString() + ", Time = " + sw.ElapsedMilliseconds.ToString() + "ms"); // Console.WriteLine(); //} //private static void TestLocalThreadQueueAsStack(LocalThreadQueue q, int elemCount, int fillFactor) //{ // int trackElemCount = elemCount; // Stopwatch sw = Stopwatch.StartNew(); // while (trackElemCount > 0) // { // int initial = trackElemCount; // for (int i = 0; i < fillFactor; i++) // { // if (!q.TryAddGlobal(initial--)) // Console.WriteLine("11"); // } // for (int i = 0; i < fillFactor; i++) // { // object tmp = null; // //q.TryRemove(out tmp); // if (!q.TryRemoveGlobal(out tmp)) // Console.WriteLine("22"); // if ((int)tmp != ++initial) // Console.WriteLine("33"); // } // trackElemCount -= fillFactor; // } // sw.Stop(); // Console.WriteLine(q.GetType().Name + ". Element count = " + elemCount.ToString() + ", FillFactor = " + fillFactor.ToString() + ", Time = " + sw.ElapsedMilliseconds.ToString() + "ms"); // Console.WriteLine(); //} private static void TestLocalThreadQueue2AsStack(ThreadPoolLocalQueue q, int elemCount, int fillFactor) { int trackElemCount = elemCount; Stopwatch sw = Stopwatch.StartNew(); while (trackElemCount > 0) { int initial = trackElemCount; for (int i = 0; i < fillFactor; i++) { if (!q.TryAddLocal(new TestThreadPoolItem(initial--))) { Console.WriteLine("11"); } } for (int i = 0; i < fillFactor; i++) { ThreadPoolWorkItem tmp = null; //q.TryRemove(out tmp); if (!q.TryTakeLocal(out tmp)) { Console.WriteLine("22"); } if ((TestThreadPoolItem)tmp != ++initial) { Console.WriteLine("33"); } } trackElemCount -= fillFactor; } sw.Stop(); Console.WriteLine(q.GetType().Name + ". Element count = " + elemCount.ToString() + ", FillFactor = " + fillFactor.ToString() + ", Time = " + sw.ElapsedMilliseconds.ToString() + "ms"); Console.WriteLine(); }
private void RunLocalThreadQueuePrimaryScenario(ThreadPoolLocalQueue q, int elemCount, int slealThCount, int fillFactor) { int trackElemCount = elemCount; int addFinished = 0; int atomicRandom = 0; Thread mainThread = null; Thread[] stealThreads = new Thread[slealThCount]; List <int> global = new List <int>(elemCount + 1); Action mainAction = () => { List <int> data = new List <int>(elemCount); Random rnd = new Random(Environment.TickCount + Interlocked.Increment(ref atomicRandom) * slealThCount); while (Volatile.Read(ref trackElemCount) >= 0) { int addCount = fillFactor; if (rnd != null) { addCount = rnd.Next(fillFactor); } for (int i = 0; i < addCount; i++) { int item = --trackElemCount; if (item < 0) { break; } if (!q.TryAddLocal(new TestThreadPoolItem(item))) { ++trackElemCount; break; } } int removeCount = rnd.Next(fillFactor); for (int i = 0; i < removeCount; i++) { ThreadPoolWorkItem item = null; if (!q.TryTakeLocal(out item)) { break; } data.Add((TestThreadPoolItem)item); } } Interlocked.Increment(ref addFinished); ThreadPoolWorkItem finalItem = null; while (q.TryTakeLocal(out finalItem)) { data.Add((TestThreadPoolItem)finalItem); } lock (global) global.AddRange(data); }; Action stealAction = () => { Random rnd = new Random(Environment.TickCount + Interlocked.Increment(ref atomicRandom) * slealThCount); List <int> data = new List <int>(); while (Volatile.Read(ref addFinished) < 1 && Volatile.Read(ref trackElemCount) > elemCount / 1000) { ThreadPoolWorkItem tmp; if (q.TrySteal(out tmp)) { data.Add((TestThreadPoolItem)tmp); } int sleepTime = rnd.Next(5) - 3; if (sleepTime > 0) { Thread.Sleep(sleepTime); } } lock (global) global.AddRange(data); }; mainThread = new Thread(new ThreadStart(mainAction)); for (int i = 0; i < stealThreads.Length; i++) { stealThreads[i] = new Thread(new ThreadStart(stealAction)); } mainThread.Start(); for (int i = 0; i < stealThreads.Length; i++) { stealThreads[i].Start(); } mainThread.Join(); for (int i = 0; i < stealThreads.Length; i++) { stealThreads[i].Join(); } Assert.AreEqual(elemCount, global.Count, "Incorrect element count"); global.Sort(); for (int i = 0; i < elemCount; i++) { Assert.AreEqual(i, global[i], "Incorrect data"); } }
public void TestAddStealManyElements() { ThreadPoolLocalQueue q = new ThreadPoolLocalQueue(); RunLocalThreadQueueAddStealTest(q, int.MaxValue / 200 + 13, 32); }
private void RunComplexTest(ThreadPoolQueueController q, int elemCount, int thCount) { int mainIndex = -1; int atomicRandom = 0; int trackElemCount = elemCount; int addFinished = 0; ThreadPoolLocalQueue[] locQ = new ThreadPoolLocalQueue[thCount]; for (int i = 0; i < locQ.Length; i++) { locQ[i] = new ThreadPoolLocalQueue(); q.AddLocalQueue(locQ[i]); } Thread[] threadsMain = new Thread[thCount]; Thread[] threadsAdditional = new Thread[thCount]; CancellationTokenSource tokSrc = new CancellationTokenSource(); List <int> global = new List <int>(elemCount); Action additionalAction = () => { Random rnd = new Random(Environment.TickCount + Interlocked.Increment(ref atomicRandom) * thCount * 2); while (true) { int item = Interlocked.Decrement(ref trackElemCount); if (item < 0) { break; } q.Add(new TestThreadPoolItem(item), null); int sleepTime = rnd.Next(1000); if (sleepTime > 0) { Thread.SpinWait(sleepTime); } if (rnd.Next(100) == 0) { q.ExtendGlobalQueueCapacity(50); } } Interlocked.Increment(ref addFinished); }; Action mainAction = () => { var localQ = locQ[Interlocked.Increment(ref mainIndex)]; Random rnd = new Random(Environment.TickCount + Interlocked.Increment(ref atomicRandom) * thCount * 2); List <int> data = new List <int>(); try { while (Volatile.Read(ref addFinished) < thCount) { ThreadPoolWorkItem tmp = null; if (q.TryTake(localQ, out tmp, -1, tokSrc.Token, true)) { data.Add((TestThreadPoolItem)tmp); } int sleepTime = rnd.Next(500); if (sleepTime > 0) { Thread.SpinWait(sleepTime); } if (rnd.Next(10) == 0) { int item = Interlocked.Decrement(ref trackElemCount); if (item >= 0) { while (!q.TryAdd(new TestThreadPoolItem(item), localQ, false, 0, CancellationToken.None)) { if (q.TryTake(localQ, out tmp, 0, CancellationToken.None, true)) { data.Add((TestThreadPoolItem)tmp); } } } } } } catch (OperationCanceledException) { } ThreadPoolWorkItem tmp2; while (q.TryTake(localQ, out tmp2, 0, CancellationToken.None, true)) { data.Add((TestThreadPoolItem)tmp2); } lock (global) global.AddRange(data); }; Task.Delay(1000).ContinueWith(t => q.ExtendGlobalQueueCapacity(50)); for (int i = 0; i < threadsMain.Length; i++) { threadsMain[i] = new Thread(new ThreadStart(mainAction)); } for (int i = 0; i < threadsAdditional.Length; i++) { threadsAdditional[i] = new Thread(new ThreadStart(additionalAction)); } for (int i = 0; i < threadsMain.Length; i++) { threadsMain[i].Start(); } for (int i = 0; i < threadsAdditional.Length; i++) { threadsAdditional[i].Start(); } for (int i = 0; i < threadsAdditional.Length; i++) { threadsAdditional[i].Join(); } tokSrc.Cancel(); for (int i = 0; i < threadsMain.Length; i++) { threadsMain[i].Join(); } Assert.AreEqual(elemCount, global.Count); global.Sort(); for (int i = 0; i < elemCount; i++) { Assert.AreEqual(i, global[i]); } for (int i = 0; i < locQ.Length; i++) { q.RemoveLocalQueue(locQ[i]); } }
private static bool TestLocalThreadQueuePrimaryScenario(ThreadPoolLocalQueue q, int elemCount, int slealThCount, int fillFactor, bool useRandom) { int trackElemCount = elemCount; int addFinished = 0; int atomicRandom = 0; Thread mainThread = null; Thread[] stealThreads = new Thread[slealThCount]; List <int> global = new List <int>(elemCount); Action mainAction = () => { List <int> data = new List <int>(elemCount); Random rnd = null; if (useRandom) { rnd = new Random(Environment.TickCount + Interlocked.Increment(ref atomicRandom) * slealThCount); } while (Volatile.Read(ref trackElemCount) >= 0) { int addCount = fillFactor; if (rnd != null) { addCount = rnd.Next(fillFactor); } for (int i = 0; i < addCount; i++) { int item = --trackElemCount; if (item < 0) { break; } if (!q.TryAddLocal(new TestThreadPoolItem(item))) { ++trackElemCount; break; } } int removeCount = fillFactor; if (rnd != null) { removeCount = rnd.Next(fillFactor); } for (int i = 0; i < removeCount; i++) { ThreadPoolWorkItem item = null; if (!q.TryTakeLocal(out item)) { break; } data.Add((TestThreadPoolItem)item); } } Interlocked.Increment(ref addFinished); ThreadPoolWorkItem finalItem = null; while (q.TryTakeLocal(out finalItem)) { data.Add((TestThreadPoolItem)finalItem); } lock (global) global.AddRange(data); }; Action stealAction = () => { Random rnd = null; if (useRandom) { rnd = new Random(Environment.TickCount + Interlocked.Increment(ref atomicRandom) * slealThCount); } List <int> data = new List <int>(); while (Volatile.Read(ref addFinished) < 1 && Volatile.Read(ref trackElemCount) > elemCount / 1000) { ThreadPoolWorkItem tmp; if (q.TrySteal(out tmp)) { data.Add((TestThreadPoolItem)tmp); } int sleepTime = Volatile.Read(ref trackElemCount) % 2; if (rnd != null) { sleepTime = rnd.Next(2); } if (sleepTime > 0) { Thread.Sleep(sleepTime); } } lock (global) global.AddRange(data); }; mainThread = new Thread(new ThreadStart(mainAction)); for (int i = 0; i < stealThreads.Length; i++) { stealThreads[i] = new Thread(new ThreadStart(stealAction)); } Stopwatch sw = Stopwatch.StartNew(); mainThread.Start(); for (int i = 0; i < stealThreads.Length; i++) { stealThreads[i].Start(); } mainThread.Join(); for (int i = 0; i < stealThreads.Length; i++) { stealThreads[i].Join(); } sw.Stop(); bool result = true; global.Sort(); if (global.Count != elemCount) { result = false; Console.WriteLine("Incorrect element count"); } HashSet <int> set = new HashSet <int>(global); if (set.Count != global.Count) { result = false; Console.WriteLine("Incorrect distinct element count"); } for (int i = 0; i < Math.Min(elemCount, global.Count); i++) { if (global[i] != i) { result = false; Console.WriteLine("Incorrect data"); break; } } Console.WriteLine("PrimaryScenario " + q.GetType().Name + ". Element count = " + elemCount.ToString() + ", Time = " + sw.ElapsedMilliseconds.ToString() + "ms"); Console.WriteLine(); return(result); }
// ============== private static bool RunComplexTestOnThreadPoolQueue(int elemCount, int thCount) { ThreadPoolQueueController q = new ThreadPoolQueueController(1000, 100); int mainIndex = -1; int trackElemCount = elemCount; int addFinished = 0; ThreadPoolLocalQueue[] locQ = new ThreadPoolLocalQueue[thCount]; for (int i = 0; i < locQ.Length; i++) { locQ[i] = new ThreadPoolLocalQueue(); q.AddLocalQueue(locQ[i]); } Thread[] threadsMain = new Thread[thCount]; Thread[] threadsAdditional = new Thread[thCount]; CancellationTokenSource tokSrc = new CancellationTokenSource(); List <int> global = new List <int>(elemCount); Action additionalAction = () => { while (true) { int item = Interlocked.Decrement(ref trackElemCount); if (item < 0) { break; } q.Add(new TestThreadPoolItem(item), null); } Interlocked.Increment(ref addFinished); }; Action mainAction = () => { var localQ = locQ[Interlocked.Increment(ref mainIndex)]; List <int> data = new List <int>(); try { int index = 0; while (Volatile.Read(ref addFinished) < thCount) { ThreadPoolWorkItem tmp = null; if (q.TryTake(localQ, out tmp, -1, tokSrc.Token, true)) { data.Add((TestThreadPoolItem)tmp); } if (((index++) % 10) == 0) { int item = Interlocked.Decrement(ref trackElemCount); if (item >= 0) { while (!q.TryAdd(new TestThreadPoolItem(item), localQ, false, 0, CancellationToken.None)) { if (q.TryTake(localQ, out tmp, 0, CancellationToken.None, true)) { data.Add((TestThreadPoolItem)tmp); } } } } } } catch (OperationCanceledException) { } ThreadPoolWorkItem tmp2; while (q.TryTake(localQ, out tmp2, 0, CancellationToken.None, true)) { data.Add((TestThreadPoolItem)tmp2); } lock (global) global.AddRange(data); }; for (int i = 0; i < threadsMain.Length; i++) { threadsMain[i] = new Thread(new ThreadStart(mainAction)); } for (int i = 0; i < threadsAdditional.Length; i++) { threadsAdditional[i] = new Thread(new ThreadStart(additionalAction)); } Stopwatch sw = Stopwatch.StartNew(); for (int i = 0; i < threadsMain.Length; i++) { threadsMain[i].Start(); } for (int i = 0; i < threadsAdditional.Length; i++) { threadsAdditional[i].Start(); } for (int i = 0; i < threadsAdditional.Length; i++) { threadsAdditional[i].Join(); } tokSrc.Cancel(); for (int i = 0; i < threadsMain.Length; i++) { threadsMain[i].Join(); } sw.Stop(); bool result = true; if (elemCount != global.Count) { Console.WriteLine("Incorrect items count"); result = false; } global.Sort(); for (int i = 0; i < Math.Min(elemCount, global.Count); i++) { if (global[i] != i) { Console.WriteLine("Incorrect items value"); result = false; break; } } Console.WriteLine(q.GetType().Name + ". Element count = " + elemCount.ToString() + ", Time = " + sw.ElapsedMilliseconds.ToString() + "ms"); Console.WriteLine(); return(result); }