public void RefCountedPipeline() { var sharedPool = new SharedPool <int[]>(() => new int[ArraySize], ParallelBranchCount * TransformCount); this.RunPipeline <Shared <int[]> >( create: i => sharedPool.GetOrCreate(), initialize: (old, i) => { old.Dispose(); var tgt = sharedPool.GetOrCreate(); Set(tgt.Resource, i); return(tgt); }, increment: (old, a) => { old.Dispose(); var tgt = sharedPool.GetOrCreate(); Inc(tgt.Resource, a.Resource, 1); return(tgt); }, add: (old, a, b) => { old.Dispose(); var tgt = sharedPool.GetOrCreate(); Add(tgt.Resource, a.Resource, b.Resource); return(tgt); }, extract: a => a.Resource[0], validateNoLoss: true, validateSync: false); }
public void RefCountedTest() { var sharedPool = new SharedPool <UnmanagedBuffer>(() => UnmanagedBuffer.Allocate(100), 1); var shared = sharedPool.GetOrCreate(); // refcount = 1 // a private copy shoudl point to the same resource var otherShared = shared.DeepClone(); // refcount = 1 + 1 Assert.AreNotEqual(shared, otherShared); Assert.AreEqual(shared.Inner, otherShared.Inner); Assert.AreEqual(shared.Resource, otherShared.Resource); // a clone should point to the same resource, but should not reuse the container var cloned = otherShared; Serializer.Clone(shared, ref cloned, new SerializationContext()); // refcount = 2 - 1 + 1 Assert.AreNotEqual(shared, cloned); Assert.AreEqual(shared.Inner, cloned.Inner); Assert.AreEqual(shared.Resource, cloned.Resource); // disposing should not affect other copies shared.Dispose(); // refcount = 2 - 1 Assert.AreEqual(0, sharedPool.AvailableCount); Assert.IsNull(shared.Inner); Assert.IsNull(shared.Resource); Assert.IsNotNull(cloned.Inner); Assert.IsNotNull(cloned.Resource); // disposing the last copy should return the resource to the pool cloned.Dispose(); // refcount = 1 - 1 Assert.AreEqual(1, sharedPool.AvailableCount); Assert.IsNull(cloned.Inner); Assert.IsNull(cloned.Resource); }
public void JoinOfShared() { var sum = 0; using (var p = Pipeline.Create()) { var pool = new SharedPool <int[]>(() => new int[1], 1); var g = Generators.Range(p, 0, 10); var s1 = g.Process <int, Shared <int[]> >( (i, e, emitter) => { using (var shared = pool.GetOrCreate()) { shared.Resource[0] = i; emitter.Post(shared, e.OriginatingTime); } }); var j = s1.Join(g); j.Select(t => t.Item2 - t.Item1.Resource[0]).Do(v => sum = sum + v); p.Run(); Assert.AreEqual(0, sum); Assert.IsTrue(pool.TotalCount > 0); Assert.AreEqual(pool.TotalCount, pool.AvailableCount); } }
public void SerializeGraph() { var buffer = new BufferWriter(100); var pool = new SharedPool <byte[]>(() => new byte[10], 1); Shared <byte[]> s = pool.GetOrCreate(); s.Resource[0] = 255; s.Resource[9] = 128; var t = Tuple.Create(s, s); Serializer.Serialize(buffer, t, new SerializationContext()); Tuple <Shared <byte[]>, Shared <byte[]> > target = null; Serializer.Deserialize(new BufferReader(buffer.Buffer), ref target, new SerializationContext()); Assert.ReferenceEquals(target.Item1, target.Item2); Assert.AreEqual(255, target.Item1.Resource[0]); Assert.AreEqual(0, target.Item1.Resource[1]); Assert.AreEqual(0, target.Item1.Resource[8]); Assert.AreEqual(128, target.Item1.Resource[9]); s.Dispose(); target.Item1.Dispose(); }
public void AddRefReleaseTest() { SharedPool <object> pool = new SharedPool <object>(() => new int?(1234), 1); // Verify that nothing is available (no objects have been allocated in the pool yet) Assert.AreEqual(pool.AvailableCount, 0); // Create our first object var origObj = pool.GetOrCreate(); Assert.AreEqual(pool.TotalCount, 1); // One object in pool Assert.AreEqual(pool.AvailableCount, 0); // None available for use (since only object is in use) // Take another reference on the object var refObj = origObj.AddRef(); // Sanity check that underlying resource is the same Assert.AreEqual(refObj.Resource, 1234); Assert.AreEqual(origObj.Resource, 1234); // Get rid of our second reference. There should still be none available // in the pool since the refObj.inner hasn't been released yet refObj.Dispose(); Assert.AreEqual(pool.AvailableCount, 0); // Next release the original object. Now everything should be released origObj.Dispose(); Assert.AreEqual(pool.AvailableCount, 1); Assert.AreEqual(origObj.Inner, null); }
public void PipelineOfShared() { int sum = 0; using (var p = Pipeline.Create()) { var pool = new SharedPool <int[]>(1); var g = Generators .Range(p, 0, 10) .Process <int, Shared <int[]> >( (i, e, emitter) => { using (var shared = pool.GetOrCreate(() => new int[1])) { shared.Resource[0] = i; emitter.Post(shared, e.OriginatingTime); } }); g.Select(a => a.Resource[0]).Do(v => sum = sum + v); p.Run(); Assert.AreEqual(5 * 9, sum); Assert.IsTrue(pool.TotalCount > 0); Assert.AreEqual(pool.TotalCount, pool.AvailableCount); } }
public void Serialize() { var buffer = new BufferWriter(100); var pool = new SharedPool <byte[]>(() => new byte[10], 1); Shared <byte[]> s = pool.GetOrCreate(); s.Resource[0] = 255; s.Resource[9] = 128; Shared <byte[]> s2 = pool.GetOrCreate(); s2.Resource[0] = 1; s2.Resource[9] = 1; // serialize twice Serializer.Serialize(buffer, s, new SerializationContext()); Serializer.Serialize(buffer, s2, new SerializationContext()); Shared <byte[]> target = null; var reader = new BufferReader(buffer.Buffer); Serializer.Deserialize(reader, ref target, new SerializationContext()); Assert.AreEqual(255, target.Resource[0]); Assert.AreEqual(0, target.Resource[1]); Assert.AreEqual(0, target.Resource[8]); Assert.AreEqual(128, target.Resource[9]); // deserialize again reusing the first instance, make sure the first instance is not trampled over var firstTarget = target.AddRef(); Serializer.Deserialize(reader, ref target, new SerializationContext()); Assert.IsFalse(object.ReferenceEquals(firstTarget, target)); Assert.IsFalse(object.ReferenceEquals(firstTarget.Inner, target.Inner)); Assert.IsFalse(object.ReferenceEquals(firstTarget.Resource, target.Resource)); Assert.AreEqual(1, target.Resource[0]); Assert.AreEqual(0, target.Resource[1]); Assert.AreEqual(0, target.Resource[8]); Assert.AreEqual(1, target.Resource[9]); // this should not throw, since refcount should be 1 on both firstTarget.Dispose(); target.Dispose(); }
public void DoubleDispose() { var sharedPool = new SharedPool <UnmanagedBuffer>(() => UnmanagedBuffer.Allocate(100), 1); var shared = sharedPool.GetOrCreate(); shared.Dispose(); try { shared.Dispose(); Assert.Fail("Expected an exception from the second Dispose call"); } catch (Exception e) { Assert.IsTrue(e is ObjectDisposedException); } }
public void RecyclerPerf() { var sharedPool = new SharedPool <UnmanagedBuffer>(() => UnmanagedBuffer.Allocate(100), 1); var shared = sharedPool.GetOrCreate(); shared.Dispose(); Stopwatch sw = Stopwatch.StartNew(); int iterations = 10; for (int i = 0; i < iterations; i++) { sharedPool.TryGet(out shared); shared.Dispose(); } sw.Stop(); Console.WriteLine($"Get + Release = {sw.ElapsedMilliseconds * 1000000d / iterations} ns"); }
// [TestMethod, Timeout(60000)] public void RefCountedFinalizationTest() { var sharedPool = new SharedPool <UnmanagedBuffer>(() => UnmanagedBuffer.Allocate(100), 1); var shared = sharedPool.GetOrCreate(); var otherShared = shared.DeepClone(); shared = null; // after GC and finalization, the live copy is not affected GC.Collect(); GC.WaitForPendingFinalizers(); Assert.AreNotEqual(IntPtr.Zero, otherShared.Resource.Data); otherShared = null; // after GC and finalization of all live copies, the resource goes back to the pool without being finalized itself GC.Collect(); GC.WaitForPendingFinalizers(); var wasRecycled = sharedPool.TryGet(out shared); Assert.IsTrue(wasRecycled); Assert.IsNotNull(shared.Resource); Assert.AreNotEqual(IntPtr.Zero, shared.Resource.Data); }
public void DeserializePooled() { const int iterations = 10; var writer = new BufferWriter(100); var pool = new SharedPool <byte[]>(() => new byte[10], 1); using (var s = pool.GetOrCreate()) { for (int i = 0; i < iterations; i++) { Serializer.Serialize(writer, s, new SerializationContext()); } } // the array should be back in the pool Assert.AreEqual(1, pool.AvailableCount); Assert.AreEqual(1, pool.TotalCount); var reader = new BufferReader(writer.Buffer); Assert.IsTrue(pool.TryGet(out Shared <byte[]> s2), "Expected a free entry in the pool!"); for (int i = 0; i < iterations; i++) { Serializer.Deserialize(reader, ref s2, new SerializationContext()); // verify that the pool doesn't grow Assert.AreEqual(pool, s2.SharedPool); Assert.AreEqual(0, pool.AvailableCount); Assert.AreEqual(1, pool.TotalCount); } s2.Dispose(); // disposing the last deserialized shared should release the array back to the pool Assert.AreEqual(1, pool.AvailableCount); }
/// <summary> /// Called once all the subscriptions are established. /// </summary> private unsafe void OnPipelineStart() { this.camera = new MediaCaptureInternal(this.configuration.DeviceId); this.camera.Open(); var isFormatSupported = false; foreach (var format in this.camera.SupportedPixelFormats()) { if (format.Pixels == this.configuration.PixelFormat) { this.camera.SetVideoFormat(this.configuration.Width, this.configuration.Height, format); isFormatSupported = true; } } if (!isFormatSupported) { throw new ArgumentException($"Pixel format {this.configuration.PixelFormat} is not supported by the camera"); } var current = this.camera.GetVideoFormat(); if (current.Width != this.configuration.Width || current.Height != this.configuration.Height) { throw new ArgumentException($"Width/height {this.configuration.Width}x{this.configuration.Height} is not supported by the camera"); } this.camera.OnFrame += (_, frame) => { var originatingTime = this.pipeline.GetCurrentTime(); if (this.Raw.HasSubscribers) { var len = frame.Length; using (Shared <byte[]> shared = RawPool.GetOrCreate(() => new byte[len])) { var buffer = shared.Resource.Length >= len ? shared : new Shared <byte[]>(new byte[len], shared.Recycler); Marshal.Copy(frame.Start, buffer.Resource, 0, len); this.Raw.Post(buffer, originatingTime); } } if (this.Out.HasSubscribers) { using (var sharedImage = ImagePool.GetOrCreate(this.configuration.Width, this.configuration.Height, PixelFormat.BGR_24bpp)) { if (this.configuration.PixelFormat == PixelFormatId.BGR24) { sharedImage.Resource.CopyFrom((IntPtr)frame.Start); this.Out.Post(sharedImage, this.pipeline.GetCurrentTime()); } else if (this.configuration.PixelFormat == PixelFormatId.YUYV) { // convert YUYV -> BGR24 (see https://msdn.microsoft.com/en-us/library/ms893078.aspx) var len = (int)(frame.Length * 1.5); using (Shared <byte[]> shared = RawPool.GetOrCreate(() => new byte[len])) { var buffer = shared.Resource.Length >= len ? shared : new Shared <byte[]>(new byte[len], shared.Recycler); var bytes = buffer.Resource; var pY = (byte *)frame.Start.ToPointer(); var pU = pY + 1; var pV = pY + 2; for (var i = 0; i < len;) { var y = (*pY - 16) * 298; var u = *pU - 128; var v = *pV - 128; var b = (y + (516 * u) + 128) >> 8; var g = (y - (100 * u) - (208 * v) + 128) >> 8; var r = (y + (409 * v) + 128) >> 8; bytes[i++] = (byte)(b < 0 ? 0 : b > 255 ? 255 : b); bytes[i++] = (byte)(g < 0 ? 0 : g > 255 ? 255 : g); bytes[i++] = (byte)(r < 0 ? 0 : r > 255 ? 255 : r); pY += 2; pU += 4; pV += 4; } this.Raw.Post(buffer, originatingTime); } } } } #if TEST_DROPPED_FRAMES System.Threading.Thread.Sleep(1000); // for testing dropped frames #endif // TEST_DROPPED_FRAMES frame.Dispose(); // release back to driver! }; this.camera.StreamBuffers(); }
/// <summary> /// Gets or creates an encoded image from the pool. /// </summary> /// <returns>A shared encoded image from the pool.</returns> public static Shared <EncodedImage> GetOrCreate() { return(Instance.GetOrCreate()); }