public async Task Start(IDictionary <string, List <string> > args) { await Task.Delay(0); if (args.ContainsKey("+all")) { args.Add("-store", new List <string>() { "mh", "mmf", "nh" }); } args.AssertAll("-store"); var opt = args["-store"]; opt.AssertNothingOutsideThese("mh", "mmf", "nh"); var allocArgs = new AllocTestArgs() { Count = 5, Size = 5_000_000, InParallel = 2, RandomizeAllocDelay = true, RandomizeFragDisposal = false, RandomizeLength = false, AwaitFragmentDisposal = true, AllocDelayMS = 0, FragmentDisposeAfterMS = 2000 // keep them alive }; if (allocArgs.Count * allocArgs.Size < 12_000_000) { Passed = false; FailureMessage = "The default highway capacity can handle all fragments. Should test out of the capacity bounds."; return; } Print.Trace(allocArgs.FullTrace(), ConsoleColor.Cyan, ConsoleColor.Black, null); var stg_ignore = new HighwaySettings(8_000_000, 2, 10_000_000); var stg_throw = new HighwaySettings(8_000_000, 2, 10_000_000); stg_ignore.OnMaxLaneReached = () => { Print.AsInnerInfo("OnMaxLaneReached(), allowing it to continue. "); return(true); }; stg_ignore.OnMaxTotalBytesReached = () => { Print.AsInnerInfo("OnMaxTotalBytesReached(), ignoring. "); return(true); }; var iH = new Dictionary <string, IMemoryHighway>(); iH.Add("mh", new HeapHighway(stg_ignore)); iH.Add("nh", new MarshalHighway(stg_ignore)); iH.Add("mmf", new MappedHighway(stg_ignore)); var dH = new Dictionary <string, IMemoryHighway>(); dH.Add("mh", new HeapHighway(stg_throw)); dH.Add("nh", new MarshalHighway(stg_throw)); dH.Add("mmf", new MappedHighway(stg_throw)); // The ignoring case try { foreach (var kp in iH) { if (opt.Contains(kp.Key)) { var hw = kp.Value; var hwName = hw.GetType().Name; using (hw) { hw.AllocAndWait(allocArgs); if (hw.GetTotalActiveFragments() > 0) { Passed = false; FailureMessage = $"The {hwName} has active fragments after the AllocAndWait()"; return; } if (hw.GetLanesCount() > stg_ignore.MaxLanesCount) { Passed = false; FailureMessage = $"The {hwName} has more than {stg_ignore.MaxLanesCount} lanes."; return; } Print.Trace(hw.FullTrace(), 2, true, ConsoleColor.Cyan, ConsoleColor.Black, null); } } } "The limits ignoring case.".AsSuccess(); // The default case: throws MemoryLaneExceptions foreach (var kp in dH) { if (opt.Contains(kp.Key)) { var hw = kp.Value; var hwName = hw.GetType().Name; using (hw) { try { hw.AllocAndWait(allocArgs); } catch (AggregateException aggr) { Interlocked.Exchange(ref allocArgs.Trace, 0); foreach (var ex in aggr.Flatten().InnerExceptions) { var mex = ex as MemoryLaneException; if (mex != null) { if (mex.ErrorCode != MemoryLaneException.Code.MaxLanesCountReached && mex.ErrorCode != MemoryLaneException.Code.MaxTotalAllocBytesReached) { Passed = false; FailureMessage = string.Format( "The {0} should have failed with MaxLanesCountReached or MaxTotalAllocBytesReached", hwName); return; } $"{mex.ErrorCode} in {hwName} as expected".AsSuccess(); } else { Passed = false; FailureMessage = ex.Message; return; } } } catch (Exception ex) { Passed = false; FailureMessage = ex.Message; return; } if (hw.GetLanesCount() > stg_throw.MaxLanesCount) { Passed = false; FailureMessage = $"The {hwName} has more than {stg_throw.MaxLanesCount} lanes, should have failed. "; return; } Print.Trace(hw.FullTrace(), 2, true, ConsoleColor.Cyan, ConsoleColor.Black, null); } } } "The default - throwing exceptions case.".AsSuccess(); } catch (Exception ex) { Passed = false; FailureMessage = ex.Message; return; } if (!Passed.HasValue) { Passed = true; } IsComplete = true; } }
public Task Start(IDictionary <string, List <string> > args) { const int IN_PARALLEL = 30; var T = new Task[IN_PARALLEL]; try { using (var hw = new HeapHighway(2000)) { // Alloc +1 ints, the last cell will be concurrently read/written by each task. // When the task id is successfully stored, the task is allowed to update its on cell. var frag = hw.Alloc((IN_PARALLEL + 1) * 4); // Launch multiple tasks for (int i = 0; i < IN_PARALLEL; i++) { T[i] = Task.Factory.StartNew((idx) => { var intSpan = frag.ToSpan <int>(); int pos = (int)idx; var laps = 0; // Await with terrible cache flushing while (Interlocked.CompareExchange(ref intSpan[IN_PARALLEL], pos, 0) != 0) { laps++; } var posAndLaps = laps + (pos * 10_000_000); Volatile.Write(ref intSpan[pos], posAndLaps); // Release Interlocked.Exchange(ref intSpan[IN_PARALLEL], 0); }, i); } Task.WaitAll(T); // Check if all tasks have updated their corresponding cells var theSpan = frag.ToSpan <int>(); for (int i = 0; i < theSpan.Length - 1; i++) { if (theSpan[i] < 0) { Passed = false; FailureMessage = $"The Task {i} hasn't touched its cell."; break; } else { Print.AsInnerInfo($"{i}: {theSpan[i]} laps"); } } Passed = true; Print.Trace(hw.FullTrace(), 2, true, ConsoleColor.Cyan, ConsoleColor.Black, null); } } catch (Exception ex) { Passed = false; FailureMessage = ex.Message; } return(Task.Delay(0)); }
public async Task Start(IDictionary <string, List <string> > args) { await Task.Delay(0); if (args.ContainsKey("+all")) { args.Add("-store", new List <string>() { "mh", "mmf", "nh" }); } args.AssertAll("-store"); var opt = args["-store"]; opt.AssertNothingOutsideThese("mh", "mmf", "nh"); var allocArgs = new AllocTestArgs() { Count = 6000, Size = 1200, InParallel = 12, RandomizeAllocDelay = false, RandomizeFragDisposal = true, RandomizeLength = false, AllocDelayMS = 10, AllocTries = 20, AwaitFragmentDisposal = false, FragmentDisposeAfterMS = 100, Trace = 0 }; var H = new Dictionary <string, IMemoryHighway>(); var ms = new HighwaySettings(300_000, 300, 700_000_000); var lanes = new int[10]; Array.Fill(lanes, 300_000); H.Add("mh", new HeapHighway(ms, lanes)); H.Add("nh", new MarshalHighway(ms, lanes)); H.Add("mmf", new MappedHighway(ms, lanes)); Print.Trace(allocArgs.FullTrace(), ConsoleColor.Cyan, ConsoleColor.Black, null); foreach (var kp in H) { if (opt.Contains(kp.Key)) { var hw = kp.Value; var hwName = hw.GetType().Name; using (hw) { hw.AllocAndWait(allocArgs); var fragsCount = hw.GetTotalActiveFragments(); if (fragsCount < args.Count) { Passed = false; FailureMessage = string.Format( "{0}: Failed to allocate all {1} fragments, got {2}.", hwName, allocArgs.Count, fragsCount); return; } Print.AsInnerInfo( "{0}: Total lanes count: {1} Total active fragments: {2}", hwName, hw.GetLanesCount(), hw.GetTotalActiveFragments()); Print.Trace(hw.FullTrace(), 2, true, ConsoleColor.Cyan, ConsoleColor.Black, null); } } } if (!Passed.HasValue) { Passed = true; } IsComplete = true; }
bool reset(List <string> opt) { var stg = new HighwaySettings(4000, 8, 10000); var iH = new Dictionary <string, IMemoryHighway>(); iH.Add("mh", new HeapHighway(stg, 4000)); iH.Add("nh", new MarshalHighway(stg, 4000)); iH.Add("mmf", new MappedHighway(stg, 4000)); foreach (var kp in iH) { var hwName = kp.Value.GetType().Name; var F = new List <MemoryFragment>(); if (opt.Contains(kp.Key)) { var hw = kp.Value; using (hw) { F.Add(hw.AllocFragment(500)); F.Add(hw.AllocFragment(500)); F.Add(hw.AllocFragment(500)); hw.AllocFragment(1000); // lost F.Add(hw.AllocFragment(500)); F.Add(hw.AllocFragment(1000)); foreach (var f in F) { f.Dispose(); } var af = hw.GetTotalActiveFragments(); if (af == 1) { Print.AsInnerInfo("{0} has {1} non disposed fragments", hwName, af); af = hw.GetTotalActiveFragments(); if (af != 1) { Passed = false; FailureMessage = string.Format("{0}: expected one ghost fragment, found {1}.", hwName, af); return(false); } Print.Trace("Forcing reset.. ", ConsoleColor.Magenta, hwName, af); var lane0 = hw[0]; lane0.Force(false, true); af = hw.GetTotalActiveFragments(); if (af != 0) { Passed = false; FailureMessage = string.Format("{0}: expected 0 ghost fragments after forcing a reset, found {1}.", hwName, af); return(false); } else { Print.Trace("{0} has {1} allocations and offset {2}", ConsoleColor.Green, hwName, lane0.Allocations, lane0.Offset); } } else { Passed = false; FailureMessage = string.Format("{0}: the active fragments count is wrong, should be 1.", hwName); return(false); } Print.Trace(hw.FullTrace(), 2, true, ConsoleColor.Cyan, ConsoleColor.Black); } } } return(true); }
async Task Process(AllocType at, Socket client, Action <int> onmessage, bool stop = false) { Print.AsInfo(at.ToString() + Environment.NewLine); try { Print.AsInfo("New client" + Environment.NewLine); IMemoryHighway hw = null; var lanes = new int[] { 1025, 2048 }; switch (at) { case AllocType.Heap: hw = new HeapHighway(lanes); break; case AllocType.MMF: hw = new MappedHighway(lanes); break; case AllocType.Marshal: hw = new MarshalHighway(lanes); break; default: throw new ArgumentNullException(); } using (hw) using (var ns = new NetworkStream(client)) { var header = new byte[4]; var spoon = new byte[16000]; var total = 0; var read = 0; var frameLen = 0; while (!stop) { total = 0; read = await ns.ReadAsync(header, 0, 4).ConfigureAwait(false); Print.AsInfo("Received header bytes: {0}.{1}.{2}.{3}", header[0], header[1], header[2], header[3]); // The other side is gone. // As long as the sender is not disposed/closed the ReadAsync will wait if (read < 1) { Print.AsError("The client is gone."); break; } frameLen = BitConverter.ToInt32(header, 0); if (frameLen < 1) { Print.AsError("Bad header, thread {0}", Thread.CurrentThread.ManagedThreadId); break; } using (var frag = hw.AllocFragment(frameLen)) { Print.AsInfo("Frame length:{0}", frameLen); // The sip length guards against jumping into the next frame var sip = 0; while (total < frameLen && !stop) { sip = frameLen - total; if (sip > spoon.Length) { sip = spoon.Length; } // the read amount could be smaller than the sip read = await ns.ReadAsync(spoon, 0, sip).ConfigureAwait(false); frag.Write(spoon, total, read); total += read; Print.AsInnerInfo("read {0} on thread {1}", read, Thread.CurrentThread.ManagedThreadId); if (total >= frameLen) { onmessage?.Invoke(total); break; } } } } } } catch (MemoryLaneException mex) { Print.AsError(mex.Message); Print.AsError(mex.ErrorCode.ToString()); Print.AsError(mex.StackTrace); } catch (Exception ex) { Print.AsError(ex.Message); } }