diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Framework/IClientAPI.cs | 59 | ||||
-rw-r--r-- | OpenSim/Framework/PriorityQueue.cs (renamed from OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs) | 132 | ||||
-rw-r--r-- | OpenSim/Framework/Util.cs | 17 |
3 files changed, 169 insertions, 39 deletions
diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index f573c32..069987b 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs | |||
@@ -572,34 +572,69 @@ namespace OpenSim.Framework | |||
572 | 572 | ||
573 | public class IEntityUpdate | 573 | public class IEntityUpdate |
574 | { | 574 | { |
575 | public ISceneEntity Entity; | 575 | private ISceneEntity m_entity; |
576 | public uint Flags; | 576 | private uint m_flags; |
577 | private int m_updateTime; | ||
578 | |||
579 | public ISceneEntity Entity | ||
580 | { | ||
581 | get { return m_entity; } | ||
582 | } | ||
583 | |||
584 | public uint Flags | ||
585 | { | ||
586 | get { return m_flags; } | ||
587 | } | ||
588 | |||
589 | public int UpdateTime | ||
590 | { | ||
591 | get { return m_updateTime; } | ||
592 | } | ||
577 | 593 | ||
578 | public virtual void Update(IEntityUpdate update) | 594 | public virtual void Update(IEntityUpdate update) |
579 | { | 595 | { |
580 | this.Flags |= update.Flags; | 596 | m_flags |= update.Flags; |
597 | |||
598 | // Use the older of the updates as the updateTime | ||
599 | if (Util.EnvironmentTickCountCompare(UpdateTime, update.UpdateTime) > 0) | ||
600 | m_updateTime = update.UpdateTime; | ||
581 | } | 601 | } |
582 | 602 | ||
583 | public IEntityUpdate(ISceneEntity entity, uint flags) | 603 | public IEntityUpdate(ISceneEntity entity, uint flags) |
584 | { | 604 | { |
585 | Entity = entity; | 605 | m_entity = entity; |
586 | Flags = flags; | 606 | m_flags = flags; |
607 | m_updateTime = Util.EnvironmentTickCount(); | ||
608 | } | ||
609 | |||
610 | public IEntityUpdate(ISceneEntity entity, uint flags, Int32 updateTime) | ||
611 | { | ||
612 | m_entity = entity; | ||
613 | m_flags = flags; | ||
614 | m_updateTime = updateTime; | ||
587 | } | 615 | } |
588 | } | 616 | } |
589 | |||
590 | 617 | ||
591 | public class EntityUpdate : IEntityUpdate | 618 | public class EntityUpdate : IEntityUpdate |
592 | { | 619 | { |
593 | // public ISceneEntity Entity; | 620 | private float m_timeDilation; |
594 | // public PrimUpdateFlags Flags; | 621 | |
595 | public float TimeDilation; | 622 | public float TimeDilation |
623 | { | ||
624 | get { return m_timeDilation; } | ||
625 | } | ||
596 | 626 | ||
597 | public EntityUpdate(ISceneEntity entity, PrimUpdateFlags flags, float timedilation) | 627 | public EntityUpdate(ISceneEntity entity, PrimUpdateFlags flags, float timedilation) |
598 | : base(entity,(uint)flags) | 628 | : base(entity, (uint)flags) |
599 | { | 629 | { |
600 | //Entity = entity; | ||
601 | // Flags = flags; | 630 | // Flags = flags; |
602 | TimeDilation = timedilation; | 631 | m_timeDilation = timedilation; |
632 | } | ||
633 | |||
634 | public EntityUpdate(ISceneEntity entity, PrimUpdateFlags flags, float timedilation, Int32 updateTime) | ||
635 | : base(entity,(uint)flags,updateTime) | ||
636 | { | ||
637 | m_timeDilation = timedilation; | ||
603 | } | 638 | } |
604 | } | 639 | } |
605 | 640 | ||
diff --git a/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs b/OpenSim/Framework/PriorityQueue.cs index b62ec07..3e6fdaa 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs +++ b/OpenSim/Framework/PriorityQueue.cs | |||
@@ -34,50 +34,81 @@ using OpenSim.Framework; | |||
34 | using OpenSim.Framework.Client; | 34 | using OpenSim.Framework.Client; |
35 | using log4net; | 35 | using log4net; |
36 | 36 | ||
37 | namespace OpenSim.Region.ClientStack.LindenUDP | 37 | namespace OpenSim.Framework |
38 | { | 38 | { |
39 | public class PriorityQueue | 39 | public class PriorityQueue |
40 | { | 40 | { |
41 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 41 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
42 | 42 | ||
43 | internal delegate bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity); | 43 | public delegate bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity); |
44 | 44 | ||
45 | // Heap[0] for self updates | 45 | /// <summary> |
46 | // Heap[1..12] for entity updates | 46 | /// Total number of queues (priorities) available |
47 | /// </summary> | ||
48 | public const uint NumberOfQueues = 12; | ||
47 | 49 | ||
48 | internal const uint m_numberOfQueues = 12; | 50 | /// <summary> |
51 | /// Number of queuest (priorities) that are processed immediately | ||
52 | /// </summary. | ||
53 | public const uint NumberOfImmediateQueues = 2; | ||
49 | 54 | ||
50 | private MinHeap<MinHeapItem>[] m_heaps = new MinHeap<MinHeapItem>[m_numberOfQueues]; | 55 | private MinHeap<MinHeapItem>[] m_heaps = new MinHeap<MinHeapItem>[NumberOfQueues]; |
51 | private Dictionary<uint, LookupItem> m_lookupTable; | 56 | private Dictionary<uint, LookupItem> m_lookupTable; |
57 | |||
58 | // internal state used to ensure the deqeues are spread across the priority | ||
59 | // queues "fairly". queuecounts is the amount to pull from each queue in | ||
60 | // each pass. weighted towards the higher priority queues | ||
52 | private uint m_nextQueue = 0; | 61 | private uint m_nextQueue = 0; |
62 | private uint m_countFromQueue = 0; | ||
63 | private uint[] m_queueCounts = { 8, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1 }; | ||
64 | |||
65 | // next request is a counter of the number of updates queued, it provides | ||
66 | // a total ordering on the updates coming through the queue and is more | ||
67 | // lightweight (and more discriminating) than tick count | ||
53 | private UInt64 m_nextRequest = 0; | 68 | private UInt64 m_nextRequest = 0; |
54 | 69 | ||
70 | /// <summary> | ||
71 | /// Lock for enqueue and dequeue operations on the priority queue | ||
72 | /// </summary> | ||
55 | private object m_syncRoot = new object(); | 73 | private object m_syncRoot = new object(); |
56 | public object SyncRoot { | 74 | public object SyncRoot { |
57 | get { return this.m_syncRoot; } | 75 | get { return this.m_syncRoot; } |
58 | } | 76 | } |
59 | 77 | ||
60 | internal PriorityQueue() : this(MinHeap<MinHeapItem>.DEFAULT_CAPACITY) { } | 78 | #region constructor |
79 | public PriorityQueue() : this(MinHeap<MinHeapItem>.DEFAULT_CAPACITY) { } | ||
61 | 80 | ||
62 | internal PriorityQueue(int capacity) | 81 | public PriorityQueue(int capacity) |
63 | { | 82 | { |
64 | m_lookupTable = new Dictionary<uint, LookupItem>(capacity); | 83 | m_lookupTable = new Dictionary<uint, LookupItem>(capacity); |
65 | 84 | ||
66 | for (int i = 0; i < m_heaps.Length; ++i) | 85 | for (int i = 0; i < m_heaps.Length; ++i) |
67 | m_heaps[i] = new MinHeap<MinHeapItem>(capacity); | 86 | m_heaps[i] = new MinHeap<MinHeapItem>(capacity); |
87 | |||
88 | m_nextQueue = NumberOfImmediateQueues; | ||
89 | m_countFromQueue = m_queueCounts[m_nextQueue]; | ||
68 | } | 90 | } |
91 | #endregion Constructor | ||
69 | 92 | ||
70 | internal int Count | 93 | #region PublicMethods |
94 | /// <summary> | ||
95 | /// Return the number of items in the queues | ||
96 | /// </summary> | ||
97 | public int Count | ||
71 | { | 98 | { |
72 | get | 99 | get |
73 | { | 100 | { |
74 | int count = 0; | 101 | int count = 0; |
75 | for (int i = 0; i < m_heaps.Length; ++i) | 102 | for (int i = 0; i < m_heaps.Length; ++i) |
76 | count += m_heaps[i].Count; | 103 | count += m_heaps[i].Count; |
104 | |||
77 | return count; | 105 | return count; |
78 | } | 106 | } |
79 | } | 107 | } |
80 | 108 | ||
109 | /// <summary> | ||
110 | /// Enqueue an item into the specified priority queue | ||
111 | /// </summary> | ||
81 | public bool Enqueue(uint pqueue, IEntityUpdate value) | 112 | public bool Enqueue(uint pqueue, IEntityUpdate value) |
82 | { | 113 | { |
83 | LookupItem lookup; | 114 | LookupItem lookup; |
@@ -91,7 +122,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
91 | lookup.Heap.Remove(lookup.Handle); | 122 | lookup.Heap.Remove(lookup.Handle); |
92 | } | 123 | } |
93 | 124 | ||
94 | pqueue = Util.Clamp<uint>(pqueue, 0, m_numberOfQueues - 1); | 125 | pqueue = Util.Clamp<uint>(pqueue, 0, NumberOfQueues - 1); |
95 | lookup.Heap = m_heaps[pqueue]; | 126 | lookup.Heap = m_heaps[pqueue]; |
96 | lookup.Heap.Add(new MinHeapItem(pqueue, entry, value), ref lookup.Handle); | 127 | lookup.Heap.Add(new MinHeapItem(pqueue, entry, value), ref lookup.Handle); |
97 | m_lookupTable[localid] = lookup; | 128 | m_lookupTable[localid] = lookup; |
@@ -99,20 +130,62 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
99 | return true; | 130 | return true; |
100 | } | 131 | } |
101 | 132 | ||
102 | internal bool TryDequeue(out IEntityUpdate value, out Int32 timeinqueue) | 133 | /// <summary> |
134 | /// Remove an item from one of the queues. Specifically, it removes the | ||
135 | /// oldest item from the next queue in order to provide fair access to | ||
136 | /// all of the queues | ||
137 | /// </summary> | ||
138 | public bool TryDequeue(out IEntityUpdate value, out Int32 timeinqueue) | ||
103 | { | 139 | { |
104 | for (int i = 0; i < m_numberOfQueues; ++i) | 140 | // If there is anything in priority queue 0, return it first no |
141 | // matter what else. Breaks fairness. But very useful. | ||
142 | for (int iq = 0; iq < NumberOfImmediateQueues; iq++) | ||
105 | { | 143 | { |
106 | // To get the fair queing, we cycle through each of the | 144 | if (m_heaps[iq].Count > 0) |
107 | // queues when finding an element to dequeue, this code | ||
108 | // assumes that the distribution of updates in the queues | ||
109 | // is polynomial, probably quadractic (eg distance of PI * R^2) | ||
110 | uint h = (uint)((m_nextQueue + i) % m_numberOfQueues); | ||
111 | if (m_heaps[h].Count > 0) | ||
112 | { | 145 | { |
113 | m_nextQueue = (uint)((h + 1) % m_numberOfQueues); | 146 | MinHeapItem item = m_heaps[iq].RemoveMin(); |
147 | m_lookupTable.Remove(item.Value.Entity.LocalId); | ||
148 | timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime); | ||
149 | value = item.Value; | ||
114 | 150 | ||
115 | MinHeapItem item = m_heaps[h].RemoveMin(); | 151 | return true; |
152 | } | ||
153 | } | ||
154 | |||
155 | // To get the fair queing, we cycle through each of the | ||
156 | // queues when finding an element to dequeue. | ||
157 | // We pull (NumberOfQueues - QueueIndex) items from each queue in order | ||
158 | // to give lower numbered queues a higher priority and higher percentage | ||
159 | // of the bandwidth. | ||
160 | |||
161 | // Check for more items to be pulled from the current queue | ||
162 | if (m_heaps[m_nextQueue].Count > 0 && m_countFromQueue > 0) | ||
163 | { | ||
164 | m_countFromQueue--; | ||
165 | |||
166 | MinHeapItem item = m_heaps[m_nextQueue].RemoveMin(); | ||
167 | m_lookupTable.Remove(item.Value.Entity.LocalId); | ||
168 | timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime); | ||
169 | value = item.Value; | ||
170 | |||
171 | return true; | ||
172 | } | ||
173 | |||
174 | // Find the next non-immediate queue with updates in it | ||
175 | for (int i = 0; i < NumberOfQueues; ++i) | ||
176 | { | ||
177 | m_nextQueue = (uint)((m_nextQueue + 1) % NumberOfQueues); | ||
178 | m_countFromQueue = m_queueCounts[m_nextQueue]; | ||
179 | |||
180 | // if this is one of the immediate queues, just skip it | ||
181 | if (m_nextQueue < NumberOfImmediateQueues) | ||
182 | continue; | ||
183 | |||
184 | if (m_heaps[m_nextQueue].Count > 0) | ||
185 | { | ||
186 | m_countFromQueue--; | ||
187 | |||
188 | MinHeapItem item = m_heaps[m_nextQueue].RemoveMin(); | ||
116 | m_lookupTable.Remove(item.Value.Entity.LocalId); | 189 | m_lookupTable.Remove(item.Value.Entity.LocalId); |
117 | timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime); | 190 | timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime); |
118 | value = item.Value; | 191 | value = item.Value; |
@@ -126,7 +199,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
126 | return false; | 199 | return false; |
127 | } | 200 | } |
128 | 201 | ||
129 | internal void Reprioritize(UpdatePriorityHandler handler) | 202 | /// <summary> |
203 | /// Reapply the prioritization function to each of the updates currently | ||
204 | /// stored in the priority queues. | ||
205 | /// </summary | ||
206 | public void Reprioritize(UpdatePriorityHandler handler) | ||
130 | { | 207 | { |
131 | MinHeapItem item; | 208 | MinHeapItem item; |
132 | foreach (LookupItem lookup in new List<LookupItem>(this.m_lookupTable.Values)) | 209 | foreach (LookupItem lookup in new List<LookupItem>(this.m_lookupTable.Values)) |
@@ -140,7 +217,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
140 | { | 217 | { |
141 | // unless the priority queue has changed, there is no need to modify | 218 | // unless the priority queue has changed, there is no need to modify |
142 | // the entry | 219 | // the entry |
143 | pqueue = Util.Clamp<uint>(pqueue, 0, m_numberOfQueues - 1); | 220 | pqueue = Util.Clamp<uint>(pqueue, 0, NumberOfQueues - 1); |
144 | if (pqueue != item.PriorityQueue) | 221 | if (pqueue != item.PriorityQueue) |
145 | { | 222 | { |
146 | lookup.Heap.Remove(lookup.Handle); | 223 | lookup.Heap.Remove(lookup.Handle); |
@@ -161,17 +238,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
161 | } | 238 | } |
162 | } | 239 | } |
163 | 240 | ||
241 | /// <summary> | ||
242 | /// </summary> | ||
164 | public override string ToString() | 243 | public override string ToString() |
165 | { | 244 | { |
166 | string s = ""; | 245 | string s = ""; |
167 | for (int i = 0; i < m_numberOfQueues; i++) | 246 | for (int i = 0; i < NumberOfQueues; i++) |
168 | { | 247 | s += String.Format("{0,7} ",m_heaps[i].Count); |
169 | if (s != "") s += ","; | ||
170 | s += m_heaps[i].Count.ToString(); | ||
171 | } | ||
172 | return s; | 248 | return s; |
173 | } | 249 | } |
174 | 250 | ||
251 | #endregion PublicMethods | ||
252 | |||
175 | #region MinHeapItem | 253 | #region MinHeapItem |
176 | private struct MinHeapItem : IComparable<MinHeapItem> | 254 | private struct MinHeapItem : IComparable<MinHeapItem> |
177 | { | 255 | { |
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 5a5046e..aaa2724 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs | |||
@@ -1537,6 +1537,23 @@ namespace OpenSim.Framework | |||
1537 | return (diff >= 0) ? diff : (diff + EnvironmentTickCountMask + 1); | 1537 | return (diff >= 0) ? diff : (diff + EnvironmentTickCountMask + 1); |
1538 | } | 1538 | } |
1539 | 1539 | ||
1540 | // Returns value of Tick Count A - TickCount B accounting for wrapping of TickCount | ||
1541 | // Assumes both tcA and tcB came from previous calls to Util.EnvironmentTickCount(). | ||
1542 | // A positive return value indicates A occured later than B | ||
1543 | public static Int32 EnvironmentTickCountCompare(Int32 tcA, Int32 tcB) | ||
1544 | { | ||
1545 | // A, B and TC are all between 0 and 0x3fffffff | ||
1546 | int tc = EnvironmentTickCount(); | ||
1547 | |||
1548 | if (tc - tcA >= 0) | ||
1549 | tcA += EnvironmentTickCountMask + 1; | ||
1550 | |||
1551 | if (tc - tcB >= 0) | ||
1552 | tcB += EnvironmentTickCountMask + 1; | ||
1553 | |||
1554 | return tcA - tcB; | ||
1555 | } | ||
1556 | |||
1540 | /// <summary> | 1557 | /// <summary> |
1541 | /// Prints the call stack at any given point. Useful for debugging. | 1558 | /// Prints the call stack at any given point. Useful for debugging. |
1542 | /// </summary> | 1559 | /// </summary> |