Added a second immediate queue to be used for the BestAvatar policy
and currently used for all of an avatars attachments by the other policies. Also changed the way items are pulled from the update queues to bias close objects even more.bulletsim
parent
08e58e7ca6
commit
a3bd769cb3
|
@ -42,22 +42,40 @@ namespace OpenSim.Framework
|
||||||
|
|
||||||
public delegate bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity);
|
public delegate bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity);
|
||||||
|
|
||||||
// Heap[0] for self updates
|
/// <summary>
|
||||||
// Heap[1..12] for entity updates
|
/// Total number of queues (priorities) available
|
||||||
|
/// </summary>
|
||||||
public const uint NumberOfQueues = 12;
|
public const uint NumberOfQueues = 12;
|
||||||
public const uint ImmediateQueue = 0;
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of queuest (priorities) that are processed immediately
|
||||||
|
/// </summary.
|
||||||
|
public const uint NumberOfImmediateQueues = 2;
|
||||||
|
|
||||||
private MinHeap<MinHeapItem>[] m_heaps = new MinHeap<MinHeapItem>[NumberOfQueues];
|
private MinHeap<MinHeapItem>[] m_heaps = new MinHeap<MinHeapItem>[NumberOfQueues];
|
||||||
private Dictionary<uint, LookupItem> m_lookupTable;
|
private Dictionary<uint, LookupItem> m_lookupTable;
|
||||||
|
|
||||||
|
// internal state used to ensure the deqeues are spread across the priority
|
||||||
|
// queues "fairly". queuecounts is the amount to pull from each queue in
|
||||||
|
// each pass. weighted towards the higher priority queues
|
||||||
private uint m_nextQueue = 0;
|
private uint m_nextQueue = 0;
|
||||||
|
private uint m_countFromQueue = 0;
|
||||||
|
private uint[] m_queueCounts = { 8, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1 };
|
||||||
|
|
||||||
|
// next request is a counter of the number of updates queued, it provides
|
||||||
|
// a total ordering on the updates coming through the queue and is more
|
||||||
|
// lightweight (and more discriminating) than tick count
|
||||||
private UInt64 m_nextRequest = 0;
|
private UInt64 m_nextRequest = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Lock for enqueue and dequeue operations on the priority queue
|
||||||
|
/// </summary>
|
||||||
private object m_syncRoot = new object();
|
private object m_syncRoot = new object();
|
||||||
public object SyncRoot {
|
public object SyncRoot {
|
||||||
get { return this.m_syncRoot; }
|
get { return this.m_syncRoot; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region constructor
|
||||||
public PriorityQueue() : this(MinHeap<MinHeapItem>.DEFAULT_CAPACITY) { }
|
public PriorityQueue() : this(MinHeap<MinHeapItem>.DEFAULT_CAPACITY) { }
|
||||||
|
|
||||||
public PriorityQueue(int capacity)
|
public PriorityQueue(int capacity)
|
||||||
|
@ -66,8 +84,16 @@ namespace OpenSim.Framework
|
||||||
|
|
||||||
for (int i = 0; i < m_heaps.Length; ++i)
|
for (int i = 0; i < m_heaps.Length; ++i)
|
||||||
m_heaps[i] = new MinHeap<MinHeapItem>(capacity);
|
m_heaps[i] = new MinHeap<MinHeapItem>(capacity);
|
||||||
}
|
|
||||||
|
|
||||||
|
m_nextQueue = NumberOfImmediateQueues;
|
||||||
|
m_countFromQueue = m_queueCounts[m_nextQueue];
|
||||||
|
}
|
||||||
|
#endregion Constructor
|
||||||
|
|
||||||
|
#region PublicMethods
|
||||||
|
/// <summary>
|
||||||
|
/// Return the number of items in the queues
|
||||||
|
/// </summary>
|
||||||
public int Count
|
public int Count
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
@ -79,6 +105,9 @@ namespace OpenSim.Framework
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enqueue an item into the specified priority queue
|
||||||
|
/// </summary>
|
||||||
public bool Enqueue(uint pqueue, IEntityUpdate value)
|
public bool Enqueue(uint pqueue, IEntityUpdate value)
|
||||||
{
|
{
|
||||||
LookupItem lookup;
|
LookupItem lookup;
|
||||||
|
@ -100,13 +129,40 @@ namespace OpenSim.Framework
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove an item from one of the queues. Specifically, it removes the
|
||||||
|
/// oldest item from the next queue in order to provide fair access to
|
||||||
|
/// all of the queues
|
||||||
|
/// </summary>
|
||||||
public bool TryDequeue(out IEntityUpdate value, out Int32 timeinqueue)
|
public bool TryDequeue(out IEntityUpdate value, out Int32 timeinqueue)
|
||||||
{
|
{
|
||||||
// If there is anything in priority queue 0, return it first no
|
// If there is anything in priority queue 0, return it first no
|
||||||
// matter what else. Breaks fairness. But very useful.
|
// matter what else. Breaks fairness. But very useful.
|
||||||
if (m_heaps[ImmediateQueue].Count > 0)
|
for (int iq = 0; iq < NumberOfImmediateQueues; iq++)
|
||||||
{
|
{
|
||||||
MinHeapItem item = m_heaps[ImmediateQueue].RemoveMin();
|
if (m_heaps[iq].Count > 0)
|
||||||
|
{
|
||||||
|
MinHeapItem item = m_heaps[iq].RemoveMin();
|
||||||
|
m_lookupTable.Remove(item.Value.Entity.LocalId);
|
||||||
|
timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime);
|
||||||
|
value = item.Value;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// To get the fair queing, we cycle through each of the
|
||||||
|
// queues when finding an element to dequeue.
|
||||||
|
// We pull (NumberOfQueues - QueueIndex) items from each queue in order
|
||||||
|
// to give lower numbered queues a higher priority and higher percentage
|
||||||
|
// of the bandwidth.
|
||||||
|
|
||||||
|
// Check for more items to be pulled from the current queue
|
||||||
|
if (m_heaps[m_nextQueue].Count > 0 && m_countFromQueue > 0)
|
||||||
|
{
|
||||||
|
m_countFromQueue--;
|
||||||
|
|
||||||
|
MinHeapItem item = m_heaps[m_nextQueue].RemoveMin();
|
||||||
m_lookupTable.Remove(item.Value.Entity.LocalId);
|
m_lookupTable.Remove(item.Value.Entity.LocalId);
|
||||||
timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime);
|
timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime);
|
||||||
value = item.Value;
|
value = item.Value;
|
||||||
|
@ -114,18 +170,21 @@ namespace OpenSim.Framework
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < NumberOfQueues; ++i)
|
// Find the next non-immediate queue with updates in it
|
||||||
|
for (int i = 1; i < NumberOfQueues; ++i)
|
||||||
{
|
{
|
||||||
// To get the fair queing, we cycle through each of the
|
m_nextQueue = (uint)((m_nextQueue + i) % NumberOfQueues);
|
||||||
// queues when finding an element to dequeue, this code
|
m_countFromQueue = m_queueCounts[m_nextQueue];
|
||||||
// assumes that the distribution of updates in the queues
|
|
||||||
// is polynomial, probably quadractic (eg distance of PI * R^2)
|
|
||||||
uint h = (uint)((m_nextQueue + i) % NumberOfQueues);
|
|
||||||
if (m_heaps[h].Count > 0)
|
|
||||||
{
|
|
||||||
m_nextQueue = (uint)((h + 1) % NumberOfQueues);
|
|
||||||
|
|
||||||
MinHeapItem item = m_heaps[h].RemoveMin();
|
// if this is one of the immediate queues, just skip it
|
||||||
|
if (m_nextQueue < NumberOfImmediateQueues)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (m_heaps[m_nextQueue].Count > 0)
|
||||||
|
{
|
||||||
|
m_countFromQueue--;
|
||||||
|
|
||||||
|
MinHeapItem item = m_heaps[m_nextQueue].RemoveMin();
|
||||||
m_lookupTable.Remove(item.Value.Entity.LocalId);
|
m_lookupTable.Remove(item.Value.Entity.LocalId);
|
||||||
timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime);
|
timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime);
|
||||||
value = item.Value;
|
value = item.Value;
|
||||||
|
@ -139,6 +198,10 @@ namespace OpenSim.Framework
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reapply the prioritization function to each of the updates currently
|
||||||
|
/// stored in the priority queues.
|
||||||
|
/// </summary
|
||||||
public void Reprioritize(UpdatePriorityHandler handler)
|
public void Reprioritize(UpdatePriorityHandler handler)
|
||||||
{
|
{
|
||||||
MinHeapItem item;
|
MinHeapItem item;
|
||||||
|
@ -184,6 +247,8 @@ namespace OpenSim.Framework
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion PublicMethods
|
||||||
|
|
||||||
#region MinHeapItem
|
#region MinHeapItem
|
||||||
private struct MinHeapItem : IComparable<MinHeapItem>
|
private struct MinHeapItem : IComparable<MinHeapItem>
|
||||||
{
|
{
|
||||||
|
|
|
@ -88,7 +88,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
// If this is an update for our own avatar give it the highest priority
|
// If this is an update for our own avatar give it the highest priority
|
||||||
if (client.AgentId == entity.UUID)
|
if (client.AgentId == entity.UUID)
|
||||||
return PriorityQueue.ImmediateQueue;
|
return 0;
|
||||||
|
|
||||||
uint priority;
|
uint priority;
|
||||||
|
|
||||||
|
@ -119,16 +119,40 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
private uint GetPriorityByTime(IClientAPI client, ISceneEntity entity)
|
private uint GetPriorityByTime(IClientAPI client, ISceneEntity entity)
|
||||||
{
|
{
|
||||||
return 1;
|
// And anything attached to this avatar gets top priority as well
|
||||||
|
if (entity is SceneObjectPart)
|
||||||
|
{
|
||||||
|
SceneObjectPart sop = (SceneObjectPart)entity;
|
||||||
|
if (sop.ParentGroup.RootPart.IsAttachment && client.AgentId == sop.ParentGroup.RootPart.AttachedAvatar)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PriorityQueue.NumberOfImmediateQueues; // first queue past the immediate queues
|
||||||
}
|
}
|
||||||
|
|
||||||
private uint GetPriorityByDistance(IClientAPI client, ISceneEntity entity)
|
private uint GetPriorityByDistance(IClientAPI client, ISceneEntity entity)
|
||||||
{
|
{
|
||||||
|
// And anything attached to this avatar gets top priority as well
|
||||||
|
if (entity is SceneObjectPart)
|
||||||
|
{
|
||||||
|
SceneObjectPart sop = (SceneObjectPart)entity;
|
||||||
|
if (sop.ParentGroup.RootPart.IsAttachment && client.AgentId == sop.ParentGroup.RootPart.AttachedAvatar)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return ComputeDistancePriority(client,entity,false);
|
return ComputeDistancePriority(client,entity,false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private uint GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity)
|
private uint GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity)
|
||||||
{
|
{
|
||||||
|
// And anything attached to this avatar gets top priority as well
|
||||||
|
if (entity is SceneObjectPart)
|
||||||
|
{
|
||||||
|
SceneObjectPart sop = (SceneObjectPart)entity;
|
||||||
|
if (sop.ParentGroup.RootPart.IsAttachment && client.AgentId == sop.ParentGroup.RootPart.AttachedAvatar)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return ComputeDistancePriority(client,entity,true);
|
return ComputeDistancePriority(client,entity,true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,8 +221,10 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
// And convert the distance to a priority queue, this computation gives queues
|
// And convert the distance to a priority queue, this computation gives queues
|
||||||
// at 10, 20, 40, 80, 160, 320, 640, and 1280m
|
// at 10, 20, 40, 80, 160, 320, 640, and 1280m
|
||||||
uint pqueue = 1;
|
uint pqueue = PriorityQueue.NumberOfImmediateQueues;
|
||||||
for (int i = 0; i < 8; i++)
|
uint queues = PriorityQueue.NumberOfQueues - PriorityQueue.NumberOfImmediateQueues;
|
||||||
|
|
||||||
|
for (int i = 0; i < queues - 1; i++)
|
||||||
{
|
{
|
||||||
if (distance < 10 * Math.Pow(2.0,i))
|
if (distance < 10 * Math.Pow(2.0,i))
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue