Compare commits

...

19 Commits

Author SHA1 Message Date
Justin Clark-Casey (justincc)
7ff27e32bc Add cinderblocks and bobshaffer2 to contributors. 2014-09-23 17:27:22 +01:00
Justin Clark-Casey (justincc)
89c153ca7f Fix issues where setting llSetTextureAnim(FALSE... did not work properly).
I ended up amalgamating patches from http://opensimulator.org/mantis/view.php?id=7313 and http://opensimulator.org/mantis/view.php?id=7318
Thanks a lot to both bobshaffer2 and cinderblocks.
2014-09-23 17:27:18 +01:00
Justin Clark-Casey (justincc)
a6c79fe956 Fix regression from recent a02dae5 where stand positions are no longer correct when a sit target is specified.
Adjusts stand position using just avatar position relative to the root prim instead.
Fixes http://opensimulator.org/mantis/view.php?id=7315 and preserves previous fix for http://opensimulator.org/mantis/view.php?id=7299
2014-09-23 17:27:13 +01:00
Justin Clark-Casey (justincc)
1e5c3f26f0 Make BulletSim thread be ThreadPriority.Highest if running
Will only effect Windows or mono with a patch such as https://gist.github.com/justincc/31e52218d098529b4696 applied
For test purposes
2014-09-16 18:32:36 +01:00
Justin Clark-Casey (justincc)
e6df61fbe9 Make outboudn and packet inbox handling threads highest priority.
Will only have any affect under Windows or mono with a patch such as https://gist.github.com/justincc/31e52218d098529b4696 (not recommended) applied.
For assessment purposes.
2014-09-16 18:27:08 +01:00
Justin Clark-Casey (justincc)
5991a98d80 Set ThreadPriority on main scene thread to highest.
This will only have an effect on Windows systems or mono with the (not recommended) mono-3.2.8 debug patch https://gist.github.com/justincc/31e52218d098529b4696 applied
2014-09-16 18:17:05 +01:00
Justin Clark-Casey (justincc)
c4ed67aeee Make proper fix for last commit wrt Mantis 7317 by replacing disallowed c char and not literal 'c' 2014-09-09 18:55:38 +01:00
Justin Clark-Casey (justincc)
258de1f17f For stat names containing periods, replace with '#' rather than throw exception
In relation to http://opensimulator.org/mantis/view.php?id=7317
2014-09-09 18:52:07 +01:00
Justin Clark-Casey (justincc)
f8fa76c09f Add loglevel to jobengine that can be controlled via "debug jobengine loglevel <level>".
Defaults to 0
Level 1 currently does verbose logging about every queued and processed job.
2014-09-09 18:42:02 +01:00
Justin Clark-Casey (justincc)
0b7736b861 Temporarily add root agent rez attachments work to job engine if it is running rather than as a fire and forget.
Experiment to see if serializing attachment rez and send initial data jobs improves other parts of sim performance.
2014-09-09 18:26:41 +01:00
Justin Clark-Casey (justincc)
a086adf427 Add experimental job engine to see if queueing some existing async work during root agent entry to a region improves perf rather than always attempting to execute everything concurrently
Job engine is controlled via "debug jobengine start|stop|status".
Can only currently be enabled and disabled dynamically at runtime.
Currently only applies to code sending initial region data (objects, other avatar data) to a client.
2014-09-09 18:14:56 +01:00
Justin Clark-Casey (justincc)
e76cc35409 Merge branch 'master' into ghosts 2014-09-09 17:22:09 +01:00
Justin Clark-Casey (justincc)
a129e9e351 Merge branch 'master' into ghosts 2014-09-03 00:26:53 +01:00
Justin Clark-Casey (justincc)
3c7eacf39b Fix recent regression from 473c5594 where camera started to judder on moving vehicles.
Other parts of OpenSimulator are relying on SP.Velocity == 0 for vehicles.
So add and use SP.GetWorldVelocity() instead when we need vehicle velocity, along the same lines as existing SP.GetWorldRotation()
2014-09-02 23:35:03 +01:00
Justin Clark-Casey (justincc)
cd6f73392a Reinsert OpenMetaverse.dll from commit fbdf507 from an accidental replace in f1f935e
This only affected pCampbot.
2014-09-02 19:00:14 +01:00
Justin Clark-Casey (justincc)
1559a3a099 Merge branch 'master' into ghosts 2014-09-02 18:34:54 +01:00
Justin Clark-Casey (justincc)
6520065625 Merge branch 'master' into ghosts 2014-08-26 18:52:50 +01:00
Justin Clark-Casey (justincc)
693bfdc0fb Merge branch 'master' into ghosts 2014-08-26 18:26:27 +01:00
Justin Clark-Casey (justincc)
f3eaa6d81e Temporary hack to disable av to av collisions in bulletsim.
Need to do this for a test.  Final implementation will be properly controlled through a property.
2014-08-26 18:17:09 +01:00
12 changed files with 375 additions and 21 deletions

