Le macbook pro 2016 avec sa touchbar magique et révolutionnaire

pas content J'ai un macbook pro 2016 depuis un bon gros mois et ça y est j'en ai marre faut que ça sorte. Ce matin il a refusé de sortir de veille, et ce soir cette bourrique qui renacle a obstinément refusé de se mettre veille. D'ailleurs la sortie de veille est un problème récurrent sur ce mac, il semblerait que l'adapteur pour écran externe hdmi soit dans le coup. Des fois en sortant de veille , ou en s'éteignant, je vois apparaitre des rectangles rouges sur l'écran du mac, en général c'est quand il renacle. C'est le genre de truc sur un vieux laptop dell sous windows on se dit "pff les drivers MACHIN c'est vraiment de la merde" ou "purée windows c'est vraiment de la merde en branche", mais là comme c'est un laptop apple "que c'est les meilleurs parce qu'ils controlent le matos et le soft et c'est pour ça que l'experience utilisateur est tellement léchée et polie" ben ça pique un peu. On pourrait aussi parler de l'adapteur pour écran externe, vendu par apple, pour la modique somme de 59euros et qui semble être impliqué dans pas mal de problèmes, cf ses notes et reviews ici: usb-c-digital-av-multiport-adapter

La grosse nouveauté de ce macbook c'est sa touchbar. Elle permet (et c'est sans doute son usage le plus spectaculaire) d'afficher la liste entière des emojis unicode quand on rédige un mail , c'est assez impressionnant et bien sûr crucialement utile. On trouve aussi sur internet plein de gens qui disent que la touche escape transformée en touche non physique sur la touchbar eh ben "saipagrave", personnellement je penche plus pour le "sapuducul". Ca m'a donné l'occasion de réaliser qu'en position de repos j'ai tendance à laisser trainer le petit doigt pas loin de cette touche escape et comme maintenant elle s'active dès qu'elle est frôlée j'ai tendance à balancer des rafales de ESC intempestifs dans emacs ou dans le terminal (des rafales parce que tant qu'on laisse le doigt dessus elle passe en mode autorepeat, c'est vraiment malin). En mode rédaction de mail, un bouton 'Send' apparait juste à côté de la touche escape, ce qui est une riche idée sauf pour ceux qui ont l'habitude d'avoir le petit doigt qui traine dans le coin. A l'extrême droite y'a le bouton marinesiri que j'ai aussi pas mal tendance à activer par erreur. Le réglage du volume sonore se fait aussi sur la touchbar, mais là ou autrefois on avait une touche pour augmenter, une touche pour baisser, il faut maintenant appuyer d'abord sur un bouton qui fait apparaitre un slider pour ensuite ajuster le volume, c'est très joli mais ça fait deux "clics" au lieu d'un. A part ça, la touchbar ne me sert à rien. Donc en gros on peut un peu dire que la touchbar c'est de la merde. Peut être qu'avec du retour haptique elle serait potable.

Le clavier est nouveau aussi, et il n'est ni magique ni révolutionnaire. En plus il fait du bruit (dans le bureau c'est clairement moi qui ai le clavier le plus bruyant maintenant), et ce n'est pas un bruit soigneusement designé qui évoque le matos cher et sophistiqué, mais plutot un vieux ploc cartonné qui me rappelle les pires netbooks avec leur claviers mous et gondolés. En plus je n'arrête pas de faire des fautes de frappe sur ce clavier.

Le bruit: j'ai pris le modele quad-coeur core i7 pour avoir une machine qui a la niaque quand il s'agit de compiler des trucs. Eh bien au bout de 10 minutes de compilation intensive le macbook réussit à faire plus de bruit que mon ancien mac pro (la grosse tour qui pèse au moins 200kg). Pas mal ! Et ça n'empeche pas le cpu d'être à 100°C (d'après l'application intel dont j'ai oublié le nom). Donc le corps du mac est confortablement chaud, comme une bonne bouillote de mamie, j'ai hâte de voir ce que ça va donner cet été.

Une feature sympa quand même: le touch-id , qui marche bien et j'apprécie de devoir saisir mon mot de passe un peu moins souvent. Et l'usb-C, si on oublie l'adapteur hdmi moisi de apple , pour le reste c'est plutot sympa.

En conclusion je décerne un 2/20 à ce macbook.

De la fragilité des outils de debug

Une des choses les plus exaspérantes avec le dev en c/c++ c'est de ne pas comprendre *pourquoi* tel outil de profiling ou de debugage n'est pas foutu d'afficher les noms de fonctions corrects, ou d'afficher le code source. C'est par exemple perdre des heures à chercher pourquoi la fonction backtrace de la glibc a besoin d'une option particuliere du compilateur (-rpath) pour donner des noms de fonctions au lieu de leur addresse, alors que celle de la libunwind se demerde toute seule comme une grande. C'est perdre des heures à chercher comment faire en sorte que perf sous linux sur arm affiche des noms de symboles plutot que des addresses hexa. Ca n'est pas spécifique à une plateforme, sur *chaque* plateforme je me retrouve à un moment où a un autre à me battre contre des outils récalcitrants et autistes , qui ne fonctionnent pas et qui ne disent pas quel est leur problème. Mentions spéciales à perf sous linux, windbg sous windows et Instruments.app sous macos.

Et donc pour Instruments.app , ce qui est nécessaire si on veut que cette mule soit capable d'annoter les sources du code profilé, c'est de bien veiller à compiler les sources en donnant le chemin *absolu* à clang, et non pas un chemin relatif.

Editer un script bash pendant qu'il est en cours d'execution

On est en 2016 et bash n'est toujours pas capable de gérer correctement la situation où on édite un script alors qu'il est en cours d'exécution (gérer correctement, càd ignorer les changements et continuer à executer le script initial, et pas tenter d'executer un bout semi-aléatoire de la nouvelle version du script pour finalement se planter comme une merde)

Performance of the Raspberry pi 3

I just got a raspberry pi 3. I used to assume that its cpu (Cortex A53) should be quite bad, even when related to a good old cortex A9 (for example this document says that the performance is expected to be equivalent for both, while this one says the A53 is slightly slower than the A9). As I now have a cortex A9 (rk3188t) on a cheap device running picuntu, and a cortex A53 on the raspberry Pi, I can compare them. The default speed of the rk3188t is 1.4GHz but I have lowered it to the frequency of the raspberry pi for an easier comparison (using cpufreq-set). So both cpus are running at 1.2GHz. For the performance comparison, I have built and run the pffft benchmark on both:

time gcc-4.8 -O3 -DHAVE_FFTW -march=armv7-a -mtune=cortex-a9 -mfloat-abi=hard -mfpu=neon -ffast-math test_pffft.c pffft.c -o test_pffft_arm fftpack.c -lm -lfftw3f

