diff --git a/CBSVisualizer/CBSVisualizer.Common/Enums/PreemptionType.cs b/CBSVisualizer/CBSVisualizer.Common/Enums/PreemptionType.cs new file mode 100644 index 0000000000000000000000000000000000000000..8b8d9400313337a4e4db946a58501a3a2358e59c --- /dev/null +++ b/CBSVisualizer/CBSVisualizer.Common/Enums/PreemptionType.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CBSVisualizer.Common.Enums +{ + /// <summary> + /// An enum specifying the available preemption types. + /// </summary> + public enum PreemptionType + { + /// <summary> + /// Non-preemptive. + /// </summary> + NonPreemptive, + + /// <summary> + /// Preemption no HOLD/RELEASE + /// </summary> + PreemptionNoHoldRelease, + + /// <summary> + /// Preemption with HOLD/RELEASE + /// </summary> + PreemptionWithHoldRelease + } +} diff --git a/CBSVisualizer/CBSVisualizer.Common/Interfaces/IPreemptionHandler.cs b/CBSVisualizer/CBSVisualizer.Common/Interfaces/IPreemptionHandler.cs new file mode 100644 index 0000000000000000000000000000000000000000..899c4f57a4225b0f0f2a5c2d233154dc414b57a0 --- /dev/null +++ b/CBSVisualizer/CBSVisualizer.Common/Interfaces/IPreemptionHandler.cs @@ -0,0 +1,34 @@ +using CBSVisualizer.Messaging.Models; + +namespace CBSVisualizer.Common.Interfaces +{ + public interface IPreemptionHandler + { + /// <summary> + /// Used by the link to determine if the send candidate can actually be sent. + /// </summary> + /// <param name="candidate">the packet that should be evaluated.</param> + /// <param name="byteBudget">the amount of bytes the link could transmit before the gate closes.</param> + /// <returns>true if the preemption handler allows the packet to be sent.</returns> + bool CanSend(PriorityPacket candidate, long byteBudget); + + + /// <summary> + /// Used by the link to determine if the currently sent packet can be preempted. + /// </summary> + /// <param name="currentPacket">the packet that is currently sent.</param> + /// <param name="leftoverBytes">the bytes that still need to be transmitted.</param> + /// <param name="byteBudget">the amount of bytes that the link can transmit before the gate closes.</param> + /// <returns>true if the packet can be preempted in favour of a higher priority packet.</returns> + bool CanPreempt(PriorityPacket currentPacket, int leftoverBytes, long byteBudget); + + + /// <summary> + /// Constructs the packet with the leftover data that will be sent after the preempting packet. + /// </summary> + /// <param name="priority">the priority of the original packet -> also the priority of the new packet.</param> + /// <param name="leftoverBytes">the leftover bytes of the packet.</param> + /// <returns></returns> + PriorityPacket ConstructPostPreemptionPacket(int priority, int leftoverBytes); + } +} diff --git a/CBSVisualizer/CBSVisualizer.MessagingCore/Events/Queue/TransmissionFinishedEvent.cs b/CBSVisualizer/CBSVisualizer.MessagingCore/Events/Queue/TransmissionFinishedEvent.cs index dba806418bd733a1f0e394f3192ec174fb58f90b..6426fe2cc2982bd43ae3d53fc3136c5e85888697 100644 --- a/CBSVisualizer/CBSVisualizer.MessagingCore/Events/Queue/TransmissionFinishedEvent.cs +++ b/CBSVisualizer/CBSVisualizer.MessagingCore/Events/Queue/TransmissionFinishedEvent.cs @@ -2,7 +2,7 @@ namespace CBSVisualizer.Messaging.Events.Queue { - public class TransmissionFinishedEvent : PubSubEvent<int> + public class TransmissionFinishedEvent : PubSubEvent<(int Priority, long BytesPerSecond)> { } } diff --git a/CBSVisualizer/CBSVisualizer.MessagingCore/Events/Queue/TransmissionStartedEvent.cs b/CBSVisualizer/CBSVisualizer.MessagingCore/Events/Queue/TransmissionStartedEvent.cs index 0537ba3f4843ba56f09a749690b8bec3b5318833..30808a892d29f520eb029800b3823ae3ece398f5 100644 --- a/CBSVisualizer/CBSVisualizer.MessagingCore/Events/Queue/TransmissionStartedEvent.cs +++ b/CBSVisualizer/CBSVisualizer.MessagingCore/Events/Queue/TransmissionStartedEvent.cs @@ -7,7 +7,7 @@ using Prism.Events; namespace CBSVisualizer.Messaging.Events.Queue { - public class TransmissionStartedEvent : PubSubEvent<(int Priority, long BytesPerSecond)> + public class TransmissionStartedEvent : PubSubEvent<int> { } } diff --git a/CBSVisualizer/CBSVisualizer.Modules.Charts/ViewModels/ChartsViewModel.cs b/CBSVisualizer/CBSVisualizer.Modules.Charts/ViewModels/ChartsViewModel.cs index de8a7e7ad5ba66027b41cf50ba49130a993a1b12..07c49359537db904c6b7c2654a559a2b6bef3670 100644 --- a/CBSVisualizer/CBSVisualizer.Modules.Charts/ViewModels/ChartsViewModel.cs +++ b/CBSVisualizer/CBSVisualizer.Modules.Charts/ViewModels/ChartsViewModel.cs @@ -5,6 +5,7 @@ using System.Collections.ObjectModel; using CBSVisualizer.Core.Mvvm; using CBSVisualizer.Messaging.Events; using CBSVisualizer.Messaging.Events.Charts; +using CBSVisualizer.Messaging.Events.Simulation; using Prism.Events; using Prism.Regions; using SciChart.Charting.Model.ChartSeries; diff --git a/CBSVisualizer/CBSVisualizer.Modules.Link/Preemption/NoPreemptionHandler.cs b/CBSVisualizer/CBSVisualizer.Modules.Link/Preemption/NoPreemptionHandler.cs new file mode 100644 index 0000000000000000000000000000000000000000..d231cabcfe7559b3ddfa0e58c157e03f1720733c --- /dev/null +++ b/CBSVisualizer/CBSVisualizer.Modules.Link/Preemption/NoPreemptionHandler.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using CBSVisualizer.Common.Interfaces; +using CBSVisualizer.Messaging.Models; + +namespace CBSVisualizer.Modules.Link.Preemption +{ + class NoPreemptionHandler : IPreemptionHandler + { + public bool CanSend(PriorityPacket candidate, long byteBudget) + { + return candidate.Size <= byteBudget; + + } + + public bool CanPreempt(PriorityPacket currentPacket, int leftoverBytes, long byteBudget) + { + return false; + } + + public PriorityPacket ConstructPostPreemptionPacket(int priority, int leftoverBytes) + { + return PriorityPacket.NoPacket; + } + } +} diff --git a/CBSVisualizer/CBSVisualizer.Modules.Link/Preemption/PreemptionNoHoldReleaseHandler.cs b/CBSVisualizer/CBSVisualizer.Modules.Link/Preemption/PreemptionNoHoldReleaseHandler.cs new file mode 100644 index 0000000000000000000000000000000000000000..a9620bde416194a5eb52983cc7dc6aa68d7b6dab --- /dev/null +++ b/CBSVisualizer/CBSVisualizer.Modules.Link/Preemption/PreemptionNoHoldReleaseHandler.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using CBSVisualizer.Common.Interfaces; +using CBSVisualizer.Messaging.Models; + +namespace CBSVisualizer.Modules.Link.Preemption +{ + public class PreemptionNoHoldReleaseHandler : IPreemptionHandler + { + private const int MinPacketSize = 64; + private const int TooSmallForPreemption = 123; + private const int HeaderSize = 16; + private const int TrailerSize = 8; + + public bool CanSend(PriorityPacket candidate, long byteBudget) + { + // The lower priority packets can always be sent, no guard band. + return true; + } + + public bool CanPreempt(PriorityPacket currentPacket, int leftoverBytes, long byteBudget) + { + // Cannot be preempted if either + // a) bytes left to transmit < min packet size (64 bytes) + // b) frame is too small to be preempted (< 123 bytes) + return leftoverBytes >= MinPacketSize && currentPacket.Size >= TooSmallForPreemption; + } + + public PriorityPacket ConstructPostPreemptionPacket(int priority, int leftoverBytes) + { + // If the CBS frame can be preempted, the overhead (header + trailer) per preemption is 24 bytes, assuming 16 bytes header + 8 bytes trailer. + return new PriorityPacket(priority, HeaderSize, leftoverBytes, TrailerSize); + } + } +} diff --git a/CBSVisualizer/CBSVisualizer.Modules.Link/Preemption/PreemptionWithHoldReleaseHandler.cs b/CBSVisualizer/CBSVisualizer.Modules.Link/Preemption/PreemptionWithHoldReleaseHandler.cs new file mode 100644 index 0000000000000000000000000000000000000000..7e77241ba883a281673aca043cf919a803b3a0d8 --- /dev/null +++ b/CBSVisualizer/CBSVisualizer.Modules.Link/Preemption/PreemptionWithHoldReleaseHandler.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using CBSVisualizer.Common.Interfaces; +using CBSVisualizer.Messaging.Models; + +namespace CBSVisualizer.Modules.Link.Preemption +{ + public class PreemptionWithHoldReleaseHandler : IPreemptionHandler + { + private const int ReducedGuardBandSize = 143; + private const int HeaderSize = 0; + private const int TrailerSize = 8; + + public bool CanSend(PriorityPacket candidate, long byteBudget) + { + // A reduced Guard Band (143 bytes) is introduced in order to protect the TT window. + return byteBudget > ReducedGuardBandSize; + } + + public bool CanPreempt(PriorityPacket currentPacket, int leftoverBytes, long byteBudget) + { + // If the current transmission will be finished outside of the guard band, we cannot preempt it. + if (byteBudget - leftoverBytes >= ReducedGuardBandSize) + { + return false; + } + + // If the packet can finish its transmission inside of the guard band, we cannot preempt it. + // Otherwise, we can preempt it. + return leftoverBytes > ReducedGuardBandSize; + } + + public PriorityPacket ConstructPostPreemptionPacket(int priority, int leftoverBytes) + { + // Overhead is 8 bytes (trailer). + return new PriorityPacket(priority, HeaderSize, leftoverBytes, TrailerSize); + } + } +} diff --git a/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs b/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs index 23472656e19a489174f274292185b45830af0091..b6f746e1ae369743d00a7a008cf1aa56348b7e55 100644 --- a/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs +++ b/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs @@ -7,10 +7,13 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; using CBSVisualizer.Common; +using CBSVisualizer.Common.Enums; +using CBSVisualizer.Common.Interfaces; using CBSVisualizer.Core.Mvvm; using CBSVisualizer.Messaging.Events.Queue; using CBSVisualizer.Messaging.Events.Simulation; using CBSVisualizer.Messaging.Models; +using CBSVisualizer.Modules.Link.Preemption; using CBSVisualizer.Services.SchedulingService.Interface; using CBSVisualizer.Services.SettingService.Implementation; using log4net; @@ -21,19 +24,55 @@ namespace CBSVisualizer.Modules.Link.ViewModels { public class LinkViewModel : RegionViewModelBase, IDisposable { + /// <summary> + /// The key of the "bitrate" setting. + /// </summary> private const string BitrateSettingKey = "bitrate"; + /// <summary> + /// The logger of this ViewModel. + /// </summary> private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod()?.DeclaringType); + private readonly IEventAggregator eventAggregator; + /// <summary> + /// A ConcurrentBag for storing the packets that the opened queues want to send. + /// </summary> private readonly ConcurrentBag<PriorityPacket> sendCandidates = new ConcurrentBag<PriorityPacket>(); + /// <summary> + /// The Setting Service, for requesting the bitrate and the preemption setting. + /// </summary> private readonly SettingService settingService; + /// <summary> + /// The PreemptionHandler implementation that is used in the current simulation run. + /// </summary> + private IPreemptionHandler preemptionHandler; + + /// <summary> + /// The thread that does the main work (selecting the currently transmitted packet, notifying the queues etc.). + /// </summary> private Thread gateThread; + + /// <summary> + /// A CancellationTokenSource for the recognition of GateClosedEvents. + /// </summary> private CancellationTokenSource gateOpenedTokenSrc = new CancellationTokenSource(); + + /// <summary> + /// The index of the last preempted queue. -1 if no preemption has taken place. + /// </summary> + private int preemptedQueue = -1; + + /// <summary> + /// These are the bytes that are left to transmit in the "Gate Opened time" of the high priority queue when a preemption has taken place + /// and the link is unable to send the whole packet before the GateClosedEvent of the lower prio gate. + /// </summary> + private long preemptingPacketLeftoverBytes; public LinkViewModel(IRegionManager regionManager, IEventAggregator eventAggregator, ISchedulingService schedulingService, SettingService settingService) @@ -80,7 +119,7 @@ namespace CBSVisualizer.Modules.Link.ViewModels gateOpenedTokenSrc = new CancellationTokenSource(); // Calculate transmittable bytes. - var transmittableBytes = settingService.GetSettingValue<int>(BitrateSettingKey) * tuple.OpenedTime / 1000; + var transmittableBytes = settingService.GetSettingValue<long>(BitrateSettingKey) * tuple.OpenedTime / 1000; eventAggregator.GetEvent<QueueGateOpenedEvent>().Publish(tuple.OpenedGates); @@ -99,6 +138,7 @@ namespace CBSVisualizer.Modules.Link.ViewModels gateOpenedTokenSrc.Cancel(); if (gateThread != null && gateThread.IsAlive) { + Debug.WriteLine("Joining Gate Thread"); gateThread.Join(); } } @@ -107,10 +147,14 @@ namespace CBSVisualizer.Modules.Link.ViewModels { eventAggregator.GetEvent<SimulationStartedEvent>().Subscribe(async () => { + + InitializePreemptionHandler(); + + Log.Info("Simulation started."); + // Start scheduling. try { - Log.Info("Simulation started."); await scheduler.StartScheduling().ConfigureAwait(false); } catch (TaskCanceledException) @@ -136,10 +180,34 @@ namespace CBSVisualizer.Modules.Link.ViewModels }, true); } - private void HandleGateOpened(ISet<int> openedGates, int byteBudget) + private void InitializePreemptionHandler() + { + switch (Enum.Parse<PreemptionType>(settingService.GetSettingValue<string>("preemption_mode"))) + { + case PreemptionType.PreemptionNoHoldRelease: + preemptionHandler = new PreemptionNoHoldReleaseHandler(); + break; + case PreemptionType.PreemptionWithHoldRelease: + preemptionHandler = new PreemptionWithHoldReleaseHandler(); + break; + case PreemptionType.NonPreemptive: + default: + preemptionHandler = new NoPreemptionHandler(); + break; + } + } + + private void HandleGateOpened(ISet<int> openedGates, long byteBudget) { // Copy transmittable bytes. - var totalBudget = byteBudget; + var totalBudget = byteBudget - preemptingPacketLeftoverBytes; + preemptingPacketLeftoverBytes = 0; + + // If this cycle contains a queue whose packet was preempted, send that packet first. + if (preemptedQueue != -1 && openedGates.Contains(preemptedQueue)) + { + totalBudget -= SendPreemptedPacket(totalBudget); + } while (!gateOpenedTokenSrc.IsCancellationRequested) { @@ -147,29 +215,69 @@ namespace CBSVisualizer.Modules.Link.ViewModels } } - private int PerformCycle(ISet<int> openedGates, int cycleByteBudget) + /// <summary> + /// Sends the previously preempted packet (if there was any). + /// </summary> + /// <param name="totalBudget">the byte budget until the next GateClosedEvent to determine if we can send the packet in time.</param> + /// <returns></returns> + private long SendPreemptedPacket(long totalBudget) + { + // Get the preempted packet. + sendCandidates.Clear(); + eventAggregator.GetEvent<PacketSubmitRequestEvent>().Publish(new HashSet<int>{preemptedQueue}); + AwaitPacketArrival(1); + + // Construct the post-preemption packet. + // Important: preemption overhead (header + trailer) does not subtract from the queue's credit. + var postPreemptionPacket = preemptionHandler.ConstructPostPreemptionPacket(preemptedQueue, sendCandidates.First().Size); + + // If we're unable to send the packet before the gate closes again, return 0 to signal that we did not waste any bytes for preempted packets. + if (postPreemptionPacket.Size > totalBudget) + { + Debug.WriteLine($"Unable to send post-preemption packet {postPreemptionPacket} before Gate Closing Event!"); + return 0; + } + + // Signal to the queue that we've accepted the preempted packet and send it atomically. + eventAggregator.GetEvent<PacketSubmitResultEvent>().Publish((preemptedQueue, PacketSubmitResult.Accepted)); + + Debug.WriteLine($"Sending post-preemption packet {postPreemptionPacket}..."); + eventAggregator.GetEvent<TransmissionStartedEvent>().Publish(postPreemptionPacket.Priority); + + Thread.Sleep(TimeSpan.FromSeconds(postPreemptionPacket.Size / + settingService.GetSettingValue<double>(BitrateSettingKey))); + + Debug.WriteLine($"Transmission of post-preemption packet {postPreemptionPacket} finished!"); + eventAggregator.GetEvent<TransmissionFinishedEvent>().Publish((postPreemptionPacket.Priority, + settingService.GetSettingValue<int>(BitrateSettingKey))); + + // Reset the preemptedQueue variable and return the size of the packet that was sent so that the byte budget can be reduced by that number. + preemptedQueue = -1; + return postPreemptionPacket.Size; + } + + private long PerformCycle(ISet<int> openedGates, long cycleByteBudget) { // Init byte budget. var cycleBudget = cycleByteBudget; - // Cleanup the previous send candidates and request new packets from the queues with opened gates. + // Cleanup the previous send candidates and request new packets from the queues with opened gates, except of the one whose packet was previously preempted. sendCandidates.Clear(); - eventAggregator.GetEvent<PacketSubmitRequestEvent>().Publish(openedGates); + + var queriedGates = new HashSet<int>(openedGates.Except(Enumerable.Repeat(preemptedQueue, 1))); + eventAggregator.GetEvent<PacketSubmitRequestEvent>().Publish(queriedGates); // Await all packets to arrive. - AwaitPacketArrival(openedGates.Count); + AwaitPacketArrival(queriedGates.Count); // When all packets have arrived, sort them descending and check if we can send them in time. var selectedPacket = PriorityPacket.NoPacket; foreach (var sendCandidate in sendCandidates.Except(Enumerable.Repeat(PriorityPacket.NoPacket, 1)) .OrderByDescending(packet => packet.Priority)) { - if (selectedPacket == PriorityPacket.NoPacket && CanSendInTime(sendCandidate, cycleBudget)) + if (selectedPacket == PriorityPacket.NoPacket && preemptionHandler.CanSend(sendCandidate, cycleBudget)) { - // If we can send it in time and there was nothing selected yet... - // ... reduce transmittable bytes. - cycleBudget -= sendCandidate.Size; - + // If we can send it and there was nothing selected yet... // ... notify the queue that its packet was selected. eventAggregator.GetEvent<PacketSubmitResultEvent>() .Publish((sendCandidate.Priority, PacketSubmitResult.Accepted)); @@ -177,9 +285,9 @@ namespace CBSVisualizer.Modules.Link.ViewModels //... add it to the sending queue. selectedPacket = sendCandidate; } - else if (selectedPacket == PriorityPacket.NoPacket && !CanSendInTime(sendCandidate, cycleBudget)) + else if (selectedPacket == PriorityPacket.NoPacket && !preemptionHandler.CanSend(sendCandidate, cycleBudget)) { - // If nothing was selected and we cannot send in time, the packet was denied due to pre-closing. + // If nothing was selected and we cannot send, the packet was denied due to pre-closing. // Notify the queue. eventAggregator.GetEvent<PacketSubmitResultEvent>() .Publish((sendCandidate.Priority, PacketSubmitResult.DeniedPreClosing)); @@ -196,24 +304,109 @@ namespace CBSVisualizer.Modules.Link.ViewModels // Send the packet that we've just selected. if (selectedPacket != PriorityPacket.NoPacket) { - TransmitPacket(selectedPacket); + TransmitPacket(selectedPacket, cycleBudget); } + // Reduce transmittable bytes. + cycleBudget -= selectedPacket.Size; return cycleBudget; } - private void TransmitPacket(PriorityPacket selectedPacket) + private void TransmitPacket(PriorityPacket selectedPacket, long byteBudget) + { + // Highest prio packet cannot be preempted. + if (selectedPacket.Priority == 7) + { + Debug.WriteLine($"Packet {selectedPacket} is being sent non-preemptable."); + TransmitNonPreemptable(selectedPacket); + } + else // All others can. + { + Debug.WriteLine($"Packet {selectedPacket} is being sent preemptable."); + TransmitPreemptable(selectedPacket, byteBudget); + } + } + + private void TransmitPreemptable(PriorityPacket selectedPacket, long byteBudget) { Log.Info($"Sending {selectedPacket}..."); - eventAggregator.GetEvent<TransmissionStartedEvent>().Publish((selectedPacket.Priority, + eventAggregator.GetEvent<TransmissionStartedEvent>().Publish(selectedPacket.Priority); + + var bytesLeft = selectedPacket.Size; + while (bytesLeft > 0) + { + // If the GateOpenedEvent for the Higher-Prio gates arrived and the preemption took place, return. + if (gateOpenedTokenSrc.IsCancellationRequested && WasPreempted(selectedPacket, byteBudget, bytesLeft)) + { + return; + } + + // Otherwise, just send 32 bytes + Thread.Sleep(TimeSpan.FromSeconds(32 / + settingService.GetSettingValue<double>(BitrateSettingKey))); + bytesLeft -= 32; + } + + Log.Info($"Transmission of {selectedPacket} finished!"); + eventAggregator.GetEvent<TransmissionFinishedEvent>().Publish((selectedPacket.Priority, settingService.GetSettingValue<int>(BitrateSettingKey))); + } + + /// <summary> + /// Check if preemption can take place and handle it. + /// </summary> + /// <param name="selectedPacket">the packet that was originally being transmitted</param> + /// <param name="byteBudget">the byte budget before the GateCloseEvent</param> + /// <param name="bytesLeft">the remaining bytes of the selected packet that need to be transmitted.</param> + /// <returns></returns> + private bool WasPreempted(PriorityPacket selectedPacket, long byteBudget, int bytesLeft) + { + // Check if a priority 7 packet is available. + var highPriorityPacket = QueryHighPriorityPacket(); + + if (highPriorityPacket != PriorityPacket.NoPacket && + preemptionHandler.CanPreempt(selectedPacket, bytesLeft, byteBudget - (selectedPacket.Size - bytesLeft))) + { + Debug.WriteLine($"Packet {selectedPacket} was preempted by packet {highPriorityPacket}"); + + // Signal to the queue that its packet has been preempted. + eventAggregator.GetEvent<PacketPreemptedEvent>().Publish((selectedPacket.Priority, bytesLeft)); + + // Transmit the high-prio packet. + TransmitNonPreemptable(highPriorityPacket); + + // Save the info about how many bytes of the preempting packet we still have to send in the "Gate Opened Time" of the High-Prio gate. + preemptingPacketLeftoverBytes = Math.Min(0, + highPriorityPacket.Size - (byteBudget - (selectedPacket.Size - bytesLeft))); + + // Remember that we have to send the leftovers of this packet before the next regular contention cycle of the lower-prio gates. + preemptedQueue = selectedPacket.Priority; + return true; + } + + return false; + } + + private PriorityPacket QueryHighPriorityPacket() + { + sendCandidates.Clear(); + eventAggregator.GetEvent<PacketSubmitRequestEvent>().Publish(new HashSet<int> {7}); + AwaitPacketArrival(1); + return sendCandidates.First(); + } + + private void TransmitNonPreemptable(PriorityPacket selectedPacket) + { + Log.Info($"Sending {selectedPacket}..."); + eventAggregator.GetEvent<TransmissionStartedEvent>().Publish(selectedPacket.Priority); Thread.Sleep(TimeSpan.FromSeconds(selectedPacket.Size / settingService.GetSettingValue<double>(BitrateSettingKey))); Log.Info($"Transmission of {selectedPacket} finished!"); - eventAggregator.GetEvent<TransmissionFinishedEvent>().Publish(selectedPacket.Priority); + eventAggregator.GetEvent<TransmissionFinishedEvent>().Publish((selectedPacket.Priority, + settingService.GetSettingValue<int>(BitrateSettingKey))); } private void AwaitPacketArrival(int openedGatesCount) @@ -225,11 +418,6 @@ namespace CBSVisualizer.Modules.Link.ViewModels } } - private bool CanSendInTime(PriorityPacket packet, int budget) - { - return packet.Size <= budget; - } - /// <summary> /// Sets the status lamps according to the set. /// </summary> diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue/QueueImplementations/ReturnToZeroQueue.cs b/CBSVisualizer/CBSVisualizer.Modules.Queue/QueueImplementations/ReturnToZeroQueue.cs index fb81ad22048541a97028b02dcb9bf6d0260f344b..f34fcf8821f9af1b930b4105f8042f8846e2b5d4 100644 --- a/CBSVisualizer/CBSVisualizer.Modules.Queue/QueueImplementations/ReturnToZeroQueue.cs +++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/QueueImplementations/ReturnToZeroQueue.cs @@ -30,9 +30,10 @@ namespace CBSVisualizer.Modules.Queue.QueueImplementations public override void OnPacketDeniedPreClosing() { + var preUpdateCredit = Credit; deniedPreClosing = true; UpdateUsingInternalSlope(); - if (Credit > 0) + if (preUpdateCredit < 0 && Credit > 0) { UpdateCredit(0); Credit = 0; diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs index 9ba6cda7bc09634803b6a084dd23bcb9eedd5fd4..ffff6fe65965459114d58f7db5ee3fcdac59645f 100644 --- a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs +++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs @@ -161,20 +161,20 @@ namespace CBSVisualizer.Modules.Queue.ViewModels } }); - eventAggregator.GetEvent<TransmissionFinishedEvent>().Subscribe(async priority => + eventAggregator.GetEvent<TransmissionFinishedEvent>().Subscribe(async tuple => { + var (priority, bitrate) = tuple; if (priority != Priority) { return; } transmissionFinishedPending = false; - await Task.Run(() => QueueImplementation.OnTransmissionFinished(Queue.GetRemoveFirstSynchronized(), settings.GetSettingValue<long>("bitrate"))); + await Task.Run(() => QueueImplementation.OnTransmissionFinished(Queue.GetRemoveFirstSynchronized(), bitrate)); }); - eventAggregator.GetEvent<TransmissionStartedEvent>().Subscribe(async tuple => + eventAggregator.GetEvent<TransmissionStartedEvent>().Subscribe(async priority => { - var (priority, bytesPerSecond) = tuple; if (priority != Priority) { return; @@ -261,7 +261,7 @@ namespace CBSVisualizer.Modules.Queue.ViewModels GeneratePacketOnClick = new DelegateCommand(async () => { - await Task.Run(() => { Queue.AddSynchronized(packetService.GeneratePacket(Priority)); }); + await Task.Run(() => Queue.AddSynchronized(packetService.GeneratePacket(Priority))); }); } } diff --git a/CBSVisualizer/CBSVisualizer.Services.SettingsService/CBSVisualizer.Services.SettingService.csproj b/CBSVisualizer/CBSVisualizer.Services.SettingsService/CBSVisualizer.Services.SettingService.csproj index eda9d73f06d6235e9421e4ce3541bb4321da4ddf..1a6d97eabd55b33cb39f8d1252cb656d61a81ae9 100644 --- a/CBSVisualizer/CBSVisualizer.Services.SettingsService/CBSVisualizer.Services.SettingService.csproj +++ b/CBSVisualizer/CBSVisualizer.Services.SettingsService/CBSVisualizer.Services.SettingService.csproj @@ -12,4 +12,8 @@ <PackageReference Include="Prism.Core" Version="7.2.0.1422" /> </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\CBSVisualizer.Common\CBSVisualizer.Common.csproj" /> + </ItemGroup> + </Project> diff --git a/CBSVisualizer/CBSVisualizer.Services.SettingsService/Implementation/SettingService.cs b/CBSVisualizer/CBSVisualizer.Services.SettingsService/Implementation/SettingService.cs index d4f53f405dbcdee903b9257292417b69256aa2bc..f2d660fae87e7808c4753af824958853da2ff7e7 100644 --- a/CBSVisualizer/CBSVisualizer.Services.SettingsService/Implementation/SettingService.cs +++ b/CBSVisualizer/CBSVisualizer.Services.SettingsService/Implementation/SettingService.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; +using CBSVisualizer.Common.Enums; using CBSVisualizer.Services.SettingService.Types; using CBSVisualizer.Services.SettingService.Types.Abstract; @@ -18,6 +19,17 @@ namespace CBSVisualizer.Services.SettingService.Implementation InitializeCommonGroup(); InitializeSchedulersGroup(); InitializeLoadGenerationGroup(); + InitializePreemptionGroup(); + } + + private void InitializePreemptionGroup() + { + var preemptionGroupMembers = new ObservableCollection<Setting>(); + + // Preemption mode. + ISet<String> preemptionModes = new HashSet<string>{Enum.GetName(typeof(PreemptionType), PreemptionType.NonPreemptive), Enum.GetName(typeof(PreemptionType), PreemptionType.PreemptionNoHoldRelease), Enum.GetName(typeof(PreemptionType), PreemptionType.PreemptionWithHoldRelease) }; + preemptionGroupMembers.Add(new SelectionSetting("preemption_mode", "Preemption Mode", preemptionModes.First(), preemptionModes)); + settingGroups.Add(new SettingGroup("Preemption", preemptionGroupMembers)); } private void InitializeLoadGenerationGroup() @@ -25,7 +37,7 @@ namespace CBSVisualizer.Services.SettingService.Implementation var loadGenerationGroupMembers = new ObservableCollection<Setting>(); // Packet interarrival time. - loadGenerationGroupMembers.Add(new StringSetting("interarrival_time", "Packet Inter-Arrival Time [ms]", "500")); + loadGenerationGroupMembers.Add(new StringSetting("interarrival_time", "Packet Inter-Arrival Time [ms]", "100")); settingGroups.Add(new SettingGroup("Load Generation", loadGenerationGroupMembers)); } @@ -50,7 +62,7 @@ namespace CBSVisualizer.Services.SettingService.Implementation var commonGroupMembers = new ObservableCollection<Setting>(); // Link bitrate. - commonGroupMembers.Add(new StringSetting("bitrate", "Link Bitrate [byte/s]", "1000")); + commonGroupMembers.Add(new StringSetting("bitrate", "Link Bitrate [byte/s]", "10000")); settingGroups.Add(new SettingGroup("Common", commonGroupMembers)); }