Do some simple queue empty checks in the main outgoing udp loop instead of always performing these on a separate fired thread.

This appears to improve cpu usage since launching a new thread is more expensive than performing a small amount of inline logic.
However, needs testing at scale.
cpu-performance
Justin Clark-Casey (justincc) 2013-07-18 21:28:36 +01:00
parent 553d9cc5d2
commit 8c6761c152
5 changed files with 92 additions and 22 deletions

View File

@ -485,6 +485,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_udpServer = udpServer;
m_udpClient = udpClient;
m_udpClient.OnQueueEmpty += HandleQueueEmpty;
m_udpClient.HasUpdates += HandleHasUpdates;
m_udpClient.OnPacketStats += PopulateStats;
m_prioritizer = new Prioritizer(m_scene);
@ -4133,8 +4134,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories)
{
// if (!m_udpServer.IsRunningOutbound)
// return;
if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
{
// if (!m_udpServer.IsRunningOutbound)
// return;
if (m_maxUpdates == 0 || m_LastQueueFill == 0)
{
m_maxUpdates = m_udpServer.PrimUpdatesPerCallback;
@ -4160,6 +4167,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit);
}
internal bool HandleHasUpdates(ThrottleOutPacketTypeFlags categories)
{
bool hasUpdates = false;
if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
{
if (m_entityUpdates.Count > 0)
hasUpdates = true;
else if (m_entityProps.Count > 0)
hasUpdates = true;
}
if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0)
{
if (ImageManager.HasUpdates())
hasUpdates = true;
}
return hasUpdates;
}
public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID)
{
AssetUploadCompletePacket newPack = new AssetUploadCompletePacket();

View File

@ -206,6 +206,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
}
public bool HasUpdates()
{
J2KImage image = GetHighestPriorityImage();
return image != null && image.IsDecoded;
}
public bool ProcessImageQueue(int packetsToSend)
{
int packetsSent = 0;

View File

@ -31,6 +31,7 @@ using System.Net;
using System.Threading;
using log4net;
using OpenSim.Framework;
using OpenSim.Framework.Monitoring;
using OpenMetaverse;
using OpenMetaverse.Packets;
@ -81,6 +82,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// hooked to put more data on the empty queue</summary>
public event QueueEmpty OnQueueEmpty;
public event Func<ThrottleOutPacketTypeFlags, bool> HasUpdates;
/// <summary>AgentID for this client</summary>
public readonly UUID AgentID;
/// <summary>The remote address of the connected client</summary>
@ -613,14 +616,37 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <param name="categories">Throttle categories to fire the callback for</param>
private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories)
{
if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
// if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
if (!m_isQueueEmptyRunning && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
{
m_isQueueEmptyRunning = true;
int start = Environment.TickCount & Int32.MaxValue;
const int MIN_CALLBACK_MS = 30;
m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
if (m_nextOnQueueEmpty == 0)
m_nextOnQueueEmpty = 1;
// Use a value of 0 to signal that FireQueueEmpty is running
m_nextOnQueueEmpty = 0;
// m_nextOnQueueEmpty = 0;
m_categories = categories;
if (HasUpdates(m_categories))
{
// Asynchronously run the callback
Util.FireAndForget(FireQueueEmpty, categories);
}
else
{
m_isQueueEmptyRunning = false;
}
}
}
private bool m_isQueueEmptyRunning;
private ThrottleOutPacketTypeFlags m_categories = 0;
/// <summary>
/// Fires the OnQueueEmpty callback and sets the minimum time that it
@ -631,22 +657,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// signature</param>
private void FireQueueEmpty(object o)
{
const int MIN_CALLBACK_MS = 30;
// int start = Environment.TickCount & Int32.MaxValue;
// const int MIN_CALLBACK_MS = 30;
// if (m_udpServer.IsRunningOutbound)
// {
ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o;
QueueEmpty callback = OnQueueEmpty;
int start = Environment.TickCount & Int32.MaxValue;
if (callback != null)
{
// if (m_udpServer.IsRunningOutbound)
// {
try { callback(categories); }
catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); }
// }
}
// }
m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
if (m_nextOnQueueEmpty == 0)
m_nextOnQueueEmpty = 1;
// m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
// if (m_nextOnQueueEmpty == 0)
// m_nextOnQueueEmpty = 1;
// }
m_isQueueEmptyRunning = false;
}
/// <summary>

View File

@ -1662,8 +1662,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// Action generic every round
Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler;
// while (true)
while (base.IsRunningOutbound)
while (true)
// while (base.IsRunningOutbound)
{
try
{

View File

@ -308,8 +308,8 @@ namespace OpenMetaverse
public void AsyncBeginSend(UDPPacketBuffer buf)
{
if (IsRunningOutbound)
{
// if (IsRunningOutbound)
// {
try
{
m_udpSocket.BeginSendTo(
@ -323,7 +323,7 @@ namespace OpenMetaverse
}
catch (SocketException) { }
catch (ObjectDisposedException) { }
}
// }
}
void AsyncEndSend(IAsyncResult result)