From 150ad80f6f456581c8dac76de06d4782d842e719 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Tue, 8 Sep 2020 21:58:38 +0100 Subject: [PATCH] on per client terrain taint control replace bad 2d bool array by a bitarray. 1d bool could be another option. bitarray uses a lot less mem but a bit more cpu, except on full set/clear, less mem is also less cpu cache pressure so lets use it, specially on linear scans on X --- .../World/Terrain/TerrainModule.cs | 117 +++++++++--------- 1 file changed, 61 insertions(+), 56 deletions(-) diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs index f29011ee17..9bc7bf3c47 100755 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs @@ -25,6 +25,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ using System; +using System.Collections; using System.Collections.Generic; using System.IO; using System.Reflection; @@ -98,70 +99,89 @@ namespace OpenSim.Region.CoreModules.World.Terrain // patch packet is queued to the client, the bit for that patch is set to 'false'. private class PatchUpdates { - private bool[,] updated; // for each patch, whether it needs to be sent to this client + private BitArray updated; // for each patch, whether it needs to be sent to this client private int updateCount; // number of patches that need to be sent public ScenePresence Presence; // a reference to the client to send to public bool sendAll; public int sendAllcurrentX; public int sendAllcurrentY; - + private int xsize; + private int ysize; public PatchUpdates(TerrainData terrData, ScenePresence pPresence) { - updated = new bool[terrData.SizeX / Constants.TerrainPatchSize, terrData.SizeY / Constants.TerrainPatchSize]; - updateCount = 0; + xsize = terrData.SizeX / Constants.TerrainPatchSize; + ysize = terrData.SizeY / Constants.TerrainPatchSize; + updated = new BitArray(xsize * ysize, true); + updateCount = xsize * ysize; Presence = pPresence; // Initially, send all patches to the client - SetAll(true); + sendAll = true; + sendAllcurrentX = 0; + sendAllcurrentY = 0; } + // Returns 'true' if there are any patches marked for sending + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public bool HasUpdates() { return (updateCount > 0); } + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public void SetByXY(int x, int y, bool state) { - this.SetByPatch(x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, state); + SetByPatch(x / Constants.TerrainPatchSize , y / Constants.TerrainPatchSize, state); } + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public bool GetByPatch(int patchX, int patchY) { - return updated[patchX, patchY]; + return updated[patchX + xsize * patchY]; } + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public void SetByPatch(int patchX, int patchY, bool state) { - bool prevState = updated[patchX, patchY]; - if (!prevState && state) - updateCount++; - if (prevState && !state) - updateCount--; - updated[patchX, patchY] = state; + int indx = patchX + xsize * patchY; + bool prevState = updated[indx]; + updated[indx] = state; + if (state) + { + if (!prevState) + updateCount++; + } + else + { + if (prevState) + updateCount--; + } } public void SetAll(bool state) { - updateCount = 0; - for (int xx = 0; xx < updated.GetLength(0); xx++) - for (int yy = 0; yy < updated.GetLength(1); yy++) - updated[xx, yy] = state; + updated.SetAll(state); + if (state) - updateCount = updated.GetLength(0) * updated.GetLength(1); + { + sendAll = true; + updateCount = xsize * ysize; + } + else updateCount = 0; + sendAllcurrentX = 0; sendAllcurrentY = 0; - sendAll = true; } // Logically OR's the terrain data's patch taint map into this client's update map. public void SetAll(TerrainData terrData) { - if (updated.GetLength(0) != (terrData.SizeX / Constants.TerrainPatchSize) - || updated.GetLength(1) != (terrData.SizeY / Constants.TerrainPatchSize)) + if (xsize != (terrData.SizeX / Constants.TerrainPatchSize) + || ysize != (terrData.SizeY / Constants.TerrainPatchSize)) { throw new Exception( String.Format("{0} PatchUpdates.SetAll: patch array not same size as terrain. arr=<{1},{2}>, terr=<{3},{4}>", - LogHeader, updated.GetLength(0), updated.GetLength(1), + LogHeader, xsize, ysize, terrData.SizeX / Constants.TerrainPatchSize, terrData.SizeY / Constants.TerrainPatchSize) ); } @@ -173,7 +193,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain // Only set tainted. The patch bit may be set if the patch was to be sent later. if (terrData.IsTaintedAt(xx, yy, false)) { - this.SetByXY(xx, yy, true); + SetByXY(xx, yy, true); } } } @@ -1119,48 +1139,33 @@ namespace OpenSim.Region.CoreModules.World.Terrain { foreach (PatchUpdates pups in m_perClientPatchUpdates.Values) { - if(pups.Presence.IsDeleted) + if(pups.Presence.IsDeleted || !pups.HasUpdates() || !pups.Presence.ControllingClient.CanSendLayerData()) continue; - // limit rate acording to udp land queue state - if (!pups.Presence.ControllingClient.CanSendLayerData()) - continue; - - if (pups.HasUpdates()) + if (m_sendTerrainUpdatesByViewDistance) { - if (m_sendTerrainUpdatesByViewDistance) + // There is something that could be sent to this client. + List toSend = GetModifiedPatchesInViewDistance(pups); + if (toSend.Count > 0) { - // There is something that could be sent to this client. - List toSend = GetModifiedPatchesInViewDistance(pups); - if (toSend.Count > 0) + // m_log.DebugFormat("{0} CheckSendingPatchesToClient: sending {1} patches to {2} in region {3}", + // LogHeader, toSend.Count, pups.Presence.Name, m_scene.RegionInfo.RegionName); + // Sort the patches to send by the distance from the presence + toSend.Sort(); + int[] patchPieces = new int[toSend.Count * 2]; + int pieceIndex = 0; + foreach (PatchesToSend pts in toSend) { - // m_log.DebugFormat("{0} CheckSendingPatchesToClient: sending {1} patches to {2} in region {3}", - // LogHeader, toSend.Count, pups.Presence.Name, m_scene.RegionInfo.RegionName); - // Sort the patches to send by the distance from the presence - toSend.Sort(); - /* - foreach (PatchesToSend pts in toSend) - { - pups.Presence.ControllingClient.SendLayerData(pts.PatchX, pts.PatchY, null); - // presence.ControllingClient.SendLayerData(xs.ToArray(), ys.ToArray(), null, TerrainPatch.LayerType.Land); - } - */ - - int[] patchPieces = new int[toSend.Count * 2]; - int pieceIndex = 0; - foreach (PatchesToSend pts in toSend) - { - patchPieces[pieceIndex++] = pts.PatchX; - patchPieces[pieceIndex++] = pts.PatchY; - } - pups.Presence.ControllingClient.SendLayerData(patchPieces); + patchPieces[pieceIndex++] = pts.PatchX; + patchPieces[pieceIndex++] = pts.PatchY; } - if (pups.sendAll && toSend.Count < 1024) - SendAllModifiedPatchs(pups); + pups.Presence.ControllingClient.SendLayerData(patchPieces); } - else + if (pups.sendAll && toSend.Count < 1024) SendAllModifiedPatchs(pups); } + else + SendAllModifiedPatchs(pups); } } }