(the raspbian distribution of the rpi3 is 32-bit so what I'm comparing here , since the A53 is 64-bit capable, is a A9 with a A53 running in 32-bit)

On the rk3188t@1.2Ghz, the compilation took 34 sec , while it took 24.9 on the pi, which is here 36% faster.

The execution took 109 sec on the rk3188t vs 66 sec on the pi, so for floating point stuff the pi is 65% faster.

If I look at the floatting point performance for pffft itself (so it is a measure of the neon simd floating point, not of the scalar floating point performance), the rk3188 reports a max value of 1164 MFlops for FFTs of length 1024 , while on the raspberry pi it achieves 2162 MFlops . So for neon stuff, the pi is 85% faster !

Here are the pffft results for the pi 3 on raspbian (when built with gcc-4.9 , which itself improves the pffft performance of 20% on both the rk3188 and the pi3 with respect to gcc-4.8, and with -mtune=cortex-a53 instead of cortex-a9, which brings another 7% of improvement):

| input len |real FFTPack|  real FFTW | real PFFFT | |cplx FFTPack|  cplx FFTW | cplx PFFFT |
|       64  |      521   |      672   |     1303   | |      534   |      887   |     1470   |
|       96  |      429   |      340   |     1253   | |      422   |      864   |     1323   |
|      128  |      508   |      740   |     1571   | |      491   |      742   |     1502   |
|      160  |      525   |      750   |     1626   | |      483   |      931   |     1463   |
|      192  |      544   |      852   |     1641   | |      495   |      877   |     1548   |
|      256  |      639   |      684   |     2007   | |      570   |      778   |     1727   |
|      384  |      483   |      873   |     1724   | |      436   |      795   |     1531   |
|      480  |      495   |      761   |     1749   | |      433   |     1040   |     1492   |
|      512  |      548   |      765   |     2043   | |      489   |      873   |     1670   |
|      640  |      557   |      892   |     2004   | |      481   |      863   |     1579   |
|      768  |      571   |      818   |     1980   | |      486   |      892   |     1684   |
|      800  |      549   |      637   |     1928   | |      450   |      657   |     1564   |
|     1024  |      645   |      842   |     2328   | |      540   |      914   |     1764   |
|     2048  |      586   |      869   |     2151   | |      487   |      931   |     1583   |
|     2400  |      530   |      672   |     1803   | |      422   |      681   |     1379   |
|     4096  |      631   |      867   |     2079   | |      476   |      843   |     1439   |
|     8192  |      515   |      811   |     1611   | |      418   |      730   |     1345   |
|     9216  |      503   |      789   |     1568   | |      424   |      812   |     1347   |
|    16384  |      501   |      749   |     1552   | |      418   |      699   |     1239   |
|    32768  |      479   |      680   |     1396   | |      346   |      529   |      825   |
|   262144  |      244   |      327   |      398   | |      240   |      409   |      387   |
|  1048576  |      229   |      270   |      350   | |      211   |      301   |      355   |

update: maybe I should say a word about the audio quality of the built-in headphone output of the rpi3 ? it is utter crap. Not sure if mine has a hardware issue or if the driver is doing some crazy shit but the output is mixed with some horrible electronic noise coming

chrooter une veille debian pour compiler des trucs

Quelques notes pour que je me souvienne comment on met en place une debian wheezy sous ubuntu tranquillos (ici avec une abi armhf):

  • installer schroot:
> apt-get install schroot
  • debootstraper la wheezy:
> debootstrap --arch armhf --foreign wheezy /armhf-wheezy http://ftp.fr.debian.org/debian
  • configurer le schroot:
> sudo vim /etc/schroot/schroot.conf

Et y entrer:

[armhf-wheezy]
description=Debian Wheezy, ARMHF
type=directory
directory=/armhf-wheezy
users=MONLOGINDEUSER
root-groups=root
aliases=armhf,default

Comme ça le home sera directement utilisable dans le chroot.

  • finir le debootstrap:
> sudo schroot
# /debootstrap/debootstrap --second-stage
# cat > /etc/apt/sources.list
deb http://ftp.fr.debian.org/debian wheezy main
deb http://httpredir.debian.org/debian wheezy-updates main
^D
# apt-get update
# apt-get install g++ libasound2-dev scons make vim

Si il y a des montage qui n'apparaissent pas dans le chroot, le plus simple et d'editer /etc/schroot/default/fstab et de les rajouter dedans.

Et c'est bon, on a un environnement de dev un peu vintage qui permet de fabriquer des binaires bien compatibles puisque compilés sur une vieille debian des familles.

Recyclage de clef-pc

C'est pas beau ça ?

Je ne suis pas peu fier d'avoir fabriqué un magnifique mini-pc équipé d'un nombre raisonnable de ports usb et d'une sortie son qui marche à partir de divers éléments inutiles et plus ou moins fonctionnels:

  • une clef-pc meegopad T02 , livrée avec un ubuntu qui ne boote que si on prend le soin de visiter le bios avant de la booter..
  • un vieux hub et divers bouts de cables usb
  • un lcd usb crystalfontz
  • un boite vide de "Mon Chéri" , en plastique rouge translucide, avec cette élégance subtile teintée de bon gout typique des produits Ferrero .
  • une boite de tic-tac
  • un bout de ferraille pour lester le fond du boitier
  • une carte son externe usb d'une valeur de 2 euros

Quand le boitier est ouvert ça donne quelque chose d'élégant et pas du tout bordelique.

Il s'avère que la clef-pc (baytrail z3537f, 2go de ram) accepte de booter toute seul si on lui met une distro 32-bit plutôt que 64-bit donc j'ai remplacé la ubuntu inutile et je lui ai collé une debian Jessie. Il s'avère aussi que le temps s'écoule de façon bizarre sur cette clef pc, il ralenti, il accélère il fait des bonds, et au final y'a des trucs qui marchent pas très bien (par exemple le mécanisme de répétition automatique des touches du clavier n'aime pas qd le temps fait des bonds en arrière). En mettant "clocksource=tsc" sur la ligne de commande du kernel ça marche mieux. Il s'avère enfin que la présence du lcd sur le meme hub usb que la carte son a tendance a produire des craquements dans celle-ci. Je pensais que c'était un probleme électrique (vu que j'ai du raccourcir et bricoler les câbles usb pour que ça loge dans le boitier), mais les craquement ne se produisent (semi-aleatoirement) que quand le device /dev/ttyUSB0 du lcd est open(). Du coup j'ai installé un kernel avec un HZ à 1000 et ça va nettement mieux. Mais je n'ai pas vraiment compris quelle est la nature du problème...

Le cpu est un atom baytrail à 1.33Ghz avec turbo boost à 1.8Ghz. Par défaut le turbo n'est pas activé et il n'y a pas de réglage dans le bios pour l'activer. On pourrait croire que la situation est désespérée, mais non, cette page donne des instruction qui permettent effectivement d'activer le turbo, et ça fait une différence notable en performance. Le wattmètre indique 7W et la température du cpu reste sous contrôle.

A l'arrivée le boitier fait tourner un synth avec une taille de buffer de 64 samples finger in the nose. Le synth est piloté par un petit script python qui s'occupe de l'interaction avec le LCD l'affichage, changer de preset, ou éteindre le boitier.

UPDATE: finalement le LCD provoque encore des craquements avec le kernel liquorix... rogntudju.

Ultra short c++ MIDI file reader

There are many full-featured libraries for reading Standard MIDI Files , but they are often doing more than just reading and end up being a bit on the over-engineered side.

Here is what could be the shortest MIDI file parser ever, in a simple self-contained c++ header file. It is short because it does not do much and does not try to be smart.

simple_midi_reader.hh

It should be able to load any MIDI file and turn it into a list of MIDI events that are correctly timestamped (tempo change events are handled). And that's all !

Wow

Wow ça fait longtemps que j'ai pas blogué.

Prompt bash

Ca faisait au moins 10 ans que j'utilisais le même prompt bash, un truc qui affiche grosso modo l'heure et le chemin courant, en couleur, basique mais leger. Un truc qui me manque parfois c'est d'avoir le temps d'execution de la derniere commande, je trouve que c'est une information interessante quand ce temps est de plus de quelques secondes. Et aussi, avoir un affichage du code de retour de la commande précedente. C'est pourquoi j'ai décidé de mettre a jour mon prompt bash ! voici ce qu'il y a maintenant dans le ~/.bashrc , il n'y a rien d'exceptionnel c'est juste des bouts de trucs trouvés sur le net mais je suis content du résultat:

url du truc (arg je n'arrive pas à coller le code directement dans dotclear, il a l'air d'en interpreter des bouts...)





Voila la tête que ça a:

Je ne vais pas dire que c'est le plus beau prompt du monde, mais je sens qu'il va faire l'affaire pour les 10 ans venir.

Utiliser -mfpmath=sse avec gcc

Un bon moyen (en 32-bit) pour se debarrasser des bizarreries du x87 c'est de compiler avec cette option -mfpmath=sse qui demande à gcc d'utiliser les instructions sse à la place du x87 et ses registres moyenageux de 80-bits. Jusque là tout va sauf que si on regarde les performances des fonctions transcendentales expf, sinf, tan, atan ( par exemple en compilant sse_mathfun_test.c avec les options -ffast-math -O3 -msse2 et -mfpmath=sse ou -mfpmath=387), eh bien on constate qu'elles sont devenues jusqu'à 2.5 fois plus lentes. Genre sur mon core 2, tan() executée avec le fpu x87 prend 119 cycles, alors que la version sse2 prend 298 cycles ! pas cool. Pour expf c'est un peu moins pire, on passe de 143 cycles à 203.

J'ai fait le test avec mingw-w64 sous windows, version 4.6.2 et 4.7.

(Coté visual c++ 2010, le runtime selectionne systematiquement la version sse2 à l'execution, mais elle est beaucoup plus rapide que celle de gcc: 146 cycles pour tan, 103 pour expf)

Latence du nexus 7

Après des mesures scientifiques, la latence "touch to fart" du nexus 7 est de 200ms (au mieux -- pour la premier application testée c'était 400ms)

Update: en fait j'avais testé avec divers synths et grand pianos, mais pas avec un vrai fart piano, et... c'est lui qui a la latence la plus faible, ~120ms ... Il semblerait que ce soit parce qu'il utilise l'api soundpool qui permet de jouer des samples predefinis avec une latence plus faible que les autres api. Mais elle n'est pas utilisable si on doit faire de la synthese ou appliquer des effets sur les samples

Google Nexus 7

Hé ouais j'ai un nexus 7 depuis quelques jours. Vous êtes incroyablement nombreux à réclamer un billet de blog à ce sujet, voici donc un petit compte-rendu:

  • j'aime bien le dos. Je comprends pourquoi chaque article sur le nexus 7 en parle, c'est un truc assez reussi pour du plastoc. C'est vraiment agréable au toucher et ça ne fait pas cheap.
  • l'écran est sympa, sans etre une resolution de folie (1280x800) ça fait quand même des pixels bien petits. Par contre faut une vue pas trop mauvaise.
  • la tablette est livrée avec 'A la recherche du temps perdu' et 'Transformers III' , manifestement google n'a pas peur des contrastes forts. On a du mal à imaginer un film plus con que transformers III.
  • jelly bean est fluide
  • ça ne chauffe pas, enfin je crois. Faudrait quand même voir en faisant tourner les 4 cores à 100% , ça doit bien finir pas devenir au moins tiede.
  • y'a pas de dock digne de ce nom, qui permettrait de brancher un périphérique usb tout en rechargeant la tablette: sainul.
  • le micro-usb c'est quand même un bien pénible a brancher/débrancher , je comprends pourquoi apple n'a pas voulu se faire chier avec ce truc.
  • l'installation du sdk + ndk android est quand même bien pourrie , le nombre de machins a installer (java, ant, eclipse, sdk, ndk, plugin eclipse, telecharger les images et les libs pour diverses releases d'android, préparer des devices virtuels pour les tests)
  • c'est quand même un peu long pour deployer une application sur la machine, genre un paquet de 13Mo prend environ 20secondes pour etre installé sur le nexus 7. Ca reste quand même nettement plus rapide que dans l'emulateur.
  • la latence audio est A PLEURER. Quand je joue du fart piano il y a bien un quart de second qui s'écoule entre le relachement de la la touche et le bruit de pet. ça valait vraiment la peine que google se vante de la latence "améliorée" dans jelly bean. Vraiment ça craint. Et en passant par opensl c'est pas mieux (en fait je crois que c'est pire, j'ai l'impression d'avoir plus d'un quart de seconde de latence)
  • y'a zero api pour gerer les periph MIDI branchés sur le port usb, encore un signe que google n'a vraiment rien a foutre de l'audio. La solution c'est de réinventer la roue avec ce genre de truc: android USB-MIDI driver. On dirait aussi que brancher et debrancher des trucs USB a tendance a faire planter la tablette..
  • le tegra 3 n'est quasiment jamais à 1.3GHz , sa fréquence de croisière quand il y a de la charge semble être 1.2GHz , et sinon il descend très vite en fréquence, 100MHz quand la tablette est idle

Google WEBP roxor

Voila un format d'image qui n'a pas reçu beaucoup d'amour quand il a été annoncé, qui n'est pas supporté par firefox, qui n'est pas encore complètement sec (y'a un gros TODO pour les PPC dans le code), et pourtant il est déjà bien. Carrément meilleur que jpg pour les images qui m'intéressent (des bitmaps assez détaillés avec parfois du texte), il permet de remplacer completement le png puisqu'il supporte la transparence. La décompression est très rapide, la lib est raisonnablement petite et portable, bref c'est de la boulette. J'avais commencé à m'intéresser à sa variante webpll pour faire du lossless, mais c'est nettement plus long a compresser/décompresser, ça ne fait que 30% de mieux que le png et webp me permet d'obtenir la qualité d'image souhaitée avec des images beaucoup plus petites.

Donc merci google pour webp, c'est vraiment sympa.

Gros dictionnaire

Un truc dont j'ai pris conscience très récemment, c'est l'importance de la taille du dictionnaire pour des algos de compression genre lzma, quand on compresse des données relativement redondantes. L'exemple typique, c'est un fichier tar contenant plusieurs fois le même fichier avec juste quelques petites altérations, le genre de chose qui arrive de temps en temps, et en tout cas qui m'arrive à moi. Si le dictionnaire lzma est assez gros, alors la compression va capter toutes ces redondances et va compresser *beaucoup plus* que si on utilise le dictionnaire par défaut. Si il est trop petit, ben ça va marcher beaucoup moins bien.

Du coup , sous linux, en utilisant un dictionnaire de 128MB (la valeur par défaut est 8MB) mon archive .7z de 54Mo passe à 19Mo seulement ! Impressive.

Ca marche aussi pour un setup.exe sous windows. Si on utilise l'excellent innosetup il y a une option pour modifier la taille de dictionnaire lzma, avec la même efficacité. C'est aussi possible avec nsis (que j'exècre), mais il faut aussi lui demander explicitement de faire une compression "solid" c-à-d de comprimer tous les fichiers en même temps, et pas un par un.

Par contre le plus gros défi c'était d'en profiter aussi sous macos. C'est plus compliqué sous osx puisque PackageMaker utilise gzip pour compresser l'archive mpkg, et là y'a pas d'options ( je ralais déjà à ce sujet ici , mais a l'époque je ne connaissais pas la feinte du dictionnaire lzma pour gagner encore plus en compression). Du coup j'ai fait une petite appli cocoa , qui embarque le mpkg dans ses ressources. Mais c'est un mpkg dont le Archive.pax.gz (qui est grosso modo un tar.gz de tous ce qu'il y a à installer) a été d'abord dégzippé puis recompressé avec lzma et un gros dictionnaire bien touffu. L'appli copie ce mpkg dans un dossier temporaire, décompresse le Archive.pax.lzma et passe ensuite le relai à l'installeur d'osx pour installer le mpkg (même pas besoin de le re-gzipper, manifestement l'installeur macos s'en accomode très bien).

Du coup on va économiser un peu de bande passante et je poireauterai un peu moins pendant les uploads de nouvelle version.

pretty fast FFT

Voici le code d'une FFT raisonnablement rapide, raisonnablement petite (le code tient dans un fichier) et raisonnablement pas chiante au niveau de la license (c'est du bsd). Paradoxalement, ce n'était pas facile d'en trouver une qui réponde à ces contraintes.

Que s'appelorio PFFFT.

rogntudju

En l'espace de deux jours, je viens de découvrir que l'imac acheté il y a un an et trois mois (donc plus sous garantie) a des taches qui se développent sur la dalle, et ce matin son disque dur a laché (enfin pas sûr a 100% mais le fait qu'il ait affiché des I/O error et ramé comme un phoque avant de refuser de rebooter et que les fsck echouent piteusement me rend peu optimiste).

J'ai un peu les boules.

Update: finalement il y a eu une happy end et je n'ai plus du tout les boules !

Format AIFF

mega sample rate vs giga float

J'étais en train de regarder le format des fichiers des AIFF (le .wav d'Apple), qui semble a priori un format assez basique, et pourtant mes bras m'en sont tombés quand j'ai vu comment il codent la fréquence d'echantillonnage du fichier: sur un ieee long double , un float géant de 10 bytes ! je me demande ce qui est passé dans la tête du type qui a pondu ça.

Excellent blog

Je kiffe: http://pulsar.webshaker.net/

clock_gettime is slow

..on the pandaboard. I just measured it , and each call to clock_gettime(CLOCK_MONOTONIC) takes approximately 800ns . On a core 2 quad it takes 27ns , and it has also a muuuuchh better resolution that the ARM one, which has a resolution of 1/32787th second. Using CLOCK_REALTIME or whatever does not improve the timings.

NEON optimized single precision sin / cos / exp and log

This is a translation of the SSE version to ARM NEON intrinsics. Je profite de l'occasion pour dire que : the official ARM NEON documentation is quite shitty.

ARM Cortex A9 Peak FLOPS

I have just measured the peak gflops performance for the cortex A9, using this snippet of code:



@@ int ni = 65536*16;

   __asm__ volatile("mov  r5, #0\n"
                    "vdup.f32 q0, r5\n"
                    "vdup.f32 q1, r5\n"
                    "vdup.f32 q2, r5\n"
                    "vdup.f32 q3, r5\n"
                    "vdup.f32 q4, r5\n"
                    "mov r5, %0\n"
                    "1:\n"
                    "vmla.f32 q0, q0, q0\n"
                    "vmla.f32 q1, q1, q1\n"
                    "vmla.f32 q2, q2, q2\n"
                    "vmla.f32 q3, q3, q3\n"
                    "vmla.f32 q4, q4, q4\n"
                    "subs r5, r5, #1\n"
                    "bne 1b\n" : : "r"(ni) : "q0", "q1", "q2", "q3", "q4", "r5");@@

Each loop does (4 float per vec) * (5 vmla operations) * (2 flop per vlma) = 40 flop, repeated ni times. The result for the 1GHz cortex A9 of my pandaboard: 3.99919 GFlops , which was quite expected but it is always good to see a confirmation. Reducing the number of VMLA (fused multiply add) in the loop results in a lower performance (the vlma latency is 5 cycles if I recall correctly, so that is also expected). Using separate VMUL and VADD operations produces 2 GFlops instead of 4.

Interestingly, replacing the five VLMA on size-4 vectors by 10 VLMA on size-2 vector produces almost the peak 4 GFlops: 3.64 GFlops.

Assembleur ARM

Vous serez heureux d'apprendre que je commence à masteuriser l'assembleur ARM ! gcc a quand même un peu de mal à pondre du code optimal pour NEON , et le cortex-A9 n'est quand même pas un foudre de guerre. Donc au lieu de passer mon temps à rearranger le code C un peu au pif pour qu'en sortie gcc recrache de l'asm bien gaulé, je me suis décidé a faire directement de l'asm. Un bon exemple se trouve dans les sources de ffmpeg, il y a même une FFT dont je suis sûr qu'elle dépote les platypus.

Et le fait est que les instructions NEON sont largement mieux foutues que l'espece de truc bancal qu'est SSE, avec ses 8 pauvres registres 128 bits, ses instructions qui ecrasent toujours une des deux operandes, et son shuffle dont chaque utilisation donne l'impression d'être en train de résoudre un problème de rubik-cube. NEON c'est 16 registres 128 bits, qui peuvent etre manipulés comme 32 registres 64-bits, des instructions avec deux registres sources et un registre destination (comme altivec). Des instructions plutot claires et non ambigues (contrairements aux shuffle/unpacklo/unpackhi/movehl,movelh etc de sse). Des instructions load/store pas chiantes avec l'alignement , par defaut elles marchent sur des données non alignées sur 16-bytes, mais si on est sûr de l'alignement on peut leur donner un hint qui permet de gagner quelque chose comme 10% de vitesse. Pas sûr qu'on puisse encore considerer tout ça comme du RISC, par exemple : vld1 {q0,q1}, [r0,:256]! charge d'un coup 32 octets dans les deux registres q0 et q1 , avec un hint d'alignement sur 256-bits, et post-incrémente r0 d'autant. Du coup, sur les calculs qui sont assez soft avec la mémoire j'arrive à approcher les 2 GFlops sur un coeur de cortex A9 à 1GHz ce qui commence a être assez satisfaisant.

Pandaboard

Depuis une semaine j'ai une Pandaboard ! Contrairement au toshiba AC100 avec son tegra2 qui pue, celle-ci est basée sur le OMAP4 de texas instruments, qui a une unité SIMD NEON, comme tous les autres cortex A9 et le futur tegra 3. Le cpu dual core fonctionne a 1GHz, la carte mesure 10x12cm , actuellement elle tourne sous ubuntu 11.04 et consomme 4W (mais je ne suis pas sur du tout de la precision du wattmetre). En gros c'est de la boulette.

Optimization tip for SCons on cygwin

Do not build many Environment() ! build one, and clone it when you need it. Each time Environment() is built, it prepares for the "mingw" tools, and this calls "gcc --version" and "g++ --version". On cygwin, where forking is extremely slow, this can take ages.

Python

python vient d'être élu Best Programming Language par les lecteurs du Linux Journal.

Ahhhh python....

def python_is_ok(s='do not sux'):
        print s
        s='sux'

def python_sux(l={}):
        if 'sux' in l:
                raise Exception('python sux')
        l['sux']=True

python_is_ok() # ok..
python_is_ok() # ok..

python_sux() # OK...
python_sux() # fail..

outputs:

do not sux
do not sux
Traceback (most recent call last):
  File "sux.py", line 13, in <module>
    python_sux() # fail..
  File "sux.py", line 7, in python_sux
    raise Exception('python sux')
Exception: python sux

Ok, ce comportement bizarre est indiqué dans le tutoriel de python, n'empeche que c'est louche.

A not so minimalistic OSC library

Finalement j'ai trouvé une utilité à oscpkt, ce n'est pas l'usage que je prévoyais quand j'ai commencé mais ça ma donné l'occasion de fignoler un peu le truc, de le rendre cross-plateforme (pour la partie sockets) et d'y ajouter le pattern matching sur les chemins OSC. J'ai aussi agrémenté la homepage avec une image de Troy McClure.

Ultra minimalistic OSC library

oscpkt , si ça peut servir à quelqu'un faites vous plaisir.

Quick comparison of the ARM Cortex A9 and Intel Atom

Here are two small benchmarks that I have just run on an Intel Atom N270, running at 1.6GHz, and a ARM Cortex A9 castrated by nvidia (the neon unit has been ablated in tegra2). The arm is a dual-core cpu running at 1GHz. Both are running ubuntu, the compiler used being gcc 4.4.

First bench: compilation of a very large (250000 lines) c++ file. This stresses the cpu and memory, but not the swap (the ARM one does not even have any swap). The compilation consumes ~300MB. This is of course a single-threaded test.

  • Atom: 1m15 sec.
  • Cortex: 1m49 sec.

That is a ratio of 1.44. gcc 4.4 on the Atom is much faster than on the cortex A9 (this is the gcc version of ubuntu maverick, so it is built for ARMv7).

The second test compares the anemic VFP floatting point unit of the Cortex A9 with the old Atom fpu. This is a typical linear system solve, in double precision, with pretty straighforward scalar code without any specific optimization or tricks, repeated 100 times. Standard compiler optimisations ( -O3 -ffast-math , with also -mfpu=vfpv3-d16 -march=cortex-a9 for the ARM)

  • Atom: t=4.68 sec.
  • Cortex: t=6.16 sec.

The ratio is 1.31 , so basically the same as the gcc compilation bench. Clock for clock, the cortex is slightly faster than Atom, but the Atom has a higher clock. And it still has its ballsSIMD unit, which will allow any Atom to humiliate the tegra2 cpu in any single precision floating point benchmark.

ARM d'honneur

Je commence à regarder la documentation de NEON, l'unité simd des ARM Cortex A8 et supérieurs. Il n'y a pas encore des masses de docs "accessibles" à ce sujet, pas évident de trouver des tutoriaux de la qualité de ceux qui existent pour Altivec ou SSE. On trouve quand même une série d'articles très interessants sur blogs.arm.com:

Et franchement après avoir lu ça on ne peut qu'éprouver un sentiment de gêne pour Intel et son SSE tellement rustique qu'il fait figure d'idiot du village (le village des instructions simd). Car oui, NEON n'est pas psychorigide sur les questions d'alignement mémoire (et c'est *tellement* chiant avec SSE, et un peu chiant avec altivec). Il est aussi capable d'opérations de shuffling très avancées, avec la possibilité, en une seule instruction, de charger, désentrelacer jusqu'à 4 vecteurs 64 bits ET de post-incrementer le registre d'adresse d'une valeur abitraire. Take that, SSE. Et enfin il propose un nombre de registres raisonnable, càd 32 registres de 64 bits, qui peuvent aussi être manipulés comme 16 registres de 128 bits (chez intel: 8 registres de 128 bits en mode 32-bits, 16 registres en mode 64-bit; chez altivec: 32 registres de 128 bits). On peut aussi remarquer que neon a une operation de multiply-add, le genre de trucs que intel n'a pas mis dans SSE, ni dans SSE2, ni dans SSE3, ni dans SSSE, ni dans SSE4v1, ni dans SSE4v2, mais dans AVX (celui des futurs Sandy bridge). Et enfin, les instructions neon ONT trois opérandes: deux termes sources, une destination. Comme altivec, et contrairement à SSE. Là aussi ça permet d'économiser des tonnes de MOVAPS stupides dont la seule raison d'être est d'éviter d'écraser la précieuse valeur d'un registre. C'est encore un domaine où Intel a fini par voir la lumière puisque AVX aura des instructions à trois opérandes.

Voila voila, donc après avoir lu tout ça je me décide, avec entrain, à faire quelques tests puisque j'ai reçu un Toshiba AC100 en début de semaine, le premier netbook à base de ARM Cortex A9 (parfum tegra2), justement pour tester neon. Un netbook fourni avec android, et sur lequel je me suis quand même bien fait chier à installer une ubuntu (c'est pas facile). Et là paf, quand je lance les programmes de test c'est "Illegal Instruction" sur la première instruction neon rencontrée. Bizarre. Effectivement le /proc/cpuinfo ne fait aucune mention de neon .

Et pour cause puisque ces gros tocards de nvidia n'ont pas implementé l'unité NEON dans tegra2. Je l'ignorais.

Je vais donc maintenant frapper ce netbook avec un marteau jusqu'à ce qu'il ne reste plus que quelque misérables copeaux que je balancerai aux chiottes, je tirerai la chasse, puis j'irai me coucher.

malloc lent

Le malloc de macos a la réputation d'être relativement pas rapide, et je viens de le constater sur un petit bout de code, qui passe la majeure partie de son temps à faire du malloc/free (vérifié avec Shark). Sous Snow Leopard, il met 14s à s'executer, alors que sous linux (dans une VM tournant sous macos), le même code, avec une version similaire de g++ et les mêmes optimisations, ne prend plus que 9s , ce qui fait une différence somme toute assez significative ! Voilà qui est édifiant.

xmodmap

Steve jobs est un génie, mais le coup de faire des claviers differents ça n'est pas à 100% une super idée. En particulier quand on veut faire tourner linux ou windows sur un mac. Comme j'ai encore passé un temps dingue a essayer d'avoir un clavier apple qui se comporte a peu prêt correctement sous linux (et qui permet en prime d'avoir le middle-click avec le clavier), voici le .Xmodmap auquel j'ai abouti:

! dans le xorg.conf je pars de : XkbModel macintosh , XkbLayout fr
! curieusement les touches @# et <> sont inversees
! en prime , j'assigne le middle click a 'ISO_Level3_Shift-<'
keycode  94 = at numbersign periodcentered Ydiaeresis periodcentered Ydiaeresis
keycode  49 = less greater lessthanequal greaterthanequal Pointer_Button2 Pointer_Button2
! je remplace le dead tilde par un tilde pas dead
keycode  57 = n N asciitilde dead_tilde asciitilde dead_tilde
! fait en sorte que les deux touches 'option' fonctionnent comme sous mac
keycode 64 = ISO_Level3_Shift
! utilise la touche 'command' en tant que alt/meta
keycode  115 = Alt_L Meta_L
! je vire les nobreakspace parce que ca pue
keycode  65 = space space space space space space

! pas trop compris la... 
remove mod1 = ISO_Level3_Shift
add mod1 = Alt_L

Ôde à mondorescue

Je voulais clôner une debian Lenny installée dans un petit boitier sur un virtualbox tournant sur le mac. On m'a suggeré que Mondo Rescue pourrait être l'outil idéal pour effectuer la transplantation, et il s'est avéré que c'était vrai. Pas besoin de lire 300ko de man page , pas besoin de comprendre des concepts compliqués, on le lance, il pose quelques questions basiques et hop, les partitions de la machine originale sont compressées (avec bzip2, pouah) et backupées dans des fichiers .iso de 4Go. Je les copie sur le mac, créé une machine virtuelle dans virtual box, monte la premiere iso et boote la VM, et hop c'est parti, la debian est clonée dans la VM. C'est tellement chouette et simple que ça m'a inspiré un haiku au nombre de syllabes incertain:

Mondo Rescue,
Tu me laisses
Sur le cul

Cross-compiler en 32-bit sur une debian 64-bit

Un truc que j'aime bien sur le mac c'est la facilité avec laquelle on compile pour du i386, du x86_64, ou du ppc, voire ppc64 (pour celui là c'est fini depuis Snow Leopard, macos 10.5 a été la seule version qui permette de compiler pour ces 4 architectures). Sous windows, avec visual c++, c'est pas super commode mais MS fournit des platform SDK pour i386 et x64 qui sont suffisants (y'a un milliard de dlls là dedans). En plus aussi bien windows que macos savent executer n'importe quelle appli 32-bit sur la variante 64-bit de l'OS. Par contre sous linux, quand on choisit d'installer une distro 64-bit, c'est qu'on a decidé de bannir le 32-bit (qui pue), parce que le 64-bit saitrogénial. Donc par défaut les paquets du genre ia32-libs ne sont pas installés. Les users ne peuvent pas executer simplement n'importe quelle appli 32-bit sur leur gentoo hyper tunée pour aller trop vite parce que les libs sont manquantes. Et c'est la croix et la bannière pour mettre en place un environnement qui permette de compiler des applis non triviales en i386 sur la distro x86_64. En tout cas moi j'ai pas mal galéré mais comme c'était il y a un bout de temps, sur une debian Lenny, j'ai oublié, du coup je vais noter ici un ou deux trucs pour m'en souvenir.

Le probleme, c'est que ia32-libs et ia32-libs-gtk ça ne fournit qu'un sous ensemble des libs qu'on peut avoir besoin d'utiliser... Par exemple, y'a pas libasound (ALSA), c'est ballot. Y'a pas liblo non plus. Etc. Alors comment qu'on fait ?

Dans l'ordre des trucs que j'ai essayé je crois que j'ai tenté l'approche "je compile le cross compilateur, qui va cross-compiler toutes les libs dont j'ai besoin", tout ça sur un core 2 solo 1.2GHz sous-ventilé autant dire que ça a vite tourné à l'échec critique.

Ensuite j'ai mis en place un chroot dans lequel j'ai installé une debian 32-bits, super pénible, pas pratique (faut chrooter pour aller compiler en 32-bit). Mais ça marche et j'ai utilisé cette méthode pendant un certain temps.

Et puis finalement la methode qui marche et qui est relativement pratique, c'est juste de telecharger les .deb i386 à la main, et de les decompresser directement dans /emul/ia32-linux . Par exemple pour liblo:

wget http://ftp.debian.org/debian/pool/main/libl/liblo/liblo0ldbl_0.23-2.2_i386.deb
dpkg -X liblo0ldbl_0.23-2.2_i386.deb /emul/ia32-linux

(et pareil pour le paquet liblo0-dev )

Et ça roulaize.

Processor preferences pane

Je croyais que le panneau de preferences de Tiger qui permettait d'activer ou pas des coeurs du CPU (ainsi que l'hyperthreading) avait disparu lors du passage à Leopard. Et bien que nenni ! Il suffit de l'installer depuis les outils developeurs, il est dans /Developer/Extras/PreferencePanes/Processor.prefPane/ . Truc bizarre, il marque "Unknown Processor" au lieu de Core i7

Noël

Hier j'ai reçu un bel imac 27 pouces core i7, ça poutre un max. C'est mon cadeau de noel que je me suis fait. Par contre en terme de chaleur c'est assez impressionnant, en fait la machine à la forme, et quasiment le dégagement de chaleur, d'un convecteur electrique. Manifestement l'electronique à l'interieur n'est pas en train de cramer, le cpu est à 60° mais on sent que ça produit de la chaleur, même quand on met la main à 10cm devant l'écran. Le micro clavier qui est livré avec est très exigeant en termes de qualité de bureau, je viens de realiser que le mien n'est plus parfaitement plat du coup le clavier est bancal c'est assez désagréable. Et j'ai presque l'impression que l'écran est trop grand, je parcours des kilometres à la souris et je trouve qu'elle n'avance pas assez vite :/

Avoiding objective-c class name conflicts with brute force

The issue is described here : there is no way to control the visibility an objective-c class, and in a plugin context where many plugins might embed variations of a unique library that means conflicts, and ugly crashes. The usual solution, as far as I understand, is just to append some prefix to your own class names. And if you build more than one product, make sure that this prefix is unique for each product. Other solutions are listed here : shared framework, or building classes at runtime but I don't want to consider them for now. So I suggest another solution, which is a brutal but efficient variation of the unique prefix appended to obj-c class names: just append a specific prefix to the names of all you obj-c classes names , lets say "BALAI_BROSSE". Compile your products as usual. And then, for each product, generate a random string of the same length, let's say "OIETDKFJKDSF" , and just do a binary search & replace on the compiled binary, replacing all occurences of BALAI_BROSSE with OEITDKFJKDSF. This step (generating the random string and doing the binary search&replace) can be easily integrated into the build process.

The program I am using to do that is here: binrepl.cc. But feel free to find it dumb and ugly, I'm sure it can be done in one line of perl.

And apparently it works perfectly , I'm not getting anymore the Class Foobar_BALAI_BROSSE is implemented in both foo0 and foo1. One of the two will be used. Which one is undefined. warnings . Which is great.

Déçu par le packagemaker de macos

Le packagemaker c'est l'appli qui permet de fabriquer des installeurs pour macos. Par le passé on ne pouvait pas faire grand chose en ligne de commande, mais maintenant c'est mieux et on peut creer des packages sans dégainer la souris et aller traffiquer dans la gui.

Par contre quand je compare la taille d'un package generé sous macos et celle du même installeur sous windows (fabriqué avec NSIS), la version mac est notablement plus grosse. J'avais mis ça sur le compte des fat binaries puisque la version mac embarque aussi des binaires ppc, mais il semblerait qu'il y ait aussi une autre explication: la compression de packagemaker juste pue. C'est du gzip des année 30. Si je compresse les fichiers du package avec lzma je me retrouve avec une archive 18Mo , alors que le mpkg pour les mêmes fichiers occupe 25Mo :'(

Ainsi j'en appelle à Steve Jobs pour qu'il fixe ça au plus vite ! Merci d'avance !

La dure vie du plugin

C'est pas tous les jours facile d'être un plugin. Le probleme principal du plugin c'est les autres. Parce qu'il n'est pas chargé seul, il est chargé en même temps que d'autres plugins plus ou moins bien elevés, et il doit partager le même espace mémoire qu'eux. Du coup quand un plugin débile commence à faire n'importe quoi et à pourrir le heap, ben c'est pas forcement lui qui plante et qui est accusé d'être buggé. C'est pas non plus toujours facile de convaincre l'auteur du plugin moisi que le bug est de son coté et pas du mien. Et ça ne fait pas non plus toujours plaisir de perdre du temps à aller identifier et corriger les bugs des autres. Bref.

Mais il n'y a pas que l'espace mémoire qui est partagé. Bien souvent, les plugins executent une partie de leur code sur les même threads (cad sequentiellement, l'un après l'autre sur le même thread et pas en parallele). Et ça c'est la porte ouverte à plein d'effets de bords merdiques.

Donc aujourd'hui, l'effet de bord merdique c'est quand un plugin s'amuse à modifier les flags du FPU et a les laisser dans un état completement naze. Par exemple , en construisant sa GUI avec Direct3D: http://blogs.msdn.com/tmiller/archive/2004/06/01/145596.aspx . Car le FPU x87 a un super mode qui force la precision de tous les calculs à 24 bits (cad la simple precision) au lieu de 53 bits (double precision) habituels. Et là c'est le drame, les systèmes linéaires pas trop bien conditionnés commencent à renvoyer des solutions vraiment très fausses, les fonctions exp() etc du runtime c++ commence à devier mechamment , le toolkit de la gui perd completement les pedales et oublie de raffraichir des bouts de gui, affiche une lettre sur deux etc..

j'ai un eeepc

J'ai un eeepc. C'est plutot moche et ça fait un peu cheap, par contre l'autonomie est sympathique.

visual c++ : sux

Bon j'en ai marre de lire un peu partout que gcc est mauvais et que msvc est un excellent compilateur (pareil pour icc). En tout cas pour ce qui concerne le SSE msvc est juste une bouse abominable qui ne sait pondre que du bloat bien lent. Et mon experience est que gcc est presque toujours meilleur que icc sur du code contenant des intrinsincs SSE, malgré toutes les options bling bling de ce dernier. Ca fait plaisir de voir que c'est confirmé ici: http://www.liranuna.com/sse-intrinsics-optimizations-in-popular-compilers/

Stupid script of the day

Here is a python script that I use to invoke the cl.exe compiler (microsoft visual c++) from the cygwin command line. It automatically rewrites the cygwin paths as native windows paths, and replaces the ugly '/foo' options of cl.exe with nice '-foo' options . It is very minimalistic, it could do much more such as trying to map much more gcc-like options to their msvc equivalent ( "-fno-exceptions" with "/EHsc" , "-g" with "/Zi" etc)

http://gruntthepeon.free.fr/cygmsvc

Mini coup de gueule contre std::sort

Aujourd'hui cher blog j'aimerais pousser un petit coup de gueule contre std::sort, dont le comportement n'est pas hyper developper-friendly quand on lui fourni une fonction de comparaison un peu buggée. Figure-toi cher lecteur que lorsque la fonction de comparaison n'est pas tout à fait un StrictWeakOrdering (genre elle renvoie a<b , b<c et a>c), le comportement du std::sort de la libstdc++ est tout simplement de partir en excursion hors des bornes du tableau qu'on est en train de trier. A l'arrivée ça crashe dur. Alors certes je ne doute pas que l'implementation de la libstdc++ est hyper-optimale et plus rapide que son ombre, néanmoins j'apprécierais qu'elle detecte quand la fonction de comparaison n'est pas coherente plutot que d'exploser en vol comme une grosse baleine en allant trier des elements qui ne sont pas dans le tableau. ça me fait râler parce que ça fait plusieurs fois que je me fais avoir par ce truc (oui j'ai du mal a écrire des StrictWeakOrdering sans bugs)

cpufreq sucks for audio

People doing real-time audio processing on Linux are generally very picky about details (real-time kernel with full preemption, fine-tuning or the IRQ priorities, ...). However I did not cross any document mentioning possible drawbacks of CPU frequency throttling. This feature is now available everywhere. Even my quad-core tower spends most of its time at 1.6GHz instead of 2.66GHz. My good old D800 laptop runs at 600MHz when it is idle, and jumps to 1.6GHz when it needs to. But the question is how fast does it transition from 600MHz to 1.6GHz ? This small program does measure it, using the TSC counter. Please note that this does not work on recent CPU as the TSC rate is no more equivalent to the processor speed (that is its rate is now constant).

And finally the result: on my single-core pentium-m, the max cpu frequency is reached after ~0.05 - 0.1 seconds on a desktop kernel (2.6.27) , and 25 ms on the "linux-rt" kernel . Definitively not a negligible latency. That means that if your audio processing load is not smooth, and you have bursts of cpu usage (for example when new notes are played on your great but cpu-hungry softsynth), then you will not be able to use 100% of your cpu, but only 600/1600*100 = 37.5% of its power ! Not great.

But maybe using threads with real-time (SCHED_RR) priority will help ? Just run the program with "-rt" argument. Now the latency is 1 full fucking second on the "normal" kernel, and +INF seconds on the linux-rt kernel !! Not great at all. Of course, cpufreq being a deamon, it has much less chances to get scheduled where a very high priority thread is consuming all cpu. Ok, that is not fair, so you can add a small usleep(10) in the main loop in order to leave it a chance to do its job (the "pthread_yield" is not enough, apparently). And then the latency is back to ~0.1sec on desktop kernel , but still >10sec on rt kernel.

As a conclusion, I would say that doing a 'cpufreq-set -g performance' when your audio software is running is certainly not a stupid idea. Especially on a single-core cpu where the cpufreq deamon is likely to be starved when things start to get hot.

Stripping dead code

Bloat is bad. Here is how to remove unused functions from your binaries:

  • On MacOS: really easy, just use the -dead_strip linker option, that Steve Jobs in his infinite wisdom, has invented for us. The -dead_strip_dylibs will also remove references to unused dynamic libraries.
  • On Linux: a bit more tricky. You have to compile the sources with the -ffunction-sections -fdata-sections , and then link with the --gc-sections flag.
  • On Windows, with msvc: you have to compile the sources with /Gy option ("enable function-level linking"), and then link with /OPT:ref /RELEASE

sin_ps en sse2

C'est l'heure de rendre hommage à msvc 2008 pour sa puxoritude. Le saviez-vous:

  • en mode 64 bits, visual c++ n'autorise plus l'assembleur inline. C'est peut être une bonne chose étant donné que bon nombres de dev windows ont tendance à pisser des kilometres d'assembleur tout pourri et non portable quand des intrinsics font le boulot mieux et plus portablement.
  • en mode 64 bits, visual c++ ne permet pas d'utiliser les fonctions MMX, eh oui ! Pourtant rien ne l'interdit en principe, c'est juste un choix débile de ms.

Ce qui m'amene à la raison d'etre de ce billet, la première mise à jour majeure de sse_mathfun.h ! Avec des bon gros bouts de code SSE2 bien filandreux inseré subtilement dans des #ifdef USE_SSE2, ce qui permet de compiler le susdit fichier avec le cl.exe 64 bits.

truc qui sux en c++

Bon j'en ai marre. Le truc qui me fait particulièrement chier avec le c++ ces derniers temps c'est ce genre de truc:

class Foo {
  virtual void quack(bool like_a_duck) const { cout << "miaou"; }
};

class Bar : public Foo {
  void quack(bool) { cout << "coin"; }
  /* RRRRAAAATAAAAAAIIIII J'AI OUBLIE LE CONST COMME UN
      GROS NUL ET LE COMPILO NE VA RIEN ME DIRE */
};

Ce que je voudrais, c'est pouvoir dire au compilateur cette fonction "quack(bool)" que je definis ici dans ma classe dérivée, c'est une fonction qui surcharge une fonction virtuelle "quack(bool)" définie dans une classe parente. Si tu ne trouves pas de fonction "quack(bool)" dans les classes parentes qui soit virtuelle, ça veut dire que j'ai fait une connerie (j'ai oublié un const, ou un & etc...) et je veux que toi, compilateur, tu fasses une erreur. Les fonctions virtuelles pures c'est bien gentil mais y'a des fois où elles ne sont pas pures et qu'on a quand même besoin de les overrider.

Un moyen d'annoter les fonctions qu'on override ça aurait l'avantage:

  • de documenter le code pour que je vois d'un coup d'oeil quelles sont celles qui sont des fonctions virtuelles overridées.
  • de vérifier que je ne me suis pas planté dans son prototype.
  • de m'économiser quelques heures de chasse au bug.

Sur codeproject y'a une tentative d'annotation des fonctions virtuelles mais c'est pas super élégant ... Y'a aussi un warning specifique dans g++ qui essaye de detecter ce genre de bugs mais c'est un truc heuristique et donc y'a des faux-positifs -> c'est de la merde.

Merging .text and .rdata on windows

Not sure that this may ever be useful to someone else, but here is how to merge the .text and .rdata of a windows PE file when compiling with mingw or cygwin. The msvc linker has a built-in option to do that

/MERGE:.rdata=.text

But the gnu linker do not provide such an option. Instead it relies on linker scripts. The following linker script "ld_script_merge_rdata_and_text.x" does the trick:

SECTIONS {
 .text : {
  *(.text)
  *(.rdata)
  *(SORT(.rdata$*))
}

I won't explain how it works because I don't really understand it /o\ there was some amount of trial and errors before I converged to this script. Here is an example of use (note that is just passed to the linker as an implicit linker script, the default linker script is not overridden):

echo 'int main() { printf("Quack quack !"); return 0; }' > quack.c
gcc -Wl,ld_script_merge_rdata_and_text.x quack.c && objdump -h a.exe

The output is:

a.exe:     file format pei-i386

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         000003a8  00401000  00401000  00000200  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE, DATA
  1 .bss          00000040  00402000  00402000  00000000  2**2
                  ALLOC
  2 .idata        00000188  00403000  00403000  00000600  2**2
                  CONTENTS, ALLOC, LOAD, DATA

Look mum ! no .rdata !

Tinypy

L'autre jour en feuilletant freshmeat je suis tombé sur tinypy. ça a juste l'air excellent, du python embarquable en 64k avec la vm et l'interpreteur, tout ça sous license MIT.. ça fait un bout de temps que j'ai envie d'embarquer un petit langage de scripting dans une appli pour faire des choses hyper-puissantes mais le problème c'est que je n'en ai pas besoin, et que je n'ai pas d'idées de choses hyper-puissantes :'(

Les regexp

Ken Thompson et Dennis RitchieComme j'avais besoin d'un petit code portable et pas trop lourd en dépendances pour matcher des regexp j'ai perdu un peu (beaucoup trop en fait) de temps à regarder comment ça marche et si je pouvais en écrire un qui soit minimal et rapide.

En gros il y a deux approches:

  • l'approche historique, qui est celle employée par Ken Thompson il y a plus de 40 ans, qui consiste à construire un automate a partir de l'expression regulière, et ensuite de lui balancer les chaines qu'on cherche à matcher et regarder ce qui en sort.
  • l'approche populaire, qui consiste a explorer de façon recursive l'arboresence de toutes les possibilités.

L'approche recursive est celle employée maintenant dans quasiment tous les moteurs de regexp. Et pourtant si on lit ce texte de Russ Cox , c'est un très mauvais choix: contrairement au NFA de Thompson, le temps de test d'une regexp un peu pathologique va exploser exponentiellement avec l'approche récursive, alors qu'avec le NFA la complexité maximale est garantie (linéaire par rapport au nombre de caractères dans l'expression regulière et dans la chaine à matcher).

The regular expression implementations used by today's popular tools are significantly slower than the ones used in many of those thirty-year-old Unix tools.



L'argumentaire de Russ Cox est très convainquant, du coup j'ai fait un petit code de regexp utilisant le NFA, en me disant que les quelques sacrifices à faire pour loger tout ça dans un automate valaient bien ces performances annoncées. Les sacrifices sont:

  • pas de backreferences du genre "(coin|pan)\1" pour matcher "coincoin" ou "panpan"
  • coût supplémentaire matcher les sous-expressions entre parenthèses (il faut ajouter des "tags" à chaque etat actif dans l'automate pour chaque groupe de parentheses)
  • coût supplementaire pour gerer les répétitions comptées "(coin){2,5}" (il faut remplacer ça par (coin)(coin)(coin)?(coin)?(coin)? dans l'automate)

Pour finir j'ai quand même voulu vérifier que mon code allait vraiment aussi vite qu'annoncé en le comparant à une version de réference: PCRE (perl-compatible regular expressions). Et là grosse deception.. D'accord PCRE explose sur des expressions débiles du genre matcher "a?a?a?a?a?a?a?a?a" avec "a", mais sur des regexp bien basiques il est généralement 3x à 10x plus rapide que mon implémentation :'(

OWNED

Rosetta

Rosetta c'est le translateur de code ppc vers x86 qui permet d'executer de façon totalement transparente des binaires initialement compilés pour powerpc sur les mac intels. Jusqu'à present je ne l'avais utilisé que via la gui mais hier je suis tombé sur ce blog qui explique comme l'utiliser en ligne de commande, et ça déchire !

Pour lancer un executable en ppc: /usr/libexec/oah/translate /path/to/ppc_program

Et encore plus fort, on peut debugger du code ppc: OAH_GDB=YES /path/to/ppc_program et à côté: gdb --oah suivi de la commande attach pid_of_ppc_program et hop

C'est génial.