Installer Debian sur un portable Asus X73SL

En voulant installer une distribution Linux sur un ordinateur portable de marque Asus, modèle X73SL je me suis heurté à plusieurs problèmes. ll m’a semblé intéressant de les consigner ici, avec les sources que j’ai utilisé pour les résoudres.

Les solutions que je vais donner ici peuvent probablement être appliquées à d’autres distributions Linux (Ubuntu, Fedora, etc) mais nécessiteront peut être un peu d’adaptation. Par ailleurs, il semblerait qu’Asus ai basé plusieurs modèle de portables sur la même carte mère, il se pourrait donc que ces solutions fonctionnent aussi pour les modèles X70, X71, X72, X73 (avec des lettres derrière cette dénomination, voir ici).

TL;DR

Pour les lecteurs (expérimentés ou non qui voudraient un solution rapide) voici le ajustements que j’ai fait :

  • La carte mère ne supporte pas le interruptions MSI, il faut les désactiver pour le noyau dans son ensemble et le driver nouveau en ajoutant les paramètres pci=nomsi et nouveau.config=NvMSI=0 à la ligne de commande du noyau. Soit en live au moment du boot, soit de manière permanente les ajoutant à la variable GRUB_CMD_LINUX en éditant /etc/default/grub, puis en lançant update-grub.
  • Le chipset ethernet SiS191 ne supporte pas un MTU supérieur à 1496, il faut donc éditer votre configuration réseau (par un menu ou une configuration NetworkManager) pour définir sa valeur à 1496

Point de départ

Mon objectif était d’installer une distribution Linux sur un vieux portable Asus (de 2009) histoire de lui donner une seconde jeunesse. Le PC est un Asus X73SL-TY024C avec la configuration suivante :

  • Intel Pentium Dual CPU T3400 @ 2.16GHz (1Mo de cache, bus à 667Mhz)
  • Carte mère avec un chipset SiS 671MX
  • 4 Go de DDR2 à 667Mhz
  • 2 disques dur SATA de 250 Go, 5400 t/min
  • GeForce 9300M GS
  • Controleur ethernet SiS191
  • Carte Wi-Fi AR5B91 (chipset Atheros AR928X) mini PCI-E

Je souhaitais au départ installer Ubuntu car elle a une joli interface qui aurait été facile d’usage pour un néophyte, mais il était impossible de démarrer l’installateur, l’écran restait noir après le passage de Grub (22.04 ou 23.04 même combat). J’ai donc décidé de me rabattre sur une Debian Bullseye (la version stable à l’heure où j’écris ces lignes). Cette fois-ci, l’installation se passe correctement. Je redémarre, passe Grub, je vois les premières lignes de logs du noyau, et ensuite plus rien, écran noir. C’est là que les problèmes commencent.

Dans les sections qui suivent, je vais détailler la méthode que j’ai utilisé pour isoler les problèmes, et les solutions que j’ai trouvé. Dans la suite de cet article je vais partir. du principe qu’une distribution (Debian) est installée et qu’elle ne démarre pas.

Ça démarre pas, je fais quoi ?

La première étape c’est d’arriver à cerner à quel moment le boot est bloqué. Dans mon cas, Grub s’affiche, je peux lancer Debian, il me dit :

Loading Linux 5.10.0-23-amd64 ...
Loading initial ramdisk ...

puis l’écran devient noir avec qui un curseur clignote en haut à gauche de l’écran. Plus tard un changement semble se produire sur l’écran, puis plus rien, tout reste noir. C’est donc à un moment, après le démarrage de Linux, que quelque chose coince.

Dans ce cas, la première étape c’est de désactiver un maximum de périphériques dans le BIOS. Sur ce modèle il faut redémarrer, aller dans le BIOS avec F2, puis Advanced et I/O interface security. On peut alors désactiver un maximum de périphériques en les passant de UNLOCKED à LOCKED. Ensuite on enregistre avec F10 et on redémarre.

Ensuite, il faut modifier (temporairement) la ligne de commande du noyau passée par Grub, de manière à laisser le noyau afficher des traces à l’écran, on saura alors ce qui se passe. Pour ça, au moment où Grub s’affiche et propose des options, il faut presser Control+X pour obtenir l’éditeur et retirer le paramètre quiet de la ligne :

linux	/boot/vmlinuz-5.10.0-23-amd64 root=UUID=[...] ro quiet

Ensuite Linux démarre, affiche des traces dans la console. Puis au moment de passer la console en mode frame buffer (console de haute résolution), l’image disparait de nouveau, et j’ai un écran noir. Il y a donc sans doute un problème avec la carte graphique ou son driver nouveau.

GeForce 9300M et Nouveau

Pour en avoir le coeur net, je redémarre, j’édite de nouveau la ligne de commande du noyau pour retirer quiet et j’ajoute nouveau.modeset=0 pour désactiver le remplacement de la console :

linux	/boot/vmlinuz-5.10.0-23-amd64 root=UUID=[...] ro quiet nouveau.modeset=0

Je redémarre et … miracle, j’obtiens une invite de login et je peux me connecter en tant qu’utilisateur root. Je décide de démarrer le serveur d’affichage (serveur X) pour voir ce qui se passe et dans le logs je trouve :

(EE) NVIDIA(GPU-0): The NVIDIA kernel module does not appear to be receiving
(EE) NVIDIA(GPU-0):     interrupts generated by the NVIDIA GPU at PCI:1:0:0. 
(EE) NVIDIA(GPU-0):     Please see Chapter 8: Common Problems in the README for additional information.

Le driver ne reçoit pas les interruptions ? En regardant la liste des options du driver nouveau j’ai remarqué un paramètres NvMSI :

NvMSI: Use MSI interrupts, on by default on the chipsets that support it

C’est exactement ce qu’il nous faut. En effet Un périphérique PCI-E n’est pas obligé d’utiliser les interruptions matériels (reliées directement au contrôleur d’interruptions du processeur) mais peut envoyer un message à travers le bus PCI-E pour faire générer un interruption par le contrôleur de bus. C’est ce qu’on appelle les Message Signaled Interrupts ou MSI. Or cette fonctionnalité n’a pas été introduite immédiatement dans PCI-Express, l’ordinateur étant un peu âgé, il se peut qu’il ne les supporte pas.

On peut donc modifier de nouveau ligne de commande du noyau depuis Grub pour voir si ça fonctionne :

linux	/boot/vmlinuz-5.10.0-23-amd64 root=UUID=[...] ro quiet nouveau.config=NvMSI=0

Un petit reboot et hop ça fonctionne, le gestionnaire de login graphique s’affiche ! Il suffit maintenant de rendre cette option permanente. Pour ça j’ai ajouté le paramètre à la configuration de Grub :

# vim /etc/default/grub
[...]
GRUB_DEFAULT=0
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="quiet"
GRUB_CMDLINE_LINUX="nouveau.config=NvMSI=0"
[...]

puis mise à jour de Grub :

# /sbin/update-grub
Generating grub configuration file ...
Found background image: /usr/share/images/desktop-base/desktop-grub.png
Found linux image: /boot/vmlinuz-5.10.0-23-amd64
Found initrd image: /boot/initrd.img-5.10.0-23-amd64
Found linux image: /boot/vmlinuz-5.10.0-21-amd64
Found initrd image: /boot/initrd.img-5.10.0-21-amd64
Warning: os-prober will be executed to detect other bootable partitions.
Its output will be used to detect bootable binaries on them and create new boot entries.
Found Windows Boot Manager on /dev/sda1@/efi/Microsoft/Boot/bootmgfw.efi
Adding boot menu entry for UEFI Firmware Settings ...
done

Après redémarrage tout va bien.

Un peu de réseau ?

Ethernet – SiS191

J’ai réactivé un par un les périphériques dans le BIOS et le problème suivant est apparu avec la carte ethernet SiS191. En effet, au bout d’un moment la connexion au réseau cesse de fonctionner, toutes les requêtes font des timeouts et le réseau devient inaccessible.

En cherchant des informations sur le support de ce chip dans Linux, j’ai découvert que ce chip a une taille maximum de MTU (Maximum Transmission Unit) de 1496 octets là ou Linux configure cette taille à 1500 octets par défaut. Ce qui fait que lorsqu’un paquet dépasse 1496 octets, la fin du paquet est tronquée, et le paquet envoyé sur le réseau est invalide. Le problème est documenté dans un bug sur le bug tracker du noyau Linux On peut vérifier le MTU défini pour une interface avec la commande :

# ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp0s4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 00:e8:4c:68:44:71 brd ff:ff:ff:ff:ff:ff
3: wlp2s0: <BROADCAST,ALLMULTI,PROMISC,NOTRAILERS,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 48:45:20:e1:0e:e7 brd ff:ff:ff:ff:ff:ff

Pour corriger le problème, il suffit de dire à NetworkManager (le gestionnaire de connexions) que toutes les connexions qui utilisent cette interface doivent définir un MTU à 1496. Pour cela on va créer un fichier de configuration :

# vim /etc/NetworkManager/conf.d/enp0s4-mtu.conf
[connection-enp0s4-mtu]
match-device=interface-name:enp0s4
ethernet.mtu=1496

Dans le fichier ci-dessus, n’oubliez pas de changer enp0s4 par le nom de votre interface ethernet. Puis on relance NetworkManager :

# systemctl restart NetworkManager

Wi-Fi

L’étape suivante c’est de ré-activer la carte Wi-Fi depuis le BIOS, et là c’est le drame. Lors du reboot, le système gèle pendant le démarrage, et impossible d’en sortir autrement que par un redémarrage à la dure.

La carte Wi-Fi installée dans le PC est une AR5B91 mini PCI-Express munie d’un chip Atheros qui est en théorie bien supportée par le driver ath9k. Le problème se situe donc sans doute ailleurs. Et en effet, la carte est elle aussi sur le bus PCI-Express, elle est donc soumise au même problème que la carte graphique : il faut désactiver le support des MSIs pour que cela fonctionne.

Il suffit de rajouter l’option pci=nomsi à la ligne de commande du noyau de la même manière qu’on l’a fait pour la carte graphique :

# vim /etc/default/grub
[...]
GRUB_DEFAULT=0
GRUB_TIMEOUT=5 GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="quiet" GRUB_CMDLINE_LINUX="nouveau.config=NvMSI=0 pci=nomsi"
[...]

# /sbin/update-grub
Generating grub configuration file ...
Found background image: /usr/share/images/desktop-base/desktop-grub.png
Found linux image: /boot/vmlinuz-5.10.0-23-amd64
Found initrd image: /boot/initrd.img-5.10.0-23-amd64
Found linux image: /boot/vmlinuz-5.10.0-21-amd64
Found initrd image: /boot/initrd.img-5.10.0-21-amd64
Warning: os-prober will be executed to detect other bootable partitions.
Its output will be used to detect bootable binaries on them and create new boot entries.
Found Windows Boot Manager on /dev/sda1@/efi/Microsoft/Boot/bootmgfw.efi
Adding boot menu entry for UEFI Firmware Settings ...
done

Un reboot, et le tour est joué !

Conclusion

Après cet ensemble de changements, le système fonctionne plutôt très bien. En revanche, on peut pas dire que l’installation soit aisée.

Références

MapReduce ? Mais qu’est-ce c’est ?

MapReduce est un schéma de développement (design pattern) proposé par Google en 2004 permettant de traiter de gros volumes de données de manière parallèle et distribuée (merci Wikipédia). D’accord, mais une fois qu’on a dit ça, on est bien avancés. Je vous propose, dans le contenu qui va suivre, d’aborder le problème de fond qui a mené à ce type de solution, et l’application de MapReduce sur un cas simple et que l’on peut se représenter.

Quel est le problème ?

Au cours des 20 dernières années, avec la croissance de l’usage d’internet et de ses applications, les volumes de données stockées, traitées a considérablement grossi. Au point où, pour les stocker, les transporter et les traiter, il n’est plus possible de le faire sur un seul serveur, localisé à un même endroit.

Les données des applications sont donc maintenant distribuées sur plusieurs machines, parfois sur plusieurs pays ou continents. Pour bien comprendre le problème, nous allons l’illustrer avec un exemple simple.

Imaginons une application qui permette de suivre la santé de ses utilisateurs. À ces fins elle conserve pour chaque utilisateur son poids et sa taille. Disons que l’on veut obtenir des données sur l’ensemble de nos utilisateurs, telles que le poids moyen, ou l’IMC moyen. Voici ce à quoi ressemble un utilisateur :

user {
    id: 8374702028476,
    name: "Pierre Ponce",
    weight: 78,
    height: 183,
}

Dans une petite application, ces utilisateurs sont stockés dans un SGBD relationnel dont nous avons l’habitude (tel que MySQL, PostgreSQL, Oracle, …). Les données sont donc dans une table, et l’on va opérer dessus en faisant des requêtes SQL sur l’ensemble ou un sous-ensemble du jeu de données. Il est très facile de compter le nombre de d’utilisateurs, obtenir la somme de tous les poids ou de toutes les tailles avec ce type de systèmes. On peut, par exemple, simplement calculer le poids moyen de l’ensemble de nos utilisateurs avec ce genre de requêtes. Je vous laisse me faire confiance, ou faire un tour du coté de SQL pour voir ce qui est possible.

Que se passe-t-il lorsque l’on veut faire ce type de traitement mais que les données sont distribuées pour des questions de volume, de proximité géographique ou de performances ? Comment utiliser les ressources parallèles de nos infrastructures pour accélérer ces traitements ?

On ne peut effectivement pas transférer toutes les données au même endroit pour faire ces calculs …

Quelques pistes

En se creusant un peu la tête on peut avoir une idée d’approche. Dans notre cas de poids moyen, il suffit de s’intéresser aux propriétés de la moyenne. Pour des utilisateurs A, B, …, F, le poids moyen se calcule de la manière suivante :

W_{avg} = (W_A + W_B + W_C + W_D + W_E + W_F) / 6

Mais on peut aussi le calculer de la manière suivante :

W_{avg1} = (W_A + W_B) / 2 \\ W_{avg2} = (W_C + W_D) / 2 \\ W_{avg3} = (W_E + W_F) / 2 \\ W_{avg} = (W_{avg1} + W_{avg2} + W_{avg3}) / 3

Ça commence à ressembler à un calcul distribué ça non ? Si on considère que les données de nos utilisateurs sont distribuées sur plusieurs serveurs, on peut tout à fait commencer par calculer une moyenne localement sur chacun, et ensuite terminer le calcul autre part. On a ainsi distribué le travail, et transféré peu de données à la fin. En conservant ça à l’esprit, on peut attaquer MapReduce.

Le principe de MapReduce

Le principe de cette méthode est d’appliquer deux opérations map() et reduce(). pour traiter le problème.

L’opération map() a pour but de nous aider à de découper le problème initial en sous problèmes plus petits et traitables en parallèle. Elle prend en général en entrée une donnée et produit un à plusieurs couples (clé, valeur) qui seront ensuite traités par reduce(). map() peut ainsi être réalisée simultanément sur un grand nombre de données, là où elles se trouvent.

Les données émises sont groupées par clés avant d’être fournies à reduce(), par exemple :

(key_1, "value_a")
(key_2, "value_b")
(key_1, "value_c")

deviendra :

(key_1, ["value_a", "value_c"])
(key_2, ["value_b"])

On peut alors appliquer reduce() sur ces nouveaux couples (clef, liste de valeurs) et pour chacun d’entre eux, et calculer une valeur finale. Là aussi, cette opération peut être réalisée en parallèle sur chaque couple. Nous allons voir une application dans les paragraphes suivants. Pour plus de détails sur la partie théorique, je vous invite à lire la publication de Google sur le sujet.

Application

Partons d’un ensemble de clients dont nous avons quelques informations corporelles, et nous souhaitons calculer l’IMC moyen de notre groupe d’utilisateurs. Pour rappel l’IMC se calcule de la manière suivante :

imc = \frac {weight_{kg}} {height_m^2}

Voici quelques utilisateurs :

{id: 7638, name: "Pierre",  height: 1.78, weight: 76},
{id: 5932, name: "Arthur",  height: 1.83, weight: 65},
{id: 213,  name: "Susanne", height: 1.65, weight: 58},
...

Voici l’implémentation de map() que nous allons appliquer :

map(Client c) {
    imc = c.weight / (c.height * c.height);
    // Emit is the classic way for map() to produce (key, value)
    emit("imc", imc);
}

Nous obtenons alors les couples suivants :

("imc", 23.99)
("imc", 19.41)
("imc", 21.30)

Qui seront transformés de la manière suivante avant d’être transmis à reduce() :

("imc", [23.99, 19.41, 21.30])

Voici l’implémentation de reduce() que l’on va appliquer :

reduce(key, values[]) {
    sum = 0;
    count = 0;
    for (v in values) {
        sum += v;
        count++;
    }

    // Emit is the classic way for reduce() to produce the final value
    emit(sum/count);
}

Le résultat de notre map/reduce est donc bien l’IMC moyen de notre ensemble d’utilisateurs.

Ici on voit bien que les map() sont exécutables en parallèle car les données en entrée sont indépendantes. Ils peuvent être exécutés sur les machines où sont stockées les données, et avec toutes les capacités de calcul disponibles localement. Par la suite, reduce() peut aussi être exécuté localement sur les résultats de map() collectés. Il faudra alors terminer le calcul de moyenne en récupérant les résultats de ce map/reduce. Mais devinez quoi ? Il ne reste que très peu de données à regrouper et calculer !

Pour creuser le problème, je vous invite à consulter les références listées ci-dessous, vous aurez ainsi plus de détails ainsi que des exemples d’implémentations.

Remerciements

À Ningyu Li qui a toujours soif d’apprendre et m’a obligé à mettre mes idées en ordre sur le sujet.

Références

Amplificateur Technics SU-V4 – Plus de son, le relai ne colle pas.

Depuis quelques années j’utilise un amplificateur Technics SU-V4 que j’ai récupéré dans le garage de mes parents. Après l’avoir dépoussiéré, nettoyé les contacts et changé quelques condensateurs bien gonflés, il a fourni de bons et loyaux services.

Amplificateur Technics SU-4v
Amplificateur Technics SU-V4

Puis récemment, il a cessé de fonctionner. Lors de la mise sous tension, tout semble s’allumer normalement mais on n’entend plus le « clic » du relai de temporisation/protection, donc impossible d’avoir du son.

Après quelques recherches j’ai déniché deux posts sur vintage-audio-laser.fr parlant du même problème et de quelques informations de diagnostique. Dans la suite de cet article, vous trouverez la méthode que j’ai utilisé pour diagnostiquer le problème et la réparation que j’ai fait.

D’après ce post [1], ce symptôme est assez courant quand l’un des deux circuit amplificateur STK-8050 est HS. Étant donné que ces circuits sont difficiles d’accès du fait des autres PCB et des refroidisseurs, et un peu onéreux, il est intéressant de savoir lequel des deux est hors service avant de procéder à un remplacement. Mais comment ?

Circuit amplificateur STK-8050.

Le plus simple est de mettre l’amplificateur sous tension, et de mesurer les tensions présentes sur les pattes du circuit. Le tableau et la photo suivants vous indiquent les tensions que vous devriez mesurer. Si vous obtenez des résultats sensiblement différents (de l’ordre du volt) et sur plusieurs pattes, vous pouvez le suspecter. Mesurer la tension entre le chassis et la patte du circuit en mettant la sonde « négative » sur le chassis.

+-------+-------------+-------+-------------+
| Patte | Tension (V) | Patte | Tension (V) |
+-------+-------------+-------+-------------+
| 1     | 46          | 9     | 0,6         |
| 2     | 0           | 10    | 1,0         |
| 3     | 0           | 11    | 1,2         |
| 4     | 0           | 12    | 1,4         |
| 5     | -46         | 13    | -1,4        |
| 6     | -1,2        | 14    | -2,0        |
| 7     | -0,6        | 15    | 0,9         |
| 8     | 1,2         | 16    | 2,0         |
+-------+-------------+-------+-------------+
Empattement du circuit intégré.

Une fois que vous avez identifié le ou les circuit(s) suspects, il faut valider votre hypothèse. Une fois de plus le post mentionné précédemment nous donne une solution. Il suffit de dessouder le circuit incriminé, le retirer du PCB (sans l’abimer au cas où), puis de mettre l’ampli sous tension. Si vous entendez le relai coller, c’est que vous avez visé juste.

Si le relai ne colle toujours pas il y a deux solutions : soit vous suspectiez le second circuit et il faut le dessouder également, soit la panne se trouve ailleurs.

Réparation

Une fois le circuit identifié, il faut le remplacer. Vous pouvez en trouver sur Ebay pour un prix entre 20 et 30 euros. Il existe également une petite entreprise française qui en vend pour environ 17 euros (INDIPC).

Je vous conseille de placer le composant dans son logement avec sa fixation avant de le souder. Placez-le sur le circuit imprimé, placez la fixation métallique et vissez là. N’oubliez pas de mettre un peu de pate thermique entre le STK et son radiateur, serrez raisonnablement pour que le STK soit bien appliqué contre le radiateur. Soudez ensuite chacune de ses pattes en faisant attention à ne pas en souder deux ensemble.

Avant de pouvoir utiliser l’amplificateur, il faut procéder à quelques réglages. Pour ceci il faut suivre la procédure décrite dans le manuel de service. Pour cela il vous faudra un multimètre pour mesurer un courant continu de l’ordre du mV. Voici la dite procédure :

Procédez soigneusement : attendez bien les 10 minutes de préchauffage et tournez les potentiomètres lentement, sans quoi vous risqueriez de griller le nouveau composant. Si vous ne voyez pas la tension évoluer, essayez de calquer la position de chaque potentiomètre sur le réglage de l’autre voie.

Une fois les réglages terminez, vous pouvez remettre l’amplificateur en fonction ! Félicitations 😉

Sources

  1. https://vintage-audio-laser.fr/viewtopic.php?t=2756
  2. https://vintage-audio-laser.fr/viewtopic.php?t=4458

Développeurs – Quelles questions poser durant un entretien d’embauche ?

Est-ce que je veux vraiment travailler dans cette entreprise ? ou Quelles questions poser durant un entretien ?

Ce post est la traduction d’un article en anglais que j’ai adoré. Il propose une série de questions à poser lors d’un entretien d’embauche en tant que développeur. J’aurai souhaité l’avoir lu avant mes précédents recrutement, et m’a été d’une aide précieuse pour mes entretiens en tant que recruteur. L’article original d’Elena est disponible ici.

J’ai pratiqué les entretiens d’embauche des deux côtés depuis un moment maintenant. En tant que candidate, pendant 9 ans, et en tant que recruteur – pour 90 entretiens.

J’ai donc décidé d’écrire les questions que je pose habituellement à l’entreprise dans laquelle je postule.

Ces questions m’aident à comprendre la culture d’entreprise, leur manière de faire et, si possible, le niveau de « maturité » des mes collègues potentiels. Habituellement, je pose ces questions à une personne technique – un développeur, au directeur technique ou à un chef d’équipe. Ils sont les personnes les plus proches du poste que je suis susceptible d’occuper, ils seront donc plus à même de me donner des détails que quelqu’un des ressources humaines.

Il est important de ne pas uniquement se concenter sur ce qu’ils vous répondent, mais aussi comment ils vous répondent. Soyez attentif à leur langage corporel, aux éventuels mensonges ou omissions volontaires dans leur propos. Par exemple, si quelqu’un vous dit « la qualité du code est très importante pour nous » mais semble hésitant ou évite votre regard, peut être que votre interlocuteur n’est pas tout à fait factuel.

Assurez-vous également de poser les questions les plus ouvertes possibles. Par exemple :

  • « Corrigez-vous les bugs ? » est une question fermée. Il est facile de répondre « oui, bien sûr » – ce n’est pas une réponse très intéressante.
  • En revanche, « Comment corrigez-vous les bugs ? » est une question ouverte. Cela oblige votre interlocuteur à répondre quelque chose de plus complet que « oui » ou « non ». Vous pourrez par exemple apprendre que l’entreprise a une équipé qualité ou non, écrit des tests ou non, préfère surveiller plutôt que tester, ou encore préfère la rapidité de livraison plutôt que la qualité, ou le contraire. Tous ces éléments ont de la valeur, et sont importants à connaître avant d’intégrer l’entreprise.

J’ai ajouté une icône de drapeau à côté de certaines questions : ⚑. Les réponses à ces questions peuvent, à mon avis, être rédhibitoires : selon leur réponse, je pourrai décider de refuser de travailler avec eux.

Vous pouvez évidemment poser vos propres questions en fonction de ce qui est le plus important pour vous. Vous avez certainement vos propres « drapeaux » en fonction de ce que vous cherchez. Cette méthode fonctionne très bien pour moi, mais vous pouvez l’adapter autant que vous le souhaitez.

Voici donc une liste de questions que je pose habituellement, organisées par grands thèmes.

Méthodes de travail et produit

Comment êtes-vous organisés ? Quelle méthode de travail utilisez-vous ? Pouvez-vous décrire un jour ou une semaine de travail de l’équipe ?

Comment est constitué l’équipe ? Combien de personnes ? Sur quels postes ?

Quelles technologies (stacks) utilisez-vous ? Comment avez vous choisi celles-ci parmi ses équivalents (concurrents) ?
Ici, je m’attends à ce que mon interlocuteur réponde quelque chose de raisonnable, réfléchi. Par exemple : « nous avons choisi cette techno parce que nous la connaissions déjà bien / nous l’avons déjà utilisé et elle fonctionne / nous l’avons soigneusement comparée aux autres et elle répond à notre besoin ». Si il répond « parce que c’est à la mode en ce moment/c’est ce que tout le monde utilise », c’est un drapeau ⚑.

Dans le cas où il répond : « on utilise les dernières technos » – Que signifie « dernière techno » et quels sont les avantages de procéder ainsi ?

Comment décririez-vous la qualité de votre produit ? ⚑
Une fois on m’a répondu : « notre code est parfait parce que j’ai l’ai écrit » ! C’est bien d’avoir confiance en soi, mais c’est aussi révélateur de la nature du travail d’équipe dans l’entreprise.

Faites-vous des revues de code ?
Oui je sais, c’est une question fermée. Mais si le sujet n’a pas été abordé dans la discussion sur la qualité du code, il est judicieux de la poser directement.

Comment gérez-vous la dette technique ?

Privilégiez-vous la vitesse de développement par rapport à la qualité ou l’inverse ? ⚑
Bien sûr, cela dépend de ce que vous attendez de l’entreprise. Si vous aimez le prototypage rapide vous vous attendrez à ce qu’ils fassent de même. Si vous êtes plutôt du genre la-qualité-avant-tout, vous attendrez une réponse différente.

Comment vous assurez-vous que votre produit fonctionne comme attendu ?
Comprenez : Comment testez-vous ? Comment surveillez-vous votre produit (monitoring, instrumentation) ? Comment communiquez-vous avec les clients ? Comment préparez-vous le développement des fonctionnalités ?

Quel est votre processus de livraison (release process) ?

Sur quel produit vais-je travailler ?
Plus de questions auto-centrées sont à la fin de cet article.

Relations client

Qui sont vos clients ?

Comment communiquez-vous avec vos clients ? Qui fait cela ? Comment collectez-vous leurs besoins, leurs retours ? ⚑
L’entreprise doit avoir des clients, ou au moins l’objectif d’en avoir. Autrement vous risquez de travailler sur quelque chose que personne ne va utiliser.

Comment donnez-vous des priorités aux tâches ?

Comment traitez-vous les retours et les demandes client ?
Ils doivent écouter les clients ! Ils doivent se battre pour satisfaire leurs clients ! Ils ne doivent pas uniquement considérer leur argent ou à l’inverse ne leur parler que technique. Si ils sont irrespectueux envers eux, c’est un drapeau ⚑ : votre interlocuteur n’est peut être pas si mature.

L’entreprise

Quelles sont les valeurs de l’entreprise ?

Comment définissez-vous et mesurez-vous le succès ?
Ils doivent l’avoir défini non ? Sinon comment peuvent-ils savoir qu’ils sont sur la bonne voie ?

Quels sont vos plans à long terme ?

Rétrospectivement, quelles erreurs avez-vous fait en tant qu’entreprise/département/équipe ? Qu’en avez-vous appris ?
Cette question peut sembler intrusive, mais vous apprendrez beaucoup sur l’entreprise et votre interlocuteur. Cela a encore plus de valeur si vous allez travailler avec votre interviewer, ou devrez lui rendre des comptes.

Comment vous assurez-vous, en tant qu’entreprise ou équipe, de travailler sur les bons sujets ?

Qui prend les décisions business ? ⚑

Qui prend les décisions techniques ? ⚑
Ce qui peut aussi être formulé : si un autre développeur et moi sommes en désaccord sur une implémentation quelconque, que va-t-il se passer ?

Ces questions de prise de décisions prennent de plus en plus d’importance à mesure que votre carrière avance. En tant que chef d’équipe, vous ne souhaiteriez probablement pas vous retrouver sans pouvoir de décision – pour quelles raisons vous embaucheraient-ils dans ce cas ?
Plus généralement, si toutes les décisions sont prises par une seule personne, ce n’est probablement pas une bonne chose. À l’inverse, si toutes les décisions sont prise collectivement, que se passe-t-il quand certains sont en désaccord ? Mieux vaut éclaircir le sujet.

L’humain

Décrivez la diversité de votre équipe ? Avez-vous des engagements concernant la diversité ? ⚑
Si votre interlocuteur n’a aucune idée de ce dont vous parlez, c’est un très mauvais signe en ce qui me concerne !
Posez cette question même si vous faites partie de la majorité. Vous aiderez les minorités en le faisant. Cela devrait aider les entreprises à aller dans la bonne direction. Une équipe équilibrée est au bénéfice de tous : le business, l’équipe, les majorités et les minorités.

Quel est l’équilibre travail/vie personnelle ?
Les employés font-ils des heures supplémentaires ? Souvent ? Pour quelles raisons ? Est-ce rémunéré ?

À travers ces réponses, recherchez une culture toxique ! Le « Nous sommes une grande famille » peut sembler attirant, mais en réalité vous avez déjà une famille, des loisirs, et d’autres engagements en dehors du travail. Ne les abandonnez pas juste pour un poste.

Comment les gens travaillent-ils en équipe ? Sur des postes équivalents (c.à.d. entre développeurs) ou sur des postes différents (c.à.d. entre développeurs et QA) ?
Je préfère les entreprises dans lesquelles poser des questions est encouragé, non répréhensible. Je pense également que le travail d’équipe créé un environnement plus sain : lorsqu’il est possible de discuter librement de tâches complexes avec quelqu’un, on avance bien plus vite. D’une manière générale, deux têtes valent mieux qu’une. D’un autre côté, si les réunions et les discussions sont trop nombreuses, cela pourrait être contre-productif.

Comment accompagnez-vous les débutants ?
Parfois ils n’ont pas de jeunes développeurs du tout – ce qui n’est pas très bon signe. Investir dans les jeunes et les aider à acquérir des compétences bénéficie à tout le monde : les séniors acquièrent des compétences d’accompagnement et transmettent la connaissance (ce qui réduit les goulots d’étranglement); les juniors apprenant beaucoup plus vite des compétences spécifiques.

Si je suis en désaccord avec quelqu’un ou que je suis harcelée de quelque manière que ce soit, que suis-je censée faire ?
C’est une questions particulièrement intéressante, surtout si votre interlocuteur est voué à être votre manager direct. Vous êtes alors en droit d’attendre un niveau de maturité élevé de leur part. Ils doivent être capable de comprendre qu’il y a un conflit, écouter toutes les parties et faire de leur mieux pour le résoudre.

Encouragez-vous la compétition interne ?
Ou si ils disent « nous aimons les défis/la compétition », qu’est-ce que cela signifie ?

Essayez de creuser le sujet : est-ce une concurrence saine, basée sur le respect et dans l’objectif de l’amélioration du produit et du process ? Quelques exemples seraient : « c’est ce qu’il y a de mieux pour l’équipe à l’instant t », « c’est ce que veulent nos clients », « comment pouvons nous améliorer le process ».
Peut être qu’ils ne parlent que de compétition technique : « comment améliore-t-on le passage à l’échelle », ou « comment améliorer les performances sur smartphones ».
Mais parfois « défis/concurrence » peut signifier que l’on va en permanence remettre en question votre professionnalisme ou vous mettre en défaut. « Ton code est pourri » ou « tes designs sont moches » sont des exemples typiques.

Comment gérez-vous le regard critique ?
Dans certaines entreprises, il est interdit de remettre en question les pratiques. D’autres sont pleines de personnes qui passent leur temps à se plaindre. Il doit y avoir un équilibre sain entre les deux.

À propos de votre interlocuteur

Dans quelle équipe et sur quel produit travaillez-vous ?

Aimez-vous travailler ici ?
Bien sûr, vous ne pouvez pas vous attendre à ce qu’il réponde qu’il déteste travailler ici et attend juste une autre opportunité pour partir. Mais vous pourrez peut-être voir une lueur dans leurs yeux si ils aiment ce qu’ils font.

Quelle est le dernier défi ou la chose la plus intéressante que vous ayez fait dans les 3 derniers mois ? ⚑
Ils vous ont probablement posé cette question, maintenant c’est votre tour. Regardez attentivement ce qu’ils considèrent comme intéressant.

Sur quel sujet souhaiteriez vous que l’entreprise consacre plus du temps ?
Voyez si ils mentionnent les technos, le produit ou les gens. Vous pourrez ainsi poser des questions sur les éléments manquants.

À propos de moi

Sur quoi vais-je travailler ?
Certaines entreprises embauchent pour leur équipe – dans ce cas ils vous le diront. D’autres entreprises embauchent pour l’entreprise dans son ensemble – vous pourriez finir dans n’importe quelle équipe, sans expérience préalable ou sur des sujets qui ne vous intéresse pas.

Quel niveau d’autonomie vais-je bénéficier ? Quelles décisions puis-je prendre ?
Encore une fois, plus vous avez de l’expérience, plus cette question est importante.

Qu’attendez-vous de moi dans les trois prochains mois ? L’année qui vient ?
Cette question montre si l’entreprise est prête à embaucher. Elle doit savoir ce qu’elle va faire faire à ses nouveaux recrutés. Ont-ils prévu un plan ? Une liste de responsabilités ? Vous saurez également si ils embauchent juste pour grossir et avoir l’air plus intéressant au prés des investisseurs.

Comment évaluez-vous les performances ? Mes performances ?

Qui sera mon manager ?
La réponse peut être très intéressante. Par exemple, une fois un directeur technique (CTO) qui m’interviewais m’a répondu que mon manager serait le président (CEO) de l’entreprise. Suite à cela j’ai eu beaucoup de questions à poser sur ce que faisait le dit CTO. Il est apparu qu’il n’avait pas vraiment d’autres responsabilités que celles d’un développeur standard, et qu’ils prenaient leurs décisions sur la base du code écrit et pas toujours en fonction du business. À mon sens, ils étaient trop junior pour être CTO.

Quelles sont mes perspectives professionnelles ? De carrière et d’avancement ?

Quel est la fourchette de salaire pour ce poste ? Les bonus ? Stock-options ? Congés ? Etc.
Cette question peut paraitre la plus importante. Et peut être qu’elle l’est. Mais ce sur quoi vous allez travailler, les gens avec qui vous allez travailler doivent aussi être pris en compte.

L’importance de poser les bonnes questions

Poser les bonnes questions vous aidera à prendre la bonne décision.

En premier lieu, elles vous montreront si c’est vraiment l’entreprise pour laquelle vous avez envie de travailler. Par exemple, une grosse entreprise qui n’accorde aucune importance à la diversité ou la résolution de conflits véhicule probablement une atmosphère toxique. Si ils n’accordent de l’importance qu’à la vitesse de livraison et n’ont aucun contrôle sur la qualité, vous en saurez plus sur le produit, la base de code et le management.
Bien sûr, vous êtes les plus à mène de savoir pour quelle entreprise vous voulez travailler. À vous de créer votre ensemble de questions et évaluer les entreprises sur ce qui compte le plus.

Ensuite, poser des questions leur montrera que vous êtes un professionnel qui n’est pas prêt à accepter n’importe quelle offre. Ils verront en vous une personne qui accorde de la valeur au temps qu’elle consacre.

Enfin, cela montrera que vous êtes intéressé par l’entretien et le poste. Une fois j’ai interviewé une personne qui n’avait qu’une seule question : si je connaissais la meilleure période pour visiter le musée de la maison d’Anne Frank (Je ne sais pas d’ailleurs, désolée – c’est toujours bondé). Après l’ensemble des entretiens, nous nous sommes rendu compte que le candidat avait posé la même question à tous les intervenants. Inutile de mentionner que le candidat n’était pas plus intéressé par le poste que par un voyage gratuit à Amsterdam.

Posez autant de questions que vous le pouvez. Plus vous aurez d’information, meilleure sera votre prise de décision.

Bonne chance pour votre prochain entretien !

Boot direct EFI sur Debian 10 (EFI stubs)

Contexte

Unified Extensible Firmware Interface (UEFI) est une spécification qui décrit une interface entre le firmware d’une carte mère et un système d’exploitation (OS). Il fait suite à l’Extensible Firmware Interface (EFI), originalement créée par Intel. Elle remplace progressivement le Basic Input Output System (BIOS) fourni à l’origine par les ordinateurs compatibles IBM PC.

Depuis quelques années, le fabricants de cartes mères fournissent des firmware compatibles à la fois avec UEFI et BIOS. Le noyau Linux, quant à lui, fourni les interfaces nécessaires pour être lancé directement par un firmware UEFI. Ce qui fait disparaître le besoin de boot loaders intermédiaires tel que GRUB.

Si vous n’avez pas besoin de ce fameux loader intermédiaire, parce que vous n’avez qu’un seul système d’exploitation par exemple, vous pouvez mettre en place le boot direct par UEFI. Dans ce qui va suivre, je vais décrire comment mettre en place cette configuration.

Configuration

Partition de boot EFI

La première étape à réaliser est de s’assurer que votre système est installé avec une partition de boot EFI lisible par votre firmware. Habituellement c’est une petite partition du disque située au début et formatée avec un système de fichier simple tel que FAT ou EXT2. Cette partition serra utilisée pour stocker le binaires compatibles avec EFI : soit votre GRUB ou le noyau Linux. Durant la phase de boot, l’UEFI va parcourir la partition à la recherche d’un binaire compatible. Voici un exemple du partitionnement sur ma machine :

# lsblk
NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sda           8:0    0 119.2G  0 disk
├─sda1        8:1    0   953M  0 part /boot/efi
└─sda2        8:2    0 118.3G  0 part /

Si vous n’avez pas ce genre de partition, vous devez en créer une, peut être en réinstallant votre système. Mais ceci est en dehors du cadre de cet article, vous pouvez trouver plus d’information à ce sujet ici.

Synchronisation des images

Pour pouvoir démarrer, l’UEFI doit pouvoir accéder à l’exécutable du noyau Linux et à l’image du ramdisk. Ce n’est possible que si ces deux éléments sont présents dans la partition que nous avons mentionné précédemment. Sur une distribution Debian, ces fichiers sont disponibles à la racine du système de fichiers ; nous aurons donc besoin d’un système pour les copier sur la partition EFI à chaque fois qu’ils sont mis à jour. Ainsi, après chaque mise à jour du système, le noyau et son ramdisk seront également mis à jour sur cette partition spéciale.

Sur le wiki de Debian EFI Stubs, la méthode proposée repose sur des scripts post installation pour le noyau et le ramdisk. Malheureusement, cela ne fonctionne plus sur la version Buster car le script post install pour initramfs (ramdisk) n’est plus disponible. Nous ferons donc cette mise à jour en utilisant les services systemd et ses déclencheurs basés sur la surveillance de fichiers. L’idée est de créer un service à exécution unique qui copiera le fichier. Néanmoins, au lieu de lancer le service au démarrage (ou autre évènement régulier), il sera déclenché par un changement sur le fichier que l’on surveille. En l’occurence le noyau et son ramdisk. Nous avons juste à le déclarer, et systemd fera le travail.

Le noyau

Allons-y : on commence par créer le service avec le fichier /etc/systemd/system/uefi-kernel-update.service :

# cat /etc/systemd/system/uefi-kernel-update.service
[Unit]
Description=UEFI Kernel update
After=network.target

[Service]
Type=oneshot
ExecStart=/bin/cp /vmlinuz /boot/efi/EFI/debian/

Ensuite on créé le déclencheur avec /etc/systemd/system/uefi-kernel-update.path :

# cat /etc/systemd/system/uefi-kernel-update.path
[Path]
PathChanged=/vmlinuz

[Install]
WantedBy=multi-user.target

Enfin on active le déclencheur :

# systemctl enable uefi-kernel-update.path
Created symlink /etc/systemd/system/multi-user.target.wants/uefi-kernel-update.path → /etc/systemd/system/uefi-kernel-update.path.
# systemctl start uefi-kernel-update.path

On peut tester que cela fonctionne correctement en faisant un  touch /vmlinuz et en vérifiant dans les logs de systemd que le service a été lancé :

# touch /vmlinuz
# journalctl -xn
Dec 14 18:14:18 fixe-damien systemd[1]: Starting UEFI Kernel update…
 -- Subject: A start job for unit uefi-kernel-update.service has begun execution
 -- Defined-By: systemd
 -- Support: https://www.debian.org/support
 -- A start job for unit uefi-kernel-update.service has begun execution.
 -- The job identifier is 2611.
 Dec 14 18:14:18 fixe-damien systemd[1]: uefi-kernel-update.service: Succeeded.
 -- Subject: Unit succeeded
 -- Defined-By: systemd
 -- Support: https://www.debian.org/support
 -- The unit uefi-kernel-update.service has successfully entered the 'dead' state.
 Dec 14 18:14:18 fixe-damien systemd[1]: Started UEFI Kernel update.
 -- Subject: A start job for unit uefi-kernel-update.service has finished successfully
 -- Defined-By: systemd
 -- Support: https://www.debian.org/support

Le ramdisk (initrd)

Répétons l’opération en créant un service et un déclencheur pour copier le fichier /initrd.img. Les fichiers sont fournis ci-dessous.

# cat /etc/systemd/system/uefi-initrd-update.service
[Unit]
Description=UEFI ignited update
After=network.target

[Service]
Type=oneshot
ExecStart=/bin/cp /initrd.img /boot/efi/EFI/debian/
# cat /etc/systemd/system/uefi-initrd-update.path
[Path]
PathChanged=/initrd.img

[Install]
WantedBy=multi-user.target

Enfin, on active le service et son déclencheur.

# systemctl enable uefi-initrd-update.path
Created symlink /etc/systemd/system/multi-user.target.wants/uefi-initrd-update.path → /etc/systemd/system/uefi-initrd-update.path.
# systemctl start uefi-initrd-update.path

N’oubliez pas de tester que cela fonctionne avec touch et journalctl.

Ajouter une entrée dans l’UEFI

Maintenant que nous sommes sur que le noyau et le ramdisk seront correctement mis à jour, il faut ajouter une entrée dans l’UEFI pour qu’il sache quel noyau lancer et comment.

Premièrement, il faut obtenir la ligne de commande du noyau (les paramètres qui lui sont passés) à partir de la configuration de GRUB. Dans le fichier /boot/grub/grub.cfg, cherchez le bloc menuentry ... { ... } qui correspond à l’entrée que GRUB utilise pour démarrer. Ensuite lisez ce bloc et cherchez la ligne linux /boot/vmlinuz..., elle nous indique les arguments passés au noyau au démarrage. Sur ma machine elle ressemble à ceci :

menuentry 'Debian GNU/Linux' ... {
  ...
  echo   'Loading Linux 4.19.0-6-amd64 ...'
  linux  /boot/vmlinuz-4.19.0-6-amd64 root=UUID=3c51b884-79b9-46f5-aff9-a2d8f68cd308 ro quiet
  echo   'Loading initial ramdisk ...'
  initrd /boot/initrd.img-4.19.0-6-amd64
}

Les arguments du noyau sont root=UUID=3c51b884-79b9-46f5-aff9-a2d8f68cd308 ro quiet. On peut maintenant utiliser efibootmgr pour ajouter une entrée dans l’UEFI, n’oubliez pas de mettre à jour la commande avec vos paramètres :

# efibootmgr -c -g -L "Debian (EFI stubs)" -l '\EFI\debian\vmlinuz' -u "root=UUID=3c51b884-79b9-46f5-aff9-a2d8f68cd308 ro quiet rootfstype=ext4 add_efi_memmap initrd=\\EFI\\debian\\initrd.img"

Si la commande échoue, vous aurez peut être besoin d’ajouter une option telle que : --disk /dev/nvme0n1.

Vous pouvez maintenant vérifier qu’elle a été ajoutée correctement :

# efibootmgr
 BootCurrent: 0008
 Timeout: 1 seconds
 BootOrder: 0008,0000,0009,0003,0001,0002,0004,0005
 Boot0000* debian
 Boot0001* Hard Drive
 Boot0002* UEFI:CD/DVD Drive
 Boot0003* CD/DVD Drive
 Boot0004* UEFI:Removable Device
 Boot0005* UEFI:Network Device
 Boot0008* Debian (EFI stubs)
 Boot0009* debian

La prochaine étape est le redémarrage ! Si tout s’est bien passé, votre machine devrait redémarrer et sauter le boot avec GRUB. Dans le cas où la configuration ne serait pas correcte, vous pourriez ne pas être capable de terminer le démarrage. Si cela arrive, vous pouvez toujours choisir manuellement l’entrée UEFI debian entry. Ainsi vous pourrez résoudre le problème.

Conclusion

Évidemment c’est essentiellement une réussite technique, car le temps passé dans GRUB lors du boot n’est pas excessif. Mais il était important pour moi de consigner cette procédure quelque part car j’utilise cette configuration tous les jours. J’espère qu’elle pourra servir à d’autres.

Par ailleurs, il y a des améliorations possibles. Par exemple, il serait pertinent de régénérer l’entrée dans l’UEFI lorsque la ligne de commande du noyau est mise à jour.

Sources

Multimedia : buffers dynamiques et gestion de latence grace au « inter-arrival jitter »

En travaillant sur le contrôle et la réduction de la latence dans une application multi-media temps réel, j’ai découvert que le premier problème que j’avais était du aux variations de latence introduites par le réseau. La principale difficulté a été d’arriver a estimer le désordre produit par le réseau sur un flux RTP entrant sans pouvoir utiliser RTCP ou n’importe que autre canal de feed-back. Dans l’article suivant, nous allons nous intéresser a la méthode que j’ai utilisé pour estimer le désordre et déduire une taille optimale de buffers pour les conditions courantes.

Contexte

Partons d’une application qui transmet un flux audio et/ou vidéo temps reel à un receveur. Par temps réel, on entend que le contenu envoyé peut être interactif, ne peut pas être envoyé à l’avance au receveur (un appel audio ou vidéo par exemple). Il faut donc trouver un compromis entre l’interactivité (une latence faible) et un contenu diffusé de manière fluide (une latence plus élevée du à l’usage d’un tampon).

La source émet un flux à travers le réseau en direction du receveur. Souvent le contenu encodé (compressé) est découpé en de petites « access units » qui seront encapsulées dans des paquets RTP et envoyées par UDP. Pour simplifier nous considèrerons que la source se contente d’envoyer un flux video en utilisant RTP par dessus UDP en direction de la cible.

La cible reçoit les paquets RTP sur un port UDP choisi aléatoirement, et les obtiens a travers une socket comme d’habitude. Tel que défini dans RTP, chaque paquet a un marqueur de temps (timestamp) qui décrit l’heure de presentation de l’access unit (consultez la RFC3550 pour plus de details sur RTP). Étant donné qu’une access unit peut être plus volumineuse que ce que peut contenir le paquet RTP, elle peut être découpée en de multiples paquets RTP. La manière de le faire dépend du codec utilisé. Pour éviter de complexifier nous considèrerons que le receveur a un assembleur qui délivre chaque access unit ré-assemblée avec son marqueur temporel.

Dans les paragraphes suivants, nous nous intéresserons aux access units et a leur marqueurs de temps avant/apres qu’il soit passe par le transport reseau. Cela revient quasiment a étudier directement les paquets RTP et simplifie le raisonnement, c’est donc une hypothèse raisonnable.

Le problème : réseau et references de temps

Du cote émetteur, les access units sont produites de manière régulière. Pour une vidéo a 30 images par secondes, l’encodeur produit en général une access unit toutes les 33 millisecondes (ms). En réalité cela dépend du codec, mais nous ferons avec. L’illustration ci-dessous montre un flux d’access units émises en suivant une période de 33 ms (30 images par secondes).

Image 1 : des access units produites régulièrement.

Si le réseau était parfait, nous devrions recevoir exactement le même flux (avec le même intervalle de temps entre les access units), mais décalé d’un délai du à l’emission, la transmission, la réception et l’opération d’assemblage (voir l’illustration ci-dessous).

Image 2 : délai de transmission dans un réseau parfait.

Mais dans le monde réel, le délai introduit par le réseau n’est pas constant. Il y a bien évidement un délai incompressible du au temps de propagation physique de l’information et au traitement des données, mais il y a aussi une part variable du à la congestion du réseau. Le véritable résultat a donc l’allure de l’illustration suivante.

Image 3 : delais dans le monde reel.

Chaque access unit est délivrée au receveur avec un délai relatif à son horloge de départ, qui varie en fonction des conditions du réseau. La latence d’une access unit peut être représentée comme suit :

\Delta_{frame}(n) = \Delta_{network} + \delta_n

Faisons un petit résume de la situation du receveur :

  • il reçoit un flux d’access units avec leur marqueur de temps,
  • les access units ne sont pas délivrées de manière régulière à cause de la congestion dans le réseau,
  • les conditions du réseau évoluent au court du temps,
  • la seule référence de temps disponible est le marqueur de temps disponible dans les paquets RTP.

Le défi est donc de trouver un moyen d’estimer la taille idéale de buffer (tampon) nécessaire pour jouer le contenu en minimisant l’impact des aléas du réseau tout en préservant l’interactivité.

Le « inter-arrival jitter » comme estimateur de l’état du réseau

Pour estimer la congestion du réseau, puis calculer une taille de tampon adéquate, nous avons besoin d’un indicateur. En cherchant des articles sur le sujet, j’ai trouvé le brouillon d’une RFC : Google Congestion Control Algorithm for Real-Time Communication. Cet algorithme déduit une « estimation du débit maximum du récepteur » (Receiver Estimated Maximum Bitrate ou REMB) en utilisant le inter-arrival jitter. Calculer un débit n’est pas exactement ce que nous cherchons mais il utilise uniquement les paquets RTP entrants et leur marqueurs de temps pour faire l’estimation. C’est déjà un bon point.

