opensim-development – Blame information for rev 1

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