Fix recent regression where adaptive throttles stopped adjusting.

Extends regression tests to test response of adaptive throttles to ack'ed and expired packets.
ghosts
Justin Clark-Casey (justincc) 2014-10-28 00:44:03 +00:00
parent 096aecc097
commit 1c12930c03
3 changed files with 62 additions and 50 deletions

View File

@ -447,31 +447,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
long total = resend + land + wind + cloud + task + texture + asset; long total = resend + land + wind + cloud + task + texture + asset;
m_throttleClient.TargetDripRate = total; m_throttleClient.TargetDripRate = total;
} }
else
{
TokenBucket bucket;
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; TokenBucket bucket;
bucket.RequestedDripRate = resend;
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land]; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend];
bucket.RequestedDripRate = land; bucket.RequestedDripRate = resend;
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind]; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land];
bucket.RequestedDripRate = wind; bucket.RequestedDripRate = land;
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud]; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind];
bucket.RequestedDripRate = cloud; bucket.RequestedDripRate = wind;
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset]; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud];
bucket.RequestedDripRate = asset; bucket.RequestedDripRate = cloud;
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset];
bucket.RequestedDripRate = task; bucket.RequestedDripRate = asset;
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task];
bucket.RequestedDripRate = texture; bucket.RequestedDripRate = task;
}
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture];
bucket.RequestedDripRate = texture;
// Reset the packed throttles cached data // Reset the packed throttles cached data
m_packedThrottles = null; m_packedThrottles = null;

View File

@ -184,7 +184,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
udpServer.Throttle.DebugLevel = 1; udpServer.Throttle.DebugLevel = 1;
udpClient.ThrottleDebugLevel = 1; udpClient.ThrottleDebugLevel = 1;
// Total is 28000 // Total is 280000
int resendBytes = 10000; int resendBytes = 10000;
int landBytes = 20000; int landBytes = 20000;
int windBytes = 30000; int windBytes = 30000;
@ -192,24 +192,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
int taskBytes = 50000; int taskBytes = 50000;
int textureBytes = 60000; int textureBytes = 60000;
int assetBytes = 70000; int assetBytes = 70000;
int totalBytes = resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes;
SetThrottles( SetThrottles(
udpClient, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); udpClient, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
// We expect individual throttle changes to currently have no effect under adaptive, since this is managed // Ratio of current adaptive drip rate to requested bytes
// purely by that throttle. However, we expect the max to change. // XXX: Should hard code this as below so we don't rely on values given by tested code to construct
// XXX: At the moment we check against defaults, but at some point there should be a better test to // expected values.
// active see change over time. double commitRatio = (double)udpClient.FlowThrottle.AdjustedDripRate / udpClient.FlowThrottle.TargetDripRate;
ThrottleRates defaultRates = udpServer.ThrottleRates;
// Current total is 66750
int totalBytes = defaultRates.Resend + defaultRates.Land + defaultRates.Wind + defaultRates.Cloud + defaultRates.Task + defaultRates.Texture + defaultRates.Asset;
int totalMaxBytes = resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes;
AssertThrottles( AssertThrottles(
udpClient, udpClient,
defaultRates.Resend, defaultRates.Land, defaultRates.Wind, defaultRates.Cloud, defaultRates.Task, LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio,
defaultRates.Texture, defaultRates.Asset, totalBytes, totalMaxBytes, 0); textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0);
// Test an increase in target throttle
udpClient.FlowThrottle.AcknowledgePackets(35000);
commitRatio = 0.2;
AssertThrottles(
udpClient,
resendBytes * commitRatio, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio,
textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0);
// Test a decrease in target throttle
udpClient.FlowThrottle.ExpirePackets(1);
commitRatio = 0.1;
AssertThrottles(
udpClient,
LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio,
textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0);
} }
/// <summary> /// <summary>
@ -376,9 +390,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
{ {
ClientInfo ci = udpClient.GetClientInfo(); ClientInfo ci = udpClient.GetClientInfo();
// Console.WriteLine( // Console.WriteLine(
// "Resend={0}, Land={1}, Wind={2}, Cloud={3}, Task={4}, Texture={5}, Asset={6}, TOTAL = {7}", // "Resend={0}, Land={1}, Wind={2}, Cloud={3}, Task={4}, Texture={5}, Asset={6}, TOTAL = {7}",
// ci.resendThrottle, ci.landThrottle, ci.windThrottle, ci.cloudThrottle, ci.taskThrottle, ci.textureThrottle, ci.assetThrottle, ci.totalThrottle); // ci.resendThrottle, ci.landThrottle, ci.windThrottle, ci.cloudThrottle, ci.taskThrottle, ci.textureThrottle, ci.assetThrottle, ci.totalThrottle);
Assert.AreEqual((int)resendBytes, ci.resendThrottle, "Resend"); Assert.AreEqual((int)resendBytes, ci.resendThrottle, "Resend");
Assert.AreEqual((int)landBytes, ci.landThrottle, "Land"); Assert.AreEqual((int)landBytes, ci.landThrottle, "Land");

View File

@ -77,8 +77,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// </summary> /// </summary>
protected Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>(); protected Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>();
#region Properties
/// <summary> /// <summary>
/// The parent bucket of this bucket, or null if this bucket has no /// The parent bucket of this bucket, or null if this bucket has no
/// parent. The parent bucket will limit the aggregate bandwidth of all /// parent. The parent bucket will limit the aggregate bandwidth of all
@ -123,7 +121,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// RequestedDripRate is set to 0. Really, this should always return m_dripRate and then we can get /// 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. /// (m_dripRate == 0 ? TotalDripRequest : m_dripRate) on some other properties.
/// </remarks> /// </remarks>
protected Int64 m_dripRate;
public virtual Int64 RequestedDripRate public virtual Int64 RequestedDripRate
{ {
get { return (m_dripRate == 0 ? TotalDripRequest : m_dripRate); } get { return (m_dripRate == 0 ? TotalDripRequest : m_dripRate); }
@ -179,6 +176,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
return (Int64)rate; return (Int64)rate;
} }
} }
protected Int64 m_dripRate;
// <summary> // <summary>
// The maximum rate for flow control. Drip rate can never be greater than this. // The maximum rate for flow control. Drip rate can never be greater than this.
@ -190,30 +188,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// </summary> /// </summary>
public Int64 TotalDripRequest { get; protected set; } public Int64 TotalDripRequest { get; protected set; }
#endregion Properties
#region Constructor
/// <summary> /// <summary>
/// Default constructor /// Default constructor
/// </summary> /// </summary>
/// <param name="identifier">Identifier for this token bucket</param> /// <param name="identifier">Identifier for this token bucket</param>
/// <param name="parent">Parent bucket if this is a child bucket, or /// <param name="parent">Parent bucket if this is a child bucket, or
/// null if this is a root bucket</param> /// null if this is a root bucket</param>
/// <param name="dripRate">Rate that the bucket fills, in bytes per /// <param name="requestedDripRate">
/// second. If zero, the bucket always remains full</param> /// Requested rate that the bucket fills, in bytes per
public TokenBucket(string identifier, TokenBucket parent, Int64 dripRate, Int64 maxDripRate) /// second. If zero, the bucket always remains full.
/// </param>
public TokenBucket(string identifier, TokenBucket parent, Int64 requestedDripRate, Int64 maxDripRate)
{ {
Identifier = identifier; Identifier = identifier;
Parent = parent; Parent = parent;
RequestedDripRate = dripRate; RequestedDripRate = requestedDripRate;
MaxDripRate = maxDripRate; MaxDripRate = maxDripRate;
m_lastDrip = Util.EnvironmentTickCount(); m_lastDrip = Util.EnvironmentTickCount();
} }
#endregion Constructor
/// <summary> /// <summary>
/// Compute a modifier for the MaxBurst rate. This is 1.0, meaning /// Compute a modifier for the MaxBurst rate. This is 1.0, meaning
/// no modification if the requested bandwidth is less than the /// no modification if the requested bandwidth is less than the
@ -374,7 +368,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
public Int64 TargetDripRate public Int64 TargetDripRate
{ {
get { return m_targetDripRate; } get { return m_targetDripRate; }
set { m_targetDripRate = Math.Max(0, value); } set
{
m_targetDripRate = Math.Max(value, m_minimumFlow);
}
} }
protected Int64 m_targetDripRate; protected Int64 m_targetDripRate;
@ -384,9 +381,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
public virtual Int64 AdjustedDripRate public virtual Int64 AdjustedDripRate
{ {
get { return m_dripRate; } get { return m_dripRate; }
set { set
{
m_dripRate = OpenSim.Framework.Util.Clamp<Int64>(value, m_minimumFlow, TargetDripRate); m_dripRate = OpenSim.Framework.Util.Clamp<Int64>(value, m_minimumFlow, TargetDripRate);
m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst);
if (Parent != null) if (Parent != null)
Parent.RegisterRequest(this, m_dripRate); Parent.RegisterRequest(this, m_dripRate);
} }
@ -399,14 +398,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// </summary> /// </summary>
protected const Int64 m_minimumFlow = m_minimumDripRate * 15; protected const Int64 m_minimumFlow = m_minimumDripRate * 15;
public AdaptiveTokenBucket(string identifier, TokenBucket parent, Int64 dripRate, Int64 maxDripRate, bool enabled) public AdaptiveTokenBucket(string identifier, TokenBucket parent, Int64 requestedDripRate, Int64 maxDripRate, bool enabled)
: base(identifier, parent, dripRate, maxDripRate) : base(identifier, parent, requestedDripRate, maxDripRate)
{ {
AdaptiveEnabled = enabled; AdaptiveEnabled = enabled;
if (AdaptiveEnabled) if (AdaptiveEnabled)
{ {
// m_log.DebugFormat("[TOKENBUCKET]: Adaptive throttle enabled"); // m_log.DebugFormat("[TOKENBUCKET]: Adaptive throttle enabled");
TargetDripRate = m_minimumFlow;
AdjustedDripRate = m_minimumFlow; AdjustedDripRate = m_minimumFlow;
} }
} }