Inter-arrival jitter

Les marqueurs de temps des paquets reçus ne sont pas suffisants pour calculer la latence en valeur absolue de ce flux. Mais grâce à eux, nous avons une information de valeur : le délai théorique entre deux images qui se suivent. Il est équivalent au délai entre l’émission de deux images par l’émetteur. La différence entre ces deux marqueurs de temps T des images n et n-1 est nommé inter-departure time (délai inter-départs) et s’exprime de la manière suivante :

T(n) - T(n-1)

De l’autre coté, en tant que récepteur, nous pouvons enregistrer pour chaque image, son heure arrivée locale et calculer le délai t qui sépare deux images consécutives n et n-1. C’est ce que l’on appelle inter-arrival time (délai inter-arrivées) et s’exprime de la façon suivante :

t(n) - t(n-1)

Si l’on compare les délais inter-arrivée et inter-départ pour deux images consécutives, nous avons un indicateur de la congestion du réseau. Dans un réseau parfait il devrait être nul, en pratique il varie. On peut l’exprimer formellement comme suit :

J(n) = t(n) - t(n-1) - (T(n) - T(n-1))

Plus de détails sont disponible dans la RFC mentionnée précédemment.

Estimations

Observer le jitter est un bon indicateur de l’état du réseau car il représente la distance entre la situation idéale (le délai entre deux images au départ) et la réalité (le délai entre deux images à l’arrivée). Plus le jitter est éloigné de 0, plus le réseau est dérangé.

Le premier estimateur que l’on peut calculer est le jitter moyen. Il fourni une estimation du désordre au cours du temps, mais pour refléter correctement la réalité cette moyenne doit être glissante, avec une fenêtre de temps relativement courte. Dans l’implémentation de GCC dans Chromium, une moyenne glissante exponentielle est utilisée. Elle permet de conserver l’influence des échantillons mesurés récemment tout en lissant les fortes variations.