View File

@@ -72,10 +72,12 @@ what it is today.
* Allen Kerensky
* BigFootAg
* BlueWall Slade
* bobshaffer2
* brianw/Sir_Ahzz
* CharlieO
* ChrisDown
* Chris Yeoh (IBM)
* cinderblocks
* controlbreak
* coyled
* ctrlaltdavid (David Rowe)

View File

@@ -0,0 +1,312 @@
/*
* 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.Concurrent;
using System.Reflection;
using System.Threading;
using log4net;
using OpenSim.Framework;
namespace OpenSim.Framework.Monitoring
{
public class Job
{
public string Name;
public WaitCallback Callback;
public object O;
public Job(string name, WaitCallback callback, object o)
{
Name = name;
Callback = callback;
O = o;
}
}
public class JobEngine
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public int LogLevel { get; set; }
public bool IsRunning { get; private set; }
/// <summary>
/// The timeout in milliseconds to wait for at least one event to be written when the recorder is stopping.
/// </summary>
public int RequestProcessTimeoutOnStop { get; set; }
/// <summary>
/// Controls whether we need to warn in the log about exceeding the max queue size.
/// </summary>
/// <remarks>
/// This is flipped to false once queue max has been exceeded and back to true when it falls below max, in
/// order to avoid spamming the log with lots of warnings.
/// </remarks>
private bool m_warnOverMaxQueue = true;
private BlockingCollection<Job> m_requestQueue;
private CancellationTokenSource m_cancelSource = new CancellationTokenSource();
private Stat m_requestsWaitingStat;
private Job m_currentJob;
/// <summary>
/// Used to signal that we are ready to complete stop.
/// </summary>
private ManualResetEvent m_finishedProcessingAfterStop = new ManualResetEvent(false);
public JobEngine()
{
RequestProcessTimeoutOnStop = 5000;
MainConsole.Instance.Commands.AddCommand(
"Debug",
false,
"debug jobengine",
"debug jobengine <start|stop|status>",
"Start, stop or get status of the job engine.",
"If stopped then all jobs are processed immediately.",
HandleControlCommand);
}
public void Start()
{
lock (this)
{
if (IsRunning)
return;
IsRunning = true;
m_finishedProcessingAfterStop.Reset();
m_requestQueue = new BlockingCollection<Job>(new ConcurrentQueue<Job>(), 5000);
m_requestsWaitingStat =
new Stat(
"JobsWaiting",
"Number of jobs waiting for processing.",
"",
"",
"server",
"jobengine",
StatType.Pull,
MeasuresOfInterest.None,
stat => stat.Value = m_requestQueue.Count,
StatVerbosity.Debug);
StatsManager.RegisterStat(m_requestsWaitingStat);
Watchdog.StartThread(
ProcessRequests,
"JobEngineThread",
ThreadPriority.Normal,
false,
true,
null,
int.MaxValue);
}
}
public void Stop()
{
lock (this)
{
try
{
if (!IsRunning)
return;
IsRunning = false;
int requestsLeft = m_requestQueue.Count;
if (requestsLeft <= 0)
{
m_cancelSource.Cancel();
}
else
{
m_log.InfoFormat("[JOB ENGINE]: Waiting to write {0} events after stop.", requestsLeft);
while (requestsLeft > 0)
{
if (!m_finishedProcessingAfterStop.WaitOne(RequestProcessTimeoutOnStop))
{
// After timeout no events have been written
if (requestsLeft == m_requestQueue.Count)
{
m_log.WarnFormat(
"[JOB ENGINE]: No requests processed after {0} ms wait. Discarding remaining {1} requests",
RequestProcessTimeoutOnStop, requestsLeft);
break;
}
}
requestsLeft = m_requestQueue.Count;
}
}
}
finally
{
m_cancelSource.Dispose();
StatsManager.DeregisterStat(m_requestsWaitingStat);
m_requestsWaitingStat = null;
m_requestQueue = null;
}
}
}
public bool QueueRequest(string name, WaitCallback req, object o)
{
if (LogLevel >= 1)
m_log.DebugFormat("[JOB ENGINE]: Queued job {0}", name);
if (m_requestQueue.Count < m_requestQueue.BoundedCapacity)
{
// m_log.DebugFormat(
// "[OUTGOING QUEUE REFILL ENGINE]: Adding request for categories {0} for {1} in {2}",
// categories, client.AgentID, m_udpServer.Scene.Name);
m_requestQueue.Add(new Job(name, req, o));
if (!m_warnOverMaxQueue)
m_warnOverMaxQueue = true;
return true;
}
else
{
if (m_warnOverMaxQueue)
{
// m_log.WarnFormat(
// "[JOB ENGINE]: Request queue at maximum capacity, not recording request from {0} in {1}",
// client.AgentID, m_udpServer.Scene.Name);
m_log.WarnFormat("[JOB ENGINE]: Request queue at maximum capacity, not recording job");
m_warnOverMaxQueue = false;
}
return false;
}
}
private void ProcessRequests()
{
try
{
while (IsRunning || m_requestQueue.Count > 0)
{
m_currentJob = m_requestQueue.Take(m_cancelSource.Token);
// QueueEmpty callback = req.Client.OnQueueEmpty;
//
// if (callback != null)
// {
// try
// {
// callback(req.Categories);
// }
// catch (Exception e)
// {
// m_log.Error("[OUTGOING QUEUE REFILL ENGINE]: ProcessRequests(" + req.Categories + ") threw an exception: " + e.Message, e);
// }
// }
if (LogLevel >= 1)
m_log.DebugFormat("[JOB ENGINE]: Processing job {0}", m_currentJob.Name);
m_currentJob.Callback.Invoke(m_currentJob.O);
if (LogLevel >= 1)
m_log.DebugFormat("[JOB ENGINE]: Processed job {0}", m_currentJob.Name);
m_currentJob = null;
}
}
catch (OperationCanceledException)
{
}
m_finishedProcessingAfterStop.Set();
}
private void HandleControlCommand(string module, string[] args)
{
// if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
// return;
if (args.Length < 3)
{
MainConsole.Instance.Output("Usage: debug jobengine <stop|start|status|loglevel>");
return;
}
string subCommand = args[2];
if (subCommand == "stop")
{
Stop();
MainConsole.Instance.OutputFormat("Stopped job engine.");
}
else if (subCommand == "start")
{
Start();
MainConsole.Instance.OutputFormat("Started job engine.");
}
else if (subCommand == "status")
{
MainConsole.Instance.OutputFormat("Job engine running: {0}", IsRunning);
MainConsole.Instance.OutputFormat("Current job {0}", m_currentJob != null ? m_currentJob.Name : "none");
MainConsole.Instance.OutputFormat(
"Jobs waiting: {0}", IsRunning ? m_requestQueue.Count.ToString() : "n/a");
MainConsole.Instance.OutputFormat("Log Level: {0}", LogLevel);
}
else if (subCommand == "loglevel")
{
// int logLevel;
int logLevel = int.Parse(args[3]);
// if (ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out logLevel))
// {
LogLevel = logLevel;
MainConsole.Instance.OutputFormat("Set log level to {0}", LogLevel);
// }
}
else
{
MainConsole.Instance.OutputFormat("Unrecognized job engine subcommand {0}", subCommand);
}
}
}
}

View File

@@ -171,7 +171,8 @@ namespace OpenSim.Framework.Monitoring
foreach (char c in DisallowedShortNameCharacters)
{
if (shortName.IndexOf(c) != -1)
throw new Exception(string.Format("Stat name {0} cannot contain character {1}", shortName, c));
shortName = shortName.Replace(c, '#');
// throw new Exception(string.Format("Stat name {0} cannot contain character {1}", shortName, c));
}
ShortName = shortName;

View File

@@ -133,6 +133,8 @@ namespace OpenSim.Framework.Monitoring
/// /summary>
public static event Action<ThreadWatchdogInfo> OnWatchdogTimeout;
public static JobEngine JobEngine { get; private set; }
/// <summary>
/// Is this watchdog active?
/// </summary>
@@ -173,6 +175,7 @@ namespace OpenSim.Framework.Monitoring
static Watchdog()
{
JobEngine = new JobEngine();
m_threads = new Dictionary<int, ThreadWatchdogInfo>();
m_watchdogTimer = new System.Timers.Timer(WATCHDOG_INTERVAL_MS);
m_watchdogTimer.AutoReset = false;
@@ -449,5 +452,20 @@ namespace OpenSim.Framework.Monitoring
m_watchdogTimer.Start();
}
public static void RunWhenPossible(string jobType, WaitCallback callback, string name, object obj, bool log = false)
{
if (Util.FireAndForgetMethod == FireAndForgetMethod.RegressionTest)
{
Culture.SetCurrentCulture();
callback(obj);
return;
}
if (JobEngine.IsRunning)
JobEngine.QueueRequest(name, callback, obj);
else
RunInThread(callback, name, obj, log);
}
}
}

View File

@@ -2055,6 +2055,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private void IncomingPacketHandler()
{
Thread.CurrentThread.Priority = ThreadPriority.Highest;
// Set this culture for the thread that incoming packets are received
// on to en-US to avoid number parsing issues
Culture.SetCurrentCulture();
@@ -2100,6 +2102,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private void OutgoingPacketHandler()
{
Thread.CurrentThread.Priority = ThreadPriority.Highest;
// Set this culture for the thread that outgoing packets are sent
// on to en-US to avoid number parsing issues
Culture.SetCurrentCulture();

View File

@@ -217,6 +217,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private void ProcessRequests()
{
Thread.CurrentThread.Priority = ThreadPriority.Highest;
try
{
while (IsRunning || m_requestQueue.Count > 0)

View File

@@ -1451,6 +1451,7 @@ namespace OpenSim.Region.Framework.Scenes
}
else
{
Thread.CurrentThread.Priority = ThreadPriority.Highest;
Update(-1);
Watchdog.RemoveThread();
m_isRunning = false;

View File

@@ -1589,20 +1589,29 @@ namespace OpenSim.Region.Framework.Scenes
public void AddTextureAnimation(Primitive.TextureAnimation pTexAnim)
{
byte[] data = new byte[16];
int pos = 0;
byte[] data;
// The flags don't like conversion from uint to byte, so we have to do
// it the crappy way. See the above function :(
if (pTexAnim.Flags == Primitive.TextureAnimMode.ANIM_OFF)
{
data = Utils.EmptyBytes;
}
else
{
data = new byte[16];
int pos = 0;
data[pos] = ConvertScriptUintToByte((uint)pTexAnim.Flags); pos++;
data[pos] = (byte)pTexAnim.Face; pos++;
data[pos] = (byte)pTexAnim.SizeX; pos++;
data[pos] = (byte)pTexAnim.SizeY; pos++;
// The flags don't like conversion from uint to byte, so we have to do
// it the crappy way. See the above function :(
Utils.FloatToBytes(pTexAnim.Start).CopyTo(data, pos);
Utils.FloatToBytes(pTexAnim.Length).CopyTo(data, pos + 4);
Utils.FloatToBytes(pTexAnim.Rate).CopyTo(data, pos + 8);
data[pos] = ConvertScriptUintToByte((uint)pTexAnim.Flags); pos++;
data[pos] = (byte)pTexAnim.Face; pos++;
data[pos] = (byte)pTexAnim.SizeX; pos++;
data[pos] = (byte)pTexAnim.SizeY; pos++;
Utils.FloatToBytes(pTexAnim.Start).CopyTo(data, pos);
Utils.FloatToBytes(pTexAnim.Length).CopyTo(data, pos + 4);
Utils.FloatToBytes(pTexAnim.Rate).CopyTo(data, pos + 8);
}
m_TextureAnimation = data;
}

View File

@@ -1228,10 +1228,14 @@ namespace OpenSim.Region.Framework.Scenes
// viewers without (e.g. v1 viewers) will not, so we still need to make this call.
if (Scene.AttachmentsModule != null)
{
Util.FireAndForget(o =>
{
Scene.AttachmentsModule.RezAttachments(this);
});
if (Watchdog.JobEngine.IsRunning)
Watchdog.RunWhenPossible(
"RezAttachments",
o => Scene.AttachmentsModule.RezAttachments(this),
string.Format("Rez attachments for {0} in {1}", Name, Scene.Name),
null);
else
Util.FireAndForget(o => Scene.AttachmentsModule.RezAttachments(this));
}
}
else
@@ -2618,7 +2622,6 @@ namespace OpenSim.Region.Framework.Scenes
}
}
Vector3 sitPartWorldPosition = part.GetWorldPosition();
ControllingClient.SendClearFollowCamProperties(part.ParentUUID);
ParentID = 0;
@@ -2647,13 +2650,13 @@ namespace OpenSim.Region.Framework.Scenes
// Vector3 standPositionAdjustment
// = part.SitTargetPosition + new Vector3(0.5f, 0f, m_sitAvatarHeight / 2f);
Vector3 adjustmentForSitPosition = (part.SitTargetPosition + OffsetPosition) * part.GetWorldRotation();
Vector3 adjustmentForSitPosition = (OffsetPosition - SIT_TARGET_ADJUSTMENT) * part.GetWorldRotation();
// XXX: This is based on the physics capsule sizes. Need to find a better way to read this rather than
// hardcoding here.
Vector3 adjustmentForSitPose = new Vector3(0.74f, 0f, 0f) * standRotation;
Vector3 standPos = sitPartWorldPosition + adjustmentForSitPosition + adjustmentForSitPose;
Vector3 standPos = part.ParentGroup.AbsolutePosition + adjustmentForSitPosition + adjustmentForSitPose;
// m_log.DebugFormat(
// "[SCENE PRESENCE]: Setting stand to pos {0}, (adjustmentForSitPosition {1}, adjustmentForSitPose {2}) rotation {3} for {4} in {5}",
@@ -3363,7 +3366,7 @@ namespace OpenSim.Region.Framework.Scenes
SentInitialDataToClient = true;
// Send all scene object to the new client
Watchdog.RunInThread(delegate
Watchdog.RunWhenPossible("SendInitialDataToClient", delegate
{
// m_log.DebugFormat(
// "[SCENE PRESENCE]: Sending initial data to {0} agent {1} in {2}, tp flags {3}",

View File

@@ -838,6 +838,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
public void BulletSPluginPhysicsThread()
{
Thread.CurrentThread.Priority = ThreadPriority.Highest;
while (m_initialized)
{
int beginSimulationRealtimeMS = Util.EnvironmentTickCount();

View File

@@ -231,7 +231,7 @@ public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeM
{ CollisionType.Avatar,
new CollisionTypeFilterGroup(CollisionType.Avatar,
(uint)CollisionFilterGroups.BCharacterGroup,
(uint)CollisionFilterGroups.BAllGroup)
(uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BCharacterGroup))
},
{ CollisionType.Groundplane,
new CollisionTypeFilterGroup(CollisionType.Groundplane,

Binary file not shown.