Skip to content

Commit

Permalink
Add final slides for REPRISES
Browse files Browse the repository at this point in the history
  • Loading branch information
jfalcou committed Nov 14, 2022
2 parents 990c428 + 18a8554 commit cab867a
Show file tree
Hide file tree
Showing 2 changed files with 226 additions and 22 deletions.
93 changes: 71 additions & 22 deletions talks/reprises/main.md.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
<center>![](images/ccby40.png style="height: 0.7rem")</center>
<small><small>Powered by Markdeep and Markdeep-Slides</small></small>

---


>>> P
>>> 0. Ma présentation a pour sujet une bibliothèque nommée Kiwaku pour le calcul haute performance qui repose sur l'utilisation de la programmation générative.

---

## Context

Expand All @@ -36,7 +36,10 @@

### Problem already addressed many times :

![](images/standards.png style="width: 40%")
<center>![](images/standards.png style="width: 40%")</center>

>>> P
>>> 1. Un peu de contexte maintenant. Les tableaux n-dimensionnels sont très courants dans le domaine du calcul haute performance. C'est par exemple la structure principale de nombreuses simulations numériques. Ces tableaux doivent être performants, faciles d'utilisation et expressifs. C'est un domaine d'étude compliqué où il n'existe pas de solution unique et où les besoins sont multiples.

---

Expand All @@ -59,6 +62,9 @@
**What if the real issue was a software design problem?**
</center>

>>> P
>>> 2. Voici quelques exemples de bibliothèques. Elles sont globalement toutes basées sur les mêmes idées et stratégies. La question que nous nous sommes posée est de savoir s'il serait possible de contourner les limitations actuelles en traitant ce problème comme une question de design logiciel plutôt que simplement de fonctionnalités offertes.

---

## nD Array Design Space
Expand All @@ -75,7 +81,11 @@
* Arbitrary restrictions on API is not a solution

!!! Tip: Our Position
Apply a different design strategy to the problem
Apply a different design strategy to the problem : generative programming

>>> 3. L'espace de conception est très vaste (exemples...)
>>> On pourrait alors penser à faire une seule grande implémentation monolithique, mais l'histoire a montré que ça mène à une grande masse de code impossible à maintenir proprement. Réduire de manière arbitraire l'API n'est pas non plus une solution.
>>> Face à ça, on propose une stratégie de conception basée sur la programmation générative.

---

Expand Down Expand Up @@ -109,25 +119,28 @@
*
********************************************************************************

>>> P
>>> 4. On a d'une part la description du programme dans le langage du domaine métier ici à gauche. Au milieu il y a les composants permettant la génération du code : la description métier du programme est traitée par un traducteur qui construit l'implémentation du programme via des sous-composants paramétriques, créant ainsi un code étant la représentation optimale de la solution donnée au programme en entrée. Paramétrique : spécialisation des composants en leur donnant des paramètres (exemple : source).

---

## Generative Programming for nD arrays

### Advantages of Generative programming
* Domain specific descriptor and components are easy to extend
* Reduce the number of implementations from $|X|\cdot|Y|$ to $|X| + |Y|$
* Reduce the number of implementations from $|X|\cdot|Y|\cdot|Z|$ to $|X| + |Y| + |Z|$
* Generative programming in C++ is based on **template metaprogramming** and **code generation**


<!--
Le rôle des templates : Modular implementation => only compile what is really needed
Notre position c'est que qu'on peut utiliser la generative programming (GP) pour résoudre ce problème de design d'une manière suffisamment flexible à l'usage pour résoudre ce problème et répondre à tous les use-case. Kiwaku est censé résoudre ce problème, exemple de code qui claque. -->

<script type="preformatted">
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ c++
// Wow, such C++ code
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
</script>
<iframe width="100%" height="57%" src="http://localhost:10240/e#g:!((g:!((g:!((h:codeEditor,i:(filename:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,selection:(endColumn:9,endLineNumber:13,positionColumn:1,positionLineNumber:13,selectionStartColumn:9,selectionStartLineNumber:13,startColumn:1,startLineNumber:13),source:'%23include+%3Ckwk/kwk.hpp%3E%0A%23include+%3Cvector%3E%0A%23include+%3Ciostream%3E%0A%0Atemplate%3Ctypename+View%3E%0Avoid+process(View%26+v)%0A%7B%0A++kwk::for_each(+%5B%5D(auto%26+c,+auto+i0,+auto+i1,+auto+i2)+%7B+c(i0,i1,i2)+/%3D+10.f%3B+%7D%0A+++++++++++++++,+v++%0A+++++++++++++++)%3B%0A%7D%0A%0Aint+main()%0A%7B%0A++using+namespace+kwk::literals%3B%0A%0A++int+n%3B%0A++std::cin+%3E%3E+n%3B%0A++std::vector%3Cfloat%3E+d(20*n)%3B%0A++for(int+i%3D0%3B+auto%26+e+:+d)+e+%3D+i%2B%2B%3B%0A%0A++auto+v+%3D+kwk::view%7Bkwk::size+%3D+kwk::of_size(4_c,+5_c,+n),++kwk::source+%3D+d%7D%3B%0A++process(v)%3B%0A%7D'),l:'5',n:'0',o:'C%2B%2B+source+%231',t:'0')),k:47.16981132075472,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:compiler,i:(compiler:g10,filters:(b:'0',binary:'1',commentOnly:'0',demangle:'0',directives:'0',execute:'0',intel:'0',libraryCode:'1',trim:'1'),flagsViewOpen:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,libs:!((name:kiwaku,ver:trunk)),options:'-O3+-DNDEBUG',selection:(endColumn:1,endLineNumber:1,positionColumn:1,positionLineNumber:1,selectionStartColumn:1,selectionStartLineNumber:1,startColumn:1,startLineNumber:1),source:1,tree:'1'),l:'5',n:'0',o:'Intel+-+G%2B%2B+10+(C%2B%2B,+Editor+%231,+Compiler+%231)',t:'0')),k:52.83018867924528,l:'4',m:100,n:'0',o:'',s:0,t:'0')),l:'2',n:'0',o:'',t:'0')),version:4"></iframe>


>>> 5. La programmation générative présente un certain nombre d'avantages. Les descripteurs et composants spécifiques au domaine sont indépendants et simples à modifier et à étendre, ce qui diminue énormément le nombre d'implémentations nécessaires : c'est une liste linéaire de fonctionnalités qui s'assemblent les unes aux autres, on a pas à gérer la combinatoire entre les composants, on a pas besoin d'écrire tous les cas. La programmation générative en C++ est basée sur la métaprogrammation via les templates et la génération de code. On a plusieurs paramètres nommés à la python (paramètres positionnels) qui sont exploités à la fois à la compilation et au runtime.
>>> Quand on prend le temps de regarder attentivement l'assembleur on observe que les informations connues à la compilation ont bien été exploitées.

---

Expand All @@ -139,8 +152,8 @@

### What do users want?
* Small and non-ambiguous interface
* Clear and concise documentation
* High discoverability
* Clear and concise documentation

### What do users deal with?
* Some APIs suffer from feature creep
Expand All @@ -151,6 +164,10 @@
* User friendly for non computer experts
* Keep API scope reasonable

>>> 7. Globalement, les utilisateurs veulent des interfaces de taille raisonnables, non ambiguës et qu'il soit possible de comprendre un intuitivement, ainsi qu'une documentation claire et concise.
>>> - Actuellement, certaines API souffrent d'une surcharge fonctionnelle (ou ballonnement logiciel) qui rendent difficiles la compréhension de chaque fonction et leur interaction. Certaines API nécessitent parfois une bonne maîtrise du langage et de certains concepts de programmation pour être utilisées efficacement.
>>> - Il serait intéressant d'offrir une API avec une étendue suffisamment lare, exhaustive et adaptée aux utilisateurs non experts en programmation.

---

## Painful example : std::vector
Expand Down Expand Up @@ -179,6 +196,10 @@
* Data access induces spurious cache misses
* Memory is not contiguous, leading to sub-par performance


>>> P
>>> 8. Je vais vous donner un exemple de ce qui ne va pas. Voici un exemple de l'allocation d'un vecteur en 5 dimensions via std::vector. On observe que c'est très verbeux et peu expressif. En plus, on est très mauvais niveau performances : la mémoire n'est pas contiguë, il y a besoin d'un très grand nombre d'allocations et le pattern d'accès aux données induit une très mauvaise utilisation des caches.

---

<!-- ## Painful example : std::pmr
Expand All @@ -204,6 +225,7 @@
--- -->


