<?xml version="1.0" encoding="UTF-8"?><!-- generator="wordpress.com" -->
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	>

<channel>
	<title>lcg &amp;laquo; WordPress.com Tag Feed</title>
	<link>http://wordpress.com/tag/lcg/</link>
	<description>Feed of posts on WordPress.com tagged "lcg"</description>
	<pubDate>Mon, 08 Sep 2008 09:27:57 +0000</pubDate>

	<generator>http://wordpress.com/tags/</generator>
	<language>en</language>

<item>
<title><![CDATA[UPDATE: LCG X-plore v1.22 (Restart Device added)]]></title>
<link>http://gerrymoth.wordpress.com/2008/07/30/lcg-x-plore-v122-restart-device-added/</link>
<pubDate>Wed, 30 Jul 2008 08:52:38 +0000</pubDate>
<dc:creator>gerrymoth</dc:creator>
<guid>http://gerrymoth.wordpress.com/2008/07/30/lcg-x-plore-v122-restart-device-added/</guid>
<description><![CDATA[null
LCG have added a new feature to X-plore, their great file manager application, to enable you to]]></description>
<content:encoded><![CDATA[[caption id="" align="alignleft" width="135" caption="null"]<a href="http://media.shozu.com/cache/portal/media/1a876f/335544325"><img src="http://media.shozu.com/cache/portal/media/1a876f/335544325_journal" alt="" width="135" height="180" /></a>[/caption]
<p>LCG have added a new feature to X-plore, their great file manager application, to enable you to restart the device.</p>
<p>Download from <a href="http://www.lonelycatgames.com/?app=xplore" target="_blank">http://www.lonelycatgames.com/?app=xplore</a></p>
<p align="right"><a href="http://www.shozu.com/portal/?utm_source=upload&#38;utm_medium=graphic&#38;utm_campaign=upload_graphic/" target="_blank"></a></p>
]]></content:encoded>
</item>
<item>
<title><![CDATA[Continuer l'optimisation avec la Lightweight Code Generation (LCG)]]></title>
<link>http://romainverdier.wordpress.com/?p=34</link>
<pubDate>Tue, 06 May 2008 13:46:33 +0000</pubDate>
<dc:creator>Romain Verdier</dc:creator>
<guid>http://romainverdier.wordpress.com/?p=34</guid>
<description><![CDATA[Cet article est un complément du précédent. Vous pouviez y lire dans la conclusion :
Nous nous so]]></description>
<content:encoded><![CDATA[<p>Cet article est un complément du <a href="http://codingly.com/2008/05/02/optimisation-des-invocations-dynamiques-de-methodes-en-c/">précédent</a>. Vous pouviez y lire dans la conclusion :</p>
<blockquote><p>Nous nous sommes contentés d’évoquer la solution d’optimisation impliquant la génération de code IL. Dans le contexte de la problématique discutée, elle n’offrait aucun avantage par rapport à celle que nous avons exposée. Pire, elle imposait une étape inutile. Toutefois, certains besoins plus complexes dépassent le cadre des invocations dynamiques de méthodes et peuvent tout de même être adressés efficacement en recourant à la génération de bytecode.</p></blockquote>
<p>S'il existe des scénarios dans lesquels le recourt à la <a href="http://msdn.microsoft.com/en-us/library/system.reflection.emit.dynamicmethod.aspx">LCG</a> est inutile voire pénalisant, il n'y a parfois aucune autre alternative lorsqu'il s'agit de mettre en place une solution où les performances sont aussi importantes que la dynamicité.</p>
<p>Vous ne trouverez pas ici un tutorial sur l'utilisation de <code>Reflection.Emit</code>, mais plutôt un exemple d'utilisation de cette technique pour répondre de façon optimale à un besoin bien spécifique. Nous essaierons en parallèle de faire ressortir quelques guidelines relatives à l'usage de la LCG.<br />
<!--more--></p>
<h3>Mais c'est quoi, ce truc ?</h3>
<p>La LCG, ou Lightweight Code Generation, fait référence à une nouveauté apparue dans la seconde version du Framework .NET. </p>
<p>Il a toujours été possible en .NET d'utiliser l'API du namespace <code><a href="http://msdn.microsoft.com/en-us/library/system.reflection.emit.aspx">System.Reflection.Emit</a></code> pour générer des assemblies, des modules et des types dynamiquement. Le principe est simple : on autorise via cette API les développeurs de la plateforme .NET à produire directement du code intermédiaire. C'est extrêmement puissant, mais très rapidement complexe. Le fait que le CIL ainsi obtenu soit (<a href="http://blogs.msdn.com/jmstall/archive/2005/02/03/366429.aspx">quasiment</a>) impossible à débuguer ne vient pas arranger les choses.</p>
<p>C'était en quelque sorte la Heavyweight Code Generation : pour générer dynamiquement le <a href="http://en.wikipedia.org/wiki/Bytecode">bytecode</a> correspondant à un traitement, il fallait la plupart du temps se taper la création d'un assembly, d'un module et d'un type pour finalement héberger la méthode encapsulant l'opération. Tout cela est souvent nécessaire, mais le reste du temps, c'est juste lourd.</p>
<p>Typiquement, lorsqu'on utilise la génération de CIL pour créer un proxy dynamiquement, on veut définir un type complet avec ses membres et ses méthodes. En revanche, pour créer une simple méthode au runtime on préfèrerait s'en passer.</p>
<p>La LCG autorise justement la création de méthodes dynamiques pouvant être réclamées par le garbage collector, et surtout ayant la capacité d'être hébergées anonymement, sans que l'on ait à créer d'assembly, de module ou de type. Outre le fait que de telles méthodes soient relativement faciles à créer (je ne parle pas de la génération de leurs corps), elles peuvent également être invoquées via des délégués. Et ça on connait, c'est efficace.</p>
<h3>Parfois, c'est inutile</h3>
<p>Dans l'article précédent, nous avons vu comment il était possible de créer un délégué pointant sur un <code>MethodInfo</code> pour considérablement optimiser les invocations dynamiques. L'exemple s'y prêtait bien : nous connaissions la signature de la méthode à appeler dynamiquement donc nous pouvions :</p>
<ul>
<li>Définir un type de délégué correspondant</li>
<li>Solliciter la méthode <code>CreateDelegate</code> de la classe <code>Delegate</code></li>
<li>Invoquer le délégué ainsi récupéré</li>
</ul>
<p>C'est vraiment ce qu'il faut retenir. <strong>Il n'y a aucune raison d'utiliser la LCG si les signatures des méthodes à appeler dynamiquement sont connues</strong> et qu'il est possible de définir les délégués correspondants.</p>
<h3>Un exemple moins ingrat</h3>
<p>Vous aurez compris que lorsque la signature des méthodes à appeler dynamiquement n'est pas connue durant le design, il est impossible de déclarer un délégué correspondant à la méthode que l'on veut appeler. Il en découle que l'invocation via délégué est à oublier, et qu'il ne reste donc que la bonne vieille méthode <code>Invoke</code> sur le <code>MethodInfo</code>.</p>
<p>Oui, celle-la même qui ruine les performances.</p>
<p>A l'origine, je voulais trouver un exemple ni trop idiot ni trop complexe pour mettre ce cas en évidence et introduire la LCG. Finalement, je n'ai pas été capable de trouver quelque chose respectant cet équilibre. Vous aurez donc droit à un exemple vraiment simple et super idiot : le <strong>cloneur</strong>.</p>
<p>Commençons par en définir l'interface :</p>
<p>[code language='csharp']<br />
public interface ICloner<br />
{<br />
    object Clone(object toClone);<br />
}<br />
[/code]</p>
<p>Les types respectant ce contrat devront fournir via la méthode <code>Clone</code> un service capable de retourner un <a href="http://www.devx.com/tips/Tip/13625">shallow clone</a> de l'objet passé en paramètre. Pour simplifier ici, nous ne considèrerons que les propriétés publiques des objets.</p>
<p>Ecrivons directement un test unitaire :</p>
<p>[code language='csharp']<br />
[Test]<br />
public void Test()<br />
{<br />
    var cloner = GetCloner();<br />
    var p = new Person<br />
            {<br />
               Id = 1,<br />
               Firstname = "Romain",<br />
               Lastname = "Verdier",<br />
               BirthDate = new DateTime(1976, 03, 02),<br />
               Height = 1.65<br />
            };<br />
    var p2 = cloner.Clone(p) as Person;<br />
    Assert.AreNotEqual(p,p2);<br />
    Assert.AreEqual(p.Id, p2.Id);<br />
    Assert.AreEqual(p.Firstname, p2.Firstname);<br />
    Assert.AreEqual(p.Lastname, p2.Lastname);<br />
    Assert.AreEqual(p.BirthDate, p2.BirthDate);<br />
    Assert.AreEqual(p.Height, p2.Height);<br />
}<br />
[/code]</p>
<p>En utilisant simplement la réflexion, on peut proposer l'implémentation non optimisée suivante :</p>
<p>[code language='csharp']<br />
public class Cloner : ICloner<br />
{<br />
    private readonly Func<Type, Func<object, object>> clonerLocator;</p>
<p>    public Cloner()<br />
    {<br />
        this.clonerLocator = ((Func<Type, Func<object, object>>)GetCloner).Memoize();<br />
    }</p>
<p>    public object Clone(object toClone)<br />
    {<br />
        var cloner = this.clonerLocator(toClone.GetType());<br />
        return cloner(toClone);<br />
    }</p>
<p>    private Func<object, object> GetCloner(Type type)<br />
    {<br />
        var constructorInfo = type.GetConstructor(Type.EmptyTypes);<br />
        if (constructorInfo == null)<br />
        {<br />
            throw new ArgumentException(string.Format("'{0}' type doesn't have a default constructor.", type.Name));<br />
        }</p>
<p>        return toClone =><br />
        {<br />
            var clone = Activator.CreateInstance(type);<br />
            var propertyInfos = type.GetProperties(BindingFlags.Instance &#124; BindingFlags.Public);<br />
            foreach (var propertyInfo in propertyInfos)<br />
            {<br />
                var setterInfo = propertyInfo.GetSetMethod();<br />
                var getterInfo = propertyInfo.GetGetMethod();<br />
                if (setterInfo != null && getterInfo != null)<br />
                {<br />
                    // Deux invocations dynamiques ont lieu ici sans que l'on puisse<br />
                    // utiliser de délégués.<br />
                    setterInfo.Invoke(clone, new object[] {getterInfo.Invoke(toClone, null)});<br />
                }<br />
            }<br />
            return clone;<br />
        }<br />
    }<br />
}<br />
[/code]</p>
<p>Notons à propos du code précédent :</p>
<ul>
<li>Peu de vérifications sont faites, c'est à la fois volontaire et mal.</li>
<li>Nous n'utilisons pas <code>GetValue</code> et <code>SetValue</code> sur les <code>PropertyInfo</code> pour rendre les invocations dynamiques de méthodes explicites : ici, on fait deux invocations dynamiques par propriété. Une sur le getter, et une sur le setter.</li>
<li>Ne pas connaitre le type de chaque propriété à l'avance signifie que l'on ne connait pas la signature des getters et des setters. Ne pas connaître la signature des getters et des setters nous empêche d'utiliser la méthode décrite dans l'article précédent.</li>
<li>La <a href="http://codingly.com/2008/05/02/optimisation-des-invocations-dynamiques-de-methodes-en-c/">memoization</a> et l'utilisation d'un locateur ne servent qu'à faciliter la comparaison que l'on pourra faire avec la prochaine solution, puisqu'on ne peut pas utiliser de caching dans celle-ci.</li>
</ul>
<p>Puisque vous aimez les chiffres comme tout le monde, j'ai créé un test de performances effectuant un million d'appels à la méthode de clonage. Et houlala, c'est lent : <strong>1000000 appels en plus de 26 secondes</strong>.</p>
<p>En utilisant la LCG, il va être possible de générer une méthode encapsulant la logique de clonage relative à un type donné. On pourra également créer un délégué pour cette méthode, afin qu'elle puisse être invoquée sans que les performances ne soient dégradées. Ce délégué - et on rejoint ici le principe d'optimisation commun à toutes les solutions - pourra être mis en cache pour éviter que la méthode dynamique ne soit regénérée systématiquement.</p>
<p>Voyons ce que ça donne :</p>
<p>[code language='csharp']<br />
public class CilCloner : ICloner<br />
{<br />
    private readonly Func<Type, Func<object, object>> clonerLocator;</p>
<p>    public Cloner()<br />
    {<br />
        this.clonerLocator = ((Func<Type, Func<object, object>>) GetCloner).Memoize();<br />
    }</p>
<p>    public object Clone(object toClone)<br />
    {<br />
        var cloner = this.clonerLocator(toClone.GetType());<br />
        return cloner(toClone);<br />
    }</p>
<p>    private Func<object, object> GetCloner(Type type)<br />
    {<br />
        var constructorInfo = type.GetConstructor(Type.EmptyTypes);<br />
        if (constructorInfo == null)<br />
        {<br />
            throw new ArgumentException(string.Format("'{0}' type doesn't have a default constructor.", type.Name));<br />
        }</p>
<p>        var dynamicMethod = new DynamicMethod(string.Format("<{0}>DoClone", type.Name),<br />
                                              typeof (object),<br />
                                              new []{typeof (object)},<br />
                                              this.GetType());</p>
<p>        var propertyInfos = type.GetProperties(BindingFlags.Instance &#124; BindingFlags.Public);</p>
<p>        var gen = dynamicMethod.GetILGenerator();<br />
        var local = gen.DeclareLocal(type);<br />
        gen.Emit(OpCodes.Newobj, constructorInfo);<br />
        gen.Emit(OpCodes.Stloc, local);<br />
        foreach(var propertyInfo in propertyInfos)<br />
        {<br />
            var setterInfo = propertyInfo.GetSetMethod();<br />
            var getterInfo = propertyInfo.GetGetMethod();<br />
            if (setterInfo != null && getterInfo != null)<br />
            {<br />
                gen.Emit(OpCodes.Ldloc, local);<br />
                gen.Emit(OpCodes.Ldarg_0);<br />
                gen.Emit(OpCodes.Callvirt, getterInfo);<br />
                gen.Emit(OpCodes.Callvirt, setterInfo);<br />
            }<br />
        }<br />
        gen.Emit(OpCodes.Ldloc, local);<br />
        gen.Emit(OpCodes.Ret);</p>
<p>        return (Func<object, object>) dynamicMethod.CreateDelegate(typeof (Func<object, object>));<br />
    }<br />
}<br />
[/code]</p>
<p>Décortiquons une fois de plus la solution, en gardant à l'esprit que le but de l'article n'est pas d'apprendre à coder en CIL :</p>
<ul>
<li>Le membre <code>clonerLocator</code> est gardé en champ d'instance afin que l'on puisse le mémoizer.</li>
<li>Le constructeur s'occupe de cette tâche en faisant appel à la méthode d'extension <code>Memoize</code> dont vous pourrez (re)trouver la définition dans l'<a href="http://codingly.com/2008/05/02/optimisation-des-invocations-dynamiques-de-methodes-en-c/">article précédent</a>.</li>
<li>La méthode <code>Clone</code>, correspondant à l'implémentation de l'interface <code>ICloner</code>, se contente de récupérer via le locateur un délégué capable d'effectuer le clone de l'objet passé en paramètre. Elle l'invoque directement ensuite.</li>
<li>Le cœur de la solution réside donc dans la méthode <code>GetCloner</code> :
<ul>
<li>Une <a href="http://www.refactoring.com/catalog/replaceNestedConditionalWithGuardClauses.html">guard clause</a> permet de vérifier si le type de l'objet à créer expose bien un constructeur par défaut.</li>
<li>Une <code>DynamicMethod</code> est crée. Il s'agit d'une méthode prenant en paramètre un <code>object</code> et retournant un <code>object</code>, qui sera capable de cloner un objet du type <code>type</code></li>
<li>Grâce à la réflexion, on récupère les métadonnées de toutes les propriétés publiques du type <code>type</code>.</li>
<li>On récupère le générateur de code IL de la méthode dynamique afin de pouvoir émettre le corps de cette dernière.</li>
<li>On génère le code IL correspondant à la déclaration d'une variable locale de type <code>type</code>. On l'initialise avec une nouvelle instance de <code>type</code>.</li>
<li>On itère sur toutes les métadonnées des propriétés, et on ne considère que celles qui sont à la fois accessibles en lecture et en écriture.</li>
<li>A chaque fois que cette condition est vérifiée, on produit le code correspondant à l'affectation de la propriété du clone (appel au setter). La valeur utilisée pour l'affectation est celle récupérée par le getter sur la propriété de l'objet à cloner.</li>
<li>On termine la construction du corps de la <code>DynamicMethod</code> en émettant les instructions IL correspondant au retour du clone.</li>
<li>Enfin, la méthode <code>GetCloner</code> crée un délégué à partir de la méthode dynamique via <code>CreateDelegate</code>, et le renvoit.</li>
</ul>
</li>
</ul>
<p>C'est beau ! La mesure des performances en utilisant le même test que précédemment indique cette fois <strong>qu'un million de clones ont été créés en 305 ms</strong>. Pour information, la méthode <code>MemberwiseClone</code> donne un résultat de 234 ms.</p>
<h3>Conclusion</h3>
<p>La Lightweight Code Generation, et plus globalement l'utilisation de <code>Reflection.Emit</code>, permet d'apporter des solutions insoupçonnées à certains problèmes bien spécifiques. Cependant, elle n'est pas gratuite et demande un investissement non négligeable de la part de ceux qui veulent la maitriser ou bien même s'en servir ponctuellement. Les développements peuvent être nettement ralentis tandis que les phases de debug et de maintenance risquent de devenir critiques.</p>
<p>Il est donc surtout important de :</p>
<ul>
<li>Savoir que la technique existe.</li>
<li>Savoir reconnaitre les scénarios qui rendent son emploi envisageable.</li>
</ul>
<p>Il existe assez peu de bonnes ressources permettant d'apprendre à maitriser cette technique. Je suis en train de lire <a href="http://www.amazon.com/CIL-Programming-Under-Hood-NET/dp/1590590414">CIL Programming: Under the Hood of .NET</a> de <a href="http://www.jasonbock.net/JB">Jason Bock</a>, sans être spécialement séduit. Je conseille aux plus curieux de commencer par la MSDN et Google, puis de consulter les sources de projets qui utilisent l'émission de bytecode. Le blog de <a href="http://evain.net/blog/">Jean-Baptiste Evain</a> est également riche en infos au sujet du CIL : il est l'auteur entre autres de <a href="http://www.mono-project.com/Cecil">Mono.Cecil</a>.</p>
<p>Mais j'y reviendrai.</p>
]]></content:encoded>
</item>
<item>
<title><![CDATA[UPDATE: LCG Slick v0.42 (Bug Fixes)]]></title>
<link>http://gerrymoth.wordpress.com/?p=111</link>
<pubDate>Thu, 10 Apr 2008 08:37:30 +0000</pubDate>
<dc:creator>gerrymoth</dc:creator>
<guid>http://gerrymoth.wordpress.com/?p=111</guid>
<description><![CDATA[I hadn&#8217;t update to LCG Slick v0.41 previously as I don&#8217;t use ICQ anymore. In fact I]]></description>
<content:encoded><![CDATA[<p>I hadn't update to <a href="http://www.lonelycatgames.com/?app=slick" target="_self">LCG Slick </a>v0.41 previously as I don't use ICQ anymore. In fact I've been using <a href="http://www.palringo.com" target="_self">Palringo</a> lately as my default IM Client on the N95 8GB, as I have 2 gmail accounts and LCG Slick can only handle 1.</p>
<p>Changelog:<br />
0.41: Fixed ICQ Login.<br />
0.42: Fixed MSN corrupted MSN contact lists, receive offline messages on AIM.</p>
]]></content:encoded>
</item>
<item>
<title><![CDATA[10 15 2007  THE BANG PARTY - DERRICK L. CARTER + KEN (ecb) + PETER (lcg)]]></title>
<link>http://savoyproductions.wordpress.com/2007/08/28/10-15-2007-the-bang-party-derrick-l-carter-ken-ecb-peter-lcg/</link>
<pubDate>Tue, 28 Aug 2007 07:25:58 +0000</pubDate>
<dc:creator>savoyproductions</dc:creator>
<guid>http://savoyproductions.wordpress.com/2007/08/28/10-15-2007-the-bang-party-derrick-l-carter-ken-ecb-peter-lcg/</guid>
<description><![CDATA[

EASTCOAST BOOGIEMEN
http://www.myspace.com/fivenightclub
]]></description>
<content:encoded><![CDATA[<p><a href="http://www.flickr.com/photos/90703518@N00/1255281109/" title="Derrick Carter_Ken Christensen_Peter Christianson"><img src="http://farm2.static.flickr.com/1283/1255281109_1b2482e384_o.jpg" width="752" height="512" alt="ECB_Bang_Front4x6_web" /></a><br><br />
<a href="http://www.flickr.com/photos/90703518@N00/1255282987/" title="Derrick Carter_Ken Christensen_Peter Christianson"><img src="http://farm2.static.flickr.com/1424/1255282987_b63b420c35_o.jpg" width="576" height="846" alt="ECB_Bang_Back4x6_web" /></a><BR><br />
<a href="http://www.myspace.com/eastcoastboogiemen2">EASTCOAST BOOGIEMEN</a><BR><br />
<a href="http://www.myspace.com/fivenightclub">http://www.myspace.com/fivenightclub</a></p>
]]></content:encoded>
</item>

</channel>
</rss>
