* Removed the throttle speed optimizations to see if it brings stability back

* Changed the outgoing packet handler to use a real function instead of a closure and to track time on a per-client basis instead of a global basis
prioritization
John Hurliman 2009-10-20 14:41:20 -07:00
parent d1ab11dc2a
commit d38f33736c
2 changed files with 72 additions and 75 deletions

View File

@ -101,6 +101,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
public bool IsPaused = true; public bool IsPaused = true;
/// <summary>Environment.TickCount when the last packet was received for this client</summary> /// <summary>Environment.TickCount when the last packet was received for this client</summary>
public int TickLastPacketReceived; public int TickLastPacketReceived;
/// <summary>Environment.TickCount of the last time the outgoing packet handler executed for this client</summary>
public int TickLastOutgoingPacketHandler;
/// <summary>Timer granularity. This is set to the measured resolution of Environment.TickCount</summary> /// <summary>Timer granularity. This is set to the measured resolution of Environment.TickCount</summary>
public readonly float G; public readonly float G;
@ -320,27 +322,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
bucket.MaxBurst = total; bucket.MaxBurst = total;
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend];
bucket.DripRate = bucket.MaxBurst = resend; bucket.DripRate = resend;
bucket.MaxBurst = resend;
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land]; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land];
bucket.DripRate = bucket.MaxBurst = land; bucket.DripRate = land;
bucket.MaxBurst = land;
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind]; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind];
bucket.DripRate = bucket.MaxBurst = wind; bucket.DripRate = wind;
bucket.MaxBurst = wind;
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud]; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud];
bucket.DripRate = bucket.MaxBurst = cloud; bucket.DripRate = cloud;
bucket.MaxBurst = cloud;
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset]; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset];
bucket.DripRate = bucket.MaxBurst = asset; bucket.DripRate = asset;
bucket.MaxBurst = asset;
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task];
bucket.DripRate = task + state + texture; bucket.DripRate = task + state;
bucket.MaxBurst = task + state + texture; bucket.MaxBurst = task + state;
bucket = m_throttleCategories[(int)ThrottleOutPacketType.State]; bucket = m_throttleCategories[(int)ThrottleOutPacketType.State];
bucket.DripRate = state + texture; bucket.DripRate = state;
bucket.MaxBurst = state + texture; bucket.MaxBurst = state;
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture];
bucket.DripRate = texture; bucket.DripRate = texture;

View File

@ -118,6 +118,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private int m_recvBufferSize; private int m_recvBufferSize;
/// <summary>Flag to process packets asynchronously or synchronously</summary> /// <summary>Flag to process packets asynchronously or synchronously</summary>
private bool m_asyncPacketHandling; private bool m_asyncPacketHandling;
/// <summary>Track whether or not a packet was sent in the
/// OutgoingPacketHandler loop so we know when to sleep</summary>
private bool m_packetSentLastLoop;
/// <summary>The measured resolution of Environment.TickCount</summary> /// <summary>The measured resolution of Environment.TickCount</summary>
public float TickCountResolution { get { return m_tickCountResolution; } } public float TickCountResolution { get { return m_tickCountResolution; } }
@ -745,10 +748,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
while (base.IsRunning) while (base.IsRunning)
{ {
IncomingPacket incomingPacket = null;
try try
{ {
IncomingPacket incomingPacket = null;
if (packetInbox.Dequeue(100, ref incomingPacket)) if (packetInbox.Dequeue(100, ref incomingPacket))
Util.FireAndForget(ProcessInPacket, incomingPacket); Util.FireAndForget(ProcessInPacket, incomingPacket);
} }
@ -769,76 +772,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// on to en-US to avoid number parsing issues // on to en-US to avoid number parsing issues
Culture.SetCurrentCulture(); Culture.SetCurrentCulture();
int now = Environment.TickCount;
int elapsedMS = 0;
int elapsed100MS = 0;
int elapsed500MS = 0;
while (base.IsRunning) while (base.IsRunning)
{ {
try try
{ {
bool resendUnacked = false; m_packetSentLastLoop = false;
bool sendAcks = false;
bool sendPings = false;
bool packetSent = false;
elapsedMS += Environment.TickCount - now; m_scene.ClientManager.ForEachSync(ClientOutgoingPacketHandler);
// Check for pending outgoing resends every 100ms // If no packets at all were sent, sleep to avoid chewing up CPU cycles
if (elapsedMS >= 100) // when there is nothing to do
{ if (!m_packetSentLastLoop)
resendUnacked = true;
elapsedMS -= 100;
++elapsed100MS;
}
// Check for pending outgoing ACKs every 500ms
if (elapsed100MS >= 5)
{
sendAcks = true;
elapsed100MS = 0;
++elapsed500MS;
}
// Send pings to clients every 5000ms
if (elapsed500MS >= 10)
{
sendPings = true;
elapsed500MS = 0;
}
m_scene.ClientManager.ForEachSync(
delegate(IClientAPI client)
{
try
{
if (client is LLClientView)
{
LLUDPClient udpClient = ((LLClientView)client).UDPClient;
if (udpClient.IsConnected)
{
if (udpClient.DequeueOutgoing())
packetSent = true;
if (resendUnacked)
ResendUnacked(udpClient);
if (sendAcks)
{
SendAcks(udpClient);
udpClient.SendPacketStats();
}
if (sendPings)
SendPing(udpClient);
}
}
}
catch (Exception ex)
{
m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler iteration for " + client.Name + " threw an exception: " + ex.Message, ex);
}
}
);
if (!packetSent)
Thread.Sleep(20); Thread.Sleep(20);
} }
catch (Exception ex) catch (Exception ex)
@ -848,6 +792,52 @@ namespace OpenSim.Region.ClientStack.LindenUDP
} }
} }
private void ClientOutgoingPacketHandler(IClientAPI client)
{
try
{
if (client is LLClientView)
{
LLUDPClient udpClient = ((LLClientView)client).UDPClient;
int thisTick = Environment.TickCount & Int32.MaxValue;
int elapsedMS = thisTick - udpClient.TickLastOutgoingPacketHandler;
if (udpClient.IsConnected)
{
// Check for pending outgoing resends every 100ms
if (elapsedMS >= 100)
{
ResendUnacked(udpClient);
// Check for pending outgoing ACKs every 500ms
if (elapsedMS >= 500)
{
SendAcks(udpClient);
// Send pings to clients every 5000ms
if (elapsedMS >= 5000)
{
SendPing(udpClient);
}
}
}
// Dequeue any outgoing packets that are within the throttle limits
if (udpClient.DequeueOutgoing())
m_packetSentLastLoop = true;
}
udpClient.TickLastOutgoingPacketHandler = thisTick;
}
}
catch (Exception ex)
{
m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler iteration for " + client.Name +
" threw an exception: " + ex.Message, ex);
}
}
private void ProcessInPacket(object state) private void ProcessInPacket(object state)
{ {
IncomingPacket incomingPacket = (IncomingPacket)state; IncomingPacket incomingPacket = (IncomingPacket)state;