From 8c6761c152d95b8c22cb140a26c7bfc214a74963 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 18 Jul 2013 21:28:36 +0100 Subject: [PATCH] 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. --- .../ClientStack/Linden/UDP/LLClientView.cs | 28 ++++++++ .../ClientStack/Linden/UDP/LLImageManager.cs | 7 ++ .../ClientStack/Linden/UDP/LLUDPClient.cs | 69 ++++++++++++++----- .../ClientStack/Linden/UDP/LLUDPServer.cs | 4 +- .../ClientStack/Linden/UDP/OpenSimUDPBase.cs | 6 +- 5 files changed, 92 insertions(+), 22 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 7229d7c15e..711a574521 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -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(); diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs index 073c357d1a..41dd4d115a 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs @@ -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; diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs index 7749446f52..202cc625a2 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs @@ -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 public event QueueEmpty OnQueueEmpty; + public event Func HasUpdates; + /// AgentID for this client public readonly UUID AgentID; /// The remote address of the connected client @@ -613,15 +616,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Throttle categories to fire the callback for 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; - // Asynchronously run the callback - Util.FireAndForget(FireQueueEmpty, categories); +// 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; + /// /// Fires the OnQueueEmpty callback and sets the minimum time that it /// can be called again @@ -631,22 +657,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// signature private void FireQueueEmpty(object o) { - const int MIN_CALLBACK_MS = 30; +// int start = Environment.TickCount & Int32.MaxValue; +// const int MIN_CALLBACK_MS = 30; - ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; - QueueEmpty callback = OnQueueEmpty; - - int start = Environment.TickCount & Int32.MaxValue; +// if (m_udpServer.IsRunningOutbound) +// { + ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; + QueueEmpty callback = OnQueueEmpty; - if (callback != null) - { - try { callback(categories); } - catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); } - } + 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; } /// diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 54cafb2bdf..e871ca287f 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1662,8 +1662,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Action generic every round Action clientPacketHandler = ClientOutgoingPacketHandler; -// while (true) - while (base.IsRunningOutbound) + while (true) +// while (base.IsRunningOutbound) { try { diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs index f143c32bb8..512f60df20 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs @@ -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)