aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/OptionalModules/Agent/UDP
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/OptionalModules/Agent/UDP')
-rw-r--r--OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs679
1 files changed, 679 insertions, 0 deletions
diff --git a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs
new file mode 100644
index 0000000..08d0fbf
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs
@@ -0,0 +1,679 @@
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
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Reflection;
32using System.Text;
33using log4net;
34using Mono.Addins;
35using Nini.Config;
36using OpenMetaverse;
37using OpenSim.Framework;
38using OpenSim.Framework.Console;
39using OpenSim.Framework.Monitoring;
40using OpenSim.Region.ClientStack.LindenUDP;
41using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Region.Framework.Scenes;
43
44namespace OpenSim.Region.OptionalModules.UDP.Linden
45{
46 /// <summary>
47 /// A module that just holds commands for inspecting the current state of the Linden UDP stack.
48 /// </summary>
49 /// <remarks>
50 /// All actual client stack functionality remains in OpenSim.Region.ClientStack.LindenUDP
51 /// </remarks>
52 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LindenUDPInfoModule")]
53 public class LindenUDPInfoModule : ISharedRegionModule
54 {
55 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
56
57 protected Dictionary<UUID, Scene> m_scenes = new Dictionary<UUID, Scene>();
58
59 public string Name { get { return "Linden UDP Module"; } }
60
61 public Type ReplaceableInterface { get { return null; } }
62
63 public void Initialise(IConfigSource source)
64 {
65// m_log.DebugFormat("[LINDEN UDP INFO MODULE]: INITIALIZED MODULE");
66 }
67
68 public void PostInitialise()
69 {
70// m_log.DebugFormat("[LINDEN UDP INFO MODULE]: POST INITIALIZED MODULE");
71 }
72
73 public void Close()
74 {
75// m_log.DebugFormat("[LINDEN UDP INFO MODULE]: CLOSED MODULE");
76 }
77
78 public void AddRegion(Scene scene)
79 {
80// m_log.DebugFormat("[LINDEN UDP INFO MODULE]: REGION {0} ADDED", scene.RegionInfo.RegionName);
81
82 lock (m_scenes)
83 m_scenes[scene.RegionInfo.RegionID] = scene;
84
85 scene.AddCommand(
86 "Comms", this, "show pqueues",
87 "show pqueues [full]",
88 "Show priority queue data for each client",
89 "Without the 'full' option, only root agents are shown."
90 + " With the 'full' option child agents are also shown.",
91 (mod, cmd) => MainConsole.Instance.Output(GetPQueuesReport(cmd)));
92
93 scene.AddCommand(
94 "Comms", this, "show queues",
95 "show queues [full]",
96 "Show queue data for each client",
97 "Without the 'full' option, only root agents are shown.\n"
98 + "With the 'full' option child agents are also shown.\n\n"
99 + "Type - Rt is a root (avatar) client whilst cd is a child (neighbour interacting) client.\n"
100 + "Since Last In - Time in milliseconds since last packet received.\n"
101 + "Pkts In - Number of packets processed from the client.\n"
102 + "Pkts Out - Number of packets sent to the client.\n"
103 + "Pkts Resent - Number of packets resent to the client.\n"
104 + "Bytes Unacked - Number of bytes transferred to the client that are awaiting acknowledgement.\n"
105 + "Q Pkts * - Number of packets of various types (land, wind, etc.) to be sent to the client that are waiting for available bandwidth.\n",
106 (mod, cmd) => MainConsole.Instance.Output(GetQueuesReport(cmd)));
107
108 scene.AddCommand(
109 "Comms", this, "show image queues",
110 "show image queues <first-name> <last-name>",
111 "Show the image queues (textures downloaded via UDP) for a particular client.",
112 (mod, cmd) => MainConsole.Instance.Output(GetImageQueuesReport(cmd)));
113
114 scene.AddCommand(
115 "Comms", this, "clear image queues",
116 "clear image queues <first-name> <last-name>",
117 "Clear the image queues (textures downloaded via UDP) for a particular client.",
118 (mod, cmd) => MainConsole.Instance.Output(HandleImageQueuesClear(cmd)));
119
120 scene.AddCommand(
121 "Comms", this, "show throttles",
122 "show throttles [full]",
123 "Show throttle settings for each client and for the server overall",
124 "Without the 'full' option, only root agents are shown."
125 + " With the 'full' option child agents are also shown.",
126 (mod, cmd) => MainConsole.Instance.Output(GetThrottlesReport(cmd)));
127
128 scene.AddCommand(
129 "Comms", this, "emergency-monitoring",
130 "emergency-monitoring",
131 "Go on/off emergency monitoring mode",
132 "Go on/off emergency monitoring mode",
133 HandleEmergencyMonitoring);
134
135 scene.AddCommand(
136 "Comms", this, "show client stats",
137 "show client stats [first_name last_name]",
138 "Show client request stats",
139 "Without the 'first_name last_name' option, all clients are shown."
140 + " With the 'first_name last_name' option only a specific client is shown.",
141 (mod, cmd) => MainConsole.Instance.Output(HandleClientStatsReport(cmd)));
142
143 }
144
145 public void RemoveRegion(Scene scene)
146 {
147// m_log.DebugFormat("[LINDEN UDP INFO MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName);
148
149 lock (m_scenes)
150 m_scenes.Remove(scene.RegionInfo.RegionID);
151 }
152
153 public void RegionLoaded(Scene scene)
154 {
155// m_log.DebugFormat("[LINDEN UDP INFO MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName);
156 }
157
158 protected string HandleImageQueuesClear(string[] cmd)
159 {
160 if (cmd.Length != 5)
161 return "Usage: image queues clear <first-name> <last-name>";
162
163 string firstName = cmd[3];
164 string lastName = cmd[4];
165
166 List<ScenePresence> foundAgents = new List<ScenePresence>();
167
168 lock (m_scenes)
169 {
170 foreach (Scene scene in m_scenes.Values)
171 {
172 ScenePresence sp = scene.GetScenePresence(firstName, lastName);
173 if (sp != null)
174 foundAgents.Add(sp);
175 }
176 }
177
178 if (foundAgents.Count == 0)
179 return string.Format("No agents found for {0} {1}", firstName, lastName);
180
181 StringBuilder report = new StringBuilder();
182
183 foreach (ScenePresence agent in foundAgents)
184 {
185 LLClientView client = agent.ControllingClient as LLClientView;
186
187 if (client == null)
188 return "This command is only supported for LLClientView";
189
190 int requestsDeleted = client.ImageManager.ClearImageQueue();
191
192 report.AppendFormat(
193 "In region {0} ({1} agent) cleared {2} requests\n",
194 agent.Scene.RegionInfo.RegionName, agent.IsChildAgent ? "child" : "root", requestsDeleted);
195 }
196
197 return report.ToString();
198 }
199
200 protected void HandleEmergencyMonitoring(string module, string[] cmd)
201 {
202 bool mode = true;
203 if (cmd.Length == 1 || (cmd.Length > 1 && cmd[1] == "on"))
204 {
205 mode = true;
206 MainConsole.Instance.Output("Emergency Monitoring ON");
207 }
208 else
209 {
210 mode = false;
211 MainConsole.Instance.Output("Emergency Monitoring OFF");
212 }
213
214 foreach (Scene s in m_scenes.Values)
215 s.EmergencyMonitoring = mode;
216 }
217
218 protected string GetColumnEntry(string entry, int maxLength, int columnPadding)
219 {
220 return string.Format(
221 "{0,-" + maxLength + "}{1,-" + columnPadding + "}",
222 entry.Length > maxLength ? entry.Substring(0, maxLength) : entry,
223 "");
224 }
225
226 /// <summary>
227 /// Generate UDP Queue data report for each client
228 /// </summary>
229 /// <param name="showParams"></param>
230 /// <returns></returns>
231 protected string GetPQueuesReport(string[] showParams)
232 {
233 bool showChildren = false;
234 string pname = "";
235
236 if (showParams.Length > 2 && showParams[2] == "full")
237 showChildren = true;
238 else if (showParams.Length > 3)
239 pname = showParams[2] + " " + showParams[3];
240
241 StringBuilder report = new StringBuilder();
242
243 int columnPadding = 2;
244 int maxNameLength = 18;
245 int maxRegionNameLength = 14;
246 int maxTypeLength = 4;
247// int totalInfoFieldsLength = maxNameLength + columnPadding + maxRegionNameLength + columnPadding + maxTypeLength + columnPadding;
248
249 report.Append(GetColumnEntry("User", maxNameLength, columnPadding));
250 report.Append(GetColumnEntry("Region", maxRegionNameLength, columnPadding));
251 report.Append(GetColumnEntry("Type", maxTypeLength, columnPadding));
252
253 report.AppendFormat(
254 "{0,7} {1,7} {2,7} {3,7} {4,7} {5,7} {6,7} {7,7} {8,7} {9,7} {10,7} {11,7}\n",
255 "Pri 0",
256 "Pri 1",
257 "Pri 2",
258 "Pri 3",
259 "Pri 4",
260 "Pri 5",
261 "Pri 6",
262 "Pri 7",
263 "Pri 8",
264 "Pri 9",
265 "Pri 10",
266 "Pri 11");
267
268 lock (m_scenes)
269 {
270 foreach (Scene scene in m_scenes.Values)
271 {
272 scene.ForEachClient(
273 delegate(IClientAPI client)
274 {
275 if (client is LLClientView)
276 {
277 bool isChild = client.SceneAgent.IsChildAgent;
278 if (isChild && !showChildren)
279 return;
280
281 string name = client.Name;
282 if (pname != "" && name != pname)
283 return;
284
285 string regionName = scene.RegionInfo.RegionName;
286
287 report.Append(GetColumnEntry(name, maxNameLength, columnPadding));
288 report.Append(GetColumnEntry(regionName, maxRegionNameLength, columnPadding));
289 report.Append(GetColumnEntry(isChild ? "Cd" : "Rt", maxTypeLength, columnPadding));
290 report.AppendLine(((LLClientView)client).EntityUpdateQueue.ToString());
291 }
292 });
293 }
294 }
295
296 return report.ToString();
297 }
298
299 /// <summary>
300 /// Generate an image queue report
301 /// </summary>
302 /// <param name="showParams"></param>
303 /// <returns></returns>
304 private string GetImageQueuesReport(string[] showParams)
305 {
306 if (showParams.Length < 5 || showParams.Length > 6)
307 return "Usage: show image queues <first-name> <last-name> [full]";
308
309 string firstName = showParams[3];
310 string lastName = showParams[4];
311
312 bool showChildAgents = showParams.Length == 6;
313
314 List<ScenePresence> foundAgents = new List<ScenePresence>();
315
316 lock (m_scenes)
317 {
318 foreach (Scene scene in m_scenes.Values)
319 {
320 ScenePresence sp = scene.GetScenePresence(firstName, lastName);
321 if (sp != null && (showChildAgents || !sp.IsChildAgent))
322 foundAgents.Add(sp);
323 }
324 }
325
326 if (foundAgents.Count == 0)
327 return string.Format("No agents found for {0} {1}", firstName, lastName);
328
329 StringBuilder report = new StringBuilder();
330
331 foreach (ScenePresence agent in foundAgents)
332 {
333 LLClientView client = agent.ControllingClient as LLClientView;
334
335 if (client == null)
336 return "This command is only supported for LLClientView";
337
338 J2KImage[] images = client.ImageManager.GetImages();
339
340 report.AppendFormat(
341 "In region {0} ({1} agent)\n",
342 agent.Scene.RegionInfo.RegionName, agent.IsChildAgent ? "child" : "root");
343 report.AppendFormat("Images in queue: {0}\n", images.Length);
344
345 if (images.Length > 0)
346 {
347 report.AppendFormat(
348 "{0,-36} {1,-8} {2,-10} {3,-9} {4,-9} {5,-7}\n",
349 "Texture ID",
350 "Last Seq",
351 "Priority",
352 "Start Pkt",
353 "Has Asset",
354 "Decoded");
355
356 foreach (J2KImage image in images)
357 report.AppendFormat(
358 "{0,36} {1,8} {2,10} {3,10} {4,9} {5,7}\n",
359 image.TextureID, image.LastSequence, image.Priority, image.StartPacket, image.HasAsset, image.IsDecoded);
360 }
361 }
362
363 return report.ToString();
364 }
365
366 /// <summary>
367 /// Generate UDP Queue data report for each client
368 /// </summary>
369 /// <param name="showParams"></param>
370 /// <returns></returns>
371 protected string GetQueuesReport(string[] showParams)
372 {
373 bool showChildren = false;
374 string pname = "";
375
376 if (showParams.Length > 2 && showParams[2] == "full")
377 showChildren = true;
378 else if (showParams.Length > 3)
379 pname = showParams[2] + " " + showParams[3];
380
381 StringBuilder report = new StringBuilder();
382
383 int columnPadding = 2;
384 int maxNameLength = 18;
385 int maxRegionNameLength = 14;
386 int maxTypeLength = 4;
387
388 int totalInfoFieldsLength
389 = maxNameLength + columnPadding
390 + maxRegionNameLength + columnPadding
391 + maxTypeLength + columnPadding;
392
393 report.Append(GetColumnEntry("User", maxNameLength, columnPadding));
394 report.Append(GetColumnEntry("Region", maxRegionNameLength, columnPadding));
395 report.Append(GetColumnEntry("Type", maxTypeLength, columnPadding));
396
397 report.AppendFormat(
398 "{0,7} {1,7} {2,7} {3,7} {4,9} {5,7} {6,7} {7,7} {8,7} {9,7} {10,8} {11,7}\n",
399 "Since",
400 "Pkts",
401 "Pkts",
402 "Pkts",
403 "Bytes",
404 "Q Pkts",
405 "Q Pkts",
406 "Q Pkts",
407 "Q Pkts",
408 "Q Pkts",
409 "Q Pkts",
410 "Q Pkts");
411
412 report.AppendFormat("{0,-" + totalInfoFieldsLength + "}", "");
413 report.AppendFormat(
414 "{0,7} {1,7} {2,7} {3,7} {4,9} {5,7} {6,7} {7,7} {8,7} {9,7} {10,8} {11,7}\n",
415 "Last In",
416 "In",
417 "Out",
418 "Resent",
419 "Unacked",
420 "Resend",
421 "Land",
422 "Wind",
423 "Cloud",
424 "Task",
425 "Texture",
426 "Asset");
427
428 lock (m_scenes)
429 {
430 foreach (Scene scene in m_scenes.Values)
431 {
432 scene.ForEachClient(
433 delegate(IClientAPI client)
434 {
435 if (client is IStatsCollector)
436 {
437
438 bool isChild = client.SceneAgent.IsChildAgent;
439 if (isChild && !showChildren)
440 return;
441
442 string name = client.Name;
443 if (pname != "" && name != pname)
444 return;
445
446 string regionName = scene.RegionInfo.RegionName;
447
448 report.Append(GetColumnEntry(name, maxNameLength, columnPadding));
449 report.Append(GetColumnEntry(regionName, maxRegionNameLength, columnPadding));
450 report.Append(GetColumnEntry(isChild ? "Cd" : "Rt", maxTypeLength, columnPadding));
451
452 IStatsCollector stats = (IStatsCollector)client;
453 report.AppendLine(stats.Report());
454 }
455 });
456 }
457 }
458
459 return report.ToString();
460 }
461
462 /// <summary>
463 /// Show throttle data
464 /// </summary>
465 /// <param name="showParams"></param>
466 /// <returns></returns>
467 protected string GetThrottlesReport(string[] showParams)
468 {
469 bool showChildren = false;
470 string pname = "";
471
472 if (showParams.Length > 2 && showParams[2] == "full")
473 showChildren = true;
474 else if (showParams.Length > 3)
475 pname = showParams[2] + " " + showParams[3];
476
477 StringBuilder report = new StringBuilder();
478
479 int columnPadding = 2;
480 int maxNameLength = 18;
481 int maxRegionNameLength = 14;
482 int maxTypeLength = 4;
483 int totalInfoFieldsLength = maxNameLength + columnPadding + maxRegionNameLength + columnPadding + maxTypeLength + columnPadding;
484
485 report.Append(GetColumnEntry("User", maxNameLength, columnPadding));
486 report.Append(GetColumnEntry("Region", maxRegionNameLength, columnPadding));
487 report.Append(GetColumnEntry("Type", maxTypeLength, columnPadding));
488
489 report.AppendFormat(
490 "{0,8} {1,8} {2,7} {3,8} {4,7} {5,7} {6,7} {7,7} {8,9} {9,7}\n",
491 "Max",
492 "Target",
493 "Actual",
494 "Resend",
495 "Land",
496 "Wind",
497 "Cloud",
498 "Task",
499 "Texture",
500 "Asset");
501
502 report.AppendFormat("{0,-" + totalInfoFieldsLength + "}", "");
503 report.AppendFormat(
504 "{0,8} {1,8} {2,7} {3,8} {4,7} {5,7} {6,7} {7,7} {8,9} {9,7}\n",
505 "kb/s",
506 "kb/s",
507 "kb/s",
508 "kb/s",
509 "kb/s",
510 "kb/s",
511 "kb/s",
512 "kb/s",
513 "kb/s",
514 "kb/s");
515
516 report.AppendLine();
517
518 lock (m_scenes)
519 {
520 foreach (Scene scene in m_scenes.Values)
521 {
522 scene.ForEachClient(
523 delegate(IClientAPI client)
524 {
525 if (client is LLClientView)
526 {
527 LLClientView llClient = client as LLClientView;
528
529 bool isChild = client.SceneAgent.IsChildAgent;
530 if (isChild && !showChildren)
531 return;
532
533 string name = client.Name;
534 if (pname != "" && name != pname)
535 return;
536
537 string regionName = scene.RegionInfo.RegionName;
538
539 LLUDPClient llUdpClient = llClient.UDPClient;
540 ClientInfo ci = llUdpClient.GetClientInfo();
541
542 report.Append(GetColumnEntry(name, maxNameLength, columnPadding));
543 report.Append(GetColumnEntry(regionName, maxRegionNameLength, columnPadding));
544 report.Append(GetColumnEntry(isChild ? "Cd" : "Rt", maxTypeLength, columnPadding));
545
546 report.AppendFormat(
547 "{0,8} {1,8} {2,7} {3,8} {4,7} {5,7} {6,7} {7,7} {8,9} {9,7}\n",
548 ci.maxThrottle > 0 ? ((ci.maxThrottle * 8) / 1000).ToString() : "-",
549 llUdpClient.FlowThrottle.AdaptiveEnabled
550 ? ((ci.targetThrottle * 8) / 1000).ToString()
551 : (llUdpClient.FlowThrottle.TotalDripRequest * 8 / 1000).ToString(),
552 (ci.totalThrottle * 8) / 1000,
553 (ci.resendThrottle * 8) / 1000,
554 (ci.landThrottle * 8) / 1000,
555 (ci.windThrottle * 8) / 1000,
556 (ci.cloudThrottle * 8) / 1000,
557 (ci.taskThrottle * 8) / 1000,
558 (ci.textureThrottle * 8) / 1000,
559 (ci.assetThrottle * 8) / 1000);
560 }
561 });
562 }
563 }
564
565 return report.ToString();
566 }
567
568 /// <summary>
569 /// Show client stats data
570 /// </summary>
571 /// <param name="showParams"></param>
572 /// <returns></returns>
573 protected string HandleClientStatsReport(string[] showParams)
574 {
575 // NOTE: This writes to m_log on purpose. We want to store this information
576 // in case we need to analyze it later.
577 //
578 if (showParams.Length <= 4)
579 {
580 m_log.InfoFormat("[INFO]: {0,-12} {1,-20} {2,-6} {3,-11} {4,-11} {5,-16}", "Region", "Name", "Root", "Time", "Reqs/min", "AgentUpdates");
581 foreach (Scene scene in m_scenes.Values)
582 {
583 scene.ForEachClient(
584 delegate(IClientAPI client)
585 {
586 if (client is LLClientView)
587 {
588 LLClientView llClient = client as LLClientView;
589 ClientInfo cinfo = llClient.UDPClient.GetClientInfo();
590 int avg_reqs = cinfo.AsyncRequests.Values.Sum() + cinfo.GenericRequests.Values.Sum() + cinfo.SyncRequests.Values.Sum();
591 avg_reqs = avg_reqs / ((DateTime.Now - cinfo.StartedTime).Minutes + 1);
592
593 string childAgentStatus;
594
595 if (llClient.SceneAgent != null)
596 childAgentStatus = llClient.SceneAgent.IsChildAgent ? "N" : "Y";
597 else
598 childAgentStatus = "Off!";
599
600 m_log.InfoFormat("[INFO]: {0,-12} {1,-20} {2,-6} {3,-11} {4,-11} {5,-16}",
601 scene.RegionInfo.RegionName, llClient.Name,
602 childAgentStatus,
603 (DateTime.Now - cinfo.StartedTime).Minutes,
604 avg_reqs,
605 string.Format(
606 "{0} ({1:0.00}%)",
607 llClient.TotalAgentUpdates,
608 cinfo.SyncRequests.ContainsKey("AgentUpdate")
609 ? (float)cinfo.SyncRequests["AgentUpdate"] / llClient.TotalAgentUpdates * 100
610 : 0));
611 }
612 });
613 }
614 return string.Empty;
615 }
616
617 string fname = "", lname = "";
618
619 if (showParams.Length > 3)
620 fname = showParams[3];
621 if (showParams.Length > 4)
622 lname = showParams[4];
623
624 foreach (Scene scene in m_scenes.Values)
625 {
626 scene.ForEachClient(
627 delegate(IClientAPI client)
628 {
629 if (client is LLClientView)
630 {
631 LLClientView llClient = client as LLClientView;
632
633 if (llClient.Name == fname + " " + lname)
634 {
635
636 ClientInfo cinfo = llClient.GetClientInfo();
637 AgentCircuitData aCircuit = scene.AuthenticateHandler.GetAgentCircuitData(llClient.CircuitCode);
638 if (aCircuit == null) // create a dummy one
639 aCircuit = new AgentCircuitData();
640
641 if (!llClient.SceneAgent.IsChildAgent)
642 m_log.InfoFormat("[INFO]: {0} # {1} # {2}", llClient.Name, Util.GetViewerName(aCircuit), aCircuit.Id0);
643
644 int avg_reqs = cinfo.AsyncRequests.Values.Sum() + cinfo.GenericRequests.Values.Sum() + cinfo.SyncRequests.Values.Sum();
645 avg_reqs = avg_reqs / ((DateTime.Now - cinfo.StartedTime).Minutes + 1);
646
647 m_log.InfoFormat("[INFO]:");
648 m_log.InfoFormat("[INFO]: {0} # {1} # Time: {2}min # Avg Reqs/min: {3}", scene.RegionInfo.RegionName,
649 (llClient.SceneAgent.IsChildAgent ? "Child" : "Root"), (DateTime.Now - cinfo.StartedTime).Minutes, avg_reqs);
650
651 Dictionary<string, int> sortedDict = (from entry in cinfo.AsyncRequests orderby entry.Value descending select entry)
652 .ToDictionary(pair => pair.Key, pair => pair.Value);
653 PrintRequests("TOP ASYNC", sortedDict, cinfo.AsyncRequests.Values.Sum());
654
655 sortedDict = (from entry in cinfo.SyncRequests orderby entry.Value descending select entry)
656 .ToDictionary(pair => pair.Key, pair => pair.Value);
657 PrintRequests("TOP SYNC", sortedDict, cinfo.SyncRequests.Values.Sum());
658
659 sortedDict = (from entry in cinfo.GenericRequests orderby entry.Value descending select entry)
660 .ToDictionary(pair => pair.Key, pair => pair.Value);
661 PrintRequests("TOP GENERIC", sortedDict, cinfo.GenericRequests.Values.Sum());
662 }
663 }
664 });
665 }
666 return string.Empty;
667 }
668
669 private void PrintRequests(string type, Dictionary<string, int> sortedDict, int sum)
670 {
671 m_log.InfoFormat("[INFO]:");
672 m_log.InfoFormat("[INFO]: {0,25}", type);
673 foreach (KeyValuePair<string, int> kvp in sortedDict.Take(12))
674 m_log.InfoFormat("[INFO]: {0,25} {1,-6}", kvp.Key, kvp.Value);
675 m_log.InfoFormat("[INFO]: {0,25}", "...");
676 m_log.InfoFormat("[INFO]: {0,25} {1,-6}", "Total", sum);
677 }
678 }
679}