From 05508b5c5610c5f56233d26aba46ee361fcab667 Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Tue, 30 Sep 2014 18:12:51 +0100
Subject: Add "debug lludp throttle log <level> <avatar-first-name>
 <avatar-last-name>" to control extra throttle related debug logging.

---
 .../Region/ClientStack/Linden/UDP/LLUDPClient.cs   | 47 ++++++++++++++++++---
 .../Region/ClientStack/Linden/UDP/LLUDPServer.cs   | 49 +++++++++++++++++++++-
 .../Region/ClientStack/Linden/UDP/TokenBucket.cs   | 33 +++++++++------
 3 files changed, 111 insertions(+), 18 deletions(-)

(limited to 'OpenSim')

diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
index 9dc9e0d..d8ca343 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
@@ -82,6 +82,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
         /// <remarks>Any level above 0 will turn on logging.</remarks>
         public int DebugDataOutLevel { get; set; }
 
+        /// <summary>
+        /// Controls whether information is logged about each outbound packet immediately before it is sent.  For debug purposes.
+        /// </summary>
+        /// <remarks>Any level above 0 will turn on logging.</remarks>
+        public int ThrottleDebugLevel 
+        { 
+            get
+            {
+                return m_throttleDebugLevel;
+            }
+
+            set
+            {
+                m_throttleDebugLevel = value;
+                m_throttleClient.DebugLevel = m_throttleDebugLevel;
+                m_throttleCategory.DebugLevel = m_throttleDebugLevel;
+                foreach (TokenBucket tb in m_throttleCategories)
+                    tb.DebugLevel = m_throttleDebugLevel;
+            }
+        }
+        private int m_throttleDebugLevel;
+
         /// <summary>Fired when updated networking stats are produced for this client</summary>
         public event PacketStats OnPacketStats;
         /// <summary>Fired when the queue for a packet category is empty. This event can be
@@ -207,9 +229,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
                 m_maxRTO = maxRTO;
 
             // Create a token bucket throttle for this client that has the scene token bucket as a parent
-            m_throttleClient = new AdaptiveTokenBucket(parentThrottle, rates.Total, rates.AdaptiveThrottlesEnabled);
+            m_throttleClient 
+                = new AdaptiveTokenBucket(
+                    string.Format("adaptive throttle for {0} in {1}", AgentID, server.Scene.Name), 
+                    parentThrottle, rates.Total, rates.AdaptiveThrottlesEnabled);
+
             // Create a token bucket throttle for the total category with the client bucket as a throttle
-            m_throttleCategory = new TokenBucket(m_throttleClient, 0);
+            m_throttleCategory 
+                = new TokenBucket(
+                    string.Format("total throttle for {0} in {1}", AgentID, server.Scene.Name), 
+                    m_throttleClient, 0);
+
             // Create an array of token buckets for this clients different throttle categories
             m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
 
@@ -221,8 +251,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 
                 // Initialize the packet outboxes, where packets sit while they are waiting for tokens
                 m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>();
+
                 // Initialize the token buckets that control the throttling for each category
-                m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetRate(type));
+                m_throttleCategories[i]
+                    = new TokenBucket(
+                        string.Format("{0} throttle for {1} in {2}", type, AgentID, server.Scene.Name), 
+                    m_throttleCategory, rates.GetRate(type));
             }
 
             // Default the retransmission timeout to one second
@@ -371,8 +405,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
             texture = (int)((1 - m_cannibalrate) * texture);
             
             //int total = resend + land + wind + cloud + task + texture + asset;
-            //m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, Total={8}",
-            //                  AgentID, resend, land, wind, cloud, task, texture, asset, total);
+
+            if (ThrottleDebugLevel > 0)
+                m_log.DebugFormat(
+                    "[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}",
+                    AgentID, m_udpServer.Scene.Name, resend, land, wind, cloud, task, texture, asset);
 
             // Update the token buckets with new throttle values
             TokenBucket bucket;
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index 0393a29..e45de51 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -434,7 +434,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
             }
             #endregion BinaryStats
 
-            m_throttle = new TokenBucket(null, sceneThrottleBps);
+            // FIXME: Can't add info here because don't know scene yet.
+//            m_throttle 
+//                = new TokenBucket(
+//                    string.Format("server throttle bucket for {0}", Scene.Name), null, sceneThrottleBps);
+
+            m_throttle = new TokenBucket("server throttle bucket", null, sceneThrottleBps);
+
             ThrottleRates = new ThrottleRates(configSource);
 
             if (usePools)
@@ -758,6 +764,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
             MainConsole.Instance.Commands.AddCommand(
                 "Debug",
                 false,
+                "debug lludp throttle log",
+                "debug lludp throttle log <level> <avatar-first-name> <avatar-last-name>",
+                "Change debug logging level for throttles.",
+                "If level >= 0 then throttle debug logging is performed.\n"
+                + "If level <= 0 then no throttle debug logging is performed.",
+                HandleThrottleCommand);
+
+            MainConsole.Instance.Commands.AddCommand(
+                "Debug",
+                false,
                 "debug lludp toggle agentupdate",
                 "debug lludp toggle agentupdate",
                 "Toggle whether agentupdate packets are processed or simply discarded.",
@@ -795,6 +811,37 @@ namespace OpenSim.Region.ClientStack.LindenUDP
             });
         }
 
+        private void HandleThrottleCommand(string module, string[] args)
+        {
+            if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != Scene)
+                return;
+
+            if (args.Length != 7)
+            {
+                MainConsole.Instance.OutputFormat("Usage: debug lludp throttle log <level> <avatar-first-name> <avatar-last-name>");
+                return;
+            }
+
+            int level;
+            if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out level))
+                return;
+
+            string firstName = args[5];
+            string lastName = args[6];
+
+            Scene.ForEachScenePresence(sp =>
+            {
+                if (sp.Firstname == firstName && sp.Lastname == lastName)
+                {
+                    MainConsole.Instance.OutputFormat(
+                        "Throttle log level for {0} ({1}) set to {2} in {3}",
+                        sp.Name, sp.IsChildAgent ? "child" : "root", level, Scene.Name);
+
+                    ((LLClientView)sp.ControllingClient).UDPClient.ThrottleDebugLevel = level;
+                }
+            });
+        }
+
         private void HandlePacketCommand(string module, string[] args)
         {
             if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != Scene)
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
index 0d4f549..658d9bb 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
@@ -43,8 +43,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
     {
         private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
         private static Int32 m_counter = 0;
-        
-//        private Int32 m_identifier;
+
+        private LLUDPClient m_client;
+
+        public string Identifier { get; private set; }
+
+        public int DebugLevel { get; set; }
         
         /// <summary>
         /// Number of ticks (ms) per quantum, drip rate and max burst
@@ -165,16 +169,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
         /// <summary>
         /// Default constructor
         /// </summary>
+        /// <param name="identifier">Identifier for this token bucket</param>
         /// <param name="parent">Parent bucket if this is a child bucket, or
         /// null if this is a root bucket</param>
-        /// <param name="maxBurst">Maximum size of the bucket in bytes, or
-        /// zero if this bucket has no maximum capacity</param>
         /// <param name="dripRate">Rate that the bucket fills, in bytes per
         /// second. If zero, the bucket always remains full</param>
-        public TokenBucket(TokenBucket parent, Int64 dripRate) 
+        public TokenBucket(string identifier, TokenBucket parent, Int64 dripRate) 
         {
-//            m_identifier = m_counter++;
-            m_counter++;
+            Identifier = identifier;
 
             Parent = parent;
             RequestedDripRate = dripRate;
@@ -301,7 +303,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
             // with no drip rate...
             if (DripRate == 0)
             {
-                m_log.WarnFormat("[TOKENBUCKET] something odd is happening and drip rate is 0");
+                m_log.WarnFormat("[TOKENBUCKET] something odd is happening and drip rate is 0 for {0}", Identifier);
                 return;
             }
             
@@ -321,7 +323,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 
     public class AdaptiveTokenBucket : TokenBucket
     {
-//        private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+        private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
 
         /// <summary>
         /// The minimum rate for flow control. Minimum drip rate is one
@@ -360,13 +362,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
         // <summary>
         // 
         // </summary>
-        public AdaptiveTokenBucket(TokenBucket parent, Int64 maxDripRate, bool enabled) : base(parent,maxDripRate)
+        public AdaptiveTokenBucket(string identifier, TokenBucket parent, Int64 maxDripRate, bool enabled) 
+            : base(identifier, parent, maxDripRate)
         {
             Enabled = enabled;
 
             if (Enabled)
             {
-                // m_log.DebugFormat("[TOKENBUCKET] Adaptive throttle enabled");
+//                m_log.DebugFormat("[TOKENBUCKET]: Adaptive throttle enabled");
                 MaxDripRate = maxDripRate;
                 AdjustedDripRate = m_minimumFlow;
             }
@@ -377,9 +380,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
         // </summary>
         public void ExpirePackets(Int32 count)
         {
-            // m_log.WarnFormat("[ADAPTIVEBUCKET] drop {0} by {1} expired packets",AdjustedDripRate,count);
             if (Enabled)
+            {
+                if (DebugLevel > 0)
+                    m_log.WarnFormat(
+                        "[ADAPTIVEBUCKET] drop {0} by {1} expired packets for {2}", 
+                        AdjustedDripRate, count, Identifier);
+
                 AdjustedDripRate = (Int64) (AdjustedDripRate / Math.Pow(2,count));
+            }
         }
 
         // <summary>
-- 
cgit v1.1