From 8e67ad25b07c6e934e7df86b3baffa2ab85145c1 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sat, 23 Feb 2013 16:49:02 -0800 Subject: [PATCH 01/11] Addition of ServerStats shared region module which collects and registers server wide statistics (CPU%, network bytes sent, ...) with StatsManager. --- .../Framework/Monitoring/ServerStats.cs | 438 ++++++++++++++++++ 1 file changed, 438 insertions(+) create mode 100644 OpenSim/Region/OptionalModules/Framework/Monitoring/ServerStats.cs diff --git a/OpenSim/Region/OptionalModules/Framework/Monitoring/ServerStats.cs b/OpenSim/Region/OptionalModules/Framework/Monitoring/ServerStats.cs new file mode 100644 index 0000000000..8f60c8d7d6 --- /dev/null +++ b/OpenSim/Region/OptionalModules/Framework/Monitoring/ServerStats.cs @@ -0,0 +1,438 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Net.NetworkInformation; +using System.Text; +using System.Threading; + +using log4net; +using Mono.Addins; +using Nini.Config; + +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Framework.Monitoring; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; + +using OpenMetaverse.StructuredData; + +namespace OpenSim.Region.OptionalModules.Framework.Monitoring +{ +[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "ServerStatistics")] +public class ServerStats : ISharedRegionModule +{ + private readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + private readonly string LogHeader = "[SERVER STATS]"; + + public bool Enabled = false; + private static Dictionary RegisteredStats = new Dictionary(); + + public readonly string CategoryServer = "server"; + + public readonly string ContainerProcessor = "processor"; + public readonly string ContainerMemory = "memory"; + public readonly string ContainerNetwork = "network"; + public readonly string ContainerProcess = "process"; + + + readonly int performanceCounterSampleInterval = 500; + int lastperformanceCounterSampleTime = 0; + + private class PerfCounterControl + { + public PerformanceCounter perfCounter; + public int lastFetch; + public string name; + public PerfCounterControl(PerformanceCounter pPc) + : this(pPc, String.Empty) + { + } + public PerfCounterControl(PerformanceCounter pPc, string pName) + { + perfCounter = pPc; + lastFetch = 0; + name = pName; + } + } + + PerfCounterControl processorPercentPerfCounter = null; + + PerfCounterControl processThreadCountPerfCounter = null; + PerfCounterControl processVirtualBytesPerfCounter = null; + PerfCounterControl processWorkingSetPerfCounter = null; + + PerfCounterControl dotNETCLRMemoryAllocatedBytesPerSecPerfCounter = null; + PerfCounterControl dotNETCLRMemoryGen0HeapSizePerfCounter = null; + PerfCounterControl dotNETCLRMemoryGen1HeapSizePerfCounter = null; + PerfCounterControl dotNETCLRMemoryGen2HeapSizePerfCounter = null; + + PerfCounterControl dotNETCLRLaTTotalContentionsPerfCounter = null; + PerfCounterControl dotNETCLRLaTContentionsPerSecPerfCounter = null; + PerfCounterControl dotNETCLRLaTLogicalThreadsPerfCounter = null; + PerfCounterControl dotNETCLRLaTPhysicalThreadsPerfCounter = null; + + #region ISharedRegionModule + // IRegionModuleBase.Name + public string Name { get { return "Server Stats"; } } + // IRegionModuleBase.ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } + // IRegionModuleBase.Initialize + public void Initialise(IConfigSource source) + { + IConfig cnfg = source.Configs["Statistics"]; + + if (cnfg != null) + Enabled = cnfg.GetBoolean("Enabled", true); + } + // IRegionModuleBase.Close + public void Close() + { + if (RegisteredStats.Count > 0) + { + foreach (Stat stat in RegisteredStats.Values) + { + StatsManager.DeregisterStat(stat); + stat.Dispose(); + } + RegisteredStats.Clear(); + } + } + // IRegionModuleBase.AddRegion + public void AddRegion(Scene scene) + { + } + // IRegionModuleBase.RemoveRegion + public void RemoveRegion(Scene scene) + { + } + // IRegionModuleBase.RegionLoaded + public void RegionLoaded(Scene scene) + { + } + // ISharedRegionModule.PostInitialize + public void PostInitialise() + { + if (RegisteredStats.Count == 0) + { + RegisterServerStats(); + } + } + #endregion ISharedRegionModule + + public void RegisterServerStats() + { + lastperformanceCounterSampleTime = Util.EnvironmentTickCount(); + PerformanceCounter tempPC; + Stat tempStat; + string tempName; + + try + { + tempName = "CPU_Percent"; + tempPC = new PerformanceCounter("Processor", "% Processor Time", "_Total"); + processorPercentPerfCounter = new PerfCounterControl(tempPC); + // A long time bug in mono is that CPU percent is reported as CPU percent idle. Windows reports CPU percent busy. + tempStat = new Stat(tempName, tempName, "", "percent", CategoryServer, ContainerProcessor, + StatType.Pull, (s) => { GetNextValue(s, processorPercentPerfCounter, Util.IsWindows() ? 1 : -1); }, + StatVerbosity.Info); + StatsManager.RegisterStat(tempStat); + RegisteredStats.Add(tempName, tempStat); + + /* Performance counters are not the way to go. Ick. Find another way. + tempName = "Thread_Count"; + tempPC = new PerformanceCounter("Process", "Thread Count", AppDomain.CurrentDomain.FriendlyName); + processThreadCountPerfCounter = new PerfCounterControl(tempPC); + tempStat = new Stat("Thread_Count", "Thread_Count", "", "threads", CategoryServer, ContainerProcess, + StatType.Pull, (s) => { GetNextValue(s, processThreadCountPerfCounter); }, StatVerbosity.Info); + StatsManager.RegisterStat(tempStat); + RegisteredStats.Add(tempName, tempStat); + + tempName = "Virtual_Bytes"; + tempPC = new PerformanceCounter("Process", "Virtual Bytes", AppDomain.CurrentDomain.FriendlyName); + processVirtualBytesPerfCounter = new PerfCounterControl(tempPC); + tempStat = new Stat("Virtual_Bytes", "Virtual_Bytes", "", "MB", CategoryServer, ContainerProcess, + StatType.Pull, (s) => { GetNextValue(s, processVirtualBytesPerfCounter, 1024.0*1024.0); }, StatVerbosity.Info); + StatsManager.RegisterStat(tempStat); + RegisteredStats.Add(tempName, tempStat); + + tempName = "Working_Set"; + tempPC = new PerformanceCounter("Process", "Working Set", AppDomain.CurrentDomain.FriendlyName); + processWorkingSetPerfCounter = new PerfCounterControl(tempPC); + tempStat = new Stat("Working_Set", "Working_Set", "", "MB", CategoryServer, ContainerProcess, + StatType.Pull, (s) => { GetNextValue(s, processWorkingSetPerfCounter, 1024.0*1024.0); }, StatVerbosity.Info); + StatsManager.RegisterStat(tempStat); + RegisteredStats.Add(tempName, tempStat); + */ + } + catch (Exception e) + { + m_log.ErrorFormat("{0} Exception creating 'Process': {1}", LogHeader, e); + } + + try + { + /* The ".NET CLR *" categories aren't working for me. + tempName = ""Bytes_Allocated_Per_Sec"; + tempPC = new PerformanceCounter(".NET CLR Memory", "Allocated Bytes/sec", AppDomain.CurrentDomain.FriendlyName); + dotNETCLRMemoryAllocatedBytesPerSecPerfCounter = new PerfCounterControl(tempPC, tempStat); + tempStat = new Stat(tempName, tempName, "", "bytes/sec", ServerCategory, MemoryContainer, + StatType.Pull, (s) => { GetNextValue(s, dotNETCLRMemoryAllocatedBytesPerSecPerfCounter); }, StatVerbosity.Info); + StatsManager.RegisterStat(tempStat); + RegisteredStats.Add(tempName, tempStat); + + tempName = "Gen_0_Heap_Size"; + tempPC = new PerformanceCounter(".NET CLR Memory", "Gen 0 heap size", AppDomain.CurrentDomain.FriendlyName); + dotNETCLRMemoryGen0HeapSizePerfCounter = new PerfCounterControl(tempPC, tempStat); + tempStat = new Stat("Gen_0_Heap_Size", "Gen_0_Heap_Size", "", "bytes", ServerCategory, MemoryContainer, + StatType.Pull, (s) => { GetNextValue(s, dotNETCLRMemoryGen0HeapSizePerfCounter); }, StatVerbosity.Info); + StatsManager.RegisterStat(tempStat); + RegisteredStats.Add(tempName, tempStat); + + tempName = "Gen_1_Heap_Size"; + tempPC = new PerformanceCounter(".NET CLR Memory", "Gen 1 heap size", AppDomain.CurrentDomain.FriendlyName); + dotNETCLRMemoryGen1HeapSizePerfCounter = new PerfCounterControl(tempPC, tempStat); + tempStat = new Stat("Gen_1_Heap_Size", "Gen_1_Heap_Size", "", "bytes", ServerCategory, MemoryContainer, + StatType.Pull, (s) => { GetNextValue(s, dotNETCLRMemoryGen1HeapSizePerfCounter); }, StatVerbosity.Info); + StatsManager.RegisterStat(tempStat); + RegisteredStats.Add(tempName, tempStat); + + tempName = "Gen_2_Heap_Size"; + tempPC = new PerformanceCounter(".NET CLR Memory", "Gen 2 heap size", AppDomain.CurrentDomain.FriendlyName); + dotNETCLRMemoryGen2HeapSizePerfCounter = new PerfCounterControl(tempPC, tempStat); + tempStat = new Stat("Gen_2_Heap_Size", "Gen_2_Heap_Size", "", "bytes", ServerCategory, MemoryContainer, + StatType.Pull, (s) => { GetNextValue(s, dotNETCLRMemoryGen2HeapSizePerfCounter); }, StatVerbosity.Info); + StatsManager.RegisterStat(tempStat); + RegisteredStats.Add(tempName, tempStat); + + tempName = "Total_Lock_Contentions"; + tempPC = new PerformanceCounter(".NET CLR LocksAndThreads", "Total # of Contentions"); + dotNETCLRLaTTotalContentionsPerfCounter = new PerfCounterControl(tempPC, tempStat); + tempStat = new Stat("Total_Lock_Contentions", "Total_Lock_Contentions", "", "contentions", ServerCategory, ProcessContainer, + StatType.Pull, (s) => { GetNextValue(s, dotNETCLRLaTTotalContentionsPerfCounter); }, StatVerbosity.Info); + StatsManager.RegisterStat(tempStat); + RegisteredStats.Add(tempName, tempStat); + + tempName = "Lock_Contentions"; + tempPC = new PerformanceCounter(".NET CLR LocksAndThreads", "Contention Rate / sec"); + dotNETCLRLaTContentionsPerSecPerfCounter = new PerfCounterControl(tempPC, tempStat); + tempStat = new Stat("Lock_Contentions", "Lock_Contentions", "", "contentions/sec", ServerCategory, ProcessContainer, + StatType.Pull, (s) => { GetNextValue(s, dotNETCLRLaTContentionsPerSecPerfCounter); }, StatVerbosity.Info); + StatsManager.RegisterStat(tempStat); + RegisteredStats.Add(tempName, tempStat); + + tempName = "Logical_Threads"; + tempPC = new PerformanceCounter(".NET CLR LocksAndThreads", "# of current logical Threads"); + dotNETCLRLaTLogicalThreadsPerfCounter = new PerfCounterControl(tempPC, tempStat); + tempStat = new Stat("Logicial_Threads", "Logicial_Threads", "", "threads", ServerCategory, ProcessContainer, + StatType.Pull, (s) => { GetNextValue(s, dotNETCLRLaTLogicalThreadsPerfCounter); }, StatVerbosity.Info); + StatsManager.RegisterStat(tempStat); + RegisteredStats.Add(tempName, tempStat); + + tempName = "Physical_Threads"; + tempPC = new PerformanceCounter(".NET CLR LocksAndThreads", "# of current physical Threads"); + dotNETCLRLaTPhysicalThreadsPerfCounter = new PerfCounterControl(tempPC, tempStat); + tempStat = new Stat("Physical_Threads", "Physical_Threads", "", "threads", ServerCategory, ProcessContainer, + StatType.Pull, (s) => { GetNextValue(s, dotNETCLRLaTPhysicalThreadsPerfCounter); }, StatVerbosity.Info); + StatsManager.RegisterStat(tempStat); + RegisteredStats.Add(tempName, tempStat); + */ + } + catch (Exception e) + { + m_log.ErrorFormat("{0} Exception creating '.NET CLR Memory': {1}", LogHeader, e); + } + + try + { + IEnumerable nics = NetworkInterface.GetAllNetworkInterfaces(); + // IEnumerable nics = NetworkInterface.GetAllNetworkInterfaces().Where( + // (network) => network.NetworkInterfaceType == NetworkInterfaceType.Ethernet); + // IEnumerable nics = NetworkInterface.GetAllNetworkInterfaces().Where( + // (network) => network.OperationalStatus == OperationalStatus.Up); + + foreach (NetworkInterface nic in nics) + { + if (nic.OperationalStatus != OperationalStatus.Up || nic.NetworkInterfaceType != NetworkInterfaceType.Ethernet) + continue; + + if (nic.Supports(NetworkInterfaceComponent.IPv4)) + { + IPv4InterfaceStatistics nicStats = nic.GetIPv4Statistics(); + if (nicStats != null) + { + tempName = "Bytes_Rcvd/" + nic.Name; + tempStat = new Stat(tempName, tempName, nic.Name, "KB", CategoryServer, ContainerNetwork, + StatType.Pull, (s) => { LookupNic(s, (ns) => { return ns.BytesReceived; }, 1024.0); }, StatVerbosity.Info); + StatsManager.RegisterStat(tempStat); + RegisteredStats.Add(tempName, tempStat); + + tempName = "Bytes_Sent/" + nic.Name; + tempStat = new Stat(tempName, tempName, nic.Name, "KB", CategoryServer, ContainerNetwork, + StatType.Pull, (s) => { LookupNic(s, (ns) => { return ns.BytesSent; }, 1024.0); }, StatVerbosity.Info); + StatsManager.RegisterStat(tempStat); + RegisteredStats.Add(tempName, tempStat); + + tempName = "Total_Bytes/" + nic.Name; + tempStat = new Stat(tempName, tempName, nic.Name, "KB", CategoryServer, ContainerNetwork, + StatType.Pull, (s) => { LookupNic(s, (ns) => { return ns.BytesSent + ns.BytesReceived; }, 1024.0); }, StatVerbosity.Info); + StatsManager.RegisterStat(tempStat); + RegisteredStats.Add(tempName, tempStat); + } + } + } + } + catch (Exception e) + { + m_log.ErrorFormat("{0} Exception creating 'Network Interface': {1}", LogHeader, e); + } + + tempName = "Process_Memory"; + tempStat = new Stat(tempName, tempName, "", "MB", CategoryServer, ContainerMemory, + StatType.Pull, (s) => { s.Value = Process.GetCurrentProcess().WorkingSet64 / 1024d / 1024d; }, StatVerbosity.Info); + StatsManager.RegisterStat(tempStat); + RegisteredStats.Add(tempName, tempStat); + + tempName = "Object_Memory"; + tempStat = new Stat(tempName, tempName, "", "MB", CategoryServer, ContainerMemory, + StatType.Pull, (s) => { s.Value = GC.GetTotalMemory(false) / 1024d / 1024d; }, StatVerbosity.Info); + StatsManager.RegisterStat(tempStat); + RegisteredStats.Add(tempName, tempStat); + + tempName = "Last_Memory_Churn"; + tempStat = new Stat(tempName, tempName, "", "MB/sec", CategoryServer, ContainerMemory, + StatType.Pull, (s) => { s.Value = Math.Round(MemoryWatchdog.LastMemoryChurn * 1000d / 1024d / 1024d, 3); }, StatVerbosity.Info); + StatsManager.RegisterStat(tempStat); + RegisteredStats.Add(tempName, tempStat); + + tempName = "Average_Memory_Churn"; + tempStat = new Stat(tempName, tempName, "", "MB/sec", CategoryServer, ContainerMemory, + StatType.Pull, (s) => { s.Value = Math.Round(MemoryWatchdog.AverageMemoryChurn * 1000d / 1024d / 1024d, 3); }, StatVerbosity.Info); + StatsManager.RegisterStat(tempStat); + RegisteredStats.Add(tempName, tempStat); + + } + + // Notes on performance counters: + // "How To Read Performance Counters": http://blogs.msdn.com/b/bclteam/archive/2006/06/02/618156.aspx + // "How to get the CPU Usage in C#": http://stackoverflow.com/questions/278071/how-to-get-the-cpu-usage-in-c + // "Mono Performance Counters": http://www.mono-project.com/Mono_Performance_Counters + private delegate double PerfCounterNextValue(); + private void GetNextValue(Stat stat, PerfCounterControl perfControl) + { + GetNextValue(stat, perfControl, 1.0); + } + private void GetNextValue(Stat stat, PerfCounterControl perfControl, double factor) + { + if (Util.EnvironmentTickCountSubtract(perfControl.lastFetch) > performanceCounterSampleInterval) + { + if (perfControl != null && perfControl.perfCounter != null) + { + try + { + // Kludge for factor to run double duty. If -1, subtract the value from one + if (factor == -1) + stat.Value = 1 - perfControl.perfCounter.NextValue(); + else + stat.Value = perfControl.perfCounter.NextValue() / factor; + } + catch (Exception e) + { + m_log.ErrorFormat("{0} Exception on NextValue fetching {1}: {2}", LogHeader, stat.Name, e); + } + perfControl.lastFetch = Util.EnvironmentTickCount(); + } + } + } + + private delegate double GetIPv4StatValue(IPv4InterfaceStatistics interfaceStat); + private void LookupNic(Stat stat, GetIPv4StatValue getter, double factor) + { + // Get the one nic that has the name of this stat + IEnumerable nics = NetworkInterface.GetAllNetworkInterfaces().Where( + (network) => network.Name == stat.Description); + try + { + foreach (NetworkInterface nic in nics) + { + IPv4InterfaceStatistics intrStats = nic.GetIPv4Statistics(); + if (intrStats != null) + stat.Value = Math.Round(getter(intrStats) / factor, 3); + break; + } + } + catch + { + // There are times interfaces go away so we just won't update the stat for this + m_log.ErrorFormat("{0} Exception fetching stat on interface '{1}'", LogHeader, stat.Description); + } + } +} + +public class ServerStatsAggregator : Stat +{ + public ServerStatsAggregator( + string shortName, + string name, + string description, + string unitName, + string category, + string container + ) + : base( + shortName, + name, + description, + unitName, + category, + container, + StatType.Push, + MeasuresOfInterest.None, + null, + StatVerbosity.Info) + { + } + public override string ToConsoleString() + { + StringBuilder sb = new StringBuilder(); + + return sb.ToString(); + } + + public override OSDMap ToOSDMap() + { + OSDMap ret = new OSDMap(); + + return ret; + } +} + +} From ee8d726ec5cbcbaca8aebbcbfd25cfba963c43f8 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sat, 23 Feb 2013 17:04:19 -0800 Subject: [PATCH 02/11] Modify StatsManager so console command "show stats category container" only outputs the statistics in the specified container in the category. --- OpenSim/Framework/Monitoring/StatsManager.cs | 29 ++++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs index 910907eb31..24db6d44c0 100644 --- a/OpenSim/Framework/Monitoring/StatsManager.cs +++ b/OpenSim/Framework/Monitoring/StatsManager.cs @@ -85,6 +85,7 @@ namespace OpenSim.Framework.Monitoring if (cmd.Length > 2) { var categoryName = cmd[2]; + var containerName = cmd.Length > 3 ? cmd[3] : String.Empty; if (categoryName == AllSubCommand) { @@ -108,7 +109,20 @@ namespace OpenSim.Framework.Monitoring } else { - OutputCategoryStatsToConsole(con, category); + if (String.IsNullOrEmpty(containerName)) + OutputCategoryStatsToConsole(con, category); + else + { + SortedDictionary container; + if (category.TryGetValue(containerName, out container)) + { + OutputContainerStatsToConsole(con, container); + } + else + { + con.OutputFormat("No such container {0} in category {1}", containerName, categoryName); + } + } } } } @@ -124,10 +138,15 @@ namespace OpenSim.Framework.Monitoring { foreach (var container in category.Values) { - foreach (Stat stat in container.Values) - { - con.Output(stat.ToConsoleString()); - } + OutputContainerStatsToConsole(con, container); + } + } + + private static void OutputContainerStatsToConsole( ICommandConsole con, SortedDictionary container) + { + foreach (Stat stat in container.Values) + { + con.Output(stat.ToConsoleString()); } } From 9f213892ea0441e0e4fb9a967850a3f0a07912b3 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sat, 23 Feb 2013 17:50:24 -0800 Subject: [PATCH 03/11] Add EventHistogram.GetHistogramAsOSDMap that returns that parameters about the histogram as well as the values. --- .../Framework/Monitoring/Stats/CounterStat.cs | 439 +++++++++--------- 1 file changed, 228 insertions(+), 211 deletions(-) diff --git a/OpenSim/Framework/Monitoring/Stats/CounterStat.cs b/OpenSim/Framework/Monitoring/Stats/CounterStat.cs index d81f1828e6..caea30dd5d 100755 --- a/OpenSim/Framework/Monitoring/Stats/CounterStat.cs +++ b/OpenSim/Framework/Monitoring/Stats/CounterStat.cs @@ -1,211 +1,228 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -using OpenMetaverse.StructuredData; - -namespace OpenSim.Framework.Monitoring -{ -// Create a time histogram of events. The histogram is built in a wrap-around -// array of equally distributed buckets. -// For instance, a minute long histogram of second sized buckets would be: -// new EventHistogram(60, 1000) -public class EventHistogram -{ - private int m_timeBase; - private int m_numBuckets; - private int m_bucketMilliseconds; - private int m_lastBucket; - private int m_totalHistogramMilliseconds; - private long[] m_histogram; - private object histoLock = new object(); - - public EventHistogram(int numberOfBuckets, int millisecondsPerBucket) - { - m_numBuckets = numberOfBuckets; - m_bucketMilliseconds = millisecondsPerBucket; - m_totalHistogramMilliseconds = m_numBuckets * m_bucketMilliseconds; - - m_histogram = new long[m_numBuckets]; - Zero(); - m_lastBucket = 0; - m_timeBase = Util.EnvironmentTickCount(); - } - - public void Event() - { - this.Event(1); - } - - // Record an event at time 'now' in the histogram. - public void Event(int cnt) - { - lock (histoLock) - { - // The time as displaced from the base of the histogram - int bucketTime = Util.EnvironmentTickCountSubtract(m_timeBase); - - // If more than the total time of the histogram, we just start over - if (bucketTime > m_totalHistogramMilliseconds) - { - Zero(); - m_lastBucket = 0; - m_timeBase = Util.EnvironmentTickCount(); - } - else - { - // To which bucket should we add this event? - int bucket = bucketTime / m_bucketMilliseconds; - - // Advance m_lastBucket to the new bucket. Zero any buckets skipped over. - while (bucket != m_lastBucket) - { - // Zero from just after the last bucket to the new bucket or the end - for (int jj = m_lastBucket + 1; jj <= Math.Min(bucket, m_numBuckets - 1); jj++) - { - m_histogram[jj] = 0; - } - m_lastBucket = bucket; - // If the new bucket is off the end, wrap around to the beginning - if (bucket > m_numBuckets) - { - bucket -= m_numBuckets; - m_lastBucket = 0; - m_histogram[m_lastBucket] = 0; - m_timeBase += m_totalHistogramMilliseconds; - } - } - } - m_histogram[m_lastBucket] += cnt; - } - } - - // Get a copy of the current histogram - public long[] GetHistogram() - { - long[] ret = new long[m_numBuckets]; - lock (histoLock) - { - int indx = m_lastBucket + 1; - for (int ii = 0; ii < m_numBuckets; ii++, indx++) - { - if (indx >= m_numBuckets) - indx = 0; - ret[ii] = m_histogram[indx]; - } - } - return ret; - } - - // Get a copy of the current histogram - public OSDArray GetHistogramAsOSDArray() - { - OSDArray ret = new OSDArray(m_numBuckets); - lock (histoLock) - { - int indx = m_lastBucket + 1; - for (int ii = 0; ii < m_numBuckets; ii++, indx++) - { - if (indx >= m_numBuckets) - indx = 0; - ret[ii] = OSD.FromLong(m_histogram[indx]); - } - } - return ret; - } - - // Zero out the histogram - public void Zero() - { - lock (histoLock) - { - for (int ii = 0; ii < m_numBuckets; ii++) - m_histogram[ii] = 0; - } - } -} - -// A statistic that wraps a counter. -// Built this way mostly so histograms and history can be created. -public class CounterStat : Stat -{ - private SortedDictionary m_histograms; - private object counterLock = new object(); - - public CounterStat( - string shortName, - string name, - string description, - string unitName, - string category, - string container, - StatVerbosity verbosity) - : base(shortName, name, description, unitName, category, container, StatType.Push, null, verbosity) - { - m_histograms = new SortedDictionary(); - } - - // Histograms are presumably added at intialization time and the list does not change thereafter. - // Thus no locking of the histogram list. - public void AddHistogram(string histoName, EventHistogram histo) - { - m_histograms.Add(histoName, histo); - } - - public delegate void ProcessHistogram(string name, EventHistogram histo); - public void ForEachHistogram(ProcessHistogram process) - { - foreach (KeyValuePair kvp in m_histograms) - { - process(kvp.Key, kvp.Value); - } - } - - public void Event() - { - this.Event(1); - } - - // Count the underlying counter. - public void Event(int cnt) - { - lock (counterLock) - { - base.Value += cnt; - - foreach (EventHistogram histo in m_histograms.Values) - { - histo.Event(cnt); - } - } - } -} -} +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using OpenMetaverse.StructuredData; + +namespace OpenSim.Framework.Monitoring +{ +// Create a time histogram of events. The histogram is built in a wrap-around +// array of equally distributed buckets. +// For instance, a minute long histogram of second sized buckets would be: +// new EventHistogram(60, 1000) +public class EventHistogram +{ + private int m_timeBase; + private int m_numBuckets; + private int m_bucketMilliseconds; + private int m_lastBucket; + private int m_totalHistogramMilliseconds; + private long[] m_histogram; + private object histoLock = new object(); + + public EventHistogram(int numberOfBuckets, int millisecondsPerBucket) + { + m_numBuckets = numberOfBuckets; + m_bucketMilliseconds = millisecondsPerBucket; + m_totalHistogramMilliseconds = m_numBuckets * m_bucketMilliseconds; + + m_histogram = new long[m_numBuckets]; + Zero(); + m_lastBucket = 0; + m_timeBase = Util.EnvironmentTickCount(); + } + + public void Event() + { + this.Event(1); + } + + // Record an event at time 'now' in the histogram. + public void Event(int cnt) + { + lock (histoLock) + { + // The time as displaced from the base of the histogram + int bucketTime = Util.EnvironmentTickCountSubtract(m_timeBase); + + // If more than the total time of the histogram, we just start over + if (bucketTime > m_totalHistogramMilliseconds) + { + Zero(); + m_lastBucket = 0; + m_timeBase = Util.EnvironmentTickCount(); + } + else + { + // To which bucket should we add this event? + int bucket = bucketTime / m_bucketMilliseconds; + + // Advance m_lastBucket to the new bucket. Zero any buckets skipped over. + while (bucket != m_lastBucket) + { + // Zero from just after the last bucket to the new bucket or the end + for (int jj = m_lastBucket + 1; jj <= Math.Min(bucket, m_numBuckets - 1); jj++) + { + m_histogram[jj] = 0; + } + m_lastBucket = bucket; + // If the new bucket is off the end, wrap around to the beginning + if (bucket > m_numBuckets) + { + bucket -= m_numBuckets; + m_lastBucket = 0; + m_histogram[m_lastBucket] = 0; + m_timeBase += m_totalHistogramMilliseconds; + } + } + } + m_histogram[m_lastBucket] += cnt; + } + } + + // Get a copy of the current histogram + public long[] GetHistogram() + { + long[] ret = new long[m_numBuckets]; + lock (histoLock) + { + int indx = m_lastBucket + 1; + for (int ii = 0; ii < m_numBuckets; ii++, indx++) + { + if (indx >= m_numBuckets) + indx = 0; + ret[ii] = m_histogram[indx]; + } + } + return ret; + } + + public OSDMap GetHistogramAsOSDMap() + { + OSDMap ret = new OSDMap(); + + ret.Add("Buckets", OSD.FromInteger(m_numBuckets)); + ret.Add("BucketMilliseconds", OSD.FromInteger(m_bucketMilliseconds)); + ret.Add("TotalMilliseconds", OSD.FromInteger(m_totalHistogramMilliseconds)); + + // Compute a number for the first bucket in the histogram. + // This will allow readers to know how this histogram relates to any previously read histogram. + int baseBucketNum = (m_timeBase / m_bucketMilliseconds) + m_lastBucket + 1; + ret.Add("BaseNumber", OSD.FromInteger(baseBucketNum)); + + ret.Add("Values", GetHistogramAsOSDArray()); + + return ret; + } + // Get a copy of the current histogram + public OSDArray GetHistogramAsOSDArray() + { + OSDArray ret = new OSDArray(m_numBuckets); + lock (histoLock) + { + int indx = m_lastBucket + 1; + for (int ii = 0; ii < m_numBuckets; ii++, indx++) + { + if (indx >= m_numBuckets) + indx = 0; + ret[ii] = OSD.FromLong(m_histogram[indx]); + } + } + return ret; + } + + // Zero out the histogram + public void Zero() + { + lock (histoLock) + { + for (int ii = 0; ii < m_numBuckets; ii++) + m_histogram[ii] = 0; + } + } +} + +// A statistic that wraps a counter. +// Built this way mostly so histograms and history can be created. +public class CounterStat : Stat +{ + private SortedDictionary m_histograms; + private object counterLock = new object(); + + public CounterStat( + string shortName, + string name, + string description, + string unitName, + string category, + string container, + StatVerbosity verbosity) + : base(shortName, name, description, unitName, category, container, StatType.Push, null, verbosity) + { + m_histograms = new SortedDictionary(); + } + + // Histograms are presumably added at intialization time and the list does not change thereafter. + // Thus no locking of the histogram list. + public void AddHistogram(string histoName, EventHistogram histo) + { + m_histograms.Add(histoName, histo); + } + + public delegate void ProcessHistogram(string name, EventHistogram histo); + public void ForEachHistogram(ProcessHistogram process) + { + foreach (KeyValuePair kvp in m_histograms) + { + process(kvp.Key, kvp.Value); + } + } + + public void Event() + { + this.Event(1); + } + + // Count the underlying counter. + public void Event(int cnt) + { + lock (counterLock) + { + base.Value += cnt; + + foreach (EventHistogram histo in m_histograms.Values) + { + histo.Event(cnt); + } + } + } +} +} From 2aae046b95cc028f0eb495857d5659971e06f604 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sun, 24 Feb 2013 07:38:24 -0800 Subject: [PATCH 04/11] Make StatsManager default output a little more readable --- OpenSim/Framework/Monitoring/Stats/Stat.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Framework/Monitoring/Stats/Stat.cs b/OpenSim/Framework/Monitoring/Stats/Stat.cs index c8d91744c1..2e7665f5a1 100644 --- a/OpenSim/Framework/Monitoring/Stats/Stat.cs +++ b/OpenSim/Framework/Monitoring/Stats/Stat.cs @@ -211,7 +211,7 @@ namespace OpenSim.Framework.Monitoring public virtual string ToConsoleString() { StringBuilder sb = new StringBuilder(); - sb.AppendFormat("{0}.{1}.{2} : {3}{4}", Category, Container, ShortName, Value, UnitName); + sb.AppendFormat("{0}.{1}.{2} : {3} {4}", Category, Container, ShortName, Value, UnitName); AppendMeasuresOfInterest(sb); From b2495c9a1e79fe8d3ec23f87d6c8177302e77b01 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sun, 24 Feb 2013 07:43:01 -0800 Subject: [PATCH 05/11] Streamline stat registration code in ServerStats. Remove most of the usage of ProcessCounters which tend to fail oddly and are not supported everywhere. --- .../Framework/Monitoring/ServerStats.cs | 210 +++++------------- 1 file changed, 50 insertions(+), 160 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Framework/Monitoring/ServerStats.cs b/OpenSim/Region/OptionalModules/Framework/Monitoring/ServerStats.cs index 8f60c8d7d6..a3d24363b1 100644 --- a/OpenSim/Region/OptionalModules/Framework/Monitoring/ServerStats.cs +++ b/OpenSim/Region/OptionalModules/Framework/Monitoring/ServerStats.cs @@ -63,6 +63,7 @@ public class ServerStats : ISharedRegionModule public readonly string ContainerNetwork = "network"; public readonly string ContainerProcess = "process"; + public string NetworkInterfaceTypes = "Ethernet"; readonly int performanceCounterSampleInterval = 500; int lastperformanceCounterSampleTime = 0; @@ -86,20 +87,6 @@ public class ServerStats : ISharedRegionModule PerfCounterControl processorPercentPerfCounter = null; - PerfCounterControl processThreadCountPerfCounter = null; - PerfCounterControl processVirtualBytesPerfCounter = null; - PerfCounterControl processWorkingSetPerfCounter = null; - - PerfCounterControl dotNETCLRMemoryAllocatedBytesPerSecPerfCounter = null; - PerfCounterControl dotNETCLRMemoryGen0HeapSizePerfCounter = null; - PerfCounterControl dotNETCLRMemoryGen1HeapSizePerfCounter = null; - PerfCounterControl dotNETCLRMemoryGen2HeapSizePerfCounter = null; - - PerfCounterControl dotNETCLRLaTTotalContentionsPerfCounter = null; - PerfCounterControl dotNETCLRLaTContentionsPerSecPerfCounter = null; - PerfCounterControl dotNETCLRLaTLogicalThreadsPerfCounter = null; - PerfCounterControl dotNETCLRLaTPhysicalThreadsPerfCounter = null; - #region ISharedRegionModule // IRegionModuleBase.Name public string Name { get { return "Server Stats"; } } @@ -108,10 +95,15 @@ public class ServerStats : ISharedRegionModule // IRegionModuleBase.Initialize public void Initialise(IConfigSource source) { - IConfig cnfg = source.Configs["Statistics"]; + IConfig cfg = source.Configs["Monitoring"]; - if (cnfg != null) - Enabled = cnfg.GetBoolean("Enabled", true); + if (cfg != null) + Enabled = cfg.GetBoolean("ServerStatsEnabled", true); + + if (Enabled) + { + NetworkInterfaceTypes = cfg.GetString("NetworkInterfaceTypes", "Ethernet"); + } } // IRegionModuleBase.Close public void Close() @@ -148,6 +140,13 @@ public class ServerStats : ISharedRegionModule } #endregion ISharedRegionModule + private void MakeStat(string pName, string pUnit, string pContainer, Action act) + { + Stat stat = new Stat(pName, pName, "", pUnit, CategoryServer, pContainer, StatType.Pull, act, StatVerbosity.Info); + StatsManager.RegisterStat(stat); + RegisteredStats.Add(pName, stat); + } + public void RegisterServerStats() { lastperformanceCounterSampleTime = Util.EnvironmentTickCount(); @@ -157,7 +156,7 @@ public class ServerStats : ISharedRegionModule try { - tempName = "CPU_Percent"; + tempName = "CPUPercent"; tempPC = new PerformanceCounter("Processor", "% Processor Time", "_Total"); processorPercentPerfCounter = new PerfCounterControl(tempPC); // A long time bug in mono is that CPU percent is reported as CPU percent idle. Windows reports CPU percent busy. @@ -167,31 +166,17 @@ public class ServerStats : ISharedRegionModule StatsManager.RegisterStat(tempStat); RegisteredStats.Add(tempName, tempStat); - /* Performance counters are not the way to go. Ick. Find another way. - tempName = "Thread_Count"; - tempPC = new PerformanceCounter("Process", "Thread Count", AppDomain.CurrentDomain.FriendlyName); - processThreadCountPerfCounter = new PerfCounterControl(tempPC); - tempStat = new Stat("Thread_Count", "Thread_Count", "", "threads", CategoryServer, ContainerProcess, - StatType.Pull, (s) => { GetNextValue(s, processThreadCountPerfCounter); }, StatVerbosity.Info); - StatsManager.RegisterStat(tempStat); - RegisteredStats.Add(tempName, tempStat); + MakeStat("TotalProcessorTime", "sec", ContainerProcessor, + (s) => { s.Value = Process.GetCurrentProcess().TotalProcessorTime.TotalSeconds; }); - tempName = "Virtual_Bytes"; - tempPC = new PerformanceCounter("Process", "Virtual Bytes", AppDomain.CurrentDomain.FriendlyName); - processVirtualBytesPerfCounter = new PerfCounterControl(tempPC); - tempStat = new Stat("Virtual_Bytes", "Virtual_Bytes", "", "MB", CategoryServer, ContainerProcess, - StatType.Pull, (s) => { GetNextValue(s, processVirtualBytesPerfCounter, 1024.0*1024.0); }, StatVerbosity.Info); - StatsManager.RegisterStat(tempStat); - RegisteredStats.Add(tempName, tempStat); + MakeStat("UserProcessorTime", "sec", ContainerProcessor, + (s) => { s.Value = Process.GetCurrentProcess().UserProcessorTime.TotalSeconds; }); - tempName = "Working_Set"; - tempPC = new PerformanceCounter("Process", "Working Set", AppDomain.CurrentDomain.FriendlyName); - processWorkingSetPerfCounter = new PerfCounterControl(tempPC); - tempStat = new Stat("Working_Set", "Working_Set", "", "MB", CategoryServer, ContainerProcess, - StatType.Pull, (s) => { GetNextValue(s, processWorkingSetPerfCounter, 1024.0*1024.0); }, StatVerbosity.Info); - StatsManager.RegisterStat(tempStat); - RegisteredStats.Add(tempName, tempStat); - */ + MakeStat("PrivilegedProcessorTime", "sec", ContainerProcessor, + (s) => { s.Value = Process.GetCurrentProcess().PrivilegedProcessorTime.TotalSeconds; }); + + MakeStat("Threads", "threads", ContainerProcessor, + (s) => { s.Value = Process.GetCurrentProcess().Threads.Count; }); } catch (Exception e) { @@ -200,112 +185,33 @@ public class ServerStats : ISharedRegionModule try { - /* The ".NET CLR *" categories aren't working for me. - tempName = ""Bytes_Allocated_Per_Sec"; - tempPC = new PerformanceCounter(".NET CLR Memory", "Allocated Bytes/sec", AppDomain.CurrentDomain.FriendlyName); - dotNETCLRMemoryAllocatedBytesPerSecPerfCounter = new PerfCounterControl(tempPC, tempStat); - tempStat = new Stat(tempName, tempName, "", "bytes/sec", ServerCategory, MemoryContainer, - StatType.Pull, (s) => { GetNextValue(s, dotNETCLRMemoryAllocatedBytesPerSecPerfCounter); }, StatVerbosity.Info); - StatsManager.RegisterStat(tempStat); - RegisteredStats.Add(tempName, tempStat); + List okInterfaceTypes = new List(NetworkInterfaceTypes.Split(',')); - tempName = "Gen_0_Heap_Size"; - tempPC = new PerformanceCounter(".NET CLR Memory", "Gen 0 heap size", AppDomain.CurrentDomain.FriendlyName); - dotNETCLRMemoryGen0HeapSizePerfCounter = new PerfCounterControl(tempPC, tempStat); - tempStat = new Stat("Gen_0_Heap_Size", "Gen_0_Heap_Size", "", "bytes", ServerCategory, MemoryContainer, - StatType.Pull, (s) => { GetNextValue(s, dotNETCLRMemoryGen0HeapSizePerfCounter); }, StatVerbosity.Info); - StatsManager.RegisterStat(tempStat); - RegisteredStats.Add(tempName, tempStat); - - tempName = "Gen_1_Heap_Size"; - tempPC = new PerformanceCounter(".NET CLR Memory", "Gen 1 heap size", AppDomain.CurrentDomain.FriendlyName); - dotNETCLRMemoryGen1HeapSizePerfCounter = new PerfCounterControl(tempPC, tempStat); - tempStat = new Stat("Gen_1_Heap_Size", "Gen_1_Heap_Size", "", "bytes", ServerCategory, MemoryContainer, - StatType.Pull, (s) => { GetNextValue(s, dotNETCLRMemoryGen1HeapSizePerfCounter); }, StatVerbosity.Info); - StatsManager.RegisterStat(tempStat); - RegisteredStats.Add(tempName, tempStat); - - tempName = "Gen_2_Heap_Size"; - tempPC = new PerformanceCounter(".NET CLR Memory", "Gen 2 heap size", AppDomain.CurrentDomain.FriendlyName); - dotNETCLRMemoryGen2HeapSizePerfCounter = new PerfCounterControl(tempPC, tempStat); - tempStat = new Stat("Gen_2_Heap_Size", "Gen_2_Heap_Size", "", "bytes", ServerCategory, MemoryContainer, - StatType.Pull, (s) => { GetNextValue(s, dotNETCLRMemoryGen2HeapSizePerfCounter); }, StatVerbosity.Info); - StatsManager.RegisterStat(tempStat); - RegisteredStats.Add(tempName, tempStat); - - tempName = "Total_Lock_Contentions"; - tempPC = new PerformanceCounter(".NET CLR LocksAndThreads", "Total # of Contentions"); - dotNETCLRLaTTotalContentionsPerfCounter = new PerfCounterControl(tempPC, tempStat); - tempStat = new Stat("Total_Lock_Contentions", "Total_Lock_Contentions", "", "contentions", ServerCategory, ProcessContainer, - StatType.Pull, (s) => { GetNextValue(s, dotNETCLRLaTTotalContentionsPerfCounter); }, StatVerbosity.Info); - StatsManager.RegisterStat(tempStat); - RegisteredStats.Add(tempName, tempStat); - - tempName = "Lock_Contentions"; - tempPC = new PerformanceCounter(".NET CLR LocksAndThreads", "Contention Rate / sec"); - dotNETCLRLaTContentionsPerSecPerfCounter = new PerfCounterControl(tempPC, tempStat); - tempStat = new Stat("Lock_Contentions", "Lock_Contentions", "", "contentions/sec", ServerCategory, ProcessContainer, - StatType.Pull, (s) => { GetNextValue(s, dotNETCLRLaTContentionsPerSecPerfCounter); }, StatVerbosity.Info); - StatsManager.RegisterStat(tempStat); - RegisteredStats.Add(tempName, tempStat); - - tempName = "Logical_Threads"; - tempPC = new PerformanceCounter(".NET CLR LocksAndThreads", "# of current logical Threads"); - dotNETCLRLaTLogicalThreadsPerfCounter = new PerfCounterControl(tempPC, tempStat); - tempStat = new Stat("Logicial_Threads", "Logicial_Threads", "", "threads", ServerCategory, ProcessContainer, - StatType.Pull, (s) => { GetNextValue(s, dotNETCLRLaTLogicalThreadsPerfCounter); }, StatVerbosity.Info); - StatsManager.RegisterStat(tempStat); - RegisteredStats.Add(tempName, tempStat); - - tempName = "Physical_Threads"; - tempPC = new PerformanceCounter(".NET CLR LocksAndThreads", "# of current physical Threads"); - dotNETCLRLaTPhysicalThreadsPerfCounter = new PerfCounterControl(tempPC, tempStat); - tempStat = new Stat("Physical_Threads", "Physical_Threads", "", "threads", ServerCategory, ProcessContainer, - StatType.Pull, (s) => { GetNextValue(s, dotNETCLRLaTPhysicalThreadsPerfCounter); }, StatVerbosity.Info); - StatsManager.RegisterStat(tempStat); - RegisteredStats.Add(tempName, tempStat); - */ - } - catch (Exception e) - { - m_log.ErrorFormat("{0} Exception creating '.NET CLR Memory': {1}", LogHeader, e); - } - - try - { IEnumerable nics = NetworkInterface.GetAllNetworkInterfaces(); - // IEnumerable nics = NetworkInterface.GetAllNetworkInterfaces().Where( - // (network) => network.NetworkInterfaceType == NetworkInterfaceType.Ethernet); - // IEnumerable nics = NetworkInterface.GetAllNetworkInterfaces().Where( - // (network) => network.OperationalStatus == OperationalStatus.Up); - foreach (NetworkInterface nic in nics) { - if (nic.OperationalStatus != OperationalStatus.Up || nic.NetworkInterfaceType != NetworkInterfaceType.Ethernet) + if (nic.OperationalStatus != OperationalStatus.Up) continue; + string nicInterfaceType = nic.NetworkInterfaceType.ToString(); + if (!okInterfaceTypes.Contains(nicInterfaceType)) + { + m_log.DebugFormat("{0} Not including stats for network interface '{1}' of type '{2}'. To include, add to [Monitoring]NetworkInterfaceTypes='Ethernet,Loopback'", + LogHeader, nic.Name, nicInterfaceType); + continue; + } + if (nic.Supports(NetworkInterfaceComponent.IPv4)) { IPv4InterfaceStatistics nicStats = nic.GetIPv4Statistics(); if (nicStats != null) { - tempName = "Bytes_Rcvd/" + nic.Name; - tempStat = new Stat(tempName, tempName, nic.Name, "KB", CategoryServer, ContainerNetwork, - StatType.Pull, (s) => { LookupNic(s, (ns) => { return ns.BytesReceived; }, 1024.0); }, StatVerbosity.Info); - StatsManager.RegisterStat(tempStat); - RegisteredStats.Add(tempName, tempStat); - - tempName = "Bytes_Sent/" + nic.Name; - tempStat = new Stat(tempName, tempName, nic.Name, "KB", CategoryServer, ContainerNetwork, - StatType.Pull, (s) => { LookupNic(s, (ns) => { return ns.BytesSent; }, 1024.0); }, StatVerbosity.Info); - StatsManager.RegisterStat(tempStat); - RegisteredStats.Add(tempName, tempStat); - - tempName = "Total_Bytes/" + nic.Name; - tempStat = new Stat(tempName, tempName, nic.Name, "KB", CategoryServer, ContainerNetwork, - StatType.Pull, (s) => { LookupNic(s, (ns) => { return ns.BytesSent + ns.BytesReceived; }, 1024.0); }, StatVerbosity.Info); - StatsManager.RegisterStat(tempStat); - RegisteredStats.Add(tempName, tempStat); + MakeStat("BytesRcvd/" + nic.Name, "KB", ContainerNetwork, + (s) => { LookupNic(s, (ns) => { return ns.BytesReceived; }, 1024.0); }); + MakeStat("BytesSent/" + nic.Name, "KB", ContainerNetwork, + (s) => { LookupNic(s, (ns) => { return ns.BytesSent; }, 1024.0); }); + MakeStat("TotalBytes/" + nic.Name, "KB", ContainerNetwork, + (s) => { LookupNic(s, (ns) => { return ns.BytesSent + ns.BytesReceived; }, 1024.0); }); } } } @@ -315,30 +221,14 @@ public class ServerStats : ISharedRegionModule m_log.ErrorFormat("{0} Exception creating 'Network Interface': {1}", LogHeader, e); } - tempName = "Process_Memory"; - tempStat = new Stat(tempName, tempName, "", "MB", CategoryServer, ContainerMemory, - StatType.Pull, (s) => { s.Value = Process.GetCurrentProcess().WorkingSet64 / 1024d / 1024d; }, StatVerbosity.Info); - StatsManager.RegisterStat(tempStat); - RegisteredStats.Add(tempName, tempStat); - - tempName = "Object_Memory"; - tempStat = new Stat(tempName, tempName, "", "MB", CategoryServer, ContainerMemory, - StatType.Pull, (s) => { s.Value = GC.GetTotalMemory(false) / 1024d / 1024d; }, StatVerbosity.Info); - StatsManager.RegisterStat(tempStat); - RegisteredStats.Add(tempName, tempStat); - - tempName = "Last_Memory_Churn"; - tempStat = new Stat(tempName, tempName, "", "MB/sec", CategoryServer, ContainerMemory, - StatType.Pull, (s) => { s.Value = Math.Round(MemoryWatchdog.LastMemoryChurn * 1000d / 1024d / 1024d, 3); }, StatVerbosity.Info); - StatsManager.RegisterStat(tempStat); - RegisteredStats.Add(tempName, tempStat); - - tempName = "Average_Memory_Churn"; - tempStat = new Stat(tempName, tempName, "", "MB/sec", CategoryServer, ContainerMemory, - StatType.Pull, (s) => { s.Value = Math.Round(MemoryWatchdog.AverageMemoryChurn * 1000d / 1024d / 1024d, 3); }, StatVerbosity.Info); - StatsManager.RegisterStat(tempStat); - RegisteredStats.Add(tempName, tempStat); - + MakeStat("ProcessMemory", "MB", ContainerMemory, + (s) => { s.Value = Process.GetCurrentProcess().WorkingSet64 / 1024d / 1024d; }); + MakeStat("ObjectMemory", "MB", ContainerMemory, + (s) => { s.Value = GC.GetTotalMemory(false) / 1024d / 1024d; }); + MakeStat("LastMemoryChurn", "MB/sec", ContainerMemory, + (s) => { s.Value = Math.Round(MemoryWatchdog.LastMemoryChurn * 1000d / 1024d / 1024d, 3); }); + MakeStat("AverageMemoryChurn", "MB/sec", ContainerMemory, + (s) => { s.Value = Math.Round(MemoryWatchdog.AverageMemoryChurn * 1000d / 1024d / 1024d, 3); }); } // Notes on performance counters: From aa538fe36f92a7c047c9db8c98514de83cb5c3e7 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sun, 24 Feb 2013 07:45:37 -0800 Subject: [PATCH 06/11] Add StatsManager registration for region specific stats as collected by MonitorModule. Left existing functionality (command line and HTTP fetch) and just added StatsManager registration. --- .../Framework/Monitoring/MonitorModule.cs | 48 ++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs b/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs index d84460a7a8..4c9ee067e2 100644 --- a/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs @@ -33,6 +33,7 @@ using log4net; using Nini.Config; using OpenMetaverse; using OpenSim.Framework; +using OpenSim.Framework.Monitoring; using OpenSim.Framework.Servers; using OpenSim.Region.CoreModules.Framework.Monitoring.Alerts; using OpenSim.Region.CoreModules.Framework.Monitoring.Monitors; @@ -100,6 +101,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring "/monitorstats/" + Uri.EscapeDataString(m_scene.RegionInfo.RegionName), StatsPage); AddMonitors(); + RegisterStatsManagerRegionStatistics(); } public void RemoveRegion(Scene scene) @@ -109,6 +111,9 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring MainServer.Instance.RemoveHTTPHandler("GET", "/monitorstats/" + m_scene.RegionInfo.RegionID); MainServer.Instance.RemoveHTTPHandler("GET", "/monitorstats/" + Uri.EscapeDataString(m_scene.RegionInfo.RegionName)); + + UnRegisterStatsManagerRegionStatistics(); + m_scene = null; } @@ -399,6 +404,47 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring { m_log.Error("[Monitor] " + reporter.Name + " for " + m_scene.RegionInfo.RegionName + " reports " + reason + " (Fatal: " + fatal + ")"); } + + private List registeredStats = new List(); + private void MakeStat(string pName, string pUnitName, Action act) + { + Stat tempStat = new Stat(pName, pName, pName, pUnitName, "scene", m_scene.RegionInfo.RegionName, StatType.Pull, act, StatVerbosity.Info); + StatsManager.RegisterStat(tempStat); + registeredStats.Add(tempStat); + } + private void RegisterStatsManagerRegionStatistics() + { + string regionName = m_scene.RegionInfo.RegionName; + + MakeStat("RootAgents", "avatars", (s) => { s.Value = m_scene.SceneGraph.GetRootAgentCount(); }); + MakeStat("ChildAgents", "avatars", (s) => { s.Value = m_scene.SceneGraph.GetChildAgentCount(); }); + MakeStat("TotalPrims", "objects", (s) => { s.Value = m_scene.SceneGraph.GetTotalObjectsCount(); }); + MakeStat("ActivePrims", "objects", (s) => { s.Value = m_scene.SceneGraph.GetActiveObjectsCount(); }); + MakeStat("ActiveScripts", "scripts", (s) => { s.Value = m_scene.SceneGraph.GetActiveScriptsCount(); }); + + MakeStat("TimeDilation", "sec/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[0]; }); + MakeStat("SimFPS", "fps", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[1]; }); + MakeStat("PhysicsFPS", "fps", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[2]; }); + MakeStat("AgentUpdates", "updates/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[3]; }); + MakeStat("FrameTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[8]; }); + MakeStat("NetTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[9]; }); + MakeStat("OtherTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[12]; }); + MakeStat("PhysicsTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[10]; }); + MakeStat("AgentTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[16]; }); + MakeStat("ImageTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[11]; }); + MakeStat("ScriptLines", "lines/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[20]; }); + MakeStat("SimSpareMS", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[21]; }); + } + + private void UnRegisterStatsManagerRegionStatistics() + { + foreach (Stat stat in registeredStats) + { + StatsManager.DeregisterStat(stat); + stat.Dispose(); + } + registeredStats.Clear(); + } } -} +} \ No newline at end of file From f7aa018a783d2e04cdba6d23b9012695f1554061 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 25 Feb 2013 10:24:28 -0800 Subject: [PATCH 07/11] Fixes mantis #6551 -- misspelled key name. Also fixed an issue with the roles cache. --- .../Groups/Remote/GroupsServiceRemoteConnectorModule.cs | 2 +- .../Addons/Groups/Remote/GroupsServiceRobustConnector.cs | 2 +- OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs | 9 ++++++++- OpenSim/Addons/Groups/Service/GroupsService.cs | 6 ++++++ 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs index d1c02db721..628ce4dd80 100644 --- a/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs +++ b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs @@ -273,7 +273,7 @@ namespace OpenSim.Groups public bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason) { string r = string.Empty; - bool success = m_CacheWrapper.AddGroupRole(roleID, description, name, powers, title, delegate + bool success = m_CacheWrapper.AddGroupRole(groupID, roleID, description, name, powers, title, delegate { return m_GroupsService.AddGroupRole(RequestingAgentID, groupID, roleID, name, description, title, powers, out r); }); diff --git a/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs b/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs index 8c257edcc0..f991d016f0 100644 --- a/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs +++ b/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs @@ -371,7 +371,7 @@ namespace OpenSim.Groups Dictionary result = new Dictionary(); if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("RoleID") || - !request.ContainsKey("Name") || !request.ContainsKey("Descrption") || !request.ContainsKey("Title") || + !request.ContainsKey("Name") || !request.ContainsKey("Description") || !request.ContainsKey("Title") || !request.ContainsKey("Powers") || !request.ContainsKey("OP")) NullResult(result, "Bad network data"); diff --git a/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs b/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs index f789626d07..e7d38c2020 100644 --- a/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs +++ b/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs @@ -393,7 +393,7 @@ namespace OpenSim.Groups } } - public bool AddGroupRole(UUID roleID, string description, string name, ulong powers, string title, BooleanDelegate d) + public bool AddGroupRole(UUID groupID, UUID roleID, string description, string name, ulong powers, string title, BooleanDelegate d) { if (d()) { @@ -406,8 +406,15 @@ namespace OpenSim.Groups role.Title = title; lock (m_Cache) + { m_Cache.AddOrUpdate("role-" + roleID.ToString(), role, GROUPS_CACHE_TIMEOUT); + // also remove this list + if (m_Cache.Contains("roles-" + groupID.ToString())) + m_Cache.Remove("roles-" + groupID.ToString()); + + } + return true; } diff --git a/OpenSim/Addons/Groups/Service/GroupsService.cs b/OpenSim/Addons/Groups/Service/GroupsService.cs index fc567dd6c3..0668870ef1 100644 --- a/OpenSim/Addons/Groups/Service/GroupsService.cs +++ b/OpenSim/Addons/Groups/Service/GroupsService.cs @@ -785,10 +785,16 @@ namespace OpenSim.Groups RoleData data = m_Database.RetrieveRole(groupID, roleID); if (add && data != null) // it already exists, can't create + { + m_log.DebugFormat("[Groups]: Group {0} already exists. Can't create it again", groupID); return false; + } if (!add && data == null) // it deosn't exist, can't update + { + m_log.DebugFormat("[Groups]: Group {0} doesn't exist. Can't update it", groupID); return false; + } if (add) data = new RoleData(); From 53470d5057d7b325abe781ef2377ac1e9b273cac Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 25 Feb 2013 10:25:36 -0800 Subject: [PATCH 08/11] Missing var in [LoginService] for HG Robust. --- bin/Robust.HG.ini.example | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/Robust.HG.ini.example b/bin/Robust.HG.ini.example index 445020faf4..53676a32c4 100644 --- a/bin/Robust.HG.ini.example +++ b/bin/Robust.HG.ini.example @@ -333,6 +333,7 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset SRV_ProfileServerURI = "http://127.0.0.1:8002" SRV_FriendsServerURI = "http://127.0.0.1:8002" SRV_IMServerURI = "http://127.0.0.1:8002" + SRV_GroupsServerURI = "http://127.0.0.1:8002" ;; Regular expressions for controlling which client versions are accepted/denied. ;; An empty string means nothing is checked. From d0cb4fc3262df2afe2ef34396c7960f7afee6b89 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 25 Feb 2013 23:04:38 +0000 Subject: [PATCH 09/11] Move map related settings from [Startup] to a new [Map] section in OpenSim.ini Existing map settings in [Startup] will continue to work, and if present will override anything in [Map] However, the proper place for such settings would now be [Map] This is to reduce the use of [Startup] as a bag for non-generic settings which should really go in sections, in common with other settings. This commit also extends Diva's previous work to allow a default setting to be given when looking at multiple sections for settings. --- OpenSim/Framework/Util.cs | 27 +++++++-- .../CoreModules/Hypergrid/HGWorldMapModule.cs | 4 +- .../World/LegacyMap/MapImageModule.cs | 24 ++++---- .../World/Warp3DMap/Warp3DImageModule.cs | 20 +++---- .../World/WorldMap/WorldMapModule.cs | 9 ++- OpenSim/Region/Framework/Scenes/Scene.cs | 11 +++- bin/OpenSim.ini.example | 55 ++++++++++--------- bin/OpenSimDefaults.ini | 50 ++++++++--------- 8 files changed, 109 insertions(+), 91 deletions(-) diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 8b8e50756d..0fa54b246d 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -917,7 +917,25 @@ namespace OpenSim.Framework /// public static T GetConfigVarFromSections(IConfigSource config, string varname, string[] sections) { - object val = default(T); + return GetConfigVarFromSections(config, varname, sections, default(T)); + } + + /// + /// Gets the value of a configuration variable by looking into + /// multiple sections in order. The latter sections overwrite + /// any values previously found. + /// + /// + /// If no value is found then the given default value is returned + /// + /// Type of the variable + /// The configuration object + /// The configuration variable + /// Ordered sequence of sections to look at + /// Default value + /// + public static T GetConfigVarFromSections(IConfigSource config, string varname, string[] sections, object val) + { foreach (string section in sections) { IConfig cnf = config.Configs[section]; @@ -925,11 +943,7 @@ namespace OpenSim.Framework continue; if (typeof(T) == typeof(String)) - { - if (val == null) // no null strings, please - val = string.Empty; val = cnf.GetString(varname, (string)val); - } else if (typeof(T) == typeof(Boolean)) val = cnf.GetBoolean(varname, (bool)val); else if (typeof(T) == typeof(Int32)) @@ -937,8 +951,9 @@ namespace OpenSim.Framework else if (typeof(T) == typeof(float)) val = cnf.GetFloat(varname, (int)val); else - m_log.WarnFormat("[UTIL]: Unhandled type {0}", typeof(T)); + m_log.ErrorFormat("[UTIL]: Unhandled type {0}", typeof(T)); } + return (T)val; } diff --git a/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs index e0921adf51..c4255b951d 100644 --- a/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs +++ b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs @@ -52,8 +52,8 @@ namespace OpenSim.Region.CoreModules.Hypergrid public override void Initialise(IConfigSource config) { - IConfig startupConfig = config.Configs["Startup"]; - if (startupConfig.GetString("WorldMapModule", "WorldMap") == "HGWorldMap") + if (Util.GetConfigVarFromSections( + config, "WorldMapModule", new string[] { "Map", "Startup" }, "WorldMap") == "HGWorldMap") m_Enabled = true; } diff --git a/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs b/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs index e7065dcd27..40638f8dea 100644 --- a/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs +++ b/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs @@ -80,17 +80,14 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap bool generateMaptiles = true; Bitmap mapbmp; - try - { - IConfig startupConfig = m_config.Configs["Startup"]; - drawPrimVolume = startupConfig.GetBoolean("DrawPrimOnMapTile", drawPrimVolume); - textureTerrain = startupConfig.GetBoolean("TextureOnMapTile", textureTerrain); - generateMaptiles = startupConfig.GetBoolean("GenerateMaptiles", generateMaptiles); - } - catch - { - m_log.Warn("[MAPTILE]: Failed to load StartupConfig"); - } + string[] configSections = new string[] { "Map", "Startup" }; + + drawPrimVolume + = Util.GetConfigVarFromSections(m_config, "DrawPrimOnMapTile", configSections, drawPrimVolume); + textureTerrain + = Util.GetConfigVarFromSections(m_config, "TextureOnMapTile", configSections, textureTerrain); + generateMaptiles + = Util.GetConfigVarFromSections(m_config, "GenerateMaptiles", configSections, generateMaptiles); if (generateMaptiles) { @@ -148,9 +145,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap { m_config = source; - IConfig startupConfig = m_config.Configs["Startup"]; - if (startupConfig.GetString("MapImageModule", "MapImageModule") != - "MapImageModule") + if (Util.GetConfigVarFromSections( + m_config, "MapImageModule", new string[] { "Startup", "Map" }, "MapImageModule") != "MapImageModule") return; m_Enabled = true; diff --git a/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs b/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs index 5e0dfa76a5..ed2b06aac2 100644 --- a/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs +++ b/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs @@ -71,8 +71,8 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap { m_config = source; - IConfig startupConfig = m_config.Configs["Startup"]; - if (startupConfig.GetString("MapImageModule", "MapImageModule") != "Warp3DImageModule") + if (Util.GetConfigVarFromSections( + m_config, "MapImageModule", new string[] { "Startup", "Map" }, "MapImageModule") != "Warp3DImageModule") return; m_Enabled = true; @@ -143,16 +143,12 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap bool drawPrimVolume = true; bool textureTerrain = true; - try - { - IConfig startupConfig = m_config.Configs["Startup"]; - drawPrimVolume = startupConfig.GetBoolean("DrawPrimOnMapTile", drawPrimVolume); - textureTerrain = startupConfig.GetBoolean("TextureOnMapTile", textureTerrain); - } - catch - { - m_log.Warn("[WARP 3D IMAGE MODULE]: Failed to load StartupConfig"); - } + string[] configSections = new string[] { "Map", "Startup" }; + + drawPrimVolume + = Util.GetConfigVarFromSections(m_config, "DrawPrimOnMapTile", configSections, drawPrimVolume); + textureTerrain + = Util.GetConfigVarFromSections(m_config, "TextureOnMapTile", configSections, textureTerrain); m_colors.Clear(); diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs index e2f525cf47..912d50ae08 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs @@ -86,11 +86,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap #region INonSharedRegionModule Members public virtual void Initialise (IConfigSource config) { - IConfig startupConfig = config.Configs["Startup"]; - if (startupConfig.GetString("WorldMapModule", "WorldMap") == "WorldMap") + string[] configSections = new string[] { "Map", "Startup" }; + + if (Util.GetConfigVarFromSections( + config, "WorldMapModule", configSections, "WorldMap") == "WorldMap") m_Enabled = true; - blacklistTimeout = startupConfig.GetInt("BlacklistTimeout", 10*60) * 1000; + blacklistTimeout + = Util.GetConfigVarFromSections(config, "BlacklistTimeout", configSections, 10 * 60) * 1000; } public virtual void AddRegion (Scene scene) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 9b17b7f650..5b615388d6 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -897,7 +897,11 @@ namespace OpenSim.Region.Framework.Scenes m_strictAccessControl = startupConfig.GetBoolean("StrictAccessControl", m_strictAccessControl); - m_generateMaptiles = startupConfig.GetBoolean("GenerateMaptiles", true); + string[] possibleMapConfigSections = new string[] { "Map", "Startup" }; + + m_generateMaptiles + = Util.GetConfigVarFromSections(config, "GenerateMaptiles", possibleMapConfigSections, true); + if (m_generateMaptiles) { int maptileRefresh = startupConfig.GetInt("MaptileRefresh", 0); @@ -911,7 +915,10 @@ namespace OpenSim.Region.Framework.Scenes } else { - string tile = startupConfig.GetString("MaptileStaticUUID", UUID.Zero.ToString()); + string tile + = Util.GetConfigVarFromSections( + config, "MaptileStaticUUID", possibleMapConfigSections, UUID.Zero.ToString()); + UUID tileID; if (tile != UUID.Zero.ToString() && UUID.TryParse(tile, out tileID)) diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 5aeae8a1f0..2756b32c75 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -268,32 +268,6 @@ ;; Default script engine to use. Currently, we only have XEngine ; DefaultScriptEngine = "XEngine" - ;# {GenerateMaptiles} {} {Generate map tiles?} {true false} true - ;; Map tile options. You can choose to generate normal maptiles or nominate an uploaded texture to - ;; be the map tile using the MaptileStaticUUID parameter in this section or for individual regions in - ;; the regions config file(s). If you do not want to upload map tiles at all, then you will need - ;; to disable the MapImageServiceModule entirely. - ; GenerateMaptiles = true - - ;# {MaptileRefresh} {GenerateMaptiles} {Maptile refresh period?} {} 0 - ;; If desired, a running region can update the map tiles periodically - ;; to reflect building activity. This names no sense of you don't have - ;; prims on maptiles. Value is in seconds. - ; MaptileRefresh = 0 - - ;# {MaptileStaticUUID} {} {Asset ID for static map texture} {} 00000000-0000-0000-0000-000000000000 - ;; If not generating maptiles, use this static texture asset ID - ; MaptileStaticUUID = "00000000-0000-0000-0000-000000000000" - - ;# {TextureOnMapTile} {} {Use terrain textures for map tiles?} {true false} true - ;; Use terrain texture for maptiles if true, use shaded green if false - ; TextureOnMapTile = true - - ;# {DrawPrimOnMapTile} {} {Draw prim shapes on map tiles?} {true false} false - ;; Draw objects on maptile. This step might take a long time if you've - ;; got a large number of objects, so you can turn it off here if you'd like. - ; DrawPrimOnMapTile = true - ;# {HttpProxy} {} {Proxy URL for llHTTPRequest and dynamic texture loading} {} http://proxy.com:8080 ;; Http proxy setting for llHTTPRequest and dynamic texture loading, if ;; required @@ -362,6 +336,35 @@ ;; This is a default that can be overwritten in some sections. ; GatekeeperURI = "http://127.0.0.1:9000" + +[Map] + ;# {GenerateMaptiles} {} {Generate map tiles?} {true false} true + ;; Map tile options. You can choose to generate normal maptiles or nominate an uploaded texture to + ;; be the map tile using the MaptileStaticUUID parameter in this section or for individual regions in + ;; the regions config file(s). If you do not want to upload map tiles at all, then you will need + ;; to disable the MapImageServiceModule entirely. + ; GenerateMaptiles = true + + ;# {MaptileRefresh} {GenerateMaptiles} {Maptile refresh period?} {} 0 + ;; If desired, a running region can update the map tiles periodically + ;; to reflect building activity. This names no sense of you don't have + ;; prims on maptiles. Value is in seconds. + ; MaptileRefresh = 0 + + ;# {MaptileStaticUUID} {} {Asset ID for static map texture} {} 00000000-0000-0000-0000-000000000000 + ;; If not generating maptiles, use this static texture asset ID + ; MaptileStaticUUID = "00000000-0000-0000-0000-000000000000" + + ;# {TextureOnMapTile} {} {Use terrain textures for map tiles?} {true false} true + ;; Use terrain texture for maptiles if true, use shaded green if false + ; TextureOnMapTile = true + + ;# {DrawPrimOnMapTile} {} {Draw prim shapes on map tiles?} {true false} false + ;; Draw objects on maptile. This step might take a long time if you've + ;; got a large number of objects, so you can turn it off here if you'd like. + ; DrawPrimOnMapTile = true + + [Estates] ; If these values are commented out then the user will be asked for estate details when required (this is the normal case). ; If these values are uncommented then they will be used to create a default estate as necessary. diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 2512428757..6ecb5dfc87 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -284,32 +284,6 @@ DefaultScriptEngine = "XEngine" - ; ## - ; ## WORLD MAP - ; ## - - ;WorldMapModule = "WorldMap" - ;MapImageModule = "MapImageModule" - - ; World map blacklist timeout in seconds - ;BlacklistTimeout = 600 - - ; Set to false to not generate any maptiles - ;GenerateMaptiles = true - - ; Refresh (in seconds) the map tile periodically - ;MaptileRefresh = 0 - - ; If not generating maptiles, use this static texture asset ID - ;MaptileStaticUUID = "00000000-0000-0000-0000-000000000000" - - ; Draw objects on maptile. This step might take a long time if you've got a large number of - ; objects, so you can turn it off here if you'd like. - DrawPrimOnMapTile = true - - ; Use terrain texture for maptiles if true, use shaded green if false - TextureOnMapTile = true - ; ## ; ## EMAIL MODULE ; ## @@ -347,6 +321,30 @@ UseTrashOnDelete = True +[Map] + ;WorldMapModule = "WorldMap" + ;MapImageModule = "MapImageModule" + + ; World map blacklist timeout in seconds + ;BlacklistTimeout = 600 + + ; Set to false to not generate any maptiles + ;GenerateMaptiles = true + + ; Refresh (in seconds) the map tile periodically + ;MaptileRefresh = 0 + + ; If not generating maptiles, use this static texture asset ID + ;MaptileStaticUUID = "00000000-0000-0000-0000-000000000000" + + ; Draw objects on maptile. This step might take a long time if you've got a large number of + ; objects, so you can turn it off here if you'd like. + DrawPrimOnMapTile = true + + ; Use terrain texture for maptiles if true, use shaded green if false + TextureOnMapTile = true + + [RegionReady] ; Enable this module to get notified once all items and scripts in the region have been completely loaded and compiled enabled = true From 00da59ae52e2a7f205376e7cc2e450e94e13754b Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 25 Feb 2013 16:27:41 -0800 Subject: [PATCH 10/11] Mantis #6552 -- stricter error (crash) if server URL is malformed. --- .../Groups/Remote/GroupsServiceRemoteConnectorModule.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs index 628ce4dd80..f1cf66c5ba 100644 --- a/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs +++ b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs @@ -74,11 +74,8 @@ namespace OpenSim.Groups { IConfig groupsConfig = config.Configs["Groups"]; string url = groupsConfig.GetString("GroupsServerURI", string.Empty); - if (url == string.Empty) - { - m_log.WarnFormat("[Groups.RemoteConnector]: Groups server URL not provided. Groups will not work."); - return; - } + if (!Uri.IsWellFormedUriString(url, UriKind.Absolute)) + throw new Exception(string.Format("[Groups.RemoteConnector]: Malformed groups server URL {0}. Fix it or disable the Groups feature.", url)); m_GroupsService = new GroupsServiceRemoteConnector(url); m_Scenes = new List(); From 2b53f08386baddeda7e0fa19a3072477c2829080 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 25 Feb 2013 21:58:00 -0800 Subject: [PATCH 11/11] BulletSim: tweeks to make avatar jump work better. --- OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 1f186c371c..f442ca22df 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -204,7 +204,7 @@ public sealed class BSCharacter : BSPhysObject // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity // errors can creap in and the avatar will slowly float off in some direction. // So, the problem is that, when an avatar is standing, we cannot tell creaping error - // from real pushing.OMV.Vector3.Zero; + // from real pushing. // The code below keeps setting the velocity to zero hoping the world will keep pushing. _velocityMotor.Step(timeStep); @@ -254,9 +254,11 @@ public sealed class BSCharacter : BSPhysObject } // If falling, we keep the world's downward vector no matter what the other axis specify. + // The check for _velocity.Z < 0 makes jumping work (temporary upward force). if (!Flying && !IsColliding) { - stepVelocity.Z = _velocity.Z; + if (_velocity.Z < 0) + stepVelocity.Z = _velocity.Z; // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity); } @@ -512,7 +514,7 @@ public sealed class BSCharacter : BSPhysObject // just assign to "Position" because of potential call loops. PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() { - DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); + DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); ForcePosition = _position; }); ret = true; @@ -572,7 +574,7 @@ public sealed class BSCharacter : BSPhysObject m_targetVelocity = value; OMV.Vector3 targetVel = value; if (_setAlwaysRun) - targetVel *= BSParam.AvatarAlwaysRunFactor; + targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 0f); PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate() {