## Painful example : std::mdspan

### Extent definition
Expand All @@ -230,6 +252,9 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
</script>

>>> p
>>> 9. Un des problèmes de std::mdspan est que l'API est très verbeuse pour des choses simples. C'est aussi intrinsèquement bridé parce qu'ils ont fait des choix de conceptions en dur dans l'API, l'API statique est figée car standardisée, pour la changer il faudrait changer le standard mais on perdrait la rétrocompatibilité, ce qui posera des problèmes. (l'interface de type donc)

---

## Painful example : Expression template libraries
Expand All @@ -238,7 +263,7 @@

<script type="preformatted">
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
auto unexpected_lazy_evaluation(matrix A, B)
auto unexpected_lazy_evaluation(matrix const& A, matrix const& B)
{
auto C = A * B; // The type of C is not matrix
return C;
Expand All @@ -258,8 +283,9 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
</script>

>>> Conclusion orale et on passe à la suite. Dire à l'oral "E.g EIGEN"
>>> EIGEN ça pue
>>> 10. L'utilisation des expression template est contre-intuitive dans certains contextes et réservée à des développeurs avertis, notamment l'utilisation du mot clef auto.
>>> (b) Variable est déclarée dans le scope de la fonction. En général l'arbre d'évaluation prend des références aux opérandes, et donc stockera une référence à un objet temporaire qui sera détruit en sortie du scope de la fonction. Auto est du coup dangereux dans la plupart des bibliothèques à base d'expression template.
>>> (c) On force une évaluation en obligeant le résultat that à être de type T, sans laisser place à l'évaluation paresseuse et aux simplifications futures.

---

Expand All @@ -269,13 +295,23 @@

## Kiwaku design - Overview

### Scope reduction
* monolithic "all in one" solutions are bound to fail
* Kiwaku only works with numerical nD arrays
### Scope reduction limits feature creep
* Monolithic designs are bound to fail
* Kiwaku design focuses on a small set of closely relates features...

### Kiwaku's features
* Owning and non-owning containers (`kwk::view`, `kwk::table`) with proper allocators
* Slicing of containers (soon)
* Algorithmic skeletons for order n containers

TODO : what's more ?
### Kiwaku's non-features
* No linear algebra
* No expression templates
* No computation

>>> P
>>> 12. Pour que ce projet ait un sens on lui assigne l'espace de conception suivant : ce n'est pas une solution monolithique, et Kiwaku ne gère que les tableaux numériques multidimensionnels. Et ce n'est absolument pas une bibliothèque de calcul, c'est du stockage et des outils pour manipuler correctement le stockage : c'est une bibliothèque d'infrastructure qui sert à construire d'autres bibliothèques.

Plutôt dans "Kiwaku design" nan ? Réduction du scope : on n'essaie pas de trouver une solution à tous les problèmes, on ne s'occupe que des tableaux numériques blablabla tu sais de quoi je parle ;)

---

Expand All @@ -295,6 +331,9 @@
* A `kwk::table` is a `kwk::view` over the memory it owns
* Efficient `kwk::view` leads to efficient `kwk::table`

