diff options
7 files changed, 145 insertions, 70 deletions
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index c303d6d..d363b15 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs | |||
@@ -26,8 +26,10 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections; | ||
29 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
30 | using System.IO; | 31 | using System.IO; |
32 | using System.Linq; | ||
31 | using System.Reflection; | 33 | using System.Reflection; |
32 | using System.Security; | 34 | using System.Security; |
33 | using log4net; | 35 | using log4net; |
@@ -876,52 +878,67 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
876 | if (!Scene.Permissions.CanIssueEstateCommand(remoteClient.AgentId, false)) | 878 | if (!Scene.Permissions.CanIssueEstateCommand(remoteClient.AgentId, false)) |
877 | return; | 879 | return; |
878 | 880 | ||
879 | Dictionary<uint, float> SceneData = new Dictionary<uint,float>(); | 881 | Dictionary<uint, float> sceneData = null; |
880 | List<UUID> uuidNameLookupList = new List<UUID>(); | 882 | List<UUID> uuidNameLookupList = new List<UUID>(); |
881 | 883 | ||
882 | if (reportType == 1) | 884 | if (reportType == 1) |
883 | { | 885 | { |
884 | SceneData = Scene.PhysicsScene.GetTopColliders(); | 886 | sceneData = Scene.PhysicsScene.GetTopColliders(); |
885 | } | 887 | } |
886 | else if (reportType == 0) | 888 | else if (reportType == 0) |
887 | { | 889 | { |
888 | SceneData = Scene.SceneGraph.GetTopScripts(); | 890 | IScriptModule scriptModule = Scene.RequestModuleInterface<IScriptModule>(); |
891 | |||
892 | if (scriptModule != null) | ||
893 | sceneData = scriptModule.GetObjectScriptsExecutionTimes(); | ||
889 | } | 894 | } |
890 | 895 | ||
891 | List<LandStatReportItem> SceneReport = new List<LandStatReportItem>(); | 896 | List<LandStatReportItem> SceneReport = new List<LandStatReportItem>(); |
892 | lock (SceneData) | 897 | if (sceneData != null) |
893 | { | 898 | { |
894 | foreach (uint obj in SceneData.Keys) | 899 | var sortedSceneData |
900 | = sceneData.Select( | ||
901 | item => new { Measurement = item.Value, Part = Scene.GetSceneObjectPart(item.Key) }); | ||
902 | |||
903 | sortedSceneData.OrderBy(item => item.Measurement); | ||
904 | |||
905 | int items = 0; | ||
906 | |||
907 | foreach (var entry in sortedSceneData) | ||
895 | { | 908 | { |
896 | SceneObjectPart prt = Scene.GetSceneObjectPart(obj); | 909 | if (entry.Part == null) |
897 | if (prt != null) | 910 | continue; |
911 | |||
912 | items++; | ||
913 | SceneObjectGroup so = entry.Part.ParentGroup; | ||
914 | |||
915 | LandStatReportItem lsri = new LandStatReportItem(); | ||
916 | lsri.LocationX = so.AbsolutePosition.X; | ||
917 | lsri.LocationY = so.AbsolutePosition.Y; | ||
918 | lsri.LocationZ = so.AbsolutePosition.Z; | ||
919 | lsri.Score = entry.Measurement; | ||
920 | lsri.TaskID = so.UUID; | ||
921 | lsri.TaskLocalID = so.LocalId; | ||
922 | lsri.TaskName = entry.Part.Name; | ||
923 | lsri.OwnerName = "waiting"; | ||
924 | lock (uuidNameLookupList) | ||
925 | uuidNameLookupList.Add(so.OwnerID); | ||
926 | |||
927 | if (filter.Length != 0) | ||
898 | { | 928 | { |
899 | SceneObjectGroup sog = prt.ParentGroup; | 929 | if ((lsri.OwnerName.Contains(filter) || lsri.TaskName.Contains(filter))) |
900 | LandStatReportItem lsri = new LandStatReportItem(); | ||
901 | lsri.LocationX = sog.AbsolutePosition.X; | ||
902 | lsri.LocationY = sog.AbsolutePosition.Y; | ||
903 | lsri.LocationZ = sog.AbsolutePosition.Z; | ||
904 | lsri.Score = SceneData[obj]; | ||
905 | lsri.TaskID = sog.UUID; | ||
906 | lsri.TaskLocalID = sog.LocalId; | ||
907 | lsri.TaskName = sog.GetPartName(obj); | ||
908 | lsri.OwnerName = "waiting"; | ||
909 | lock (uuidNameLookupList) | ||
910 | uuidNameLookupList.Add(sog.OwnerID); | ||
911 | |||
912 | if (filter.Length != 0) | ||
913 | { | 930 | { |
914 | if ((lsri.OwnerName.Contains(filter) || lsri.TaskName.Contains(filter))) | ||
915 | { | ||
916 | } | ||
917 | else | ||
918 | { | ||
919 | continue; | ||
920 | } | ||
921 | } | 931 | } |
922 | 932 | else | |
923 | SceneReport.Add(lsri); | 933 | { |
934 | continue; | ||
935 | } | ||
924 | } | 936 | } |
937 | |||
938 | SceneReport.Add(lsri); | ||
939 | |||
940 | if (items >= 100) | ||
941 | break; | ||
925 | } | 942 | } |
926 | } | 943 | } |
927 | 944 | ||
diff --git a/OpenSim/Region/Framework/Interfaces/IScriptModule.cs b/OpenSim/Region/Framework/Interfaces/IScriptModule.cs index 18c45dd..9fb4a25 100644 --- a/OpenSim/Region/Framework/Interfaces/IScriptModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IScriptModule.cs | |||
@@ -27,6 +27,7 @@ | |||
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections; | 29 | using System.Collections; |
30 | using System.Collections.Generic; | ||
30 | using OpenMetaverse; | 31 | using OpenMetaverse; |
31 | 32 | ||
32 | namespace OpenSim.Region.Framework.Interfaces | 33 | namespace OpenSim.Region.Framework.Interfaces |
@@ -74,5 +75,11 @@ namespace OpenSim.Region.Framework.Interfaces | |||
74 | /// Starts the processing threads. | 75 | /// Starts the processing threads. |
75 | /// </summary> | 76 | /// </summary> |
76 | void StartProcessing(); | 77 | void StartProcessing(); |
78 | |||
79 | /// <summary> | ||
80 | /// Get the execution times of all scripts in each object. | ||
81 | /// </summary> | ||
82 | /// <returns>A dictionary where the key is a local object ID and the value is an execution time in milliseconds.</returns> | ||
83 | Dictionary<uint, float> GetObjectScriptsExecutionTimes(); | ||
77 | } | 84 | } |
78 | } | 85 | } \ No newline at end of file |
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index bc3400a..5c542d6 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs | |||
@@ -733,6 +733,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
733 | #endregion | 733 | #endregion |
734 | 734 | ||
735 | #region Get Methods | 735 | #region Get Methods |
736 | |||
736 | /// <summary> | 737 | /// <summary> |
737 | /// Get the controlling client for the given avatar, if there is one. | 738 | /// Get the controlling client for the given avatar, if there is one. |
738 | /// | 739 | /// |
@@ -1074,36 +1075,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
1074 | return Entities.GetEntities(); | 1075 | return Entities.GetEntities(); |
1075 | } | 1076 | } |
1076 | 1077 | ||
1077 | public Dictionary<uint, float> GetTopScripts() | ||
1078 | { | ||
1079 | Dictionary<uint, float> topScripts = new Dictionary<uint, float>(); | ||
1080 | |||
1081 | EntityBase[] EntityList = GetEntities(); | ||
1082 | int limit = 0; | ||
1083 | foreach (EntityBase ent in EntityList) | ||
1084 | { | ||
1085 | if (ent is SceneObjectGroup) | ||
1086 | { | ||
1087 | SceneObjectGroup grp = (SceneObjectGroup)ent; | ||
1088 | if ((grp.RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.Scripted) != 0) | ||
1089 | { | ||
1090 | if (grp.scriptScore >= 0.01) | ||
1091 | { | ||
1092 | topScripts.Add(grp.LocalId, grp.scriptScore); | ||
1093 | limit++; | ||
1094 | if (limit >= 100) | ||
1095 | { | ||
1096 | break; | ||
1097 | } | ||
1098 | } | ||
1099 | grp.scriptScore = 0; | ||
1100 | } | ||
1101 | } | ||
1102 | } | ||
1103 | |||
1104 | return topScripts; | ||
1105 | } | ||
1106 | |||
1107 | #endregion | 1078 | #endregion |
1108 | 1079 | ||
1109 | #region Other Methods | 1080 | #region Other Methods |
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 878476e..afb5ccf 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | |||
@@ -229,8 +229,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
229 | get { return RootPart.VolumeDetectActive; } | 229 | get { return RootPart.VolumeDetectActive; } |
230 | } | 230 | } |
231 | 231 | ||
232 | public float scriptScore; | ||
233 | |||
234 | private Vector3 lastPhysGroupPos; | 232 | private Vector3 lastPhysGroupPos; |
235 | private Quaternion lastPhysGroupRot; | 233 | private Quaternion lastPhysGroupRot; |
236 | 234 | ||
@@ -1184,12 +1182,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1184 | 1182 | ||
1185 | public void AddScriptLPS(int count) | 1183 | public void AddScriptLPS(int count) |
1186 | { | 1184 | { |
1187 | if (scriptScore + count >= float.MaxValue - count) | 1185 | m_scene.SceneGraph.AddToScriptLPS(count); |
1188 | scriptScore = 0; | ||
1189 | |||
1190 | scriptScore += (float)count; | ||
1191 | SceneGraph d = m_scene.SceneGraph; | ||
1192 | d.AddToScriptLPS(count); | ||
1193 | } | 1186 | } |
1194 | 1187 | ||
1195 | public void AddActiveScriptCount(int count) | 1188 | public void AddActiveScriptCount(int count) |
diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs index 8762642..11f54a2 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs | |||
@@ -78,6 +78,21 @@ namespace OpenSim.Region.ScriptEngine.Interfaces | |||
78 | /// </summary> | 78 | /// </summary> |
79 | string State { get; set; } | 79 | string State { get; set; } |
80 | 80 | ||
81 | /// <summary> | ||
82 | /// Time the script was last started | ||
83 | /// </summary> | ||
84 | DateTime TimeStarted { get; } | ||
85 | |||
86 | /// <summary> | ||
87 | /// Tick the last measurement period was started. | ||
88 | /// </summary> | ||
89 | long MeasurementPeriodTickStart { get; } | ||
90 | |||
91 | /// <summary> | ||
92 | /// Ticks spent executing in the last measurement period. | ||
93 | /// </summary> | ||
94 | long MeasurementPeriodExecutionTime { get; } | ||
95 | |||
81 | IScriptEngine Engine { get; } | 96 | IScriptEngine Engine { get; } |
82 | UUID AppDomain { get; set; } | 97 | UUID AppDomain { get; set; } |
83 | string PrimName { get; } | 98 | string PrimName { get; } |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index 968351b..b177287 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs | |||
@@ -172,6 +172,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
172 | 172 | ||
173 | public TaskInventoryItem ScriptTask { get; private set; } | 173 | public TaskInventoryItem ScriptTask { get; private set; } |
174 | 174 | ||
175 | public DateTime TimeStarted { get; private set; } | ||
176 | |||
177 | public long MeasurementPeriodTickStart { get; private set; } | ||
178 | |||
179 | public long MeasurementPeriodExecutionTime { get; private set; } | ||
180 | |||
181 | public static readonly long MaxMeasurementPeriod = 30 * TimeSpan.TicksPerMinute; | ||
182 | |||
175 | public void ClearQueue() | 183 | public void ClearQueue() |
176 | { | 184 | { |
177 | m_TimerQueued = false; | 185 | m_TimerQueued = false; |
@@ -458,6 +466,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
458 | 466 | ||
459 | Running = true; | 467 | Running = true; |
460 | 468 | ||
469 | TimeStarted = DateTime.Now; | ||
470 | MeasurementPeriodTickStart = Util.EnvironmentTickCount(); | ||
471 | MeasurementPeriodExecutionTime = 0; | ||
472 | |||
461 | if (EventQueue.Count > 0) | 473 | if (EventQueue.Count > 0) |
462 | { | 474 | { |
463 | if (m_CurrentWorkItem == null) | 475 | if (m_CurrentWorkItem == null) |
@@ -710,8 +722,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
710 | m_EventStart = DateTime.Now; | 722 | m_EventStart = DateTime.Now; |
711 | m_InEvent = true; | 723 | m_InEvent = true; |
712 | 724 | ||
725 | int start = Util.EnvironmentTickCount(); | ||
726 | |||
727 | // Reset the measurement period when we reach the end of the current one. | ||
728 | if (start - MeasurementPeriodTickStart > MaxMeasurementPeriod) | ||
729 | MeasurementPeriodTickStart = start; | ||
730 | |||
713 | m_Script.ExecuteEvent(State, data.EventName, data.Params); | 731 | m_Script.ExecuteEvent(State, data.EventName, data.Params); |
714 | 732 | ||
733 | MeasurementPeriodExecutionTime += Util.EnvironmentTickCount() - start; | ||
734 | |||
715 | m_InEvent = false; | 735 | m_InEvent = false; |
716 | m_CurrentEvent = String.Empty; | 736 | m_CurrentEvent = String.Empty; |
717 | 737 | ||
@@ -720,7 +740,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
720 | // This will be the very first event we deliver | 740 | // This will be the very first event we deliver |
721 | // (state_entry) in default state | 741 | // (state_entry) in default state |
722 | // | 742 | // |
723 | |||
724 | SaveState(m_Assembly); | 743 | SaveState(m_Assembly); |
725 | 744 | ||
726 | m_SaveState = false; | 745 | m_SaveState = false; |
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 105d97d..bddb1b9 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | |||
@@ -1891,6 +1891,59 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1891 | } | 1891 | } |
1892 | } | 1892 | } |
1893 | 1893 | ||
1894 | public Dictionary<uint, float> GetObjectScriptsExecutionTimes() | ||
1895 | { | ||
1896 | long tickNow = Util.EnvironmentTickCount(); | ||
1897 | Dictionary<uint, float> topScripts = new Dictionary<uint, float>(); | ||
1898 | |||
1899 | lock (m_Scripts) | ||
1900 | { | ||
1901 | foreach (IScriptInstance si in m_Scripts.Values) | ||
1902 | { | ||
1903 | if (!topScripts.ContainsKey(si.LocalID)) | ||
1904 | topScripts[si.LocalID] = 0; | ||
1905 | |||
1906 | // long ticksElapsed = tickNow - si.MeasurementPeriodTickStart; | ||
1907 | // float framesElapsed = ticksElapsed / (18.1818 * TimeSpan.TicksPerMillisecond); | ||
1908 | |||
1909 | // Execution time of the script adjusted by it's measurement period to make scripts started at | ||
1910 | // different times comparable. | ||
1911 | // float adjustedExecutionTime | ||
1912 | // = (float)si.MeasurementPeriodExecutionTime | ||
1913 | // / ((float)(tickNow - si.MeasurementPeriodTickStart) / ScriptInstance.MaxMeasurementPeriod) | ||
1914 | // / TimeSpan.TicksPerMillisecond; | ||
1915 | |||
1916 | long ticksElapsed = tickNow - si.MeasurementPeriodTickStart; | ||
1917 | |||
1918 | // Avoid divide by zerp | ||
1919 | if (ticksElapsed == 0) | ||
1920 | ticksElapsed = 1; | ||
1921 | |||
1922 | // Scale execution time to the ideal 55 fps frame time for these reasons. | ||
1923 | // | ||
1924 | // 1) XEngine does not execute scripts per frame, unlike other script engines. Hence, there is no | ||
1925 | // 'script execution time per frame', which is the original purpose of this value. | ||
1926 | // | ||
1927 | // 2) Giving the raw execution times is misleading since scripts start at different times, making | ||
1928 | // it impossible to compare scripts. | ||
1929 | // | ||
1930 | // 3) Scaling the raw execution time to the time that the script has been running is better but | ||
1931 | // is still misleading since a script that has just been rezzed may appear to have been running | ||
1932 | // for much longer. | ||
1933 | // | ||
1934 | // 4) Hence, we scale execution time to an idealised frame time (55 fps). This is also not perfect | ||
1935 | // since the figure does not represent actual execution time and very hard running scripts will | ||
1936 | // never exceed 18ms (though this is a very high number for script execution so is a warning sign). | ||
1937 | float adjustedExecutionTime | ||
1938 | = ((float)si.MeasurementPeriodExecutionTime / ticksElapsed) * 18.1818f; | ||
1939 | |||
1940 | topScripts[si.LocalID] += adjustedExecutionTime; | ||
1941 | } | ||
1942 | } | ||
1943 | |||
1944 | return topScripts; | ||
1945 | } | ||
1946 | |||
1894 | public void SuspendScript(UUID itemID) | 1947 | public void SuspendScript(UUID itemID) |
1895 | { | 1948 | { |
1896 | // m_log.DebugFormat("[XEngine]: Received request to suspend script with ID {0}", itemID); | 1949 | // m_log.DebugFormat("[XEngine]: Received request to suspend script with ID {0}", itemID); |