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 [email protected] 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 <[email protected]> > > 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 > [email protected] > https://lists.berlios.de/mailman/listinfo/opensim-commits > > _______________________________________________ Opensim-dev mailing list [email protected] https://lists.berlios.de/mailman/listinfo/opensim-dev
