Add experimental "debug attachments throttle <ms>" setting (command line) and ThrottlePer100PrimsRezzed in [Attachments] in config
This is an experimental setting to control cpu spikes when an attachment heavy avatar logs in or avatars with medium attachments lgoin simultaneously. It inserts a ms sleep specified in terms of attachments prims after each rez when an avatar logs in. Default is 0 (no throttling). "debug attachments <level>" changes to "debug attachments log <level>" which controls logging. A logging level of 1 will show the throttling performed if applicable. Also adds "debug attachments status" command to show current throttle and debug logging levels.TeleportWork
parent
0c4c084bed
commit
216e785ca9
|
@ -29,6 +29,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using log4net;
|
using log4net;
|
||||||
using Mono.Addins;
|
using Mono.Addins;
|
||||||
|
@ -51,6 +52,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||||
|
|
||||||
public int DebugLevel { get; set; }
|
public int DebugLevel { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Period to sleep per 100 prims in order to avoid CPU spikes when an avatar with many attachments logs in
|
||||||
|
/// or many avatars with a medium levels of attachments login simultaneously.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// A value of 0 will apply no pause. The pause is specified in milliseconds.
|
||||||
|
/// </remarks>
|
||||||
|
public int ThrottlePer100PrimsRezzed { get; set; }
|
||||||
|
|
||||||
private Scene m_scene;
|
private Scene m_scene;
|
||||||
private IInventoryAccessModule m_invAccessModule;
|
private IInventoryAccessModule m_invAccessModule;
|
||||||
|
|
||||||
|
@ -66,10 +76,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||||
{
|
{
|
||||||
IConfig config = source.Configs["Attachments"];
|
IConfig config = source.Configs["Attachments"];
|
||||||
if (config != null)
|
if (config != null)
|
||||||
|
{
|
||||||
Enabled = config.GetBoolean("Enabled", true);
|
Enabled = config.GetBoolean("Enabled", true);
|
||||||
|
|
||||||
|
ThrottlePer100PrimsRezzed = config.GetInt("ThrottlePer100PrimsRezzed", 0);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
Enabled = true;
|
Enabled = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void AddRegion(Scene scene)
|
public void AddRegion(Scene scene)
|
||||||
{
|
{
|
||||||
|
@ -87,24 +103,43 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||||
MainConsole.Instance.Commands.AddCommand(
|
MainConsole.Instance.Commands.AddCommand(
|
||||||
"Debug",
|
"Debug",
|
||||||
false,
|
false,
|
||||||
"debug attachments",
|
"debug attachments log",
|
||||||
"debug attachments [0|1]",
|
"debug attachments log [0|1]",
|
||||||
"Turn on attachments debugging\n"
|
"Turn on attachments debug logging",
|
||||||
+ " <= 0 - turns off debugging\n"
|
" <= 0 - turns off debug logging\n"
|
||||||
+ " >= 1 - turns on attachment message logging\n",
|
+ " >= 1 - turns on attachment message debug logging",
|
||||||
HandleDebugAttachments);
|
HandleDebugAttachmentsLog);
|
||||||
|
|
||||||
|
MainConsole.Instance.Commands.AddCommand(
|
||||||
|
"Debug",
|
||||||
|
false,
|
||||||
|
"debug attachments throttle",
|
||||||
|
"debug attachments throttle <ms>",
|
||||||
|
"Turn on attachments throttling.",
|
||||||
|
"This requires a millisecond value. " +
|
||||||
|
" == 0 - disable throttling.\n"
|
||||||
|
+ " > 0 - sleeps for this number of milliseconds per 100 prims rezzed.",
|
||||||
|
HandleDebugAttachmentsThrottle);
|
||||||
|
|
||||||
|
MainConsole.Instance.Commands.AddCommand(
|
||||||
|
"Debug",
|
||||||
|
false,
|
||||||
|
"debug attachments status",
|
||||||
|
"debug attachments status",
|
||||||
|
"Show current attachments debug status",
|
||||||
|
HandleDebugAttachmentsStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Should probably be subscribing to CloseClient too, but this doesn't yet give us IClientAPI
|
// TODO: Should probably be subscribing to CloseClient too, but this doesn't yet give us IClientAPI
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleDebugAttachments(string module, string[] args)
|
private void HandleDebugAttachmentsLog(string module, string[] args)
|
||||||
{
|
{
|
||||||
int debugLevel;
|
int debugLevel;
|
||||||
|
|
||||||
if (!(args.Length == 3 && int.TryParse(args[2], out debugLevel)))
|
if (!(args.Length == 4 && int.TryParse(args[3], out debugLevel)))
|
||||||
{
|
{
|
||||||
MainConsole.Instance.OutputFormat("Usage: debug attachments [0|1]");
|
MainConsole.Instance.OutputFormat("Usage: debug attachments log [0|1]");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -114,6 +149,29 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void HandleDebugAttachmentsThrottle(string module, string[] args)
|
||||||
|
{
|
||||||
|
int ms;
|
||||||
|
|
||||||
|
if (args.Length == 4 && int.TryParse(args[3], out ms))
|
||||||
|
{
|
||||||
|
ThrottlePer100PrimsRezzed = ms;
|
||||||
|
MainConsole.Instance.OutputFormat(
|
||||||
|
"Attachments rez throttle per 100 prims is now {0} in {1}", ThrottlePer100PrimsRezzed, m_scene.Name);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MainConsole.Instance.OutputFormat("Usage: debug attachments throttle <ms>");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleDebugAttachmentsStatus(string module, string[] args)
|
||||||
|
{
|
||||||
|
MainConsole.Instance.OutputFormat("Settings for {0}", m_scene.Name);
|
||||||
|
MainConsole.Instance.OutputFormat("Debug logging level: {0}", DebugLevel);
|
||||||
|
MainConsole.Instance.OutputFormat("Throttle per 100 prims: {0}ms", ThrottlePer100PrimsRezzed);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Listen for client triggered running state changes so that we can persist the script's object if necessary.
|
/// Listen for client triggered running state changes so that we can persist the script's object if necessary.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -240,7 +298,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||||
List<AvatarAttachment> attachments = sp.Appearance.GetAttachments();
|
List<AvatarAttachment> attachments = sp.Appearance.GetAttachments();
|
||||||
foreach (AvatarAttachment attach in attachments)
|
foreach (AvatarAttachment attach in attachments)
|
||||||
{
|
{
|
||||||
uint p = (uint)attach.AttachPoint;
|
uint attachmentPt = (uint)attach.AttachPoint;
|
||||||
|
|
||||||
// m_log.DebugFormat(
|
// m_log.DebugFormat(
|
||||||
// "[ATTACHMENTS MODULE]: Doing initial rez of attachment with itemID {0}, assetID {1}, point {2} for {3} in {4}",
|
// "[ATTACHMENTS MODULE]: Doing initial rez of attachment with itemID {0}, assetID {1}, point {2} for {3} in {4}",
|
||||||
|
@ -258,14 +316,28 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||||
{
|
{
|
||||||
// If we're an NPC then skip all the item checks and manipulations since we don't have an
|
// If we're an NPC then skip all the item checks and manipulations since we don't have an
|
||||||
// inventory right now.
|
// inventory right now.
|
||||||
RezSingleAttachmentFromInventoryInternal(
|
SceneObjectGroup objatt
|
||||||
sp, sp.PresenceType == PresenceType.Npc ? UUID.Zero : attach.ItemID, attach.AssetID, p, true);
|
= RezSingleAttachmentFromInventoryInternal(
|
||||||
|
sp, sp.PresenceType == PresenceType.Npc ? UUID.Zero : attach.ItemID, attach.AssetID, attachmentPt, true);
|
||||||
|
|
||||||
|
|
||||||
|
if (ThrottlePer100PrimsRezzed > 0)
|
||||||
|
{
|
||||||
|
int throttleMs = (int)Math.Round((float)objatt.PrimCount / 100 * ThrottlePer100PrimsRezzed);
|
||||||
|
|
||||||
|
if (DebugLevel > 0)
|
||||||
|
m_log.DebugFormat(
|
||||||
|
"[ATTACHMENTS MODULE]: Throttling by {0}ms after rez of {1} with {2} prims for attachment to {3} on point {4} in {5}",
|
||||||
|
throttleMs, objatt.Name, objatt.PrimCount, sp.Name, attachmentPt, m_scene.Name);
|
||||||
|
|
||||||
|
Thread.Sleep(throttleMs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
UUID agentId = (sp.ControllingClient == null) ? (UUID)null : sp.ControllingClient.AgentId;
|
UUID agentId = (sp.ControllingClient == null) ? (UUID)null : sp.ControllingClient.AgentId;
|
||||||
m_log.ErrorFormat("[ATTACHMENTS MODULE]: Unable to rez attachment with itemID {0}, assetID {1}, point {2} for {3}: {4}\n{5}",
|
m_log.ErrorFormat("[ATTACHMENTS MODULE]: Unable to rez attachment with itemID {0}, assetID {1}, point {2} for {3}: {4}\n{5}",
|
||||||
attach.ItemID, attach.AssetID, p, agentId, e.Message, e.StackTrace);
|
attach.ItemID, attach.AssetID, attachmentPt, agentId, e.Message, e.StackTrace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -919,8 +991,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||||
|
|
||||||
if (DebugLevel > 0)
|
if (DebugLevel > 0)
|
||||||
m_log.DebugFormat(
|
m_log.DebugFormat(
|
||||||
"[ATTACHMENTS MODULE]: Rezzed single object {0} for attachment to {1} on point {2} in {3}",
|
"[ATTACHMENTS MODULE]: Rezzed single object {0} with {1} prims for attachment to {2} on point {3} in {4}",
|
||||||
objatt.Name, sp.Name, attachmentPt, m_scene.Name);
|
objatt.Name, objatt.PrimCount, sp.Name, attachmentPt, m_scene.Name);
|
||||||
|
|
||||||
// HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller.
|
// HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller.
|
||||||
objatt.HasGroupChanged = false;
|
objatt.HasGroupChanged = false;
|
||||||
|
|
|
@ -703,11 +703,18 @@
|
||||||
; on every login
|
; on every login
|
||||||
ReuseTextures = false
|
ReuseTextures = false
|
||||||
|
|
||||||
|
|
||||||
[Attachments]
|
[Attachments]
|
||||||
; Controls whether avatar attachments are enabled.
|
; Controls whether avatar attachments are enabled.
|
||||||
; Defaults to true - only set to false for debugging purposes
|
; Defaults to true - only set to false for debugging purposes
|
||||||
Enabled = true
|
Enabled = true
|
||||||
|
|
||||||
|
; Controls the number of milliseconds that are slept per 100 prims rezzed in attachments
|
||||||
|
; Experimental setting to control CPU spiking when avatars with many attachments login
|
||||||
|
; or when multiple avatars with medium level attachments login simultaneously.
|
||||||
|
; If 0 then no throttling is performed.
|
||||||
|
ThrottlePer100PrimsRezzed = 0;
|
||||||
|
|
||||||
|
|
||||||
[Mesh]
|
[Mesh]
|
||||||
; enable / disable Collada mesh support
|
; enable / disable Collada mesh support
|
||||||
|
|
Loading…
Reference in New Issue