[Opensim-dev] [Opensim-commits] r9924 - in trunk: OpenSim/Region/ClientStack/LindenUDP bin
John Sheridan
john at pseudospace.net
Wed Jul 1 05:28:33 UTC 2009
I'm sitting here clearing up a few scrap prims to make one of my builds
a bit more efficient (changing from 15 prim factory windows to 5 for
example) when it occurred to me. I've noticed that while opensim is
chugging along, updating the sim database and sending stuff back to my
inventory, movement in-world starts to lag and studder a bit. Once its
done things understandably go back to normal. I wonder a change similar
to Dr. Scofield's texture handler only for the database / prim storage
routines could make even further of a difference? I'd imagine if so,
the initial rez-in for example when an avi is wearing 300 some-odd prims
in attachments would have less of an impact. Just a thought... :)
Thanks,
- John / Orion Pseudo
drscofield at opensimulator.org wrote:
> Author: drscofield
> Date: 2009-06-25 00:42:06 -0700 (Thu, 25 Jun 2009)
> New Revision: 9924
>
> Modified:
> trunk/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs
> trunk/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
> trunk/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs
> trunk/bin/OpenSim.ini.example
> Log:
> From: Alan Webb <alan_webb at us.ibm.com>
>
> This change moves texture send processing out of the main
> packet processing loop and moves it to a timer based
> processing cycle.
>
> Texture packets are sent to the client consistently over
> time. The timer is discontinued whenever there are no
> textures to transmit.
>
> The behavior of the texture sending mechanism is controlled
> by three variables in the LLCLient section of the config
> file:
>
> [1] TextureRequestRate (mS) determines how many times per second
> texture send processing will occur. The default is 100mS.
> [2] TextureSendLimit determines how many different textures
> will be considered on each cycle. Textures are selected
> by priority. The old mechanism specified a value of 10 for
> this parameter and this is the default
> [3] TextureDataLimit determines how many packets will be sent for
> each of the selected textures. The old mechanism specified a
> value of 5, so this is the default.
>
> So the net effect is that TextureSendLimit*TextureDataLimit
> packets will be sent every TextureRequestRate mS.
>
> Once we have gotten a reasonable feeling for how these parameters
> affect overall processing, it would be nice to autonmically manage
> these values using information about the current status of the
> region and network.
>
> Note that this also resolves the pathologcal problem that
> previously existed which was that a seated avatar generated very
> few in-bound packets (theoretically) and would therefore be the
> least able to retrieve the images being displayed by a
> projector script.
>
> Modified: trunk/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs
> ===================================================================
> --- trunk/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs 2009-06-25 07:39:48 UTC (rev 9923)
> +++ trunk/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs 2009-06-25 07:42:06 UTC (rev 9924)
> @@ -260,7 +260,7 @@
> return false;
> }
> }
> - public bool SendPackets(LLClientView client)
> + public bool SendPackets(LLClientView client, int maxpack)
> {
>
> if (!m_completedSendAtCurrentDiscardLevel)
> @@ -284,7 +284,7 @@
> }
>
> int count = 0;
> - while (SendMore && count < 5 && m_packetNumber <= m_stopPacket)
> + while (SendMore && count < maxpack && m_packetNumber <= m_stopPacket)
> {
> count++;
> SendMore = SendPacket(client);
> @@ -391,6 +391,10 @@
> }
> }
> }
> + else
> + {
> + m_packetNumber = m_stopPacket;
> + }
> }
> }
> }
>
> Modified: trunk/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
> ===================================================================
> --- trunk/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs 2009-06-25 07:39:48 UTC (rev 9923)
> +++ trunk/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs 2009-06-25 07:42:06 UTC (rev 9924)
> @@ -80,6 +80,8 @@
> private List<ObjectUpdatePacket.ObjectDataBlock> m_primFullUpdates =
> new List<ObjectUpdatePacket.ObjectDataBlock>();
>
> + private Timer m_textureRequestTimer;
> +
> private bool m_clientBlocked;
>
> private int m_probesWithNoIngressPackets;
> @@ -140,6 +142,10 @@
> protected int m_primTerseUpdateRate = 10;
> protected int m_primFullUpdateRate = 14;
>
> + protected int m_textureRequestRate = 100;
> + protected int m_textureSendLimit = 10;
> + protected int m_textureDataLimit = 5;
> +
> protected int m_packetMTU = 1400;
>
> protected IAssetService m_assetService;
> @@ -344,6 +350,8 @@
>
> private readonly IGroupsModule m_GroupsModule;
>
> + private AgentUpdateArgs lastarg = null;
> +
> //private TerrainUnacked handlerUnackedTerrain = null;
>
> //**
> @@ -544,6 +552,15 @@
> m_primFullUpdateRate = clientConfig.GetInt("FullUpdateRate",
> m_primFullUpdateRate);
>
> + m_textureRequestRate = clientConfig.GetInt("TextureRequestRate",
> + m_textureRequestRate);
> +
> + m_textureSendLimit = clientConfig.GetInt("TextureSendLimit",
> + m_textureSendLimit);
> +
> + m_textureDataLimit = clientConfig.GetInt("TextureDataLimit",
> + m_textureDataLimit);
> +
> m_packetMTU = clientConfig.GetInt("PacketMTU", 1400);
> }
> }
> @@ -577,6 +594,7 @@
> m_avatarTerseUpdateTimer.Stop();
> m_primTerseUpdateTimer.Stop();
> m_primFullUpdateTimer.Stop();
> + m_textureRequestTimer.Stop();
>
> // This is just to give the client a reasonable chance of
> // flushing out all it's packets. There should probably
> @@ -660,6 +678,7 @@
> m_avatarTerseUpdateTimer.Stop();
> m_primTerseUpdateTimer.Stop();
> m_primFullUpdateTimer.Stop();
> + m_textureRequestTimer.Stop();
> }
>
> public void Restart()
> @@ -682,6 +701,11 @@
> m_primFullUpdateTimer = new Timer(m_primFullUpdateRate);
> m_primFullUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessPrimFullUpdates);
> m_primFullUpdateTimer.AutoReset = false;
> +
> + m_textureRequestTimer = new Timer(m_textureRequestRate);
> + m_textureRequestTimer.Elapsed += new ElapsedEventHandler(ProcessTextureRequests);
> + m_textureRequestTimer.AutoReset = false;
> +
> }
>
> public void Terminate()
> @@ -914,6 +938,11 @@
> m_primFullUpdateTimer = new Timer(m_primFullUpdateRate);
> m_primFullUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessPrimFullUpdates);
> m_primFullUpdateTimer.AutoReset = false;
> +
> + m_textureRequestTimer = new Timer(m_textureRequestRate);
> + m_textureRequestTimer.Elapsed += new ElapsedEventHandler(ProcessTextureRequests);
> + m_textureRequestTimer.AutoReset = false;
> +
> m_scene.AddNewClient(this);
>
> RefreshGroupMembership();
> @@ -985,6 +1014,26 @@
> }
> }
>
> + protected virtual void TextureRequestHandler()
> + {
> + m_log.DebugFormat("[TRH] Thread started");
> + while (m_imageManager != null)
> + {
> + try
> + {
> + while (m_imageManager != null)
> + {
> + }
> + }
> + catch (Exception e)
> + {
> + m_log.WarnFormat("[TRH] Exception in handler loop: {0}", e.Message);
> + m_log.Debug(e);
> + }
> + }
> + m_log.DebugFormat("[TRH] Thread terminated");
> + }
> +
> # endregion
>
> // Previously ClientView.API partial class
> @@ -3032,6 +3081,21 @@
> }
> }
>
> + // Unlike the other timers, this one is only started after
> + // the first request is seen.
> +
> + void ProcessTextureRequests(object sender, ElapsedEventArgs e)
> + {
> + if (m_imageManager != null)
> + {
> + if (m_imageManager.ProcessImageQueue(m_textureSendLimit,
> + m_textureDataLimit))
> + {
> + m_textureRequestTimer.Start();
> + }
> + }
> + }
> +
> void ProcessPrimFullUpdates(object sender, ElapsedEventArgs e)
> {
> lock (m_primFullUpdates)
> @@ -3237,7 +3301,7 @@
> ushort numParts, UUID ImageUUID, uint ImageSize, byte[] ImageData, byte imageCodec)
> {
> ImageDataPacket im = new ImageDataPacket();
> - im.Header.Reliable = true;
> + im.Header.Reliable = false;
> im.ImageID.Packets = numParts;
> im.ImageID.ID = ImageUUID;
>
> @@ -3253,7 +3317,7 @@
> public void SendImageNextPart(ushort partNumber, UUID imageUuid, byte[] imageData)
> {
> ImagePacketPacket im = new ImagePacketPacket();
> - im.Header.Reliable = true;
> + im.Header.Reliable = false;
> im.ImageID.Packet = partNumber;
> im.ImageID.ID = imageUuid;
> im.ImageData.Data = imageData;
> @@ -4727,14 +4791,9 @@
> /// <param name="Pack">OpenMetaverse.packet</param>
> public void ProcessInPacket(Packet Pack)
> {
> - // check if we've got a local packet handler for this packet.type. See RegisterLocalPacketHandlers()
> +
> if (ProcessPacketMethod(Pack))
> {
> - //there is a handler registered that handled this packet type
> -
> - // in the end, we dereference this, so we have to check if it's null
> - if (m_imageManager != null)
> - m_imageManager.ProcessImageQueue(5);
> return;
> }
>
> @@ -5303,6 +5362,7 @@
> case PacketType.AgentUpdate:
> if (OnAgentUpdate != null)
> {
> + bool update = false;
> AgentUpdatePacket agenUpdate = (AgentUpdatePacket)Pack;
>
> #region Packet Session and User Check
> @@ -5315,26 +5375,58 @@
> #endregion
>
> AgentUpdatePacket.AgentDataBlock x = agenUpdate.AgentData;
> - AgentUpdateArgs arg = new AgentUpdateArgs();
> - arg.AgentID = x.AgentID;
> - arg.BodyRotation = x.BodyRotation;
> - arg.CameraAtAxis = x.CameraAtAxis;
> - arg.CameraCenter = x.CameraCenter;
> - arg.CameraLeftAxis = x.CameraLeftAxis;
> - arg.CameraUpAxis = x.CameraUpAxis;
> - arg.ControlFlags = x.ControlFlags;
> - arg.Far = x.Far;
> - arg.Flags = x.Flags;
> - arg.HeadRotation = x.HeadRotation;
> - arg.SessionID = x.SessionID;
> - arg.State = x.State;
>
> - handlerAgentUpdate = OnAgentUpdate;
> - if (handlerAgentUpdate != null)
> - OnAgentUpdate(this, arg);
> + // We can only check when we have something to check
> + // against.
>
> - handlerAgentUpdate = null;
> - //agenUpdate.AgentData.ControlFlags, agenUpdate.AgentData.BodyRotationa);
> + if (lastarg != null)
> + {
> + update =
> + (
> + (x.BodyRotation != lastarg.BodyRotation) ||
> + (x.CameraAtAxis != lastarg.CameraAtAxis) ||
> + (x.CameraCenter != lastarg.CameraCenter) ||
> + (x.CameraLeftAxis != lastarg.CameraLeftAxis) ||
> + (x.CameraUpAxis != lastarg.CameraUpAxis) ||
> + (x.ControlFlags != lastarg.ControlFlags) ||
> + (x.Far != lastarg.Far) ||
> + (x.Flags != lastarg.Flags) ||
> + (x.State != lastarg.State) ||
> + (x.HeadRotation != lastarg.HeadRotation) ||
> + (x.SessionID != lastarg.SessionID) ||
> + (x.AgentID != lastarg.AgentID)
> + );
> + }
> + else
> + update = true;
> +
> + // These should be ordered from most-likely to
> + // least likely to change. I've made an initial
> + // guess at that.
> +
> + if (update)
> + {
> + AgentUpdateArgs arg = new AgentUpdateArgs();
> + arg.AgentID = x.AgentID;
> + arg.BodyRotation = x.BodyRotation;
> + arg.CameraAtAxis = x.CameraAtAxis;
> + arg.CameraCenter = x.CameraCenter;
> + arg.CameraLeftAxis = x.CameraLeftAxis;
> + arg.CameraUpAxis = x.CameraUpAxis;
> + arg.ControlFlags = x.ControlFlags;
> + arg.Far = x.Far;
> + arg.Flags = x.Flags;
> + arg.HeadRotation = x.HeadRotation;
> + arg.SessionID = x.SessionID;
> + arg.State = x.State;
> + handlerAgentUpdate = OnAgentUpdate;
> + lastarg = arg; // save this set of arguments for nexttime
> + if (handlerAgentUpdate != null)
> + OnAgentUpdate(this, arg);
> +
> + handlerAgentUpdate = null;
> + }
> +
> }
> break;
>
> @@ -6392,10 +6484,14 @@
>
> // in the end, we null this, so we have to check if it's null
> if (m_imageManager != null)
> + {
> m_imageManager.EnqueueReq(args);
> + m_textureRequestTimer.Start();
> + }
> }
> }
> break;
> +
> case PacketType.TransferRequest:
> //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request");
>
> @@ -9502,10 +9598,8 @@
> #endregion
> }
>
> - // in the end, we dereference this, so we have to check if it's null
> - if (m_imageManager != null)
> - m_imageManager.ProcessImageQueue(10);
> PacketPool.Instance.ReturnPacket(Pack);
> +
> }
>
> private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket)
>
> Modified: trunk/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs
> ===================================================================
> --- trunk/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs 2009-06-25 07:39:48 UTC (rev 9923)
> +++ trunk/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs 2009-06-25 07:42:06 UTC (rev 9924)
> @@ -26,6 +26,7 @@
> */
>
> using System;
> +using System.Threading;
> using System.Collections.Generic;
> using OpenMetaverse;
> using OpenMetaverse.Imaging;
> @@ -96,46 +97,42 @@
>
> J2KImage imgrequest = m_imagestore[newRequest.RequestedAssetID];
>
> + // This is the inbound request sequence number. We can ignore
> + // "old" ones.
> +
> if (newRequest.requestSequence > imgrequest.m_lastSequence)
> {
> +
> imgrequest.m_lastSequence = newRequest.requestSequence;
>
> - //First of all, is this being killed?
> - //if (newRequest.Priority == 0.0f && newRequest.DiscardLevel == -1)
> - //{
> - //Do nothing (leaving the if for future use)
> - //}
> - //else
> - //{
> + //Check the priority
>
> + double priority = imgrequest.m_requestedPriority;
> + if (priority != newRequest.Priority)
> + {
> + //Remove the old priority
> + m_priorities.Remove(imgrequest.m_designatedPriorityKey);
> + //Assign a new unique priority
> + imgrequest.m_requestedPriority = newRequest.Priority;
> + imgrequest.m_designatedPriorityKey = AssignPriority(newRequest.RequestedAssetID, newRequest.Priority);
> + }
>
> - //Check the priority
> - double priority = imgrequest.m_requestedPriority;
> - if (priority != newRequest.Priority)
> - {
> - //Remove the old priority
> - m_priorities.Remove(imgrequest.m_designatedPriorityKey);
> - //Assign a new unique priority
> - imgrequest.m_requestedPriority = newRequest.Priority;
> - imgrequest.m_designatedPriorityKey = AssignPriority(newRequest.RequestedAssetID, newRequest.Priority);
> - }
> + //Update the requested discard level
> + imgrequest.m_requestedDiscardLevel = newRequest.DiscardLevel;
>
> - //Update the requested discard level
> - imgrequest.m_requestedDiscardLevel = newRequest.DiscardLevel;
> + //Update the requested packet number
> + imgrequest.m_requestedPacketNumber = newRequest.PacketNumber;
>
> - //Update the requested packet number
> - imgrequest.m_requestedPacketNumber = newRequest.PacketNumber;
> + //Check if this will create an outstanding texture request
> + bool activated = imgrequest.m_completedSendAtCurrentDiscardLevel;
> + //Run an update
>
> - //Check if this will create an outstanding texture request
> - bool activated = imgrequest.m_completedSendAtCurrentDiscardLevel;
> - //Run an update
> - imgrequest.RunUpdate();
> - if (activated && !imgrequest.m_completedSendAtCurrentDiscardLevel && imgrequest.m_decoded)
> - {
> - m_outstandingtextures++;
> - }
> + imgrequest.RunUpdate();
>
> - //}
> + if (activated && !imgrequest.m_completedSendAtCurrentDiscardLevel && imgrequest.m_decoded)
> + {
> + Interlocked.Increment(ref m_outstandingtextures);
> + }
> }
> }
> else
> @@ -198,10 +195,12 @@
>
> }
>
> - public void ProcessImageQueue(int count)
> + public bool ProcessImageQueue(int count, int maxpack)
> {
> +
> // this can happen during Close()
> - if (m_client == null) return;
> + if (m_client == null)
> + return false;
>
> //Count is the number of textures we want to process in one go.
> //As part of this class re-write, that number will probably rise
> @@ -214,7 +213,7 @@
> if (m_lastloopprocessed == 0)
> {
> if (m_client.PacketHandler == null || m_client.PacketHandler.PacketQueue == null || m_client.PacketHandler.PacketQueue.TextureThrottle == null)
> - return;
> + return false;
> //This is decent for a semi fast machine, but we'll calculate it more accurately based on time below
> threshold = m_client.PacketHandler.PacketQueue.TextureThrottle.Current / 6300;
> m_lastloopprocessed = DateTime.Now.Ticks;
> @@ -239,10 +238,10 @@
> }
>
> if (m_client.PacketHandler == null)
> - return;
> + return false;
>
> if (m_client.PacketHandler.PacketQueue == null)
> - return;
> + return false;
>
> //First of all make sure our packet queue isn't above our threshold
>
> @@ -252,24 +251,21 @@
> {
> bool justreset = false;
>
> -
> -
> for (int x = m_priorities.Count - 1; x > -1; x--)
> {
>
> J2KImage imagereq = m_imagestore[m_priorities.Values[x]];
> if (imagereq.m_decoded == true && !imagereq.m_completedSendAtCurrentDiscardLevel)
> {
> -
> numCollected++;
> //SendPackets will send up to ten packets per cycle
> - if (imagereq.SendPackets(m_client))
> + if (imagereq.SendPackets(m_client, maxpack))
> {
> //Send complete
> if (!imagereq.m_completedSendAtCurrentDiscardLevel)
> {
> imagereq.m_completedSendAtCurrentDiscardLevel = true;
> - m_outstandingtextures--;
> + Interlocked.Decrement(ref m_outstandingtextures);
> //Re-assign priority to bottom
> //Remove the old priority
> m_priorities.Remove(imagereq.m_designatedPriorityKey);
> @@ -310,13 +306,10 @@
>
> justreset = true; //prevents us from getting stuck in a loop
> }
> -
> -
> }
> }
>
> -
> -
> + return m_outstandingtextures != 0;
> }
>
> //Faux destructor
>
> Modified: trunk/bin/OpenSim.ini.example
> ===================================================================
> --- trunk/bin/OpenSim.ini.example 2009-06-25 07:39:48 UTC (rev 9923)
> +++ trunk/bin/OpenSim.ini.example 2009-06-25 07:42:06 UTC (rev 9924)
> @@ -1208,12 +1208,15 @@
>
> [LLClient]
> ; Resend packets markes as reliable until they are received
> + ;
> ;ReliableIsImportant = false
>
> ; Maximum number of times to resend packets marked reliable
> + ;
> ;MaxReliableResends = 3
>
> ; Configures how ObjectUpdates are compressed.
> + ;
> ;TerseUpdatesPerPacket=10
> ;FullUpdatesPerPacket=14
> ;TerseUpdateRate=10
> @@ -1221,7 +1224,23 @@
>
> ;PacketMTU = 1400
>
> + ; TextureUpdateRate (mS) determines how many times per second
> + ; texture send processing will occur. The default is 100mS.
> + ;
> + ;TextureRequestRate = 100
>
> + ; TextureSendLimit determines how many different textures
> + ; will be considered on each cycle. Textures are selected
> + ; by priority. The old mechanism specified a value of 10 for
> + ; this parameter.
> + ;
> + ;TextureSendLimit = 10
> +
> + ; TextureDataLimit determines how many packets will be sent for
> + ; each of the selected textures. Default is 5.
> + ;
> + ;TextureDataLimit = 5
> +
> ;;
> ;; These are defatuls that are overwritten below in [Architecture].
> ;; These defaults allow OpenSim to work out of the box with
>
> _______________________________________________
> Opensim-commits mailing list
> Opensim-commits at lists.berlios.de
> https://lists.berlios.de/mailman/listinfo/opensim-commits
>
>
More information about the Opensim-dev
mailing list