From 5e4d6cab00cb29cd088ab7b62ab13aff103b64cb Mon Sep 17 00:00:00 2001 From: onefang Date: Sun, 19 May 2019 21:24:15 +1000 Subject: Dump OpenSim 0.9.0.1 into it's own branch. --- .../Region/ClientStack/Linden/UDP/TokenBucket.cs | 405 +++++++++------------ 1 file changed, 179 insertions(+), 226 deletions(-) (limited to 'OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs') diff --git a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs index 4616203..1daf091 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs @@ -43,150 +43,143 @@ namespace OpenSim.Region.ClientStack.LindenUDP { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - public string Identifier { get; private set; } + private static Int32 m_counter = 0; - public int DebugLevel { get; set; } - - /// - /// Number of ticks (ms) per quantum, drip rate and max burst - /// are defined over this interval. - /// - protected const Int32 m_ticksPerQuantum = 1000; +// private Int32 m_identifier; + + protected const float m_timeScale = 1e-3f; /// - /// This is the number of quantums worth of packets that can - /// be accommodated during a burst + /// This is the number of m_minimumDripRate bytes + /// allowed in a burst + /// roughtly, with this settings, the maximum time system will take + /// to recheck a bucket in ms + /// /// - protected const Double m_quantumsPerBurst = 1.5; - + protected const float m_quantumsPerBurst = 5; + /// /// - protected const Int32 m_minimumDripRate = LLUDPServer.MTU; - - /// Time of the last drip, in system ticks - protected Int32 m_lastDrip; + protected const float m_minimumDripRate = 1500; + + /// Time of the last drip + protected double m_lastDrip; /// /// The number of bytes that can be sent at this moment. This is the /// current number of tokens in the bucket /// - protected Int64 m_tokenCount; + protected float m_tokenCount; /// /// Map of children buckets and their requested maximum burst rate /// - protected Dictionary m_children = new Dictionary(); + + protected Dictionary m_children = new Dictionary(); + +#region Properties /// /// The parent bucket of this bucket, or null if this bucket has no /// parent. The parent bucket will limit the aggregate bandwidth of all /// of its children buckets /// - public TokenBucket Parent { get; protected set; } - + protected TokenBucket m_parent; + public TokenBucket Parent + { + get { return m_parent; } + set { m_parent = value; } + } /// - /// Maximum burst rate in bytes per second. This is the maximum number - /// of tokens that can accumulate in the bucket at any one time. This + /// This is the maximum number + /// of tokens that can accumulate in the bucket at any one time. This /// also sets the total request for leaf nodes /// - protected Int64 m_burstRate; - public Int64 RequestedBurstRate + protected float m_burst; + + protected float m_maxDripRate = 0; + public virtual float MaxDripRate { - get { return m_burstRate; } - set { m_burstRate = (value < 0 ? 0 : value); } + get { return m_maxDripRate; } + set { m_maxDripRate = value; } } - public Int64 BurstRate + public float RequestedBurst { - get { - double rate = RequestedBurstRate * BurstRateModifier(); - if (rate < m_minimumDripRate * m_quantumsPerBurst) + get { return m_burst; } + set { + float rate = (value < 0 ? 0 : value); + if (rate < 1.5f * m_minimumDripRate) + rate = 1.5f * m_minimumDripRate; + else if (rate > m_minimumDripRate * m_quantumsPerBurst) rate = m_minimumDripRate * m_quantumsPerBurst; - - return (Int64) rate; + + m_burst = rate; + } + } + + public float Burst + { + get { + float rate = RequestedBurst * BurstModifier(); + if (rate < m_minimumDripRate) + rate = m_minimumDripRate; + return (float)rate; } } - + /// /// The requested drip rate for this particular bucket. /// /// /// 0 then TotalDripRequest is used instead. /// Can never be above MaxDripRate. - /// Tokens are added to the bucket at any time + /// Tokens are added to the bucket at any time /// is called, at the granularity of - /// the system tick interval (typically around 15-22ms) - /// FIXME: It is extremely confusing to be able to set a RequestedDripRate of 0 and then receive a positive - /// number on get if TotalDripRequest is set. This also stops us being able to retrieve the fact that - /// RequestedDripRate is set to 0. Really, this should always return m_dripRate and then we can get - /// (m_dripRate == 0 ? TotalDripRequest : m_dripRate) on some other properties. - /// - public virtual Int64 RequestedDripRate - { - get { return (m_dripRate == 0 ? TotalDripRequest : m_dripRate); } - set - { - if (value <= 0) - m_dripRate = 0; - else if (MaxDripRate > 0 && value > MaxDripRate) - m_dripRate = MaxDripRate; - else - m_dripRate = value; + /// the system tick interval (typically around 15-22ms) + protected float m_dripRate; - m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); + public float RequestedDripRate + { + get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); } + set { + m_dripRate = (value < 0 ? 0 : value); + m_totalDripRequest = m_dripRate; - if (Parent != null) - Parent.RegisterRequest(this, m_dripRate); + if (m_parent != null) + m_parent.RegisterRequest(this,m_dripRate); } } - /// - /// Gets the drip rate. - /// - /// - /// DripRate can never be above max drip rate or below min drip rate. - /// If we are a child bucket then the drip rate return is modifed by the total load on the capacity of the - /// parent bucket. - /// - public virtual Int64 DripRate + public float DripRate { - get - { - double rate; - - // FIXME: This doesn't properly work if we have a parent and children and a requested drip rate set - // on ourselves which is not equal to the child drip rates. - if (Parent == null) - { - if (TotalDripRequest > 0) - rate = Math.Min(RequestedDripRate, TotalDripRequest); - else - rate = RequestedDripRate; - } - else - { - rate = (double)RequestedDripRate * Parent.DripRateModifier(); - } + get { + float rate = Math.Min(RequestedDripRate,TotalDripRequest); + if (m_parent == null) + return rate; + rate *= m_parent.DripRateModifier(); if (rate < m_minimumDripRate) rate = m_minimumDripRate; - else if (MaxDripRate > 0 && rate > MaxDripRate) - rate = MaxDripRate; - return (Int64)rate; + return (float)rate; } } - protected Int64 m_dripRate; - - // - // The maximum rate for flow control. Drip rate can never be greater than this. - // - public Int64 MaxDripRate { get; set; } /// /// The current total of the requested maximum burst rates of children buckets. /// - public Int64 TotalDripRequest { get; protected set; } + protected float m_totalDripRequest; + public float TotalDripRequest + { + get { return m_totalDripRequest; } + set { m_totalDripRequest = value; } + } + +#endregion Properties + +#region Constructor + /// /// Default constructor @@ -194,20 +187,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Identifier for this token bucket /// Parent bucket if this is a child bucket, or /// null if this is a root bucket - /// - /// Requested rate that the bucket fills, in bytes per - /// second. If zero, the bucket always remains full. - /// - public TokenBucket(string identifier, TokenBucket parent, Int64 requestedDripRate, Int64 maxDripRate) + /// Maximum size of the bucket in bytes, or + /// zero if this bucket has no maximum capacity + /// Rate that the bucket fills, in bytes per + /// second. If zero, the bucket always remains full + public TokenBucket(TokenBucket parent, float dripRate, float MaxBurst) { - Identifier = identifier; + m_counter++; Parent = parent; - RequestedDripRate = requestedDripRate; - MaxDripRate = maxDripRate; - m_lastDrip = Util.EnvironmentTickCount(); + RequestedDripRate = dripRate; + RequestedBurst = MaxBurst; + m_lastDrip = Util.GetTimeStampMS() + 100000.0; // skip first drip } +#endregion Constructor + /// /// Compute a modifier for the MaxBurst rate. This is 1.0, meaning /// no modification if the requested bandwidth is less than the @@ -215,22 +210,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// hierarchy. However, if any of the parents is over-booked, then /// the modifier will be less than 1. /// - protected double DripRateModifier() + protected float DripRateModifier() { - Int64 driprate = DripRate; - double modifier = driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest; - -// if (DebugLevel > 0) -// m_log.DebugFormat( -// "[TOKEN BUCKET]: Returning drip modifier {0}/{1} = {2} from {3}", -// driprate, TotalDripRequest, modifier, Identifier); - - return modifier; + float driprate = DripRate; + return driprate >= TotalDripRequest ? 1.0f : (driprate / TotalDripRequest); } /// /// - protected double BurstRateModifier() + protected float BurstModifier() { // for now... burst rate is always m_quantumsPerBurst (constant) // larger than drip rate so the ratio of burst requests is the @@ -242,29 +230,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Register drip rate requested by a child of this throttle. Pass the /// changes up the hierarchy. /// - public void RegisterRequest(TokenBucket child, Int64 request) + public void RegisterRequest(TokenBucket child, float request) { lock (m_children) { m_children[child] = request; - TotalDripRequest = 0; - foreach (KeyValuePair cref in m_children) - TotalDripRequest += cref.Value; + m_totalDripRequest = 0; + foreach (KeyValuePair cref in m_children) + m_totalDripRequest += cref.Value; } - - // Pass the new values up to the parent - if (Parent != null) - { - Int64 effectiveDripRate; - - if (RequestedDripRate > 0) - effectiveDripRate = Math.Min(RequestedDripRate, TotalDripRequest); - else - effectiveDripRate = TotalDripRequest; - Parent.RegisterRequest(this, effectiveDripRate); - } + // Pass the new values up to the parent + if (m_parent != null) + m_parent.RegisterRequest(this, Math.Min(RequestedDripRate, TotalDripRequest)); } /// @@ -277,23 +256,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP { m_children.Remove(child); - TotalDripRequest = 0; - foreach (KeyValuePair cref in m_children) - TotalDripRequest += cref.Value; + m_totalDripRequest = 0; + foreach (KeyValuePair cref in m_children) + m_totalDripRequest += cref.Value; } // Pass the new values up to the parent if (Parent != null) Parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest)); } - + /// /// Remove a given number of tokens from the bucket /// /// Number of tokens to remove from the bucket /// True if the requested number of tokens were removed from /// the bucket, otherwise false - public bool RemoveTokens(Int64 amount) + public bool RemoveTokens(int amount) { // Deposit tokens for this interval Drip(); @@ -310,24 +289,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP return false; } - /// - /// Deposit tokens into the bucket from a child bucket that did - /// not use all of its available tokens - /// - protected void Deposit(Int64 count) + public bool CheckTokens(int amount) { - m_tokenCount += count; + return (m_tokenCount - amount >= 0); + } - // Deposit the overflow in the parent bucket, this is how we share - // unused bandwidth - Int64 burstrate = BurstRate; - if (m_tokenCount > burstrate) - m_tokenCount = burstrate; + public int GetCatBytesCanSend(int timeMS) + { +// return (int)(m_tokenCount + timeMS * m_dripRate * 1e-3); + return (int)(timeMS * DripRate * 1e-3); } /// /// Add tokens to the bucket over time. The number of tokens added each - /// call depends on the length of time that has passed since the last + /// call depends on the length of time that has passed since the last /// call to Drip /// /// True if tokens were added to the bucket, otherwise false @@ -337,128 +312,106 @@ namespace OpenSim.Region.ClientStack.LindenUDP // with no drip rate... if (DripRate == 0) { - m_log.WarnFormat("[TOKENBUCKET] something odd is happening and drip rate is 0 for {0}", Identifier); + m_log.WarnFormat("[TOKENBUCKET] something odd is happening and drip rate is 0 for {0}", m_counter); return; } - - // Determine the interval over which we are adding tokens, never add - // more than a single quantum of tokens - Int32 deltaMS = Math.Min(Util.EnvironmentTickCountSubtract(m_lastDrip), m_ticksPerQuantum); - m_lastDrip = Util.EnvironmentTickCount(); - - // This can be 0 in the very unusual case that the timer wrapped - // It can be 0 if we try add tokens at a sub-tick rate + + double now = Util.GetTimeStampMS(); + double deltaMS = now - m_lastDrip; + m_lastDrip = now; + if (deltaMS <= 0) return; - Deposit(deltaMS * DripRate / m_ticksPerQuantum); + m_tokenCount += (float)deltaMS * DripRate * m_timeScale; + + float burst = Burst; + if (m_tokenCount > burst) + m_tokenCount = burst; } } public class AdaptiveTokenBucket : TokenBucket { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); public bool AdaptiveEnabled { get; set; } /// - /// Target drip rate for this bucket. + /// The minimum rate for flow control. Minimum drip rate is one + /// packet per second. /// - /// Usually set by the client. If adaptive is enabled then throttles will increase until we reach this. - public Int64 TargetDripRate - { - get { return m_targetDripRate; } - set + + protected const float m_minimumFlow = 50000; + + // + // The maximum rate for flow control. Drip rate can never be + // greater than this. + // + + public override float MaxDripRate + { + get { return (m_maxDripRate == 0 ? m_totalDripRequest : m_maxDripRate); } + set { - m_targetDripRate = Math.Max(value, m_minimumFlow); + m_maxDripRate = (value == 0 ? m_totalDripRequest : Math.Max(value, m_minimumFlow)); } } - protected Int64 m_targetDripRate; + + private bool m_enabled = false; // - // Adjust drip rate in response to network conditions. + // Adjust drip rate in response to network conditions. // - public virtual Int64 AdjustedDripRate + public float AdjustedDripRate { get { return m_dripRate; } - set + set { - m_dripRate = OpenSim.Framework.Util.Clamp(value, m_minimumFlow, TargetDripRate); - m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); + m_dripRate = OpenSim.Framework.Util.Clamp(value, m_minimumFlow, MaxDripRate); - if (Parent != null) - Parent.RegisterRequest(this, m_dripRate); + if (m_parent != null) + m_parent.RegisterRequest(this, m_dripRate); } } - - /// - /// The minimum rate for adaptive flow control. - /// - protected Int64 m_minimumFlow = 32000; - /// - /// Constructor for the AdaptiveTokenBucket class - /// Unique identifier for the client - /// Parent bucket in the hierarchy - /// - /// The ceiling rate for adaptation - /// The floor rate for adaptation - /// - public AdaptiveTokenBucket(string identifier, TokenBucket parent, Int64 requestedDripRate, Int64 maxDripRate, Int64 minDripRate, bool enabled) - : base(identifier, parent, requestedDripRate, maxDripRate) - { - AdaptiveEnabled = enabled; - if (AdaptiveEnabled) - { -// m_log.DebugFormat("[TOKENBUCKET]: Adaptive throttle enabled"); - m_minimumFlow = minDripRate; - TargetDripRate = m_minimumFlow; - AdjustedDripRate = m_minimumFlow; - } - } - - /// - /// Reliable packets sent to the client for which we never received an ack adjust the drip rate down. - /// Number of packets that expired without successful delivery - /// - public void ExpirePackets(Int32 packets) + // + // + // + public AdaptiveTokenBucket(TokenBucket parent, float maxDripRate, float maxBurst, bool enabled) + : base(parent, maxDripRate, maxBurst) { - if (AdaptiveEnabled) - { - if (DebugLevel > 0) - m_log.WarnFormat( - "[ADAPTIVEBUCKET] drop {0} by {1} expired packets for {2}", - AdjustedDripRate, packets, Identifier); + m_enabled = enabled; - // AdjustedDripRate = (Int64) (AdjustedDripRate / Math.Pow(2,packets)); + m_maxDripRate = (maxDripRate == 0 ? m_totalDripRequest : Math.Max(maxDripRate, m_minimumFlow)); - // Compute the fallback solely on the rate allocated beyond the minimum, this - // should smooth out the fallback to the minimum rate - AdjustedDripRate = m_minimumFlow + (Int64) ((AdjustedDripRate - m_minimumFlow) / Math.Pow(2, packets)); - } + if (enabled) + m_dripRate = m_maxDripRate * .5f; + else + m_dripRate = m_maxDripRate; + if (m_parent != null) + m_parent.RegisterRequest(this, m_dripRate); } /// - /// Reliable packets acked by the client adjust the drip rate up. - /// Number of packets successfully acknowledged + /// Reliable packets sent to the client for which we never received an ack adjust the drip rate down. + /// Number of packets that expired without successful delivery /// - public void AcknowledgePackets(Int32 packets) + public void ExpirePackets(Int32 count) { - if (AdaptiveEnabled) - AdjustedDripRate = AdjustedDripRate + packets * LLUDPServer.MTU; + // m_log.WarnFormat("[ADAPTIVEBUCKET] drop {0} by {1} expired packets",AdjustedDripRate,count); + if (m_enabled) + AdjustedDripRate = (Int64)(AdjustedDripRate / Math.Pow(2, count)); } - /// - /// Adjust the minimum flow level for the adaptive throttle, this will drop adjusted - /// throttles back to the minimum levels - /// minDripRate--the new minimum flow - /// - public void ResetMinimumAdaptiveFlow(Int64 minDripRate) + // + // + // + public void AcknowledgePackets(Int32 count) { - m_minimumFlow = minDripRate; - TargetDripRate = m_minimumFlow; - AdjustedDripRate = m_minimumFlow; + if (m_enabled) + AdjustedDripRate = AdjustedDripRate + count; } } -} \ No newline at end of file +} -- cgit v1.1