OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
SimExtraStatsCollector.cs
Go to the documentation of this file.
1 /*
2  * Copyright (c) Contributors, http://opensimulator.org/
3  * See CONTRIBUTORS.TXT for a full list of copyright holders.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the OpenSimulator Project nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 using System;
29 using System.Collections.Generic;
30 using System.Diagnostics;
31 using System.Linq;
32 using System.Text;
33 using OpenMetaverse;
34 using OpenMetaverse.StructuredData;
35 using OpenSim.Framework.Monitoring.Interfaces;
36 
37 
38 namespace OpenSim.Framework.Monitoring
39 {
44  {
45 // private long assetsInCache;
46 // private long texturesInCache;
47 // private long assetCacheMemoryUsage;
48 // private long textureCacheMemoryUsage;
49 // private TimeSpan assetRequestTimeAfterCacheMiss;
50 // private long blockedMissingTextureRequests;
51 
52 // private long assetServiceRequestFailures;
53 // private long inventoryServiceRetrievalFailures;
54 
55  private volatile float timeDilation;
56  private volatile float simFps;
57  private volatile float physicsFps;
58  private volatile float agentUpdates;
59  private volatile float rootAgents;
60  private volatile float childAgents;
61  private volatile float totalPrims;
62  private volatile float activePrims;
63  private volatile float totalFrameTime;
64  private volatile float netFrameTime;
65  private volatile float physicsFrameTime;
66  private volatile float otherFrameTime;
67  private volatile float imageFrameTime;
68  private volatile float inPacketsPerSecond;
69  private volatile float outPacketsPerSecond;
70  private volatile float unackedBytes;
71  private volatile float agentFrameTime;
72  private volatile float pendingDownloads;
73  private volatile float pendingUploads;
74  private volatile float activeScripts;
75  private volatile float spareTime;
76  private volatile float sleepTime;
77  private volatile float physicsStep;
78 
79 
80  private volatile float scriptLinesPerSecond;
81  private volatile float m_frameDilation;
82  private volatile float m_usersLoggingIn;
83  private volatile float m_totalGeoPrims;
84  private volatile float m_totalMeshes;
85  private volatile float m_inUseThreads;
86 
87 // /// <summary>
88 // /// These statistics are being collected by push rather than pull. Pull would be simpler, but I had the
89 // /// notion of providing some flow statistics (which pull wouldn't give us). Though admittedly these
90 // /// haven't yet been implemented...
91 // /// </summary>
92 // public long AssetsInCache { get { return assetsInCache; } }
93 //
94 // /// <value>
95 // /// Currently unused
96 // /// </value>
97 // public long TexturesInCache { get { return texturesInCache; } }
98 //
99 // /// <value>
100 // /// Currently misleading since we can't currently subtract removed asset memory usage without a performance hit
101 // /// </value>
102 // public long AssetCacheMemoryUsage { get { return assetCacheMemoryUsage; } }
103 //
104 // /// <value>
105 // /// Currently unused
106 // /// </value>
107 // public long TextureCacheMemoryUsage { get { return textureCacheMemoryUsage; } }
108 
109  public float TimeDilation { get { return timeDilation; } }
110  public float SimFps { get { return simFps; } }
111  public float PhysicsFps { get { return physicsFps; } }
112  public float AgentUpdates { get { return agentUpdates; } }
113  public float RootAgents { get { return rootAgents; } }
114  public float ChildAgents { get { return childAgents; } }
115  public float TotalPrims { get { return totalPrims; } }
116  public float ActivePrims { get { return activePrims; } }
117  public float TotalFrameTime { get { return totalFrameTime; } }
118  public float NetFrameTime { get { return netFrameTime; } }
119  public float PhysicsFrameTime { get { return physicsFrameTime; } }
120  public float OtherFrameTime { get { return otherFrameTime; } }
121  public float ImageFrameTime { get { return imageFrameTime; } }
122  public float InPacketsPerSecond { get { return inPacketsPerSecond; } }
123  public float OutPacketsPerSecond { get { return outPacketsPerSecond; } }
124  public float UnackedBytes { get { return unackedBytes; } }
125  public float AgentFrameTime { get { return agentFrameTime; } }
126  public float PendingDownloads { get { return pendingDownloads; } }
127  public float PendingUploads { get { return pendingUploads; } }
128  public float ActiveScripts { get { return activeScripts; } }
129  public float ScriptLinesPerSecond { get { return scriptLinesPerSecond; } }
130 
131 // /// <summary>
132 // /// This is the time it took for the last asset request made in response to a cache miss.
133 // /// </summary>
134 // public TimeSpan AssetRequestTimeAfterCacheMiss { get { return assetRequestTimeAfterCacheMiss; } }
135 //
136 // /// <summary>
137 // /// Number of persistent requests for missing textures we have started blocking from clients. To some extent
138 // /// this is just a temporary statistic to keep this problem in view - the root cause of this lies either
139 // /// in a mishandling of the reply protocol, related to avatar appearance or may even originate in graphics
140 // /// driver bugs on clients (though this seems less likely).
141 // /// </summary>
142 // public long BlockedMissingTextureRequests { get { return blockedMissingTextureRequests; } }
143 //
144 // /// <summary>
145 // /// Record the number of times that an asset request has failed. Failures are effectively exceptions, such as
146 // /// request timeouts. If an asset service replies that a particular asset cannot be found, this is not counted
147 // /// as a failure
148 // /// </summary>
149 // public long AssetServiceRequestFailures { get { return assetServiceRequestFailures; } }
150 
157 // public long InventoryServiceRetrievalFailures { get { return inventoryServiceRetrievalFailures; } }
158 
162  //public float TotalFrameTime { get { return totalFrameTime; } }
163 
167  //public float PhysicsFrameTime { get { return physicsFrameTime; } }
168 
172  private IDictionary<UUID, PacketQueueStatsCollector> packetQueueStatsCollectors
173  = new Dictionary<UUID, PacketQueueStatsCollector>();
174 
175 // public void AddAsset(AssetBase asset)
176 // {
177 // assetsInCache++;
178 // //assetCacheMemoryUsage += asset.Data.Length;
179 // }
180 //
181 // public void RemoveAsset(UUID uuid)
182 // {
183 // assetsInCache--;
184 // }
185 //
186 // public void AddTexture(AssetBase image)
187 // {
188 // if (image.Data != null)
189 // {
190 // texturesInCache++;
191 //
192 // // This could have been a pull stat, though there was originally a nebulous idea to measure flow rates
193 // textureCacheMemoryUsage += image.Data.Length;
194 // }
195 // }
196 //
197 // /// <summary>
198 // /// Signal that the asset cache has been cleared.
199 // /// </summary>
200 // public void ClearAssetCacheStatistics()
201 // {
202 // assetsInCache = 0;
203 // assetCacheMemoryUsage = 0;
204 // texturesInCache = 0;
205 // textureCacheMemoryUsage = 0;
206 // }
207 //
208 // public void AddAssetRequestTimeAfterCacheMiss(TimeSpan ts)
209 // {
210 // assetRequestTimeAfterCacheMiss = ts;
211 // }
212 //
213 // public void AddBlockedMissingTextureRequest()
214 // {
215 // blockedMissingTextureRequests++;
216 // }
217 //
218 // public void AddAssetServiceRequestFailure()
219 // {
220 // assetServiceRequestFailures++;
221 // }
222 
223 // public void AddInventoryServiceRetrievalFailure()
224 // {
225 // inventoryServiceRetrievalFailures++;
226 // }
227 
233  public void RegisterPacketQueueStatsProvider(UUID uuid, IPullStatsProvider provider)
234  {
235  lock (packetQueueStatsCollectors)
236  {
237  // FIXME: If the region service is providing more than one region, then the child and root agent
238  // queues are wrongly replacing each other here.
239  packetQueueStatsCollectors[uuid] = new PacketQueueStatsCollector(provider);
240  }
241  }
242 
247  public void DeregisterPacketQueueStatsProvider(UUID uuid)
248  {
249  lock (packetQueueStatsCollectors)
250  {
251  packetQueueStatsCollectors.Remove(uuid);
252  }
253  }
254 
261  {
262  // FIXME: SimStats shouldn't allow an arbitrary stat packing order (which is inherited from the original
263  // SimStatsPacket that was being used).
264 
265  // For an unknown reason the original designers decided not to
266  // include the spare MS statistic inside of this class, this is
267  // located inside the StatsBlock at location 21, thus it is skipped
268  timeDilation = stats.StatsBlock[0].StatValue;
269  simFps = stats.StatsBlock[1].StatValue;
270  physicsFps = stats.StatsBlock[2].StatValue;
271  agentUpdates = stats.StatsBlock[3].StatValue;
272  rootAgents = stats.StatsBlock[4].StatValue;
273  childAgents = stats.StatsBlock[5].StatValue;
274  totalPrims = stats.StatsBlock[6].StatValue;
275  activePrims = stats.StatsBlock[7].StatValue;
276  totalFrameTime = stats.StatsBlock[8].StatValue;
277  netFrameTime = stats.StatsBlock[9].StatValue;
278  physicsFrameTime = stats.StatsBlock[10].StatValue;
279  imageFrameTime = stats.StatsBlock[11].StatValue;
280  otherFrameTime = stats.StatsBlock[12].StatValue;
281  inPacketsPerSecond = stats.StatsBlock[13].StatValue;
282  outPacketsPerSecond = stats.StatsBlock[14].StatValue;
283  unackedBytes = stats.StatsBlock[15].StatValue;
284  agentFrameTime = stats.StatsBlock[16].StatValue;
285  pendingDownloads = stats.StatsBlock[17].StatValue;
286  pendingUploads = stats.StatsBlock[18].StatValue;
287  activeScripts = stats.StatsBlock[19].StatValue;
288  sleepTime = stats.StatsBlock[20].StatValue;
289  spareTime = stats.StatsBlock[21].StatValue;
290  physicsStep = stats.StatsBlock[22].StatValue;
291 
292  scriptLinesPerSecond = stats.ExtraStatsBlock[0].StatValue;
293  m_frameDilation = stats.ExtraStatsBlock[1].StatValue;
294  m_usersLoggingIn = stats.ExtraStatsBlock[2].StatValue;
295  m_totalGeoPrims = stats.ExtraStatsBlock[3].StatValue;
296  m_totalMeshes = stats.ExtraStatsBlock[4].StatValue;
297  m_inUseThreads = stats.ExtraStatsBlock[5].StatValue;
298  }
299 
304  public override string Report()
305  {
306  StringBuilder sb = new StringBuilder(Environment.NewLine);
307 // sb.Append("ASSET STATISTICS");
308 // sb.Append(Environment.NewLine);
309 
310  /*
311  sb.Append(
312  string.Format(
313 @"Asset cache contains {0,6} non-texture assets using {1,10} K
314 Texture cache contains {2,6} texture assets using {3,10} K
315 Latest asset request time after cache miss: {4}s
316 Blocked client requests for missing textures: {5}
317 Asset service request failures: {6}"+ Environment.NewLine,
318  AssetsInCache, Math.Round(AssetCacheMemoryUsage / 1024.0),
319  TexturesInCache, Math.Round(TextureCacheMemoryUsage / 1024.0),
320  assetRequestTimeAfterCacheMiss.Milliseconds / 1000.0,
321  BlockedMissingTextureRequests,
322  AssetServiceRequestFailures));
323  */
324 
325  /*
326  sb.Append(
327  string.Format(
328 @"Asset cache contains {0,6} assets
329 Latest asset request time after cache miss: {1}s
330 Blocked client requests for missing textures: {2}
331 Asset service request failures: {3}" + Environment.NewLine,
332  AssetsInCache,
333  assetRequestTimeAfterCacheMiss.Milliseconds / 1000.0,
334  BlockedMissingTextureRequests,
335  AssetServiceRequestFailures));
336  */
337 
338  sb.Append(Environment.NewLine);
339  sb.Append("CONNECTION STATISTICS");
340  sb.Append(Environment.NewLine);
341 
342  List<Stat> stats = StatsManager.GetStatsFromEachContainer("clientstack", "ClientLogoutsDueToNoReceives");
343 
344  sb.AppendFormat(
345  "Client logouts due to no data receive timeout: {0}\n\n",
346  stats != null ? stats.Sum(s => s.Value).ToString() : "unknown");
347 
348 // sb.Append(Environment.NewLine);
349 // sb.Append("INVENTORY STATISTICS");
350 // sb.Append(Environment.NewLine);
351 // sb.Append(
352 // string.Format(
353 // "Initial inventory caching failures: {0}" + Environment.NewLine,
354 // InventoryServiceRetrievalFailures));
355 
356  sb.Append(Environment.NewLine);
357  sb.Append("SAMPLE FRAME STATISTICS");
358  sb.Append(Environment.NewLine);
359  sb.Append("Dilatn SimFPS PhyFPS AgntUp RootAg ChldAg Prims AtvPrm AtvScr ScrLPS");
360  sb.Append(Environment.NewLine);
361  sb.Append(
362  string.Format(
363  "{0,6:0.00} {1,6:0} {2,6:0.0} {3,6:0.0} {4,6:0} {5,6:0} {6,6:0} {7,6:0} {8,6:0} {9,6:0}",
364  timeDilation, simFps, physicsFps, agentUpdates, rootAgents,
365  childAgents, totalPrims, activePrims, activeScripts, scriptLinesPerSecond));
366 
367  sb.Append(Environment.NewLine);
368  sb.Append(Environment.NewLine);
369  // There is no script frame time currently because we don't yet collect it
370  sb.Append("PktsIn PktOut PendDl PendUl UnackB TotlFt NetFt PhysFt OthrFt AgntFt ImgsFt");
371  sb.Append(Environment.NewLine);
372  sb.Append(
373  string.Format(
374  "{0,6:0} {1,6:0} {2,6:0} {3,6:0} {4,6:0} {5,6:0.0} {6,6:0.0} {7,6:0.0} {8,6:0.0} {9,6:0.0} {10,6:0.0}\n\n",
375  inPacketsPerSecond, outPacketsPerSecond, pendingDownloads, pendingUploads, unackedBytes, totalFrameTime,
376  netFrameTime, physicsFrameTime, otherFrameTime, agentFrameTime, imageFrameTime));
377 
378  /* 20130319 RA: For the moment, disable the dump of 'scene' catagory as they are mostly output by
379  * the two formatted printouts above.
380  SortedDictionary<string, SortedDictionary<string, Stat>> sceneStats;
381  if (StatsManager.TryGetStats("scene", out sceneStats))
382  {
383  foreach (KeyValuePair<string, SortedDictionary<string, Stat>> kvp in sceneStats)
384  {
385  foreach (Stat stat in kvp.Value.Values)
386  {
387  if (stat.Verbosity == StatVerbosity.Info)
388  {
389  sb.AppendFormat("{0} ({1}): {2}{3}\n", stat.Name, stat.Container, stat.Value, stat.UnitName);
390  }
391  }
392  }
393  }
394  */
395 
396  /*
397  sb.Append(Environment.NewLine);
398  sb.Append("PACKET QUEUE STATISTICS");
399  sb.Append(Environment.NewLine);
400  sb.Append("Agent UUID ");
401  sb.Append(
402  string.Format(
403  " {0,7} {1,7} {2,7} {3,7} {4,7} {5,7} {6,7} {7,7} {8,7} {9,7}",
404  "Send", "In", "Out", "Resend", "Land", "Wind", "Cloud", "Task", "Texture", "Asset"));
405  sb.Append(Environment.NewLine);
406 
407  foreach (UUID key in packetQueueStatsCollectors.Keys)
408  {
409  sb.Append(string.Format("{0}: ", key));
410  sb.Append(packetQueueStatsCollectors[key].Report());
411  sb.Append(Environment.NewLine);
412  }
413  */
414 
415  sb.Append(base.Report());
416 
417  return sb.ToString();
418  }
419 
424  public override string XReport(string uptime, string version)
425  {
426  return OSDParser.SerializeJsonString(OReport(uptime, version));
427  }
428 
433  public override OSDMap OReport(string uptime, string version)
434  {
435  // Get the amount of physical memory, allocated with the instance of this program, in kilobytes;
436  // the working set is the set of memory pages currently visible to this program in physical RAM
437  // memory and includes both shared (e.g. system libraries) and private data
438  double memUsage = Process.GetCurrentProcess().WorkingSet64 / 1024.0;
439 
440  // Get the number of threads from the system that are currently
441  // running
442  int numberThreadsRunning = 0;
443  foreach (ProcessThread currentThread in
444  Process.GetCurrentProcess().Threads)
445  {
446  // A known issue with the current process .Threads property is
447  // that it can return null threads, thus don't count those as
448  // running threads and prevent the program function from failing
449  if (currentThread != null &&
450  currentThread.ThreadState == ThreadState.Running)
451  {
452  numberThreadsRunning++;
453  }
454  }
455 
456  OSDMap args = new OSDMap(30);
457 // args["AssetsInCache"] = OSD.FromString (String.Format ("{0:0.##}", AssetsInCache));
458 // args["TimeAfterCacheMiss"] = OSD.FromString (String.Format ("{0:0.##}",
459 // assetRequestTimeAfterCacheMiss.Milliseconds / 1000.0));
460 // args["BlockedMissingTextureRequests"] = OSD.FromString (String.Format ("{0:0.##}",
461 // BlockedMissingTextureRequests));
462 // args["AssetServiceRequestFailures"] = OSD.FromString (String.Format ("{0:0.##}",
463 // AssetServiceRequestFailures));
464 // args["abnormalClientThreadTerminations"] = OSD.FromString (String.Format ("{0:0.##}",
465 // abnormalClientThreadTerminations));
466 // args["InventoryServiceRetrievalFailures"] = OSD.FromString (String.Format ("{0:0.##}",
467 // InventoryServiceRetrievalFailures));
468  args["Dilatn"] = OSD.FromString (String.Format ("{0:0.##}", timeDilation));
469  args["SimFPS"] = OSD.FromString (String.Format ("{0:0.##}", simFps));
470  args["PhyFPS"] = OSD.FromString (String.Format ("{0:0.##}", physicsFps));
471  args["AgntUp"] = OSD.FromString (String.Format ("{0:0.##}", agentUpdates));
472  args["RootAg"] = OSD.FromString (String.Format ("{0:0.##}", rootAgents));
473  args["ChldAg"] = OSD.FromString (String.Format ("{0:0.##}", childAgents));
474  args["Prims"] = OSD.FromString (String.Format ("{0:0.##}", totalPrims));
475  args["AtvPrm"] = OSD.FromString (String.Format ("{0:0.##}", activePrims));
476  args["AtvScr"] = OSD.FromString (String.Format ("{0:0.##}", activeScripts));
477  args["ScrLPS"] = OSD.FromString (String.Format ("{0:0.##}", scriptLinesPerSecond));
478  args["PktsIn"] = OSD.FromString (String.Format ("{0:0.##}", inPacketsPerSecond));
479  args["PktOut"] = OSD.FromString (String.Format ("{0:0.##}", outPacketsPerSecond));
480  args["PendDl"] = OSD.FromString (String.Format ("{0:0.##}", pendingDownloads));
481  args["PendUl"] = OSD.FromString (String.Format ("{0:0.##}", pendingUploads));
482  args["UnackB"] = OSD.FromString (String.Format ("{0:0.##}", unackedBytes));
483  args["TotlFt"] = OSD.FromString (String.Format ("{0:0.##}", totalFrameTime));
484  args["NetFt"] = OSD.FromString (String.Format ("{0:0.##}", netFrameTime));
485  args["PhysFt"] = OSD.FromString (String.Format ("{0:0.##}", physicsFrameTime));
486  args["OthrFt"] = OSD.FromString (String.Format ("{0:0.##}", otherFrameTime));
487  args["AgntFt"] = OSD.FromString (String.Format ("{0:0.##}", agentFrameTime));
488  args["ImgsFt"] = OSD.FromString (String.Format ("{0:0.##}", imageFrameTime));
489  args["Memory"] = OSD.FromString (base.XReport (uptime, version));
490  args["Uptime"] = OSD.FromString (uptime);
491  args["Version"] = OSD.FromString (version);
492 
493  args["FrameDilatn"] = OSD.FromString(String.Format("{0:0.##}", m_frameDilation));
494  args["Logging in Users"] = OSD.FromString(String.Format("{0:0.##}",
495  m_usersLoggingIn));
496  args["GeoPrims"] = OSD.FromString(String.Format("{0:0.##}",
497  m_totalGeoPrims));
498  args["Mesh Objects"] = OSD.FromString(String.Format("{0:0.##}",
499  m_totalMeshes));
500  args["XEngine Thread Count"] = OSD.FromString(String.Format("{0:0.##}",
501  m_inUseThreads));
502  args["Util Thread Count"] = OSD.FromString(String.Format("{0:0.##}",
503  Util.GetSmartThreadPoolInfo().InUseThreads));
504  args["System Thread Count"] = OSD.FromString(String.Format(
505  "{0:0.##}", numberThreadsRunning));
506  args["ProcMem"] = OSD.FromString(String.Format("{0:#,###,###.##}",
507  memUsage));
508 
509  return args;
510  }
511  }
512 
513 
518  {
519  private IPullStatsProvider m_statsProvider;
520 
522  {
523  m_statsProvider = provider;
524  }
525 
530  public string Report()
531  {
532  return m_statsProvider.GetStats();
533  }
534 
535  public string XReport(string uptime, string version)
536  {
537  return "";
538  }
539 
540  public OSDMap OReport(string uptime, string version)
541  {
542  OSDMap ret = new OSDMap();
543  return ret;
544  }
545  }
546 }
Implemented by classes which collect up non-viewer statistical information
override OSDMap OReport(string uptime, string version)
Report back collected statistical information as an OSDMap
void DeregisterPacketQueueStatsProvider(UUID uuid)
Deregister a packet queue stats provider
string XReport(string uptime, string version)
Report back collected statistical information in json
Implemented by objects which allow statistical information to be pulled from them.
OpenMetaverse.StructuredData.OSDMap OSDMap
Enapsulate statistics for a simulator/scene.
Definition: SimStats.cs:39
Collects sim statistics which aren't already being collected for the linden viewer's statistics pane ...
void ReceiveClassicSimStatsPacket(SimStats stats)
This is the method on which the classic sim stats reporter (which collects stats for client purposes)...
override string Report()
Report back collected statistical information.
Pull packet queue stats from packet queues and report
Statistics which all collectors are interested in reporting
OSDMap OReport(string uptime, string version)
Report back collected statistical information as an OSDMap of key/values
override string XReport(string uptime, string version)
Report back collected statistical information as json serialization.
string Report()
Report back collected statistical information.
void RegisterPacketQueueStatsProvider(UUID uuid, IPullStatsProvider provider)
Register as a packet queue stats provider