\alpha \text{ est le coefficient de la moyenne glissante} \\
J(n) \text{ est le inter-arrival jitter pour l'image } n \\
J_{avg}(n) \text{ est la moyenne glissante pour l'image } n \\
J_{avg}(n) = \alpha * J(n) + (1 - \alpha) * J_{avg}(n-1)

Le paramètre de lissage α doit être choisi en fonction du cas d’utilisation et de l’implémentation. Si l’on joue un flux à 30 images par seconde, une value de 0,1 pour α signifie que la moyenne s’applique sur 10 inter-arrival jitter, elle tient donc compte des 10 * 33ms = 330 dernières millisecondes.

La moyenne est un bon indicateur de départ, mais se révèle en fait relativement faible utilisé seul car elle est fortement sensible aux variations et ne fourni aucune véritable information sur la distribution du jitter. Pour être précis, on ne s’intéresse pas à la taille de buffer qui satisfait le jitter moyen, mais plutôt à celle qui permet de prendre en compte le jitter de la majorité des images. N’oublions pas que le but est d’avoir une expérience de lecture fluide de notre vidéo.

Nous cherchons donc un indicateur qui permette d’estimer une durée de buffer idéale afin de lisser l’impact du réseau pour la majorité des images. En disant cela on se rapproche de la solution : il nous faut un taille de buffer associée à un intervalle de confiance. En calculant l’écart type σ à partir des jitters mesurés, nous pouvons construite un intervalle autour du jitter moyen qui nous fournira la durée de buffer idéale pour 68% (la moyenne plus σ), 95% (la moyenne plus 2σ) voir même 99,7% (la moyenne plus 3σ) des images entrantes. Pour en savoir plus sur l’écart type et les intervalles de confiance, rendez-vous ici.

Nous pouvons donc calculer calculer une variance mobile sur les jitters en utilisant la moyenne exponentielle :

V(n) = \alpha * (J_{avg}(n) - J(n))^2 + (1 - \alpha) * V(n-1)

Puis en déduire l’écart type :

\sigma(n) = \sqrt{V(n)}

Prenons un exemple ! Après quelques secondes de streaming, le jitter moyen est de 15 ms et l’écart type de 37 ms. Si l’on considère un intervalle de confiance de 3σ, le calcul de la durée optimale du buffer est :

D_{buf}(n) = J_{avg}(n) + 3 * \sigma(n) = 15 + 3 * 37 = 126 \text{ ms}

En utilisant cette durée de buffer, nous savons couvrir 99,7% du jitter des images. Cette durée peut être ré-estimée régulièrement au cours du temps afin de toujours conserver le délai optimal. Ce faisant, la latence est conservée à sa valeur minimum tout en préservant une expérience de lecture fluide.

Conclusion

Calculer quelques indicateurs à partir du inter-arrival jitter est le procédé le plus simple que j’ai trouvé dans la littérature au cours de mes recherches sur le sujet. Il permet de fournir une expérience de lecture fluide tout en préservant une latence minimum. Il requiert, par ailleurs, peu d’information en entrée pour un indicateur fiable.

Remerciements

  • Tristan Braud pour m’avoir aidé à comprendre les concepts derrière le jitter et les statistiques menant au calcul de taille de buffer.
  • Rémi Peuvergne  pour ses conseils sur l’article et ses illustrations.

Références

Voyager au Japon, un peu de logistique !

Nous avons récemment voyagé au Japon par nos propres moyens et, même si l’organisation est assez simple dans ce magnifique pays, je me suis dit que partager quelques informations sur le coté logistique pourrait toujours être utile ! Dans la suite de cet article je vais partager avec vous les moyens de transport que nous avons utilisé, les astuces et petites choses à savoir pour que votre voyage se déroule tout en douceur.

De l’aéroport de Narita à Tokyo

Notre vol depuis Paris atterrissait à l’aéroport de Tokyo – Narita. L’aéroport est assez commode puisqu’il est desservi par plusieurs lignes de train qui vous permettrons de rejoindre Tokyo, nous avons utilisé deux des trois que je vais indiquer ci-dessous.

  • Keisei Skyliner, c’est la ligne la plus rapide pour relier l’aéroport à Tokyo (environ 40 minutes) mais c’est aussi la plus chère : environ 2.470¥ (~19€).
  • Keisei local, c’est la ligne que nous avons pris en arrivant, elle est beaucoup moins cher (1.240¥ soit presque 10€) mais elle met plus de temps (70 minutes) pour relier Tokyo. Nous avons acheté notre billet à un ficher Keisei de l’aéroport et nous sommes descendus à la gare de Ueno.
  • JR Narita Express (N’EX), elle est rapide (moins d’une heure) et particulièrement économique quand on a le JR Pass car sans frais supplémentaires. Elle est plus compliquée à prendre depuis l’aéroport puisque ses trains peuvent prendre des directions différentes : certains désservent les gares de l’ouest et du nord, d’autres se dirigent vers le sud. Néanmoins ils passent tous par la gare de Tokyo. Attention pour voyager sur cette ligne, vous devez réserver votre place à bord du train. Vous pouvez le faire au guichet juste avant de le prendre (en arrivant après votre vol) mais le risque existe qu’il soit complet. À titre d’information, c’est la ligne que nous avons pris le jour du départ depuis la gare de Tokyo vers l’aéroport, il nous était facile de réserver nos place auparavant.

L’agence Japan Rail (JR East Travel Service Center) et les guichets des lignes Keisei se trouvent au premier sous sol du terminal 1 de l’aéroport (étage B1F).

Astuce : l’un des avantages des trains au Japon c’est que les lignes ont des noms et des couleurs. Pensez à repérer ces informations sur les plans ou demandez les au guichet, vous pourrez ainsi les utiliser pour suivre les panneaux indicateurs, même si ils sont écrits en japonais !

Le site Kanpai décrit très bien les différents modes de transport disponible depuis l’aéroport, n’hésitez pas à le consulter : Kanpai – Comment rallier Tokyo depuis l’aéroport de Narita ?.

Se déplacer dans Tokyo

Tokyo Metro

Le métro de Tokyo est particulièrement bien déployé et facile d’utilisation. Il existe 9 lignes identifiées par un nom, une lettre ainsi qu’une couleur. Les stations sont numérotées et représentées par la lettre de la ligne ainsi que son numéro, cerclé dans la couleur de la ligne. Cette page (Wikipédia) vous donne un aperçu du réseau et des noms de lignes. Si vous comprenez ce schéma, vous serez capable d’assurer vos correspondances dans les stations et de savoir facilement quel quai prendre.

Par exemple la ligne Marunouchi est représentée par un M cerclé de rouge. La station Shinjuku est désignée M8. Si vous êtes dans cette station et que vous souhaitez aller à la gare de Tokyo (station M17), trouvez les quais de la ligne en suivant le M cerclé de rouge. Puis choisissez le quai indiquant M9-M25. Gardez le nez en l’air ou sur les poteaux, les indications se trouvent à ces endroits.

Comment payer ?

Il existe deux solutions, l’argent liquide ou les « IC cards ». En argent liquide ce n’est pas très compliqué mais un peu fastidieux, vous devez d’abord estimer le prix de votre trajet en regardant les plans et la grille tarifaire, puis acheter un ticket de la valeur correspondant sur un automate. Ensuite passez le ticket dans la machine à l’entrée du métro. À votre sortie, passez le ticket dans le validateur de sortie, si la machine vous refuse, vous devez aller payer les frais supplémentaires sur l’un des automates disponibles avant le passage de porte.

L’autre solution consiste à utiliser une carte rechargeable. Appelées « IC Cards » elles fonctionnent un peu comme feu les cartes Monéo. Il en existe différente sortes : Suica, Pasmo, etc. Elles fonctionnent toutes de la même manière et sont même compatibles avec les systèmes des autres villes (au moins Kyoto et Hiroshima de ce que nous avons essayé). Nous avons opté pour une carte Suica que nous avons obtenu dans l’agence JR de l’aéroport. Vous pouvez également en obtenir une dans une agence Tokyo Metro. À l’obtention vous fournissez 1000, 2000 yens ou plus à créditer sur la carte, une partie sera retenue comme caution (500¥) le reste est utilisable pour le transport. Une fois votre carte chargée, il vous suffit de la passer au portail de l’entrée, puis à celui de sortie, le montant de votre trajet est débité automatiquement.

À noter :

  • vous pouvez recharger la carte sur n’importe quel automate qui a le logo Suica ou Pasmo
  • le rechargement ne peut se faire qu’en liquide, pas de carte bancaire
  • la carte peut contenir 20000¥ au maximum
  • à la restitution de la carte son montant et la caution vous sont rendu moins 210¥
  • vous pouvez également payer dans certain magasins avec la carte

Cet article de Kanpai vous fournira plein de détails sur ces cartes et leurs usages : Carte Suica – L’indispensable au Japon.

Lignes JR (Yamanote, …)

La ligne de train Yamanote est une ligne circulaire qui dessert 29 stations dont les grandes gares de Shibuya, Shinjuku, Ueno ou encore Ikebukuro. Elle délimite naturellement le centre ville et est incontournable pour les visiteurs. En voici le plan :Cette ligne est exploitée par la compagnie JR East ce qui fait qu’elle est gratuite pour les voyageurs possédant le JR Pass.

Cette ligne est exploitée par la compagnie JR East ce qui fait qu’elle est gratuite pour les voyageurs possédant le JR Pass.

Si cette ligne est idéale pour tout un tas de déplacement, il ne faut pas se limiter à celle-ci. Plusieurs lignes JR desservent Tokyo et ses alentours et il serait dommage de ne pas en profiter.  Vous pouvez encore une fois consulter le site Kanpai pour connaître tous les détails sur la ligne Yamanote ici.Lignes JR (Yamanote, …)

Voyager en Shinkansen

Le Shinkansen est l’équivalent du TGV français. Nous l’avons utilisé pour relier Tokyo et Kyoto, puis Kyoto et Hiroshima et enfin revenir à Tokyo. Je vais donc m’appuyer sur ces trajets dans mes explications suivantes.

De Tokyo à Kyoto

La ligne permettant de relier ces deux villes s’appelle Tokaido. Elle va de Tokyo à la gare de Shin-Osaka, un peu après Tokyo. La gare de Kyoto se trouve sur celle ligne peu avant Shin-Osaka. Trois Shinkansen différents roulent sur cette ligne (de la plus rapide à la plus lente) :

  • le Nozomi relie Tokyo à (Shin-)Osaka en 2h40 mais il n’est pas accessible avec le JR Pass,
  • Hikari fait le même trajet en 3h en s’arrêtant dans quelques gares supplémentaires mais lui est prise en charge par le JR Pass,
  •  enfin le Kodama réalise le même trajet en s’arrêtant dans toutes les gares sur la ligne, il est également pris en charge par le JR Pass.

En ce qui nous concerne, nous avons pris un train Hikari depuis la gare de Tokyo en direction de Shin-Osaka et nous sommes arrêtés à Kyoto.

Chacun de ces trains peut être pris avec ou sans réservation. Si vous souhaitez réserver votre place, rendez-vous à un comptoir de la Japan Rail et réservez votre place. Utilisez ensuite le billet pour passer les valideurs. Si vous ne souhaitez pas réserver, passez simplement le valideur avec votre pass. Une fois sur le quai, des panneaux indique quelles sont les voitures avec réservation et sans réservation, installez-vous dans celle qui vous correspond ! Attention cependant, si vous voyagez sans réservation et que les wagons sans réservations sont pleins, il faudra attendre le prochain.

De Kyoto à Hiroshima

De Kyoto à Hiroshima, le principe est globalement le même. Il vous faut aller jusqu’à Shin-Osaka avec l’un des trains mentionné ci-dessus, ensuite prenez un train sur la ligne Sanyo Shinkansen. 4 types de trains sont disponibles :

  • les Nozomi et Mizuho sont les plus rapides, ils mettent 1h25 pour faire le trajet mais ne sont pas accessibles avec le Japan Rail pass;
  • le Sakura fait le trajet en 1h32, vous pouvez le prendre avec le JR pass;
  • le Hikari met 2h13 pour faire la même distance et est également pris en charge.

Si vous n’avez pas de JR pass, il vous en coutera environ 9700 yens.

Récolte du miel

L’année dernière nous avons acquis quelques ruches pour produire du miel comme un loisir. En démarrant cette nouvelle saison, j’ai eu envie de poster quelques photos faites au moment de la précédente récolte, les voici !

Une hausse pleine de miel
Une hausse pleine de miel
Un cadre bien rempli mais pas encore operculé.
Un cadre quasiment prêt à la récolte.
Un cadre plein de miel vu de prés.
Retrait des opercules d'un cadre bien rempli.
Retrait des opercules d’un cadre bien rempli.
Découpage des opercules, le miel commence à couler.
Le miel en sortie d’extracteur.

The Android Illuminati … brrr

This one worth it 😉

/platform_frameworks_base/blob/master/core/java/android/os/Process.java
959
960
961
962
963
964
965
966
967
/**
 * @hide
 * Private impl for avoiding a log message... DO NOT USE without doing
 * your own log, or the Android Illuminati will find you some night and
 * beat you up.
 */
public static final void killProcessQuiet(int pid) {
    sendSignalQuiet(pid, SIGNAL_KILL);
}

Du compost sur ma terrasse !

Fatigué de devoir descendre une poubelle à moitié pleine parce qu’elle était trop odorante, et un peu poussé par un sentiment d’écologisme, j’ai décidé de faire mon propre compost. Oui mais … j’habite en appartement, autant dire que le bac au fond du jardin c’était perdu d’avance.

Un ami m’a donné l’idée de faire mon compost dans un seau sur la terrasse, nous avons réalisé ce petit projet ensemble. L’idée était que ce soit fonctionnel, mais aussi un peu esthétique. Voici le matériel utilisé :

  • Seau de 15l (seau à mélanges, Castorama, environ 3€),
  • Un dessous pour pot de fleur nettement plus large que le fond du seau (environ 7 €),
  • Du terreau, suffisement pour remplir le dessous,
  • Un peu de gazon à semer, ou d’autres plantes pour garnir le tour.

Photo du matériel initial.

Fournitures initiales

Dans un premier temps il faut percer le fond du saut de petits trous qui permettront au liquide généré par votre compost de s’évacuer. Puis, garnir le dessous de pot de terreau.

compost-first-step

Quelques trous dans le seau et un peu de terreau !

Posez ensuite le seau sur le lit de terreau et semez vos plantes, ici du gazon, autour. Cela permettra de décorer l’ensemble, et aussi de consommer ce que votre compost émètra dans la terre.

compost-final-step

L’ensemble, prêt à composter.

Vous pouvez mettre un peu de terre au fond du seau si vous le souhaitez, ça le rend plus facile à nettoyer. Entreposez ensuite le tout dans un endroit à l’abri des fortes pluies et fermez le couvercle. Vous n’aurez ainsi pas d’odeurs. Après quelques semaines, les plantes semées poussent et votre bac à compost pour balcon devient sortable.

compost-with-grass

Quelques semaines plus tard, avec de l’herbe et une collection d’épluchures !

Ça vaut ce que ça vaut, mais j’ai trouvé un compromis entre mon problème de poubelles et ma petite conscience écologique 😉 A vos outils !