Langage Axum

Session présentée par Yann SCHWARZ (membre ALT.NET) et Bruno Boucard.



Ce fût une très bonne présentation en binôme sur le sujet de la programmation parallèle (sujet qui m'intéresse car me rappelle un peu ma jeunesse pendant mes études) et particulièrement sur Axum, un DSL dédié à ce délicat domaine.

Etat des lieux

Chez MS, Windows server supporte jusqu'à 256 coeurs, la fréquence en "herz" n'est donc plus le seul critère pour les performances d'applications.

On pose les difficultés actuelles pour le traitement // :

Exemple par un calcul matriciel en //, présentation d'un code C++ : insatisfaisant car compliqué, bien souvent source d'erreurs dans l'algo, paramètre statique pour le nombre de coeurs à utiliser, inmaintenable (et rend donc non sereine toute modification).

La programmation // : il est difficile d'assurer la fiabilité et l'exactitude d'un système qui utilise des locks : peut rendre plus lent l'exécution du code, un constat : le lock coûte cher.

Vient ensuite un exemple sur l'asynchronisme :

  • exemple trivial, pattern sur les threads : BeginInvoke + callback (EndInvoke) : problème : pas lisibilité ds le code (qui appelle qui, qui appelle quoi)
  • utilisation de InterLocked Increment/Decrement + BeginInvoke / EndInvoke : un peu plus lisible

pourquoi est-ce si compliqué ? les langages impératifs ont été faits pour des appels synchrones, seul hic : en asynchrone, on perd l'intention du code (lisibilité, quel portion de code fait quoi ?)

Nouvelles approches

Une liste de quelques nouvelles approches sur la programmation // :

  • .NET 4 : Task Parallel Library (TPL) : abstraction du découpage en threads
  • Atomicité : casse-tête : on s'inspire des bdd transactionnelles pour avoir de la mémoire transactionnelle : STM.NET (en incubation chez MS), Haskell, Clojure : bien mais trop complexes
  • approche données, on ne touche plus à rien : tout est immuable, fonctionnel pur : Erlang, Haskell
  • le modèle "acteurs" : communication uniquement par messages entre acteurs : pas de données partagées, messages asynchrones, traitements distincts et isolés : Erlang (langage dans le Mainstream, utilisé dans les commutateurs téléphoniques) et Axum.

Comme souvent, à chaque besoin son modèle de programmation :

  • données : TPL, PLINQ
  • tâches : TPL
  • flux données : Axum (approche workflow)

Principes Axum

  • un DSL au parfum C#
  • repose sur la BCL (Base Class Libraries)
  • au stade expérimental : en incubation chez MS

les concepts :

  • domaine : périmètre des données partagées entre agents
  • agent (ou acteur) : unité de traitement qui communique via messages
  • channel : modalité de conversation entre agents (contenus dans un domaine)
  • schéma : format des messages échangés (doit être sérialisable, et donc immuable)

structure d'un système Axum

Les domaines contiennent des agents, les domaines communiquent entre eux par channel, on privilégie la composabilité. Une application est découpée en domaines, les états du domaine sont accessibles par les agents via des channels asynchrones.

Après les bases posées, arrive une démo, un ping pong entre agents, cela permet de découvrir le DSL, et les mots clés de ce dernier pour décrire les traitements.

Un programme axum a une extension .ax (utilisation de l'assembly Microsoft.Axum)

Quelques mots clés du DSL: domain, agent, channel, receive

Un extrait d'un code Axum

public MainAgent()
{
   var pp = PingPong.CreateInNewDomain();
   for(int i=0; i<10;i++)
   {
        pp::Pong <-- true;
        receive(pp:Ping);
   }
   pp::Ping <-- false;
}
 
public channel Pingpong // ~interface ServiceContract en WCF
{
   input bool Pong;
   output Signal Ping; // Signal = void  
}
 
public agent PingAgent : channel PingPong
{
  public PingAgent() // boucle principale de l'agent, on met souvent tout le code de l'agent dedans
  {
      while( receive(Pong)) // receive bloquant
     {
            Ping <-- Signal; //
      }
      Ping <-- Signal;
  }
}

Axum permet aussi de chercher un agent hébergé sur une autre machine (provider Connect<PingPong> "http://server")

Partage de données : par défaut aucune donnée n'est partagée, un agent doit se déclarer pour consommer la donnée, avec des rôles :

  • Writer : peut modifier l'état du domaine,
  • Reader : peut lire l'état partagé.

Une fois les rôles définis, Axum décide du mode d'exécution : parallèle, r/w lock, séquentiel

Axum en action (Dataflow Networks)

  • exprimer explicitement la séquence de traitement dans le code
  • Opérateurs pour les patterns de communication : forward, forward-once, multiplex, join, broadcast, alternate sous forme d'opérandes qui ressemblent fort à des smileys :-->, ==>, -<< (Broadcast) , &>-, >>- (Multiplex), -<: (Alternate)

Exemples d'application : traitements de N images, de chat (chat de facebook développé en Erlang car des millions en //), jeu de la vie

Interopérabilité

  • utilisation de la BCL uniquement si c'est garanti par contrats (safe ou non-safe) : si des effets de bord sont détectés par le compilateur Axum, ce dernier n'acceptera pas le code
  • consommé du .NET classique et vice versa

Principe d'Axum : what you see is what you get (principe de moindre surprise)

ASP.NET 4.0 Webforms

Session présentée par Aurélien VERLA (Wygmam)

Intro

les briquent qui se reposent sur ASP.NET Core : Webforms, MVC, Ajax, Dynamic Data, la session abordera uniquement la partie WebForms 4.0

Simplification du web.config et quelques améliorations :

  • beaucoup de paramètres du web.config sont déportés dans le machine.config
  • décliné en Debug ou Release : Web.Debug.config, Web.Release.config : pour avoir des paramètres différents selon la plateforme (via tranformation XSLT) (section <compilation xdt:Transform="RemoveAttributes(debug)"/>)

Code snippet pour accélérer l'écriture des controls : exemple sur asp.Label : pré-remplira le attributs (runat, Text, ...) et se positionnera sur l'attribut à remplir : Ctrl+X+K (ou Ctrl+K+X)

Gain bande passante

Quelques améliorations ont été apportées pour réduire la quantité de données qui transite entre le navigateur et le serveur.

  • rendering de certains contrôles :
       asp:Menu : RenderingMode : pour modifier le rendu : table à ul li en mode list
       asp:ListView : LayoutTemplate rendu optionnel
       asp:RadioButtonList ou CheckBoxList : span par défaut, rendu par liste possible (ul li)
       asp:FormView : RenderOuterTable
  • ViewState : nouvelle approche sur l'activation ou la désactivation
       page EnableViewState="true|false"
       control ViewStateMode="Enabled|Disabled|Inherit"
  • ClientID : ClientIDMode="AutoID|Inherit|Static|Predictable" : AutoID : val par défaut, Static : ID contrôle = ID serveur (pas de concaténation avec les noms des contrôles pères), Predictable : pouvoir prédire un identifiant, cas d'une grille (ex ListView) avec N elts (ClientIDRowSuffix : id du groupe)

Autres nouveautés

  • ASP.NET Chart Control : contrôle de charting (démo System.Web.DataVisualization) - possibilité de le binder à une source - 35 styles différents
  • Query Extender : asp:LinqDataSource comme datasource : asp:QueryExtender qui pointe sur le linqdatasource
<asp:QueryExtender>
               <asp:SearchExpression DataFields="field" SearchType="">
                      <asp:ControlParameter ControlID="TextBox1"/>
                </asp>
               <asp:PropertyExpression>
                   <asp:ControlParameter GroupID="controlgroupid" />
               </asp>
           </asp>

autres filtres possibles : RangeExpression, orderByExpression, ThenByExpression, CustomExpression

Tips

  • GridView : EnablePersistedSelection : fait persister la ligne sélectionnée lors d'une pagination
  • <%: <script>Alert('toto') </script> %> : raccourci : (2 points) : équivalent à Server.HtmlEncode
  • classe CSS aspNetHidden générée pour les div générées qui englobent
  • classe CSS aspNetDisabled : pour les controles en mode disabled
  • classe utilitaire déportée HttpUtility : HtmlEncode, HtmlDecode, UrlEncode, UrlDecode, plus besoin d'appeller HttpContext...

SEO

  • Routing : apport des friendly urls : System.Web.Routing : MapPageRoute("nom","chemin/{id}","~/verspage/mapage.aspx")

fonctionnalités : RouteValue::id, RouteUrl::id=32, RouteData.Values, RedirectoToPermanent("lab",new {id=1}) : pour générer des HTTP code 301, Page.MetaKeywords, Page.MetaDescription

Détecter et éviter les fuites mémoires en .NET

Présentée par Yann SCHWARTZ, Fabrice MARGUERIE (de metaSapiens). Session très didactique qui m'a plu car ce type d'erreurs sont souvent communes (pour l'avoir expérimenté). La session est basée sur un article écrit par FM sur DNG.

Les principes

  • la mémoire du processus : la pile, le tas
  • le Garbage Collector : fonctionne lorsque l'objet n'est plus référencé nul part - ce qui retient les instances (causes) : références statiques, GCHandles (pont entre le managé et le non ménégé), Références des piles (une pile par thread), Finalization queue
  • fuite de mémoire : type particulier de consommation de mémoire non intentionnelle


Rappel : en .NET : des objets accessibles par au moins une référence ne seront pas relachés par le GC

une goutte d'eau n'est pas un problème, mais le goutte par goutte peut amener une grosse fuite

Les détecter

  • se concentrer sur nos classes à nous et non celles du framework

Démo application PhotoLight en winforms : ouvertures de fenêtres qui augmentent la mémoire, qui ne redescend jamais, même en forcant le GC

  • outils pour pouvoir qualifier avec des niveaux de diagnostic différents
  - analyseur de perfs Windows (PerfMon) : Processus, Octets privés pour l'application PhotoLight
  - vue haut niveau, audit général : dotTrace
  - + en détail : .NET Memory profiler
  - pour les explorateurs : WinDbg

- dotTrace : profiling de perf ou de mémoire. Dump memory pour une photo de la mémoire par type d'objets, shortest root paths (qui tient une référence d'un objet ?).

2 approches :

  • Approche par Namespace (Dump) pour voir nos objets applicatifs (et non ceux des assembly MS) - Merged Shortest pour remonter vers les objets qui maintiennent une référence
  • Approche différentielle entre 2 photos mémoire (Mark) : voir les objets qui persistent alors qu'il n'y a plus besoin

cause dans la démo (ouverture d'une image, OptionsForm): abonnement à un évènement statique InstalledFontsChanged dans la fenêtre OptionsForm de l'appli sans jamais se désabonner : la fenêtre dans laquelle on s'est abonné à l'évènement n'est donc jamais désallouée (OptionsForm) - solution : se désabonner ds le dispose : Disposed+=InstalledFontsChanger-=method



- .NET Memory Profiler : permet d'avoir une liste de conseils, plus puissant que dotTrace mais moins user friendly

Profil application pour s'attacher à l'exécutable

cause dans la démo (ouverture options de l'appli, DetailsForm) : analyse le code et alerte - Shortest root path (chemin des références des objets) - abonnement à un évènement (non statique) de la fenêtre mère (qui vit tout le tps donc) sans désabonnement - solution : se désabonner dans la fenêtre fille à cet évènement qui pointe vers la fenêtre mère (MainForm) (Disposed-=evt)



Cas récurrents de causes de fuites mémoire : évènements et problème de fuites invisibles (ou moins détectables) car dépendances inversées



- WinDbg : installation minimale, permet d'explorer un dump mémoire

Extensions : Sos.dll : permet d'examiner la mémoire managée, s'attacher à un process puis en ligne de commandes.

       .cmdtree d:\cmdtree.txt
       .loadby sos mscorwks;
       .load sosex

Exemples de commandes à connaitre :

  • !DumpHeap : liste des instances du tas
  • !DumpObject
  • !GCRoot : trouve l'instance racine d'une instance (réf)
  • !DumpHeap -stat (pour ordonner)
  • !DumpHeat -stat -type PhotoLight (filtrer par type)
  • !DumpHeat -mt idclr (colonne MT)
  • !do idclr (do watch)
  • !GCRoot idclr (qui maintient cette réf)

cause dans la démo : menu = new ContextMenuStrip() qui crée un abonnement évènement : dépendance cachée - solution : appeler menu.Dispose() explicitement ou ContextMenuStrip(this.components)

- Process Explorer : affiche les process .NET en jaune, puis compteur de perf de l'appli : .NET CLR loading pour voir les objets chargés

bug ds. new XmlSerializer avec le 2è para new XmlRootAttributes("settings") : n'est plus en cache

Causes possibles des fuites mémoire

  • attention aux réf. statiques - évènements statiques
  • évènements sans désabonnement
  • Dispose non appelé
  • code compilé à la volée (XSLT pré-compilé) avec System.Reflection.Emit ou CodeDom


Prévenir

  • analyse statique (NDepend)
  • chaque += est un ennemi => utiliser les -=, using et Dispose, WeakEvents (réf faibles), EventBroker
  • ou relancer l'appli par le recyclage de pool ds IIS par ex (approche pragmatique) (NB : très utile, je peux vous le dire)

Slides et sources

Déjà disponibles, merci guys