* 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 basisprioritization
parent
d1ab11dc2a
commit
d38f33736c
|
@ -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;
|
||||||
|
|
|
@ -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,45 +772,27 @@ 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;
|
Thread.Sleep(20);
|
||||||
elapsedMS -= 100;
|
|
||||||
++elapsed100MS;
|
|
||||||
}
|
}
|
||||||
// Check for pending outgoing ACKs every 500ms
|
catch (Exception ex)
|
||||||
if (elapsed100MS >= 5)
|
|
||||||
{
|
{
|
||||||
sendAcks = true;
|
m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler loop threw an exception: " + ex.Message, ex);
|
||||||
elapsed100MS = 0;
|
}
|
||||||
++elapsed500MS;
|
|
||||||
}
|
}
|
||||||
// Send pings to clients every 5000ms
|
|
||||||
if (elapsed500MS >= 10)
|
|
||||||
{
|
|
||||||
sendPings = true;
|
|
||||||
elapsed500MS = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_scene.ClientManager.ForEachSync(
|
private void ClientOutgoingPacketHandler(IClientAPI client)
|
||||||
delegate(IClientAPI client)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -815,36 +800,41 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
{
|
{
|
||||||
LLUDPClient udpClient = ((LLClientView)client).UDPClient;
|
LLUDPClient udpClient = ((LLClientView)client).UDPClient;
|
||||||
|
|
||||||
|
int thisTick = Environment.TickCount & Int32.MaxValue;
|
||||||
|
int elapsedMS = thisTick - udpClient.TickLastOutgoingPacketHandler;
|
||||||
|
|
||||||
if (udpClient.IsConnected)
|
if (udpClient.IsConnected)
|
||||||
{
|
{
|
||||||
if (udpClient.DequeueOutgoing())
|
// Check for pending outgoing resends every 100ms
|
||||||
packetSent = true;
|
if (elapsedMS >= 100)
|
||||||
if (resendUnacked)
|
{
|
||||||
ResendUnacked(udpClient);
|
ResendUnacked(udpClient);
|
||||||
if (sendAcks)
|
|
||||||
|
// Check for pending outgoing ACKs every 500ms
|
||||||
|
if (elapsedMS >= 500)
|
||||||
{
|
{
|
||||||
SendAcks(udpClient);
|
SendAcks(udpClient);
|
||||||
udpClient.SendPacketStats();
|
|
||||||
}
|
// Send pings to clients every 5000ms
|
||||||
if (sendPings)
|
if (elapsedMS >= 5000)
|
||||||
|
{
|
||||||
SendPing(udpClient);
|
SendPing(udpClient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler iteration for " + client.Name + " threw an exception: " + ex.Message, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!packetSent)
|
// Dequeue any outgoing packets that are within the throttle limits
|
||||||
Thread.Sleep(20);
|
if (udpClient.DequeueOutgoing())
|
||||||
|
m_packetSentLastLoop = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
udpClient.TickLastOutgoingPacketHandler = thisTick;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler loop threw an exception: " + ex.Message, ex);
|
m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler iteration for " + client.Name +
|
||||||
}
|
" threw an exception: " + ex.Message, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue