aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJohn Hurliman2009-10-21 18:03:41 -0700
committerJohn Hurliman2009-10-21 18:03:41 -0700
commit6492640e72776d9f0a015e6a719c8cef28ccb7e3 (patch)
treeaf67792558e46e5b5abce59032223b8bae388859
parent* Clarified what FireQueueEmpty is doing with a MIN_CALLBACK_MS constant and ... (diff)
downloadopensim-SC-6492640e72776d9f0a015e6a719c8cef28ccb7e3.zip
opensim-SC-6492640e72776d9f0a015e6a719c8cef28ccb7e3.tar.gz
opensim-SC-6492640e72776d9f0a015e6a719c8cef28ccb7e3.tar.bz2
opensim-SC-6492640e72776d9f0a015e6a719c8cef28ccb7e3.tar.xz
* Change the OnQueueEmpty signature to send the flags of the queues that are empty instead of firing once per empty queue
* Change the OnQueueEmpty firing to use a minimum time until next fire instead of a sleep * Set OutgoingPacket.TickCount = 0 earlier to avoid extra resends when things are running slowly (inside a profiler, for example)
-rw-r--r--OpenSim/Framework/ThrottleOutPacketType.cs12
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs50
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs110
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs4
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs5
5 files changed, 120 insertions, 61 deletions
diff --git a/OpenSim/Framework/ThrottleOutPacketType.cs b/OpenSim/Framework/ThrottleOutPacketType.cs
index e21ff32..d56231a 100644
--- a/OpenSim/Framework/ThrottleOutPacketType.cs
+++ b/OpenSim/Framework/ThrottleOutPacketType.cs
@@ -51,4 +51,16 @@ namespace OpenSim.Framework
51 /// <remarks>This is a sub-category of Task</remarks> 51 /// <remarks>This is a sub-category of Task</remarks>
52 State = 7, 52 State = 7,
53 } 53 }
54
55 [Flags]
56 public enum ThrottleOutPacketTypeFlags
57 {
58 Land = 1 << 0,
59 Wind = 1 << 1,
60 Cloud = 1 << 2,
61 Task = 1 << 3,
62 Texture = 1 << 4,
63 Asset = 1 << 5,
64 State = 1 << 6,
65 }
54} 66}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
index 0bb7a71..432fee7 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
@@ -3550,33 +3550,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3550 OutPacket(attach, ThrottleOutPacketType.Task); 3550 OutPacket(attach, ThrottleOutPacketType.Task);
3551 } 3551 }
3552 3552
3553 void HandleQueueEmpty(ThrottleOutPacketType queue) 3553 void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories)
3554 { 3554 {
3555 switch (queue) 3555 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
3556 { 3556 {
3557 case ThrottleOutPacketType.Texture: 3557 lock (m_avatarTerseUpdates.SyncRoot)
3558 ProcessTextureRequests(); 3558 {
3559 break; 3559 if (m_avatarTerseUpdates.Count > 0)
3560 case ThrottleOutPacketType.Task: 3560 ProcessAvatarTerseUpdates();
3561 lock (m_avatarTerseUpdates.SyncRoot) 3561 }
3562 { 3562 }
3563 if (m_avatarTerseUpdates.Count > 0)
3564 ProcessAvatarTerseUpdates();
3565 }
3566 break;
3567 case ThrottleOutPacketType.State:
3568 lock (m_primFullUpdates.SyncRoot)
3569 {
3570 if (m_primFullUpdates.Count > 0)
3571 ProcessPrimFullUpdates();
3572 }
3573 3563
3574 lock (m_primTerseUpdates.SyncRoot) 3564 if ((categories & ThrottleOutPacketTypeFlags.State) != 0)
3575 { 3565 {
3576 if (m_primTerseUpdates.Count > 0) 3566 lock (m_primFullUpdates.SyncRoot)
3577 ProcessPrimTerseUpdates(); 3567 {
3578 } 3568 if (m_primFullUpdates.Count > 0)
3579 break; 3569 ProcessPrimFullUpdates();
3570 }
3571
3572 lock (m_primTerseUpdates.SyncRoot)
3573 {
3574 if (m_primTerseUpdates.Count > 0)
3575 ProcessPrimTerseUpdates();
3576 }
3577 }
3578
3579 if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0)
3580 {
3581 ProcessTextureRequests();
3580 } 3582 }
3581 } 3583 }
3582 3584
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
index 2d86a40..a9bc7d2 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
@@ -50,11 +50,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
50 /// are waiting on ACKs for</param> 50 /// are waiting on ACKs for</param>
51 public delegate void PacketStats(int inPackets, int outPackets, int unAckedBytes); 51 public delegate void PacketStats(int inPackets, int outPackets, int unAckedBytes);
52 /// <summary> 52 /// <summary>
53 /// Fired when the queue for a packet category is empty. This event can be 53 /// Fired when the queue for one or more packet categories is empty. This
54 /// hooked to put more data on the empty queue 54 /// event can be hooked to put more data on the empty queues
55 /// </summary> 55 /// </summary>
56 /// <param name="category">Category of the packet queue that is empty</param> 56 /// <param name="category">Categories of the packet queues that are empty</param>
57 public delegate void QueueEmpty(ThrottleOutPacketType category); 57 public delegate void QueueEmpty(ThrottleOutPacketTypeFlags categories);
58 58
59 #endregion Delegates 59 #endregion Delegates
60 60
@@ -128,6 +128,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
128 private int m_packetsReceivedReported; 128 private int m_packetsReceivedReported;
129 /// <summary>Total number of sent packets that we have reported to the OnPacketStats event(s)</summary> 129 /// <summary>Total number of sent packets that we have reported to the OnPacketStats event(s)</summary>
130 private int m_packetsSentReported; 130 private int m_packetsSentReported;
131 /// <summary>Holds the Environment.TickCount value of when the next OnQueueEmpty can be fired</summary>
132 private int m_nextOnQueueEmpty = 1;
131 133
132 /// <summary>Throttle bucket for this agent's connection</summary> 134 /// <summary>Throttle bucket for this agent's connection</summary>
133 private readonly TokenBucket m_throttle; 135 private readonly TokenBucket m_throttle;
@@ -140,9 +142,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
140 /// <summary>A container that can hold one packet for each outbox, used to store 142 /// <summary>A container that can hold one packet for each outbox, used to store
141 /// dequeued packets that are being held for throttling</summary> 143 /// dequeued packets that are being held for throttling</summary>
142 private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; 144 private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT];
143 /// <summary>Flags to prevent queue empty callbacks from stacking up on
144 /// top of each other</summary>
145 private readonly bool[] m_onQueueEmptyRunning = new bool[THROTTLE_CATEGORY_COUNT];
146 /// <summary>A reference to the LLUDPServer that is managing this client</summary> 145 /// <summary>A reference to the LLUDPServer that is managing this client</summary>
147 private readonly LLUDPServer m_udpServer; 146 private readonly LLUDPServer m_udpServer;
148 147
@@ -405,6 +404,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
405 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue; 404 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue;
406 TokenBucket bucket; 405 TokenBucket bucket;
407 bool packetSent = false; 406 bool packetSent = false;
407 ThrottleOutPacketTypeFlags emptyCategories = 0;
408 408
409 //string queueDebugOutput = String.Empty; // Serious debug business 409 //string queueDebugOutput = String.Empty; // Serious debug business
410 410
@@ -452,17 +452,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
452 // empty callback now so it has a chance to fill before we 452 // empty callback now so it has a chance to fill before we
453 // get back here 453 // get back here
454 if (queue.Count == 0) 454 if (queue.Count == 0)
455 BeginFireQueueEmpty(i); 455 emptyCategories |= CategoryToFlag(i);
456 } 456 }
457 else 457 else
458 { 458 {
459 // No packets in this queue. Fire the queue empty callback 459 // No packets in this queue. Fire the queue empty callback
460 // if it has not been called recently 460 // if it has not been called recently
461 BeginFireQueueEmpty(i); 461 emptyCategories |= CategoryToFlag(i);
462 } 462 }
463 } 463 }
464 } 464 }
465 465
466 if (emptyCategories != 0)
467 BeginFireQueueEmpty(emptyCategories);
468
466 //m_log.Info("[LLUDPCLIENT]: Queues: " + queueDebugOutput); // Serious debug business 469 //m_log.Info("[LLUDPCLIENT]: Queues: " + queueDebugOutput); // Serious debug business
467 return packetSent; 470 return packetSent;
468 } 471 }
@@ -509,49 +512,90 @@ namespace OpenSim.Region.ClientStack.LindenUDP
509 /// </summary> 512 /// </summary>
510 /// <param name="throttleIndex">Throttle category to fire the callback 513 /// <param name="throttleIndex">Throttle category to fire the callback
511 /// for</param> 514 /// for</param>
512 private void BeginFireQueueEmpty(int throttleIndex) 515 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories)
513 { 516 {
514 // Unknown is -1 and Resend is 0. Make sure we are only firing the 517 if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
515 // callback for categories other than those
516 if (throttleIndex > 0)
517 { 518 {
518 if (!m_onQueueEmptyRunning[throttleIndex]) 519 // Use a value of 0 to signal that FireQueueEmpty is running
519 { 520 m_nextOnQueueEmpty = 0;
520 m_onQueueEmptyRunning[throttleIndex] = true; 521 // Asynchronously run the callback
521 Util.FireAndForget(FireQueueEmpty, throttleIndex); 522 Util.FireAndForget(FireQueueEmpty, categories);
522 }
523 } 523 }
524 } 524 }
525 525
526 /// <summary> 526 /// <summary>
527 /// Checks to see if this queue empty callback is already running, 527 /// Fires the OnQueueEmpty callback and sets the minimum time that it
528 /// then firing the event 528 /// can be called again
529 /// </summary> 529 /// </summary>
530 /// <param name="o">Throttle category to fire the callback for, stored 530 /// <param name="o">Throttle categories to fire the callback for,
531 /// as an object to match the WaitCallback delegate signature</param> 531 /// stored as an object to match the WaitCallback delegate
532 /// signature</param>
532 private void FireQueueEmpty(object o) 533 private void FireQueueEmpty(object o)
533 { 534 {
534 const int MIN_CALLBACK_MS = 30; 535 const int MIN_CALLBACK_MS = 30;
535 536
536 int i = (int)o; 537 ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o;
537 ThrottleOutPacketType type = (ThrottleOutPacketType)i;
538 QueueEmpty callback = OnQueueEmpty; 538 QueueEmpty callback = OnQueueEmpty;
539 539
540 int start = Environment.TickCount & Int32.MaxValue; 540 int start = Environment.TickCount & Int32.MaxValue;
541 541
542 if (callback != null) 542 if (callback != null)
543 { 543 {
544 try { callback(type); } 544 try { callback(categories); }
545 catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + type + ") threw an exception: " + e.Message, e); } 545 catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); }
546 } 546 }
547 547
548 // Make sure all queue empty calls take at least some amount of time, 548 m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
549 // otherwise we'll peg a CPU trying to fire these too fast 549 if (m_nextOnQueueEmpty == 0)
550 int elapsedMS = (Environment.TickCount & Int32.MaxValue) - start; 550 m_nextOnQueueEmpty = 1;
551 if (elapsedMS < MIN_CALLBACK_MS) 551 }
552 System.Threading.Thread.Sleep(MIN_CALLBACK_MS - elapsedMS);
553 552
554 m_onQueueEmptyRunning[i] = false; 553 /// <summary>
554 /// Converts a <seealso cref="ThrottleOutPacketType"/> integer to a
555 /// flag value
556 /// </summary>
557 /// <param name="i">Throttle category to convert</param>
558 /// <returns>Flag representation of the throttle category</returns>
559 private static ThrottleOutPacketTypeFlags CategoryToFlag(int i)
560 {
561 ThrottleOutPacketType category = (ThrottleOutPacketType)i;
562
563 /*
564 * Land = 1,
565 /// <summary>Wind data</summary>
566 Wind = 2,
567 /// <summary>Cloud data</summary>
568 Cloud = 3,
569 /// <summary>Any packets that do not fit into the other throttles</summary>
570 Task = 4,
571 /// <summary>Texture assets</summary>
572 Texture = 5,
573 /// <summary>Non-texture assets</summary>
574 Asset = 6,
575 /// <summary>Avatar and primitive data</summary>
576 /// <remarks>This is a sub-category of Task</remarks>
577 State = 7,
578 */
579
580 switch (category)
581 {
582 case ThrottleOutPacketType.Land:
583 return ThrottleOutPacketTypeFlags.Land;
584 case ThrottleOutPacketType.Wind:
585 return ThrottleOutPacketTypeFlags.Wind;
586 case ThrottleOutPacketType.Cloud:
587 return ThrottleOutPacketTypeFlags.Cloud;
588 case ThrottleOutPacketType.Task:
589 return ThrottleOutPacketTypeFlags.Task;
590 case ThrottleOutPacketType.Texture:
591 return ThrottleOutPacketTypeFlags.Texture;
592 case ThrottleOutPacketType.Asset:
593 return ThrottleOutPacketTypeFlags.Asset;
594 case ThrottleOutPacketType.State:
595 return ThrottleOutPacketTypeFlags.State;
596 default:
597 return 0;
598 }
555 } 599 }
556 } 600 }
557} 601}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
index 40d3771..a9f4b2c 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
@@ -424,10 +424,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
424 outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT); 424 outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT);
425 outgoingPacket.Category = ThrottleOutPacketType.Resend; 425 outgoingPacket.Category = ThrottleOutPacketType.Resend;
426 426
427 // The TickCount will be set to the current time when the packet
428 // is actually sent out again
429 outgoingPacket.TickCount = 0;
430
431 // Bump up the resend count on this packet 427 // Bump up the resend count on this packet
432 Interlocked.Increment(ref outgoingPacket.ResendCount); 428 Interlocked.Increment(ref outgoingPacket.ResendCount);
433 //Interlocked.Increment(ref Stats.ResentPackets); 429 //Interlocked.Increment(ref Stats.ResentPackets);
diff --git a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs
index 3e2e81c..e43f7cf 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs
@@ -123,6 +123,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
123 { 123 {
124 if (expiredPackets == null) 124 if (expiredPackets == null)
125 expiredPackets = new List<OutgoingPacket>(); 125 expiredPackets = new List<OutgoingPacket>();
126
127 // The TickCount will be set to the current time when the packet
128 // is actually sent out again
129 packet.TickCount = 0;
130
126 expiredPackets.Add(packet); 131 expiredPackets.Add(packet);
127 } 132 }
128 } 133 }