aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2012-10-11 23:28:53 +0100
committerJustin Clark-Casey (justincc)2012-10-11 23:28:53 +0100
commit1f2472d0fcd86a7ae09c01ecb3508eab001ce033 (patch)
tree2668a8dc7ede987d1b104292508c311c03a37e59 /OpenSim/Framework
parentAssign endVector before control leaves ObjectCommandsModule.TryParseVectorRan... (diff)
downloadopensim-SC_OLD-1f2472d0fcd86a7ae09c01ecb3508eab001ce033.zip
opensim-SC_OLD-1f2472d0fcd86a7ae09c01ecb3508eab001ce033.tar.gz
opensim-SC_OLD-1f2472d0fcd86a7ae09c01ecb3508eab001ce033.tar.bz2
opensim-SC_OLD-1f2472d0fcd86a7ae09c01ecb3508eab001ce033.tar.xz
Extend "show stats" command to "show stats [list|all|<category name>]"
This allows different categories of stats to be shown, with options to list categories or show all stats. Currently categories are scene and simulator and only a very few stats are currently registered via this mechanism. This commit also adds percentage stats for packets and blocks reused from the packet pool.
Diffstat (limited to 'OpenSim/Framework')
-rw-r--r--OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs16
-rw-r--r--OpenSim/Framework/Monitoring/StatsManager.cs193
-rw-r--r--OpenSim/Framework/Servers/BaseOpenSimServer.cs32
3 files changed, 189 insertions, 52 deletions
diff --git a/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
index 8ac9090..aa86202 100644
--- a/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
+++ b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
@@ -359,13 +359,19 @@ Asset service request failures: {3}" + Environment.NewLine,
359 inPacketsPerSecond, outPacketsPerSecond, pendingDownloads, pendingUploads, unackedBytes, totalFrameTime, 359 inPacketsPerSecond, outPacketsPerSecond, pendingDownloads, pendingUploads, unackedBytes, totalFrameTime,
360 netFrameTime, physicsFrameTime, otherFrameTime, agentFrameTime, imageFrameTime)); 360 netFrameTime, physicsFrameTime, otherFrameTime, agentFrameTime, imageFrameTime));
361 361
362 foreach (KeyValuePair<string, Stat> kvp in StatsManager.RegisteredStats) 362 Dictionary<string, Dictionary<string, Stat>> sceneStats;
363 {
364 Stat stat = kvp.Value;
365 363
366 if (stat.Category == "scene" && stat.Verbosity == StatVerbosity.Info) 364 if (StatsManager.TryGetStats("scene", out sceneStats))
365 {
366 foreach (KeyValuePair<string, Dictionary<string, Stat>> kvp in sceneStats)
367 { 367 {
368 sb.AppendFormat("Slow frames ({0}): {1}\n", stat.Container, stat.Value); 368 foreach (Stat stat in kvp.Value.Values)
369 {
370 if (stat.Verbosity == StatVerbosity.Info)
371 {
372 sb.AppendFormat("{0} ({1}): {2}{3}\n", stat.Name, stat.Container, stat.Value, stat.UnitName);
373 }
374 }
369 } 375 }
370 } 376 }
371 377
diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs
index b5dc24f..a67c5f8 100644
--- a/OpenSim/Framework/Monitoring/StatsManager.cs
+++ b/OpenSim/Framework/Monitoring/StatsManager.cs
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using OpenSim.Framework.Console;
30 31
31namespace OpenSim.Framework.Monitoring 32namespace OpenSim.Framework.Monitoring
32{ 33{
@@ -35,13 +36,23 @@ namespace OpenSim.Framework.Monitoring
35 /// </summary> 36 /// </summary>
36 public class StatsManager 37 public class StatsManager
37 { 38 {
39 // Subcommand used to list other stats.
40 public const string AllSubCommand = "all";
41
42 // Subcommand used to list other stats.
43 public const string ListSubCommand = "list";
44
45 // All subcommands
46 public static HashSet<string> SubCommands = new HashSet<string> { AllSubCommand, ListSubCommand };
47
38 /// <summary> 48 /// <summary>
39 /// Registered stats. 49 /// Registered stats categorized by category/container/shortname
40 /// </summary> 50 /// </summary>
41 /// <remarks> 51 /// <remarks>
42 /// Do not add or remove from this dictionary. 52 /// Do not add or remove directly from this dictionary.
43 /// </remarks> 53 /// </remarks>
44 public static Dictionary<string, Stat> RegisteredStats = new Dictionary<string, Stat>(); 54 public static Dictionary<string, Dictionary<string, Dictionary<string, Stat>>> RegisteredStats
55 = new Dictionary<string, Dictionary<string, Dictionary<string, Stat>>>();
45 56
46 private static AssetStatsCollector assetStats; 57 private static AssetStatsCollector assetStats;
47 private static UserStatsCollector userStats; 58 private static UserStatsCollector userStats;
@@ -51,6 +62,76 @@ namespace OpenSim.Framework.Monitoring
51 public static UserStatsCollector UserStats { get { return userStats; } } 62 public static UserStatsCollector UserStats { get { return userStats; } }
52 public static SimExtraStatsCollector SimExtraStats { get { return simExtraStats; } } 63 public static SimExtraStatsCollector SimExtraStats { get { return simExtraStats; } }
53 64
65 public static void RegisterConsoleCommands(CommandConsole console)
66 {
67 console.Commands.AddCommand(
68 "General",
69 false,
70 "show stats",
71 "show stats [list|all|<category>]",
72 "Show statistical information for this server",
73 "If no final argument is specified then legacy statistics information is currently shown.\n"
74 + "If list is specified then statistic categories are shown.\n"
75 + "If all is specified then all registered statistics are shown.\n"
76 + "If a category name is specified then only statistics from that category are shown.\n"
77 + "THIS STATS FACILITY IS EXPERIMENTAL AND DOES NOT YET CONTAIN ALL STATS",
78 HandleShowStatsCommand);
79 }
80
81 public static void HandleShowStatsCommand(string module, string[] cmd)
82 {
83 ICommandConsole con = MainConsole.Instance;
84
85 if (cmd.Length > 2)
86 {
87 var categoryName = cmd[2];
88
89 if (categoryName == AllSubCommand)
90 {
91 foreach (var category in RegisteredStats.Values)
92 {
93 OutputCategoryStatsToConsole(con, category);
94 }
95 }
96 else if (categoryName == ListSubCommand)
97 {
98 con.Output("Statistic categories available are:");
99 foreach (string category in RegisteredStats.Keys)
100 con.OutputFormat(" {0}", category);
101 }
102 else
103 {
104 Dictionary<string, Dictionary<string, Stat>> category;
105 if (!RegisteredStats.TryGetValue(categoryName, out category))
106 {
107 con.OutputFormat("No such category as {0}", categoryName);
108 }
109 else
110 {
111 OutputCategoryStatsToConsole(con, category);
112 }
113 }
114 }
115 else
116 {
117 // Legacy
118 con.Output(SimExtraStats.Report());
119 }
120 }
121
122 private static void OutputCategoryStatsToConsole(
123 ICommandConsole con, Dictionary<string, Dictionary<string, Stat>> category)
124 {
125 foreach (var container in category.Values)
126 {
127 foreach (Stat stat in container.Values)
128 {
129 con.OutputFormat(
130 "{0}.{1}.{2} : {3}{4}", stat.Category, stat.Container, stat.ShortName, stat.Value, stat.UnitName);
131 }
132 }
133 }
134
54 /// <summary> 135 /// <summary>
55 /// Start collecting statistics related to assets. 136 /// Start collecting statistics related to assets.
56 /// Should only be called once. 137 /// Should only be called once.
@@ -73,43 +154,100 @@ namespace OpenSim.Framework.Monitoring
73 return userStats; 154 return userStats;
74 } 155 }
75 156
157 /// <summary>
158 /// Registers a statistic.
159 /// </summary>
160 /// <param name='stat'></param>
161 /// <returns></returns>
76 public static bool RegisterStat(Stat stat) 162 public static bool RegisterStat(Stat stat)
77 { 163 {
164 Dictionary<string, Dictionary<string, Stat>> category = null, newCategory;
165 Dictionary<string, Stat> container = null, newContainer;
166
78 lock (RegisteredStats) 167 lock (RegisteredStats)
79 { 168 {
80 if (RegisteredStats.ContainsKey(stat.UniqueName)) 169 // Stat name is not unique across category/container/shortname key.
81 { 170 // XXX: For now just return false. This is to avoid problems in regression tests where all tests
82 // XXX: For now just return false. This is to avoid problems in regression tests where all tests 171 // in a class are run in the same instance of the VM.
83 // in a class are run in the same instance of the VM. 172 if (TryGetStat(stat, out category, out container))
84 return false; 173 return false;
85 174
86// throw new Exception( 175 // We take a copy-on-write approach here of replacing dictionaries when keys are added or removed.
87// "StatsManager already contains stat with ShortName {0} in Category {1}", stat.ShortName, stat.Category); 176 // This means that we don't need to lock or copy them on iteration, which will be a much more
88 } 177 // common operation after startup.
178 if (container != null)
179 newContainer = new Dictionary<string, Stat>(container);
180 else
181 newContainer = new Dictionary<string, Stat>();
182
183 if (category != null)
184 newCategory = new Dictionary<string, Dictionary<string, Stat>>(category);
185 else
186 newCategory = new Dictionary<string, Dictionary<string, Stat>>();
89 187
90 // We take a replace-on-write approach here so that we don't need to generate a new Dictionary 188 newContainer[stat.ShortName] = stat;
91 Dictionary<string, Stat> newRegisteredStats = new Dictionary<string, Stat>(RegisteredStats); 189 newCategory[stat.Container] = newContainer;
92 newRegisteredStats[stat.UniqueName] = stat; 190 RegisteredStats[stat.Category] = newCategory;
93 RegisteredStats = newRegisteredStats;
94 } 191 }
95 192
96 return true; 193 return true;
97 } 194 }
98 195
196 /// <summary>
197 /// Deregister a statistic
198 /// </summary>>
199 /// <param name='stat'></param>
200 /// <returns></returns
99 public static bool DeregisterStat(Stat stat) 201 public static bool DeregisterStat(Stat stat)
100 { 202 {
203 Dictionary<string, Dictionary<string, Stat>> category = null, newCategory;
204 Dictionary<string, Stat> container = null, newContainer;
205
101 lock (RegisteredStats) 206 lock (RegisteredStats)
102 { 207 {
103 if (!RegisteredStats.ContainsKey(stat.UniqueName)) 208 if (!TryGetStat(stat, out category, out container))
104 return false; 209 return false;
105 210
106 Dictionary<string, Stat> newRegisteredStats = new Dictionary<string, Stat>(RegisteredStats); 211 newContainer = new Dictionary<string, Stat>(container);
107 newRegisteredStats.Remove(stat.UniqueName); 212 newContainer.Remove(stat.UniqueName);
108 RegisteredStats = newRegisteredStats; 213
214 newCategory = new Dictionary<string, Dictionary<string, Stat>>(category);
215 newCategory.Remove(stat.Container);
216
217 newCategory[stat.Container] = newContainer;
218 RegisteredStats[stat.Category] = newCategory;
109 219
110 return true; 220 return true;
111 } 221 }
112 } 222 }
223
224 public static bool TryGetStats(string category, out Dictionary<string, Dictionary<string, Stat>> stats)
225 {
226 return RegisteredStats.TryGetValue(category, out stats);
227 }
228
229 public static bool TryGetStat(
230 Stat stat,
231 out Dictionary<string, Dictionary<string, Stat>> category,
232 out Dictionary<string, Stat> container)
233 {
234 category = null;
235 container = null;
236
237 lock (RegisteredStats)
238 {
239 if (RegisteredStats.TryGetValue(stat.Category, out category))
240 {
241 if (category.TryGetValue(stat.Container, out container))
242 {
243 if (container.ContainsKey(stat.ShortName))
244 return true;
245 }
246 }
247 }
248
249 return false;
250 }
113 } 251 }
114 252
115 /// <summary> 253 /// <summary>
@@ -157,9 +295,26 @@ namespace OpenSim.Framework.Monitoring
157 295
158 public virtual double Value { get; set; } 296 public virtual double Value { get; set; }
159 297
298 /// <summary>
299 /// Constructor
300 /// </summary>
301 /// <param name='shortName'>Short name for the stat. Must not contain spaces. e.g. "LongFrames"</param>
302 /// <param name='name'>Human readable name for the stat. e.g. "Long frames"</param>
303 /// <param name='unitName'>
304 /// Unit name for the stat. Should be preceeded by a space if the unit name isn't normally appeneded immediately to the value.
305 /// e.g. " frames"
306 /// </param>
307 /// <param name='category'>Category under which this stat should appear, e.g. "scene". Do not capitalize.</param>
308 /// <param name='container'>Entity to which this stat relates. e.g. scene name if this is a per scene stat.</param>
309 /// <param name='verbosity'>Verbosity of stat. Controls whether it will appear in short stat display or only full display.</param>
310 /// <param name='description'>Description of stat</param>
160 public Stat( 311 public Stat(
161 string shortName, string name, string unitName, string category, string container, StatVerbosity verbosity, string description) 312 string shortName, string name, string unitName, string category, string container, StatVerbosity verbosity, string description)
162 { 313 {
314 if (StatsManager.SubCommands.Contains(category))
315 throw new Exception(
316 string.Format("Stat cannot be in category '{0}' since this is reserved for a subcommand", category));
317
163 ShortName = shortName; 318 ShortName = shortName;
164 Name = name; 319 Name = name;
165 UnitName = unitName; 320 UnitName = unitName;
@@ -203,7 +358,7 @@ namespace OpenSim.Framework.Monitoring
203 358
204 public PercentageStat( 359 public PercentageStat(
205 string shortName, string name, string category, string container, StatVerbosity verbosity, string description) 360 string shortName, string name, string category, string container, StatVerbosity verbosity, string description)
206 : base(shortName, name, " %", category, container, verbosity, description) 361 : base(shortName, name, "%", category, container, verbosity, description)
207 { 362 {
208 } 363 }
209 } 364 }
diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs
index 7a5c16d..aac9c45 100644
--- a/OpenSim/Framework/Servers/BaseOpenSimServer.cs
+++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs
@@ -96,11 +96,6 @@ namespace OpenSim.Framework.Servers
96 get { return m_httpServer; } 96 get { return m_httpServer; }
97 } 97 }
98 98
99 /// <summary>
100 /// Holds the non-viewer statistics collection object for this service/server
101 /// </summary>
102 protected IStatsCollector m_stats;
103
104 public BaseOpenSimServer() 99 public BaseOpenSimServer()
105 { 100 {
106 m_startuptime = DateTime.Now; 101 m_startuptime = DateTime.Now;
@@ -177,10 +172,6 @@ namespace OpenSim.Framework.Servers
177 "show info", 172 "show info",
178 "Show general information about the server", HandleShow); 173 "Show general information about the server", HandleShow);
179 174
180 m_console.Commands.AddCommand("General", false, "show stats",
181 "show stats",
182 "Show statistics", HandleShow);
183
184 m_console.Commands.AddCommand("General", false, "show threads", 175 m_console.Commands.AddCommand("General", false, "show threads",
185 "show threads", 176 "show threads",
186 "Show thread status", HandleShow); 177 "Show thread status", HandleShow);
@@ -226,12 +217,7 @@ namespace OpenSim.Framework.Servers
226 { 217 {
227 StringBuilder sb = new StringBuilder("DIAGNOSTICS\n\n"); 218 StringBuilder sb = new StringBuilder("DIAGNOSTICS\n\n");
228 sb.Append(GetUptimeReport()); 219 sb.Append(GetUptimeReport());
229 220 sb.Append(StatsManager.SimExtraStats.Report());
230 if (m_stats != null)
231 {
232 sb.Append(m_stats.Report());
233 }
234
235 sb.Append(Environment.NewLine); 221 sb.Append(Environment.NewLine);
236 sb.Append(GetThreadsReport()); 222 sb.Append(GetThreadsReport());
237 223
@@ -382,10 +368,6 @@ namespace OpenSim.Framework.Servers
382 { 368 {
383 Notice("set log level [level] - change the console logging level only. For example, off or debug."); 369 Notice("set log level [level] - change the console logging level only. For example, off or debug.");
384 Notice("show info - show server information (e.g. startup path)."); 370 Notice("show info - show server information (e.g. startup path).");
385
386 if (m_stats != null)
387 Notice("show stats - show statistical information for this server");
388
389 Notice("show threads - list tracked threads"); 371 Notice("show threads - list tracked threads");
390 Notice("show uptime - show server startup time and uptime."); 372 Notice("show uptime - show server startup time and uptime.");
391 Notice("show version - show server version."); 373 Notice("show version - show server version.");
@@ -409,11 +391,6 @@ namespace OpenSim.Framework.Servers
409 ShowInfo(); 391 ShowInfo();
410 break; 392 break;
411 393
412 case "stats":
413 if (m_stats != null)
414 Notice(m_stats.Report());
415 break;
416
417 case "threads": 394 case "threads":
418 Notice(GetThreadsReport()); 395 Notice(GetThreadsReport());
419 break; 396 break;
@@ -604,8 +581,7 @@ namespace OpenSim.Framework.Servers
604 581
605 public string osSecret { 582 public string osSecret {
606 // Secret uuid for the simulator 583 // Secret uuid for the simulator
607 get { return m_osSecret; } 584 get { return m_osSecret; }
608
609 } 585 }
610 586
611 public string StatReport(IOSHttpRequest httpRequest) 587 public string StatReport(IOSHttpRequest httpRequest)
@@ -613,11 +589,11 @@ namespace OpenSim.Framework.Servers
613 // If we catch a request for "callback", wrap the response in the value for jsonp 589 // If we catch a request for "callback", wrap the response in the value for jsonp
614 if (httpRequest.Query.ContainsKey("callback")) 590 if (httpRequest.Query.ContainsKey("callback"))
615 { 591 {
616 return httpRequest.Query["callback"].ToString() + "(" + m_stats.XReport((DateTime.Now - m_startuptime).ToString() , m_version) + ");"; 592 return httpRequest.Query["callback"].ToString() + "(" + StatsManager.SimExtraStats.XReport((DateTime.Now - m_startuptime).ToString() , m_version) + ");";
617 } 593 }
618 else 594 else
619 { 595 {
620 return m_stats.XReport((DateTime.Now - m_startuptime).ToString() , m_version); 596 return StatsManager.SimExtraStats.XReport((DateTime.Now - m_startuptime).ToString() , m_version);
621 } 597 }
622 } 598 }
623 599