>>> 13. - Les views Kiwaku ne sont jamais les propriétaires (de mémoire, elles sont une interface similaire aux tableaux n-dimensionnels, permettant d'accéder à la mémoire vers laquelle elles pointent. Elles sont pensées pour prendre le moins d'espace mémoire possible à vide : le sizeof de l'objet doit être minimal, sans compter les données.
>>> - Les tables Kiwaku possèdent leur mémoire allouée via un allocateur spécifique ou directement sur la pile. Leur interface doit être semblable aux vues Kiwaku, et elles sont aussi pensées pour prendre le moins d'espace mémoire possible.
>>> - Au final, une table kiwaku n'est qu'une vue possédant sa mémoire. Des vues performantes mènent à des tables performantes.

---

Expand All @@ -314,26 +353,36 @@
| `kwk::label` | any string-like values |
| `kwk::allocator` | any types modeling `kwk::concepts::allocator` |


>>> 14. Les options supportées par Kiwaku sont perpendiculaires les unes aux autres, c'est à dire qu'elles sont chacunes spécifiques et qu'elle ne se recoupent pas. Il suffit de leur associer une valeur dans les constructeurs pour les définir, il n'est pas nécessaire de respecter un ordre de déclaration.
>>> Elles sont aussi utilisées pour optimiser les performances à la fois lors de la compilation et de l'exécution. je n'ai pas le temps de rentrer dans les détails, mais globalement il y a...

---

## Simple view construction

<iframe width="100%" height="75%" src="http://localhost:10240/e#g:!((g:!((g:!((h:codeEditor,i:(filename:'1',fontScale:18,fontUsePx:'0',j:1,lang:c%2B%2B,selection:(endColumn:1,endLineNumber:1,positionColumn:1,positionLineNumber:1,selectionStartColumn:1,selectionStartLineNumber:1,startColumn:1,startLineNumber:1),source:'//+simple_view.cpp%0A%23include+%3Ckwk/kwk.hpp%3E%0A%23include+%3Ciostream%3E%0A%0Aint+main()%0A%7B%0A++using+namespace+kwk%3B%0A%0A++double+data%5B6%5D+%3D+%7B1.2,2.3,3.4,4.5,5.6,6.7%7D%3B%0A%0A++auto+vd+%3D+view%7B+source+%3D+data+%7D%3B%0A++std::cout+%3C%3C+vd.shape()+%3C%3C+%22%5Cn%22%3B%0A++std::cout+%3C%3C+vd.rank()+%3C%3C+%22%5Cn%22%3B%0A++%0A++for(std::size_t+i+%3D+0%3B+i+%3C+vd.size()%3B%2B%2Bi)%0A++++vd(i)+*%3D+10.%3B%0A%0A++for(auto+e+:+data)%0A++++std::cout+%3C%3C+e+%3C%3C+%22+%22%3B%0A%7D+'),l:'5',n:'0',o:'C%2B%2B+source+%231',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((g:!((h:compiler,i:(compiler:g10,filters:(b:'0',binary:'1',commentOnly:'0',demangle:'0',directives:'0',execute:'0',intel:'0',libraryCode:'0',trim:'1'),flagsViewOpen:'1',fontScale:18,fontUsePx:'0',j:1,lang:c%2B%2B,libs:!((name:kiwaku,ver:trunk)),options:'-O3+-DNDEBUG+-std%3Dc%2B%2B20',selection:(endColumn:1,endLineNumber:1,positionColumn:1,positionLineNumber:1,selectionStartColumn:1,selectionStartLineNumber:1,startColumn:1,startLineNumber:1),source:1,tree:'1'),l:'5',n:'0',o:'Intel+-+G%2B%2B+10+(C%2B%2B,+Editor+%231,+Compiler+%231)',t:'0')),k:50,l:'4',m:50,n:'0',o:'',s:0,t:'0'),(g:!((h:output,i:(compiler:1,editor:1,fontScale:18,fontUsePx:'0',tree:'1',wrap:'1'),l:'5',n:'0',o:'Output+of+Intel+-+G%2B%2B+10+(Compiler+%231)',t:'0')),header:(),l:'4',m:50,n:'0',o:'',s:0,t:'0')),k:50,l:'3',n:'0',o:'',t:'0')),l:'2',n:'0',o:'',t:'0')),version:4"></iframe>

>>> 15. Là on a un exemple de code montrant la construction d'une vue à partir d'un tableau C classique. La taille du tableau est déduite automatiquement du tableau C passé en option via kwk::source.
>>> On a bien un tableau de taille 6 à une dimension. On voit également qu'on peut itérer sur la vue de la même manière que sur un conteneur classique et que la mémoire est bien gérée correctement.

---

## Rank 3 view from standard range

<iframe width="100%" height="75%" src="http://localhost:10240/e#z:OYLghAFBqd5QCxAYwPYBMCmBRdBLAF1QCcAaPECAMzwBtMA7AQwFtMQByARg9KtQYEAysib0QXABx8BBAKoBnTAAUAHpwAMvAFYTStJg1DIApACYAQuYukl9ZATwDKjdAGFUtAK4sGe1wAyeAyYAHI%2BAEaYxHoADqgKhE4MHt6%2BcQlJAkEh4SxRMVy2mPaOAkIETMQEqT5%2BRXaYDskVVQQ5YZHRegqV1bXpDX3twZ353VwAlLaoXsTI7BzmAMzByN5YANQmy24A1gDuewD0h3sAdAixsTvYJhoAgitrG5jbuwBuTUTEt/dPZlWDHWXi2OzcTl6xEwrD%2Bj3%2BwQImxYTGCEEm/xMAHYrI9NpsvIkjJtmGwFLEmAtNmcdrinnjNr10CAQF8HCRwehZhF6LdNugmJUIFIMcs6f98UwvERNh90O8ACKyvCYA7YiyM2bzN47JUCyrbBn440m02kTaoKgAfUSAC9MBAzKRls6MUbTR78eaDFFaIrtmYzBEmEorVRoQBHcxmCWeuPYhW02OxpkstDS95ucGy9DnBQIJixB2TTPZ6MmACsbgY5bFKYIzJQsyR4Oz%2BBY4I0twgcpLrd2AbMm1Ug8NDzjJv7bn5eA7uy43d7pYH0eHo9jE%2BX0/b4Jjy2wPfQfd2ZcDlertbp%2BNTTYzU5z52Ihj26K3g/PNbPdfhDP4xAgN52pgVpIngQ66psXZipsYGZjOc5uHuB69kmljWGBbrjsaf4AQ2LJASBMFcP6UEangxFtrO4ILvuh6ilYaGWORmEmjhgF4PahF4BoJG0jBPGUQhUHIUeqEMRY3ElmOHpyhA3HkEUGH%2BnJXaWFMAYalwGgAFRyQual9pYmxaTpckxgZSY/lhOFSjKbwgPygpMCxxo3umLYngOOqedOq6XpODJuc2b7llWNZhZeyaBXht4eVmA5yiFZ4RV%2BGqYliCocNMtCcBWvB%2BBwWikKgnBZoxGoKFqVIrDwpAEJoWXTHsIAVho%2BicAALPlDXFZwvAKCAbX1YVWWkHAsAwIgTYsLEdDROQlBoDNc0xMAWl8HQBDRANEARD1ETBFUACenC1UtbCCAA8gwtAnSNpBYCiRjiPd%2BDQs0XwDfdmCqE00qLEViIlD1tB4BET7EEdHhYD1BDELOp2jVQBjAAoABqKoHJdRYFbV/CCCIYjsFIMiCIoKjqPduhFAYRgoNY1j6GDA2wKS7B7HgBxMHsXikF8MRw14DB7JM0yoLEZQMF9AC0l3LJs0sKqECrYBYcgAOIK0yuqmOVZhFY0zTOBArgDPUpCBKMeQFBkiSS2bttZAwHTWxMxSlC0wwOw0JTfJ7bQu10hS2F7nh1D0wyB%2BMhTTJVcwLHocOYIsPDZbl3X3SVHAAJKCCUCubOrDNGVpmwQGV4nmrghAkAGyxFJsHjLfQxB11MvDDVooukM1rXtRwXWkCwIDLB15xmB1ACcHVYlwHUVpIWJYssWLSAVRVZ/1g11Q10zjVNzaxNKC0QEts0t/4%2BA/Ho%2BPCKI4gk7f5NqLD0Ip7wBxPrEiNpxweWkOvXgWdLrSiPkiS0mxc5bT9NLQuxdNI8XLqgZu0Q26TA7rvaYCAYRYBiOifug9h4ADYKznCxK1CsZhJAVg6lwQMRDAwAJ6pvWw29O6NR7i1NqOUODLAzhvPqO8Rrdx4WYfhQDBHsO7vzRIzgOpAA%3D"></iframe>

>>> P
>>> 16. Je présente ici un exemple plus complet de création d'une vue 3D à partir d'un std:vector basique. On voit qu'on a bien les dimensions attendues pour la vue, et qu'on a un bel affichage bien formaté avec le nom qu'on a assigné à cette vue. On peut aussi observer que les valeurs sont bien dans l'ordre attendu.

---

## Code generation comparison with standard C

<iframe width="100%" height="75%" src="http://localhost:10240/e#z:OYLghAFBqd5TKALEBjA9gEwKYFFMCWALugE4A0BIEAZgQDbYB2AhgLbYgDkAjF%2BTXRMiAZVQtGIHgA4BQogFUAztgAKAD24AGfgCsp5eiyahUAUgBMAIUtXyKxqiIEh1ZpgDC6egFc2TA3cAGQImbAA5PwAjbFIDAAd0JWIXJi9ffwSklKEQsMi2GLiee2xHZyERIhZSInS/AJKHbCdUqpqiPIjo2IMlatr6zKaBztDuwt6eAEp7dB9SVE4uSwBmUNRfHABqM1WPAGsAdwOAemODgDokePi93DMtAEFHp6JsNnijd72PIgBPeLMdjYbYAFXI2xYPhIlzh2wA8kp7q8AG7oAiYbbACDbC4gECogjYI6/CFIuGXe7bVHTV5mADsNme222glIEH6mAJ8SIpEINBoAH0iNsCHsACJaPZWcX7VGXZIAL2wEDpqxs1lsBDpLNZNIgOu2ACpJdsLJdVgBWAAsNBl9IZEvpz3RmLZQoutHo6BYRGN215FDFwm2TF1LyZr1ZOLxJwJRJJjKs%2BJASnmi1BZqDkNTyqzqwlYcZEvVzMjEq4s3o3Ct/ACXB05HQ3A8tls23TCyWuwsqz45CI2ir5AgKAwnwYsUo1An8SncWAPC0AgY71ISmoUWH5CioRq/24A4nHGECKY9EPjf4ODYxmAkmv5EIpBazlR2E3T%2Bw6haMOWA6hO8NZPvQBBRKQB5eDgO58gQbBHiONBGMASgAGrEkcCJAg2A6CMIYgSJwMhyMIyhqJoT76CURgmGg7bWIY4GbrArAcCABwEEcLAHD45AfnEfI%2BEwBzTLM6C8qkX4ALQIqs2zSRK4QSrgVgKAA4gpXKSuYWrWBYTbNK0rgQO4QyNOQwTjAURRZMkFRpN4DR2TkTBdDZUylOUbSjOZfRlG%2BPkdO5PTFPYvlOcM4XBdZoVSLMXaZgYfLYABI4gXW5ANk2LZcAAksIZQKds6kMVY2zLtsEBtnpdjbPgxBkL2/aQl4k6MKQzUzPwQ7XmJ5AHCANoWqsACcw08Fa/bSAAbKNqxaKNhjcDa/AIVaK7ZfwuX8JuK69TosxwLA45YHghAkBQVC0FObFpaRojiJIJH4YoKgaDu%2BgWIY970bVXmBSZZmRRZVn5HFJSJPZqR%2BZD2QOSFkxhUZDntIMIP%2Bd5lSjIjtkjB0sPRbUuNTAlGZLNwawbFsBYeKgXI4PaqwPM8aIYliwqoN6vr%2BoGfKQkBYYRsm0ZsmQnJENyIBBgKwqinKUoynKHhMA6tU6qLrJBmYVqyjrRamoW5qWraTPliW6W1vWO65TVmrlYlPZrBYPXDkdp3tdO11zguIBLiudD0Oum4QNuT57qwpBXse6BsKeRDnpeO63vej5Ni%2BgUfl%2BTY/n%2B7yIZQhUgU2YEQVBZ2waQ8GIbMyEsKhGEkthzAF69hHPbIr3kR9VEgN9tGmGVTFRCxarNpJQgyXJClKSpamadJ2mFrp9sGbtAXGQEplMJ4GMlGDEx4%2BQUOuYTJ8I7FSOY4DTBo3Ue8A5vd8k8jEUZBZ/QxeDV8zHM3acN9FKaVqxWyyjbbgBVgLFVKrVCqWgqp21sJCBql1mrfW2G1ecHU0HTFdn1WYSBsAsBwHEMeIFVrkHWptcBXBdogH2m7WYg0xqXBtAyaQo0rQMlGpNaQ/YZpWmWlwVY1snw7UHG7UciAxwgFljOWg8h27EU7vIbulES5IE3DRTRssARAnoeQUgmi%2B6GJ0QQQUejOBaBAVwTKW1mzcAlOYmg2xG5HFiNsSBRVpIlTKnAmkShPFF2gX45ceDDoEKISQ6gTCQAzS0JcK0FhlzDS0NIG0PAZp8MmkIih9jxF7QkfgoRLswFiO4OEqsswBLJFcDaIAA"></iframe>

>>> p
>>> 17. Là c'est un petit exemple pour montrer que l'utilisation d'une vue Kiwaku ne coute pas plus cher que l'utilisation d'un tableau C classique, et que l'assembleur généré est exactement le même.

---

# Conclusion
Expand Down
Loading

0 comments on commit cab867a

Please sign in to comment.