mageekblog - Mot-clé - wmiiLe blog personnel de Frédéric Hardy. Au menu, PHP, agilité, FreeBSD, cuisine et photographies.2021-12-02T08:20:54+01:00Frédéric Hardyurn:md5:26874ca5b8cd4cac8d08b0e68e64f63aDotclearwmiirc.php sur ohlohurn:md5:f0b196baed3414b40c86ba7adfb7f0c12009-02-06T11:33:00+01:002009-02-06T11:42:09+01:00mageekguyPHPwmiiwmiirc.php <p>Je viens de créer le projet correspondant à <a href="http://svn.mageekbox.net/repositories/wmiirc.php">wmiirc.php</a> sur <a href="https://www.ohloh.net/p/wmiircphp">ohloh</a>.</p>
<p>J'étais en effet assez curieux de voir ce que l'analyseur de code allait me sortir comme résultat.</p>
<p>Au final, ils ne sont pas bien passionnants et m'ont plutôt déçu, car je m'attendais à des métriques beaucoup plus intéressantes que la répartition par langage ou le ratio entre la quantité de code et celle de commentaire.</p>
<p>La seule donnée intéressante à mes yeux renvoyée par l'analyseur est que le projet contient environs 2800 lignes de <a href="http://www.php.net">PHP</a>.</p>
<p>Petite curiosité, il contiendrait apparament 7% de code code HTML, ce qui est relativement bizarre pour un script PHP qui fonctionne en ligne de commande et qui ne contient aucune ligne de code HTML.</p>
<p>La seule explication que j'ai pu trouver à cette anomalie est qu'ohloh a pris en compte le lien vers <a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.html">la licence GPL 2</a> contenu dans les commentaires en en-tête de chaque fichier du projet.</p>http://blog.mageekbox.net/?post/2009/02/06/wmiirc.php-sur-ohloh#comment-formhttp://blog.mageekbox.net/?feed/atom/comments/23wmiirc.php VS wmiir VS ruby-ixpurn:md5:cdb35a6d541c548724855fac256f41fd2009-01-28T14:00:00+01:002009-01-28T16:22:09+01:00mageekguyPHPPHPRubyruby-ixpwmiiwmiirc.php<p>Afin d'avoir une idée approximative des performances du <a href="http://svn.mageekbox.net/repositories/wmiirc.php/trunk/classes/wmii9PlanClient.php">client 9Plan</a> de <a href="http://svn.mageekbox.net/repositories/wmiirc.php/trunk">wmiirc.php</a>, j'ai effectué un comparatif avec <code>wmiir</code>, l'utilitaire permettant d'accèder au sytème de fichiers 9Plan de <a href="http://www.suckless.org/wmii/">wmii</a>.</p>
<p>Pour ce faire, j'ai utilisé deux scripts :</p>
<ol>
<li>L'un est en <a href="http://www.gnu.org/software/bash/">bash</a> et utilise <code>wmiir</code>.</li>
<li>L'autre est en <a href="http://www.php.net">PHP</a> et fait appel au <a href="http://svn.mageekbox.net/repositories/wmiirc.php/trunk/classes/wmii9PlanClient.php">client 9Plan</a> de <a href="http://svn.mageekbox.net/repositories/wmiirc.php/trunk">wmiirc.php</a>.</li>
</ol>
<p>Ces deux scripts ont le même but (stupide) : Lire 1000 fois le fichier <code>/ctl</code> de <a href="http://www.suckless.org/wmii/">wmii</a>.</p> <p>Le script en bash est le suivant :</p>
<pre><code>#!/usr/local/bin/bash<br />for i in {1..1000}; do<br /> wmiir read /ctl > /dev/null;<br />done<br /></code></pre>
<p>Le script en <a href="http://www.php.net">PHP</a> est le suivant :</p>
<pre><code>#!/usr/bin/env -S php -n<br />connect();<br /><br />$file = new wmii9PlanFile('/ctl');<br /><br />for ($i = 0; $i < 1000; $i++)<br />{<br /> $interface->read($file);<br />}<br /><br />?></code></pre>
<p>Une fois ces deux scripts écrits, il suffit d'éxécuter les commandes suivantes pour avoir une idée du temps d'éxécution :</p>
<pre><code># sudo chmod u+x ./test.php ./test.sh<br /># time ./test.php<br /># time ./test.sh<br /></code></pre>
<p>Les résultats montrent que le code <a href="http://www.php.net">PHP</a> est approximativement 4.3 fois plus rapide que <code>wmiir</code>, codé en C.</p>
<p>Par curiosité, j'ai comparé mes résultats avec ceux de <a href="http://home.gna.org/rubyixp/">ruby-ixp</a>, une classe écrite en <a href="http://www.ruby-lang.org/en/">ruby</a> qui permet également d'accèder à un serveur de fichiers 9Plan.</p>
<p>Il en ressort que cette dernière est 1.8 fois plus rapide que <code>wmiir</code>.</p>
<p>De là à dire que le code de <a href="http://svn.mageekbox.net/repositories/wmiirc.php/trunk">wmiirc.php</a> est 2 fois plus rapide que celui de <a href="http://home.gna.org/rubyixp/">ruby-ixp</a>, il y a un pas que je me garderais personnellement de franchir puisque le test de <a href="http://home.gna.org/rubyixp/">ruby-ixp</a> a apparament été effectué :</p>
<ul>
<li>avec une ancienne version de la classe.</li>
<li>avec un ancienne version de <a href="http://www.ruby-lang.org/en/">ruby</a>.</li>
<li>avec une ancienne version de <a href="http://www.suckless.org/wmii/">wmii</a>.</li>
</ul>
<p>Cependant, je suis certain que <del>des trolleurs</del> certain pourfendeurs de <a href="http://www.ruby-lang.org/en/">ruby</a>, adorateurs de<a href="http://www.php.net">PHP</a>, sauront en tirer parti...</p>
<p>Pour information, j'ai effectué mon test sur un portable core2duo à 1.5 Ghz sous <a href="http://www.freebsd.org">FreeBSD 7.1</a> et wmii 3.6, avec <a href="http://www.php.net">PHP</a> 5.2.8 et le Suhosin-Patch 0.9.6.3.</p>http://blog.mageekbox.net/?post/2009/01/28/wmiirc.php-VS-wmiir-vs-ruby-ixp#comment-formhttp://blog.mageekbox.net/?feed/atom/comments/19Implémentation d'un client 9P en PHPurn:md5:d0ac9761c025293b6faa7943a7153cbd2009-01-25T21:04:00+01:002010-05-09T14:32:29+02:00mageekguyPHPPHPwmiiwmiirc.php<p>J'avais prévu dès le départ de mon projet <a href="http://svn.mageekbox.net/repositories/wmiirc.php">wmiirc.php</a> d'implémenter un client <a href="http://en.wikipedia.org/wiki/9P">9Plan</a> en <a href="http://www.php.net">PHP</a>, pour m'affranchir de l'utilitaire en ligne de commande fourni avec <a href="http://www.suckless.org/wmii" lang="en">wmii</a>, nommé <code>wmiir</code>.</p>
<p>En effet, son utilisation nécéssite d'utiliser les méthodes <code><a href="http://www.php.net/exec">exec()</a></code>, <code><a href="http://www.php.net/proc_open">proc_open()</a></code> et consoeurs, qui sont pénalisantes en terme de performance.</p>
<p>Or, un <span lang="en">window manager</span> doit être le plus réactif possible.</p>
<p>Je devais donc supprimer les appels à <code>wmiir</code> de mon code afin de gagner en confort d'utilisation au niveau de <a href="http://www.suckless.org/wmii" lang="en">wmii</a>.</p>
<p>Je vais donc vous décrire, au cours des semaines qui viennent, la façon dont j'ai implémenté le protocole 9Plan en PHP pour y parvenir.</p> <p>Je vais donc commencer par vous décrire les objets que j'ai créé pour cette implémentation, je poursuivrai par leur mise en relation et je terminerai par leur intégration dans <a href="http://svn.mageekbox.net/repositories/wmiirc.php">wmiirc.php</a>.</p>
<h1>Le modèle objet</h1>
<p>Pour savoir ce que je devais faire pour créer ce client, J'ai commencé par lire la <a href="http://plan9.bell-labs.com/magic/man2html/5/intro">documentation</a> relative au protocole, qui, même si elle n'est pas très parlante et ne regorge pas d'exemple, m'a permis de définir le modèle objet à mettre en oeuvre.</p>
<p>En résumé, 9Plan est un protocole client/serveur qui permet de manipuler un <a href="http://en.wikipedia.org/wiki/Virtual_file_system" lang="en">système de fichiers virtuel</a>.</p>
<p>Lorsqu'un client désire une information, par exemple le contenu d'un fichier, il effectue une requête vers le serveur à l'aide d'un <code>Tmessage</code>, et reçoit la réponse de ce dernier sous la forme d'un <code>Rmessage</code>.</p>
<p>Ces deux types de messages ont un en-tête identique, composé de trois champs :</p>
<ol>
<li>La taille en octet du message.</li>
<li>Le type du message.</li>
<li>Une étiquette, qui permet de faire correspondre un <code>Rmessage</code> à un <code>Tmessage</code> et qui permet de gérer des transactions.</li>
</ol>
<p>En <a href="http://www.php.net">PHP</a>, cela peut se traduire par la classe abstraite suivante :</p>
<pre><code>abstract class wmiiMessage<br />{<br /> protected $type = 0;<br /> protected $tag = 0;<br /><br /> public function __construct($type)<br /> {<br /> $this->type = $type;<br /> }<br /><br /> public function getType()<br /> {<br /> return $this->type;<br /> }<br /><br /> public function setTag($tag)<br /> {<br /> $this->tag = $tag;<br /> return $this;<br /> }<br />}</code></pre>
<p>Vous noterez que j'ai omis de gérer la taille du message car je n'en ai aucunement besoin dans le cadre de <a href="http://www.svn.mageekbox.net/repositories/wmiirc.php">wmiirc.php</a>.</p>
<p>Nous avons donc maintenant une classe abstraite capable de prendre en charge la partie commune entre les <code>Tmessage</code> et les <code>Rmessage</code>.</p>
<p>Nous allons maintenant voir la définition des ces deux types de message à partir de cette classe de base.</p>
<p>Le <code>Tmessage</code> sert aux demandes d'informations. Il doit donc être encodé avant d'être envoyé au serveur.
</p>
<p>le <code>Rmessage</code> sert à la réception des informations, en réponse à un <code>Tmessage</code>. Il doit donc être décodé lors de sa réception.</p>
<p>Il est donc possible d'implémenter les <code>Tmessage</code> et les <code>Rmessage</code> de la manière suivante, en dérivant notre classe abstraitre de départ :</p>
<pre><code>abstract class wmii9PlanTMessage extends wmii9PlanMessage<br />{<br /> public function __construct($type, $tag)<br /> {<br /> parent::__construct($type);<br /> $this->tag = $tag;<br /> }<br /><br /> public function encode()<br /> {<br /> $data = pack('Cv', $this->type, $this->tag) . $this->encodeMessage();<br /><br /> return pack('V', strlen($data) + 4) . $data;<br /> }<br />}<br /><br />abstract class wmii9PlanRMessage extends wmii9PlanMessage<br />{<br /> public function __construct($type, $data)<br /> {<br /> parent::__construct($type);<br /><br /> $this->decode($data);<br /> }<br /><br /> protected function decode($data)<br /> {<br /> $this->tag = current(unpack('vtag', $data));<br /><br /> $this->decodeMessage(substr($data, 2));<br /><br /> return $this;<br /> }<br /><br /> protected abstract function decodeMessage($data);<br />}<br /></code></pre>
<p>Nous disposons maintenant de l'ensemble des classes nécèssaires pour gérer les différents types de message requis par le protocole.</p>
<p>Il suffit de créer une classe par type, héritant soit de <code>wmii9PlanTMessage</code> ou de <code>wmii9PlanRMessage</code> suivant qu'il s'agit d'un <code>Tmessage</code> ou d'un <code>Rmessage</code>, par exemple de la manière suivante :</p>
<pre><code>class wmii9PlanTwalkMessage extends wmii9PlanTMessage<br />{<br /> const type = 110;<br /><br /> protected $fid = 0;<br /> protected $newFid = 0;<br /> protected $path = '';<br /><br /><br /> public function __construct($tag, $fid, $newFid, array $path)<br /> {<br /> parent::__construct(self::type, $tag);<br /><br /> $this->fid = $fid;<br /> $this->newFid = $newFid;<br /> $this->path = $path;<br /> }<br /><br /> protected function encodeMessage()<br /> {<br /> $data = pack('VVv', $this->fid, $this->newFid, sizeof($this->path));<br /><br /> foreach ($this->path as $wname)<br /> {<br /> $data .= self::encodeString($wname);<br /> }<br /><br /> return $data;<br /> }<br />}<br /></code></pre>
<p>L'implémentation des différents types de message se fait donc très rapidement, via la surcharge des méthodes <code>decodeMessage()</code> et <code>encodeMessage()</code>, sans aucune duplication de code, le code commun aux différentes classes étant encapsulé dans les classes parentes.</p>
<h1>L'encodage et le décodage</h1>
<p>Les lecteurs attentifs auront remarqué l'utilisation des fonctions <code><a href="http://www.php.net/pack">pack()</a></code> et <code><a href="http://www.php.net/unpack">unpack()</a></code> dans le code ci-dessus.</p>
<p>Leur mise en oeuvre est rendu nécéssaire par le fait que le protocole 9Plan est un protocole binaire.</p>
<p>Il n'y a rien à dire de bien particulier sur ces fonctions, si ce n'est qu'il y a de nombreux <a href="http://bugs.php.net/search.php?cmd=display&search_for=pack&x=0&y=0">bugs</a> s'y rapportant et que leur mise en oeuvre s'apparente à celle des fonctions de la famille <code><a href="http://www.php.net/sprintf">printf()</a></code>.</p>
<p>Cependant, 9Plan fait appel à des mots binaires de 64 bits que ne savent pas gérer les fonctions <code><a href="http://www.php.net/pack">pack()</a></code> et <code><a href="http://www.php.net/unpack">unpack()</a></code>.</p>
<p>Pour contourner le problème au niveau de l'encodage, j'ai concaténé deux mots binaires de 32 bits, en donnant la valeur 0 au mot binaire de poids fort.</p>
<p>Pour le décodage, je ne décode que les 32 premiers bits du mot binaire de 64 bits.</p>
<p>Cette solution n'est pas parfaite et pour être honnête, elle me déplaît foncièrement.</p>
<p>En effet, mon code ne sera pas capable de gérer correctement les valeurs dépassant la capacité d'un entier non signé sur 32 bits, qui est le plus grand mot binaire que sait gérer PHP sur une architecture 32 bits.</p>
<p>Cependant, dans le cas de <a href="http://svn.mageekbox.net/repositories/wmiirc.php">wmiirc.php</a>, des valeurs dépassant la capacité de ce mot binaire ne peuvent pas survenir, et je fais contre mauvaise fortune bon coeur.</p>
<p>Cela me fait d'ailleurs penser que les implémentations de <code><a href="http://www.php.net/pack">pack()</a></code> et <code><a href="http://www.php.net/unpack">unpack()</a></code> sont dépendantes de l'arhitecture matérielle utilisée.</p>
<p>Il y a donc de fortes chances pour que ceux qui utilisent mon code sur une architecture 64 bits rencontrent quelques <a href="http://www.mysqlperformanceblog.com/2007/03/27/integers-in-php-running-with-scissors-and-portability/">difficultés</a>.</p>http://blog.mageekbox.net/?post/2009/01/16/implementation-d-un-client-9P-en-PHP#comment-formhttp://blog.mageekbox.net/?feed/atom/comments/18Quand PHP s'accouple avec un window manager...urn:md5:46207fa075e03be315e67755fb79b83b2009-01-08T13:53:00+01:002009-01-09T11:11:41+01:00mageekguyPHPwmii<p>J'ai pendant des années été un adepte inconditionnel d'<a href="http://fr.wikipedia.org/wiki/Openbox">openbox</a>, un <q><span lang="en">window manager</span></q> pour <a href="http://fr.wikipedia.org/wiki/Xorg">X.Org</a>, sur les machines que j'utilise pour développer.</p>
<p>Il a l'avantage d'être léger, graphiquement simple mais esthétique,
et surtout hautement configurable via un unique fichier de
configuration en <abbr title="eXtended Markup Language">xml</abbr>, bref tout pour me plaire...</p>
<p>Sauf que ma façon de travailler a évoluer au cours des années, et
que je me suis rendu compte que je positionnais toujours mes fenêtres
aux mêmes endroits, sur les mêmes bureaux virtuels, avec les mêmes
dimensions, et le tout au clavier.</p>
<p>Je me suis donc intéréssé aux <q><span lang="en">window manager</span></q>
qui s'occupent de faire tout cela tout seul, comme des grands, et qui
en plus optimisent la taille des fenêtres au maximum en fonction de
l'espace disponible à l'écran, tout en étant intégralement utilisables
au clavier.</p>
<p>Après avoir étudié entre autre awesome, ratpoison, xmonad et dwm, mon choix a été le grand frère de ce dernier, <a href="http://www.suckless.org/wmii/">wmii</a>.</p> <p>Cependant, contrairement à <a href="http://fr.wikipedia.org/wiki/Openbox">openbox</a>, <a href="http://www.suckless.org/wmii/">wmii</a> ne dispose pas du moindre fichier de configuration.</p>
<p>En effet, il est intégralement piloté par un script qui récupére chaque évenement reçu par le <q><span lang="en">window manager</span></q> et qui éxécute les actions correspondantes.
</p>
<p>Or, le script fourni par défaut est pour le moins complexe, puisqu'il est écrit à l'aide de commande <a href="http://fr.wikipedia.org/wiki/Bourne_shell">sh</a> et qu'il utilise massivement <code>sed</code>, <code>awk</code> et consors.</p>
<p>Et si modifier le script pour définir les raccourcis que doit utiliser wmii n'est pas compliqué, lui ajouter de nouveaux comportements est tout de suite complexe pour une personne qui ne maîtrise pas toutes les arcanes de la programmation en <a href="http://fr.wikipedia.org/wiki/Bourne_shell">sh</a>.</p>
<p>Heureusement, des alternatives au script par défaut ont été développées, tel que <a href="http://eigenclass.org/hiki.rb?wmii+ruby">ruby-wmii</a>.</p>
<p>En effet, <a href="http://www.suckless.org/wmii/">wmii</a> a l'originalité de pouvoir être intégralement géré via un système de fichiers virtuel basé sur le protocole <a href="http://en.wikipedia.org/wiki/9P">9P</a>.</p>
<p>Tout script ou programme capable de s'interfacer avec un tel système de fichier est donc capable de contrôler <a href="http://www.suckless.org/wmii/">wmii</a> et de remplacer le script fourni par défaut.</p>
<p>J'ai donc étudié sérieusement la possibilité d'utiliser <a href="http://eigenclass.org/hiki.rb?wmii+ruby">ruby-wmii</a>.</p>
<p>Après tout, j'hésitais depuis longtemps à apprendre python ou ruby faute de projet suffiasement personnel et motivant, c'était donc une bonne opportunité de me mettre à ruby.</p>
<p>Sauf que je suis allergique à la syntaxe de ce langage, j'ai beau essayer, je n'arrive pas à m'y faire.</p>
<p>De plus, la citation suivante, par l'auteur de ruby-wmii, m'a définitivement achevé :</p>
<blockquote><p>
Note that ruby-ixp leaks memory, but this is not a problem since you can restart wmiirc without leaving X once a day or so with Alt+a wmiirc (you could easily have it restart automatically too).
</p>
</blockquote>
<p>Je veux bien beaucoup de choses, mais il ne faut tout de même pas trop pousser.</p>
<p>Du coup, j'ai décidé de faire mon propre script.</p>
<p>Je me suis donc amusé avec le mode <abbr title="Command Line Interface">CLI</abbr> de PHP et ses extensions <code><a href="http://fr.php.net/pcntl%22">pcntl</a></code> et <code><a href="http://www.php.net/posix">posix</a></code>, et au final, j'ai un <a href="http://svn.mageekbox.net/repositories/wmiirc.php/trunk/wmiirc.php.dist">script</a> facilement configurable qui fait ce que je veux, comme je le veux, que j'ai nommé <a href="http://svn.mageekbox.net/repositories/wmiirc.php/trunk">wmiirc.php</a>.</p>
<p>Et comme c'était noël il y a peu de temps, j'ai décidé de mettre <a href="http://svn.mageekbox.net/repositories/wmiirc.php/trunk">le tout</a> sous licence <abbr title="Gnu Public Licence">GPL</abbr>, histoire que ceux qui sont adeptes des interfaces graphiques soviétiques mais efficaces se fasse un peu plaisir.</p>
<p>Cependant, attention, le code a été développé et testé sous <a href="http://www.freebsd.org">FreeBSD</a>, et demandera certainement quelques adaptations pour fonctionner sous Linux ou un autre <a href="http://fr.wikipedia.org/wiki/Unix">UNIX</a>.</p>
<p>De plus, il va certainement évoluer dans les jours ou les mois qui viennent, puisque pour des raisons de rapidité de développement, l'interface avec le système de fichier <a href="http://en.wikipedia.org/wiki/9P">9P</a> passe par un programme externe fourni avec <a href="http://www.suckless.org/wmii/">wmii</a> alors qu'il est parfaitement possible de le faire nativement en <a href="http://www.php.net">PHP</a>, sans compter que je suis un éternel insatisfait du code que je produis...</p>
<p>[PS] VIsiblement, certain on des problèmes pour récupérer les fichiers. La commande est la suivante :</p>
<pre><code># svn export http://svn.mageekbox.net/repositories/wmiirc.php/trunk<br /></code></pre>http://blog.mageekbox.net/?post/2009/01/08/Quand-PHP-s-accouple-avec-un-window-manager...#comment-formhttp://blog.mageekbox.net/?feed/atom/comments/16