Sunday, December 26, 2010

Speed Limit: 32

Now, that's fairly annoying. It looks like the TCP WiFi transfers with the "devkitpro r32" is roughly 3 times slowlier than its r21 counterpart (in purple) for the same receiving code. That's especially annoying since it significantly increase the duration of a self-upgrade cycle during development.

The new performance (in black, as reported by wireshark) is impaired by regular "waits" of ~200ms before the PC retransmits some data. And I'm doing the test with a local server here. A larger RTT would likely reduce the performance even more. Retransmissions happen form the start, and that's fairly normal for a wireless transmission. I ran some early code comparison between the ARM9 TCP code of the two dswifi versions, but I couldn't spot any major change that could explain this behaviour.


J'ai finalement suffisament rafistolé runMe pour qu'il puisse de nouveau faire sa mise à jour automatique -- la clé de voûte de mon cycle de développement sur DS. Je pouvais déjà jouer à redémarrer sous Moonshell, puis passer dans le menu R4, utiliser le vieux runMe "21" pour télécharger le nouveau tryMe "32", retourner à Moonshell puis au menu R4 pour démarrer le programme tryMe. Pas extraordinaire. Problème: les transfers par WiFi sont devenus nettement plus lents. Jusqu'à 3x plus lents si j'en crois mes captures wireshark (ci dessus, runme-21 en mauve, runme-32 en noir).

Pourtant, à en croire le code de TCP dans libdswifi9, rien n'a changé ... ou presque. Rien en tout cas qui puisse expliquer ces pauses de 200ms récurrentes dans le deuxième scénario. J'investigue un peu plus grâce au zoom infini de WireShark pour découvrir que la DS annonce juste avant cette pause une fenêtre de réception de plus en plus petite, qui finit par atteindre une taille nulle. Et ça, en langage TCP, c'est le signe que le récepteur ne suit plus: les buffers saturent.

One intriguing thing is that, somewhat prior one of these long wait is that the receiver's window size is reduced from 1400 bytes to 1127, then 591 and finally 55 bytes ... It will then remain with a 0 receiver window for a few packets and then move back to 1400. In TCP language, this is an indication that the receiver struggles to process the received data on time. But the code that invokes "recv()" hasn't changed either ... that sounds like a problem coming from the "write-to-filesystem" side of the program ... from the libFAT.

It looks like libFAT has received more substantial changes, especially regarding the cache management. I used runMe's "receive to memory" mode, which is limitted in file size, but still operated at the usual peak speed. If a sequence number graph doesn't talk to you, the performance monitor just on the right should. The first "bridge" bar is the transfer to disk, the second "tower" bar is the transfer to memory. I haven't figured how to fix that yet, but at least I am in position to say that TCP is clear of charges.


Puisque le code qui transfère les données de dswifi à libfat n'a pas changé d'un iota, le problème est plus que probablement dans la libfat, qui a subi des modifications relativement importantes -- notamment au niveau de la gestion de son cache. Et vu que les données arrivent par le réseau à une taille qui n'est pas la taille "naturelle" pour écrire sur disque, un petit défaut dans la libFAT pourrait facilement avoir un effet conséquent sur les performances. Dernier petit test pour me convaincre de continuer dans cette direction : un transfer Wifi en mémoire (et non pas vers un fichier), fonctionalité un peu désuète de runMe mais qui tombe à pic ici. Résultat sans appel: on retrouve la vitesse à laquelle runMe m'avait habitué.

C'est donc un dswifi blanchi qui quitte la garde à vue tandis que je m'apprète à jouer une âpre partie de cache-cache avec le gros lard louche connu sous le nom de libFAT.

No comments: