aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2012-03-16 00:34:30 +0000
committerJustin Clark-Casey (justincc)2012-03-16 00:34:30 +0000
commita4b01ef38a735ffe70b402061871a9c99f2757ed (patch)
treeb60dcc1cbfaeb0cb0184f4b9619a7e95afe0a4de
parentMerge branch 'master' of ssh://opensimulator.org/var/git/opensim (diff)
downloadopensim-SC-a4b01ef38a735ffe70b402061871a9c99f2757ed.zip
opensim-SC-a4b01ef38a735ffe70b402061871a9c99f2757ed.tar.gz
opensim-SC-a4b01ef38a735ffe70b402061871a9c99f2757ed.tar.bz2
opensim-SC-a4b01ef38a735ffe70b402061871a9c99f2757ed.tar.xz
Replace script-lines-per-second with the script execution time scaled by its measurement period and an idealised frame time.
The previous lines-per-second measurement used for top scripts report was inaccurate, since lines executed does not reflect time taken to execute. Also, every fetch of the report would reset all the numbers limiting its usefulness and we weren't even guaranteed to see the top 100. The actual measurement value should be script execution time per frame but XEngine does not work this way. Therefore, we use actual script execution time scaled by the measurement period and an idealised frame time. This is still not ideal but gives reasonable results and allows scripts to be compared. This commit moves script execution time calculations from SceneGraph into IScriptModule implementations.
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs77
-rw-r--r--OpenSim/Region/Framework/Interfaces/IScriptModule.cs9
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneGraph.cs31
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs9
-rw-r--r--OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs15
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs21
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XEngine.cs53
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
28using System; 28using System;
29using System.Collections;
29using System.Collections.Generic; 30using System.Collections.Generic;
30using System.IO; 31using System.IO;
32using System.Linq;
31using System.Reflection; 33using System.Reflection;
32using System.Security; 34using System.Security;
33using log4net; 35using 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
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic;
30using OpenMetaverse; 31using OpenMetaverse;
31 32
32namespace OpenSim.Region.Framework.Interfaces 33namespace 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);