Regarding DS<->DS TCP slowness (and DSi XL hang)
Posted: Sun Apr 11, 2010 10:43 pm
I have some findings in the DS Wifi layer that I'm currently trying to use with my homebrew game to communicate DS<->DS using tcp. I have experienced problems with slow communication and that the communication hangs after a while. As of now I have found out that the hang was caused by using a DSi XL. And that the main cause of the slowness was that all tcp-packets are always being replied to causing packet flooding for communication between two DS units.
Here are my current notes:
- The communication hang seems to have been caused by using a DS Lite/DSi XL combo when testing. When using two DS Lite it will work without any hangs. Still slow though. Tested the DSi flashcart in the DS Lite and it worked so the DSi XL is to blame.
- The game is supposed to send 16 bytes using tcp in both directions between units every 3:rd frame. Debug printouts of WSTAT_RXPACKETS/WSTAT_TXPACKETS reveals that there are a LOT (100+) of packets being sent and received between each of these 16 byte packets.
- The lag seems get longer the communication has been going on. Looking at printouts at game startup it looks like it starts with a few extra packets between the 16 bytes but the extra packets gets more and more up to 100+.
- After a lot of testing and debug printing the main source of the slowness problem was found to be that tcp-packets were always being replied to. This caused flooding of tcp-packets when using DS<->DS communication. When another tcp-layer is one of the endpoints imagine that this will not happen.
- On a sidenote, at first I thought that it was stuff like nagle and delayed ack that caused the slowness. While examining the inner workings of the tcp layer I discovered some limitations. I think that the update timer should be triggered more often than every 50ms. There are things like SGIP_TCP_TRANSMIT_DELAY set to 25ms which will not work as expected with current timers. I imagine fiddling with these parameters in the future, but for this to do any difference a 5ms-10ms timer would be nice. I will do some more testing.
What I did that made things work a lot better for me was a change at line 408 in sgIP_TCP.c From:
if(shouldReply || delta1>=0) { // send a packet in reply, ha!
To:
if(shouldReply || delta1>0) { // send a packet in reply, ha!
This will cause direct replies to tcp-packets only being sent when there is new payload data received. This change actually reverts a change introduced in revision 1507. The change comment was "Fixed bug causing lib to not re-ack data packets that were resent.". However, the correct solution for this problem can not be to ack every packet causing packet floods when the other side acts the same way. I think a solution that would fix also fix "re-ack of data resent data packets" would be to ack every packet with payload data; even if there was no *new* data. A check of datalen before it is adapted for already received data. I will do some testing with this approach.
I thought I would share my findings even though I will still continue to investigate my problems. The communication is still a bit too slow for my game. For my exchange of 16 bytes in both directions there are still 3 packets in both directions. I believe that it should be 2+2 packets, a data packet and a direct ack-reply in both directions. I also imagine to see if I can find some method of further reducing latency in message handling for my game. It is very possible that I will switch to UDP to avoid all tcp-quirks; as many games do.
Regards,
Bengt
Here are my current notes:
- The communication hang seems to have been caused by using a DS Lite/DSi XL combo when testing. When using two DS Lite it will work without any hangs. Still slow though. Tested the DSi flashcart in the DS Lite and it worked so the DSi XL is to blame.
- The game is supposed to send 16 bytes using tcp in both directions between units every 3:rd frame. Debug printouts of WSTAT_RXPACKETS/WSTAT_TXPACKETS reveals that there are a LOT (100+) of packets being sent and received between each of these 16 byte packets.
- The lag seems get longer the communication has been going on. Looking at printouts at game startup it looks like it starts with a few extra packets between the 16 bytes but the extra packets gets more and more up to 100+.
- After a lot of testing and debug printing the main source of the slowness problem was found to be that tcp-packets were always being replied to. This caused flooding of tcp-packets when using DS<->DS communication. When another tcp-layer is one of the endpoints imagine that this will not happen.
- On a sidenote, at first I thought that it was stuff like nagle and delayed ack that caused the slowness. While examining the inner workings of the tcp layer I discovered some limitations. I think that the update timer should be triggered more often than every 50ms. There are things like SGIP_TCP_TRANSMIT_DELAY set to 25ms which will not work as expected with current timers. I imagine fiddling with these parameters in the future, but for this to do any difference a 5ms-10ms timer would be nice. I will do some more testing.
What I did that made things work a lot better for me was a change at line 408 in sgIP_TCP.c From:
if(shouldReply || delta1>=0) { // send a packet in reply, ha!
To:
if(shouldReply || delta1>0) { // send a packet in reply, ha!
This will cause direct replies to tcp-packets only being sent when there is new payload data received. This change actually reverts a change introduced in revision 1507. The change comment was "Fixed bug causing lib to not re-ack data packets that were resent.". However, the correct solution for this problem can not be to ack every packet causing packet floods when the other side acts the same way. I think a solution that would fix also fix "re-ack of data resent data packets" would be to ack every packet with payload data; even if there was no *new* data. A check of datalen before it is adapted for already received data. I will do some testing with this approach.
I thought I would share my findings even though I will still continue to investigate my problems. The communication is still a bit too slow for my game. For my exchange of 16 bytes in both directions there are still 3 packets in both directions. I believe that it should be 2+2 packets, a data packet and a direct ack-reply in both directions. I also imagine to see if I can find some method of further reducing latency in message handling for my game. It is very possible that I will switch to UDP to avoid all tcp-quirks; as many games do.
Regards,
Bengt