clockwerk-opensim – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 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.Linq;
31 using System.Reflection;
32 using System.Text;
33 using log4net;
34 using Mono.Addins;
35 using Nini.Config;
36 using OpenMetaverse;
37 using OpenSim.Framework;
38 using OpenSim.Framework.Console;
39 using OpenSim.Framework.Monitoring;
40 using OpenSim.Region.ClientStack.LindenUDP;
41 using OpenSim.Region.Framework.Interfaces;
42 using OpenSim.Region.Framework.Scenes;
43  
44 namespace 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,7} {2,8} {3,7} {4,7} {5,7} {6,7} {7,9} {8,7}\n",
491 "Max",
492 "Total",
493 "Resend",
494 "Land",
495 "Wind",
496 "Cloud",
497 "Task",
498 "Texture",
499 "Asset");
500  
501 report.AppendFormat("{0,-" + totalInfoFieldsLength + "}", "");
502 report.AppendFormat(
503 "{0,8} {1,7} {2,8} {3,7} {4,7} {5,7} {6,7} {7,9} {8,7}\n",
504 "kb/s",
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  
514 report.AppendLine();
515  
516 bool firstClient = true;
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 if (firstClient)
530 {
531 report.AppendLine(GetServerThrottlesReport(llClient.UDPServer));
532 firstClient = false;
533 }
534  
535 bool isChild = client.SceneAgent.IsChildAgent;
536 if (isChild && !showChildren)
537 return;
538  
539 string name = client.Name;
540 if (pname != "" && name != pname)
541 return;
542  
543 string regionName = scene.RegionInfo.RegionName;
544  
545 LLUDPClient llUdpClient = llClient.UDPClient;
546 ClientInfo ci = llUdpClient.GetClientInfo();
547  
548 report.Append(GetColumnEntry(name, maxNameLength, columnPadding));
549 report.Append(GetColumnEntry(regionName, maxRegionNameLength, columnPadding));
550 report.Append(GetColumnEntry(isChild ? "Cd" : "Rt", maxTypeLength, columnPadding));
551  
552 report.AppendFormat(
553 "{0,8} {1,7} {2,8} {3,7} {4,7} {5,7} {6,7} {7,9} {8,7}",
554 (ci.maxThrottle * 8) / 1000,
555 (ci.totalThrottle * 8) / 1000,
556 (ci.resendThrottle * 8) / 1000,
557 (ci.landThrottle * 8) / 1000,
558 (ci.windThrottle * 8) / 1000,
559 (ci.cloudThrottle * 8) / 1000,
560 (ci.taskThrottle * 8) / 1000,
561 (ci.textureThrottle * 8) / 1000,
562 (ci.assetThrottle * 8) / 1000);
563  
564 report.AppendLine();
565 }
566 });
567 }
568 }
569  
570 return report.ToString();
571 }
572  
573 protected string GetServerThrottlesReport(LLUDPServer udpServer)
574 {
575 StringBuilder report = new StringBuilder();
576  
577 int columnPadding = 2;
578 int maxNameLength = 18;
579 int maxRegionNameLength = 14;
580 int maxTypeLength = 4;
581  
582 string name = "SERVER AGENT RATES";
583  
584 report.Append(GetColumnEntry(name, maxNameLength, columnPadding));
585 report.Append(GetColumnEntry("-", maxRegionNameLength, columnPadding));
586 report.Append(GetColumnEntry("-", maxTypeLength, columnPadding));
587  
588 ThrottleRates throttleRates = udpServer.ThrottleRates;
589 report.AppendFormat(
590 "{0,8} {1,7} {2,8} {3,7} {4,7} {5,7} {6,7} {7,9} {8,7}",
591 "-",
592 (throttleRates.Total * 8) / 1000,
593 (throttleRates.Resend * 8) / 1000,
594 (throttleRates.Land * 8) / 1000,
595 (throttleRates.Wind * 8) / 1000,
596 (throttleRates.Cloud * 8) / 1000,
597 (throttleRates.Task * 8) / 1000,
598 (throttleRates.Texture * 8) / 1000,
599 (throttleRates.Asset * 8) / 1000);
600  
601 return report.ToString();
602 }
603  
604 /// <summary>
605 /// Show client stats data
606 /// </summary>
607 /// <param name="showParams"></param>
608 /// <returns></returns>
609 protected string HandleClientStatsReport(string[] showParams)
610 {
611 // NOTE: This writes to m_log on purpose. We want to store this information
612 // in case we need to analyze it later.
613 //
614 if (showParams.Length <= 4)
615 {
616 m_log.InfoFormat("[INFO]: {0,-12} {1,-20} {2,-6} {3,-11} {4,-11} {5,-16}", "Region", "Name", "Root", "Time", "Reqs/min", "AgentUpdates");
617 foreach (Scene scene in m_scenes.Values)
618 {
619 scene.ForEachClient(
620 delegate(IClientAPI client)
621 {
622 if (client is LLClientView)
623 {
624 LLClientView llClient = client as LLClientView;
625 ClientInfo cinfo = llClient.UDPClient.GetClientInfo();
626 int avg_reqs = cinfo.AsyncRequests.Values.Sum() + cinfo.GenericRequests.Values.Sum() + cinfo.SyncRequests.Values.Sum();
627 avg_reqs = avg_reqs / ((DateTime.Now - cinfo.StartedTime).Minutes + 1);
628  
629 string childAgentStatus;
630  
631 if (llClient.SceneAgent != null)
632 childAgentStatus = llClient.SceneAgent.IsChildAgent ? "N" : "Y";
633 else
634 childAgentStatus = "Off!";
635  
636 m_log.InfoFormat("[INFO]: {0,-12} {1,-20} {2,-6} {3,-11} {4,-11} {5,-16}",
637 scene.RegionInfo.RegionName, llClient.Name,
638 childAgentStatus,
639 (DateTime.Now - cinfo.StartedTime).Minutes,
640 avg_reqs,
641 string.Format(
642 "{0} ({1:0.00}%)",
643 llClient.TotalAgentUpdates,
644 (float)cinfo.SyncRequests["AgentUpdate"] / llClient.TotalAgentUpdates * 100));
645 }
646 });
647 }
648 return string.Empty;
649 }
650  
651 string fname = "", lname = "";
652  
653 if (showParams.Length > 3)
654 fname = showParams[3];
655 if (showParams.Length > 4)
656 lname = showParams[4];
657  
658 foreach (Scene scene in m_scenes.Values)
659 {
660 scene.ForEachClient(
661 delegate(IClientAPI client)
662 {
663 if (client is LLClientView)
664 {
665 LLClientView llClient = client as LLClientView;
666  
667 if (llClient.Name == fname + " " + lname)
668 {
669  
670 ClientInfo cinfo = llClient.GetClientInfo();
671 AgentCircuitData aCircuit = scene.AuthenticateHandler.GetAgentCircuitData(llClient.CircuitCode);
672 if (aCircuit == null) // create a dummy one
673 aCircuit = new AgentCircuitData();
674  
675 if (!llClient.SceneAgent.IsChildAgent)
676 m_log.InfoFormat("[INFO]: {0} # {1} # {2}", llClient.Name, Util.GetViewerName(aCircuit), aCircuit.Id0);
677  
678 int avg_reqs = cinfo.AsyncRequests.Values.Sum() + cinfo.GenericRequests.Values.Sum() + cinfo.SyncRequests.Values.Sum();
679 avg_reqs = avg_reqs / ((DateTime.Now - cinfo.StartedTime).Minutes + 1);
680  
681 m_log.InfoFormat("[INFO]:");
682 m_log.InfoFormat("[INFO]: {0} # {1} # Time: {2}min # Avg Reqs/min: {3}", scene.RegionInfo.RegionName,
683 (llClient.SceneAgent.IsChildAgent ? "Child" : "Root"), (DateTime.Now - cinfo.StartedTime).Minutes, avg_reqs);
684  
685 Dictionary<string, int> sortedDict = (from entry in cinfo.AsyncRequests orderby entry.Value descending select entry)
686 .ToDictionary(pair => pair.Key, pair => pair.Value);
687 PrintRequests("TOP ASYNC", sortedDict, cinfo.AsyncRequests.Values.Sum());
688  
689 sortedDict = (from entry in cinfo.SyncRequests orderby entry.Value descending select entry)
690 .ToDictionary(pair => pair.Key, pair => pair.Value);
691 PrintRequests("TOP SYNC", sortedDict, cinfo.SyncRequests.Values.Sum());
692  
693 sortedDict = (from entry in cinfo.GenericRequests orderby entry.Value descending select entry)
694 .ToDictionary(pair => pair.Key, pair => pair.Value);
695 PrintRequests("TOP GENERIC", sortedDict, cinfo.GenericRequests.Values.Sum());
696 }
697 }
698 });
699 }
700 return string.Empty;
701 }
702  
703 private void PrintRequests(string type, Dictionary<string, int> sortedDict, int sum)
704 {
705 m_log.InfoFormat("[INFO]:");
706 m_log.InfoFormat("[INFO]: {0,25}", type);
707 foreach (KeyValuePair<string, int> kvp in sortedDict.Take(12))
708 m_log.InfoFormat("[INFO]: {0,25} {1,-6}", kvp.Key, kvp.Value);
709 m_log.InfoFormat("[INFO]: {0,25}", "...");
710 m_log.InfoFormat("[INFO]: {0,25} {1,-6}", "Total", sum);
711 }
712 }
713 }