{"id":43,"date":"2017-04-03T13:30:19","date_gmt":"2017-04-03T13:30:19","guid":{"rendered":"http:\/\/learningcenter.paratools.com\/?p=43"},"modified":"2022-04-14T14:04:48","modified_gmt":"2022-04-14T14:04:48","slug":"profilage-avec-linux-perf","status":"publish","type":"post","link":"https:\/\/learningcenter.paratools.com\/?p=43","title":{"rendered":"Profilage avec Linux Perf"},"content":{"rendered":"<p>Dans ce tutorial, nous allons utiliser Linux-Perf pour collecter les donn\u00e9es de performance d&rsquo;une application parall\u00e8le. Notre but ici et de permettre simplement l&rsquo;identification des points\u00a0 chauds d&rsquo;un code donn\u00e9, le tout en \u00e9tant agnostique au runtime sous-jacent.<\/p>\n<p>\u00c0 la fin de ce module vous saurez:<\/p>\n<ul>\n<li>Collecter des donn\u00e9es de performance avec Linux-perf<\/li>\n<li>Analyser ces donn\u00e9es avec \u00ab\u00a0perf report\u00a0\u00bb<\/li>\n<li>Visualiser ces donn\u00e9es avec \u00ab\u00a0flamegraph\u00a0\u00bb<\/li>\n<\/ul>\n<p><!--more--><\/p>\n<h1>Pr\u00e8-requis<\/h1>\n<p>Linux-Perf repose sur des fonctionnalit\u00e9s noyau. Il est donc possible qu&rsquo;il ne soit pas disponible dans certains environnements si vous n&rsquo;\u00eates pas l&rsquo;administrateur du syst\u00e8me. De plus, certains admins sont r\u00e9ticents relativement \u00e0 son installation car certaines autorisations sont requises pour permetre \u00e0 perf de fonctionner.<\/p>\n<p>En particuler la valeur du fichier\u00a0<em>\/proc\/sys\/kernel\/perf_event_paranoid<\/em> est d\u00e9terminante dans votre capacit\u00e9 \u00e0 utliser perf. Si vous n&rsquo;\u00eates pas root sur votre syst\u00e8me, commencez par v\u00e9rifier cette valeur. Si elle est de 2, il est possible que vous ne puissiez pas utiliser Perf, m\u00eame si la commande est disponible.<\/p>\n<p>La signification des valeurs et la suivante:<\/p>\n<ul>\n<li>-1 : Permettre l&rsquo;utilisation de tous les \u00e9v\u00e8nements par tous les utlilisateurs<\/li>\n<li>&gt;=0 : Interdire les \u00ab\u00a0raw tracepoints\u00a0\u00bb sans la capatit\u00e9 CAP_IOC_LOCK<\/li>\n<li>&gt;=1 : Interdire la lecture des \u00e9v\u00e8nements CPU sans la capacit\u00e9 CAP_SYS_ADMIN<\/li>\n<li>&gt;=2 : Interdire le profiling noyau aux utilisateurs sans la capacit\u00e9 CAP_SYS_ADMIN<\/li>\n<\/ul>\n<p>Certains syst\u00e8mes sont r\u00e9cicents \u00e0 permettre l&rsquo;utilisation de perf du fait de certaines failles par exemple (<a href=\"https:\/\/cve.mitre.org\/cgi-bin\/cvename.cgi?name=CVE-2013-2094\">CVE-2013-2094<\/a>), il peut donc il y avoir des objections \u00e0 la mise en place de cette option sur des syst\u00e8mes partag\u00e9s.<\/p>\n<p>Si vous \u00eates root sur vote machine, tout est plus simple car vous pourrez faire varier cette valeur en fonction de vos besoins de profilage.<\/p>\n<p>Pour lire la valeur:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\n\r\ncat \/proc\/sys\/kernel\/perf_event_paranoid\r\n\r\n<\/pre>\n<p>Et naturellement pour d\u00e9finir cette valeur (en root uniquement):<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\n\r\necho &quot;1&quot; &gt; \/proc\/sys\/kernel\/perf_event_paranoid\r\n\r\n<\/pre>\n<h1>Installation<\/h1>\n<p>Sous Centos 7, il est possible d&rsquo;installer perf en faisant:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nsudo yum install perf gawk\r\n<\/pre>\n<p>Sous Ubuntu:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nsudo apt install linux-tools-common gawk\r\n<\/pre>\n<p>Pour tester votre installation vous pouvez simplement faire la commande suivante:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nperf record ls\r\n<\/pre>\n<p>Cela devrait produire une sortie proche de celle-ci:<\/p>\n<blockquote><p>perf.data<br \/>\n[ perf record: Woken up 1 times to write data ]<br \/>\n[ perf record: Captured and wrote 0.013 MB perf.data (21 samples) ]<\/p><\/blockquote>\n<h1>Collecte de donn\u00e9es<\/h1>\n<p>Nous allons maitenant faire notre premi\u00e8re mesure avec linux Perf. Cet outil est tr\u00e8s avanc\u00e9 et permet de faire du suivi \u00e0 tr\u00e8s faible grain. Vous \u00eates donc encourag\u00e9s \u00e0 aller plus loin que ce que nous allons efleurer dans ce tutoriel.<\/p>\n<p>Nous commencerons par un programme trivial en C (test.c) :<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n#include &lt;stdio.h&gt;\r\n\r\nint main(int argc, char **argv)\r\n{\r\n   int i;\r\n   int j;\r\n\r\n   double result = 0.0;\r\n\r\n   for (i = 0; i &lt; 100000; ++i)\r\n   {\r\n      for (j = 0; j &lt; 10000; ++j) { result += i + j * 0,1; } } printf(&quot;--&gt; %g\\n&quot;, result );\r\n\r\n   return 0;\r\n}\r\n<\/pre>\n<p>Compilons le code en mode d\u00e9bug :<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\ngcc -g -O3 -o test .\/test.c\r\n<\/pre>\n<p>Maintenant r\u00e9alisons un profilage simple avec Perf:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nperf record .\/test\r\n<\/pre>\n<p>La sortie devrait \u00eatre proche de la suivante, avec des informations relatives \u00e0 Perf:<\/p>\n<blockquote><p>4.99995e+13<br \/>\n[ perf record: Woken up 2 times to write data ]<br \/>\n[ perf record: Captured and wrote 0.278 MB perf.data (6994 samples) ]<\/p><\/blockquote>\n<h1>Exploration des donn\u00e9es<\/h1>\n<p>La sortie la plus simple de Perf est obtenue sur la sortie standard avec :<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nperf report --stdio\r\n<\/pre>\n<p>Ce qui produit le profil suivant (reproduit ici partiellement):<\/p>\n<blockquote><p># To display the perf.data header info, please use &#8211;header\/&#8211;header-only options.<br \/>\n#<br \/>\n#<br \/>\n# Total Lost Samples: 0<br \/>\n#<br \/>\n# Samples: 6K of event &lsquo;cycles:pp&rsquo;<br \/>\n# Event count (approx.): 3018622192<br \/>\n#<br \/>\n# Overhead Command Shared Object Symbol<br \/>\n# &#8230;&#8230;.. &#8230;&#8230;. &#8230;&#8230;&#8230;&#8230;&#8230;.. &#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;<br \/>\n#<br \/>\n99.67% a.out a.out [.] main<br \/>\n0.09% a.out [kernel.kallsyms] [k] irq_return<br \/>\n0.04% a.out [kernel.kallsyms] [k] native_write_msr_safe<br \/>\n(&#8230;)<br \/>\n#<br \/>\n# (Tip: See assembly instructions with percentage: perf annotate )<br \/>\n#<\/p><\/blockquote>\n<p>On remarque surtout que 99,67 % du temps est pass\u00e9 dans la fonction main, mais d&rsquo;o\u00f9 ces informations sont-elles venues ? observez dans le dossier courant, il ya un nouveau fichier \u00ab\u00a0perf.dat\u00a0\u00bb, c&rsquo;est ce fichier qui a permis la communication de \u00ab\u00a0record\u00a0\u00bb \u00e0 \u00ab\u00a0report\u00a0\u00bb. Ce nom est le nom par d\u00e9faut, raison pour laquelle nous n&rsquo;avons pas eu \u00e0 le sp\u00e9cifier. Il est possible de le modifier en utilisant respectivement \u00ab\u00a0-o\u00a0\u00bb dans record et \u00ab\u00a0-i\u00a0\u00bb dans report. \u00c0 ce point nous vous encourageons \u00e0 regarder l&rsquo;aide de ces commandes de la mani\u00e8re suivante pour v\u00e9rifier ces options:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nperf report -h\r\nperf record -h\r\n<\/pre>\n<p>Perf permet \u00e9galement d&rsquo;annoter le code source d&rsquo;une fonction de mani\u00e8re simple, dans le dossier o\u00f9 vous avez effectu\u00e9 votre mesure, appeler la commande suivante:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nperf annotate main --stdio\r\n<\/pre>\n<p>Notez que si vous omettez &#8211;stdio, vous aurez une version interactive du code source annot\u00e9. Cette commande produit alors la sortie d\u00e9sassembl\u00e9e du code accompagn\u00e9e du code source d&rsquo;origine (car nous avons compil\u00e9 avec -g). Nous\u00a0pouvons alors dire exactement \u00e0 quelle ligne le programme a pass\u00e9 la majeure partie de son temps (cf. capture d&rsquo;\u00e9cran).<\/p>\n<p><a href=\"http:\/\/learningcenter.paratools.com\/wp-content\/uploads\/2017\/04\/PERF.png\"><img loading=\"lazy\" class=\"aligncenter size-thumbnail wp-image-103\" src=\"http:\/\/learningcenter.paratools.com\/wp-content\/uploads\/2017\/04\/PERF-150x150.png\" alt=\"\" width=\"150\" height=\"150\" \/><\/a><\/p>\n<p>Il est possible d&rsquo;appliquer cette commande \u00e0 toute fonction qui contient des \u00e9chantillons de mesure, ces fonctions sont list\u00e9es par la commande \u00ab\u00a0perf report\u00a0\u00bb. De plus si vous la lan\u00e7ez sans l&rsquo;option \u00ab\u00a0&#8211;stdio\u00a0\u00bb vous pourrez naviguer de mani\u00e8re interactive entre les fonctions mesur\u00e9es. Il est \u00e9galement possible d&rsquo;effectuer cette anotation depuis cette interface ncurses. Elle est donc plus pratique \u00e0 l&rsquo;usage bien que les sorties textuelles que nous avons expos\u00e9es sont les plus utiles pour se concentrer sur une seule fonction d&rsquo;int\u00e9r\u00eat.<\/p>\n<h1>Sorties Avanc\u00e9es<\/h1>\n<p>Il existe de nombreux modules permettant de post-traiter la sortie de Perf, nous alons ici nous concentrer sur l&rsquo;un d&rsquo;entre eux, le Flamegraph. C&rsquo;est un outil compl\u00e9mentaire disponible sur Github <a href=\"http:\/\/www.brendangregg.com\/flamegraphs.html\">http:\/\/www.brendangregg.com\/flamegraphs.html<\/a>. Encore une fois, nous n&rsquo;exposerons pas toutes les possibilit\u00e9s de ce programme, nous vous invitons \u00e0 vous r\u00e9f\u00e9rer \u00e0 la <a href=\"https:\/\/github.com\/brendangregg\/FlameGraph\/blob\/master\/README.md\">documentation<\/a>.<\/p>\n<p>Installez tout d&rsquo;abord flamegraph en clonant le d\u00e9p\u00f4t GIT:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\ngit clone https:\/\/github.com\/brendangregg\/FlameGraph.git\r\n<\/pre>\n<p>Ensuite rentrez dans le dossier et notez le chemin de l&rsquo;installation:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\ncd FlameGraph\r\npwd\r\n<\/pre>\n<p>Par exemple:<\/p>\n<blockquote><p>\/home\/jbbesnard\/store\/repo\/FlameGraph<\/p><\/blockquote>\n<p>Nous feront par la suite r\u00e9f\u00e9rence \u00e0 ce chemin en tant que FL_PREFIX.<\/p>\n<p>Pour simplifier l&rsquo;utilisation de l&rsquo;outil nous allons devoir faire un petit script bash (il est entendu que vous adapterez la valeur de FL_PREFIX):<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\n#!\/bin\/sh\r\n\r\nFL_PREFIX=\/home\/jbbesnard\/store\/repo\/FlameGraph\r\n\r\nperf script $@ | $FL_PREFIX\/stackcollapse-perf.pl | $FL_PREFIX\/flamegraph.pl\r\n<\/pre>\n<p>Ce script appelle FlameGraph de la mani\u00e8re la plus simple possible et g\u00e9n\u00e8re un fichier SVG sur la sortie standard. Il est possible de lui passer des options qui seront toutes pass\u00e9es \u00e0 \u00ab\u00a0perf script\u00a0\u00bb (par exemple -i myprof.dat). Vous pouvez placer ce script dans votre PATH pour l&rsquo;utiliser par la suite lors de vos mesures comme suit. Nous consid\u00e9rons que le script s&rsquo;appelle <b>flg<\/b>.<\/p>\n<p>Dans ce nouveau cas, nous allons intrumenter les piles d&rsquo;appel, la commande de profilage devient donc:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nperf record --call-graph fp .\/test\r\n<\/pre>\n<p>Partons des donn\u00e9es obtenue sur le benchmark Lulesh en contexte non OpenMP pour simplifier. Vous pouvez les t\u00e9l\u00e9charger <a href=\"http:\/\/france.paratools.com\/perf.data\">ICI<\/a>.<\/p>\n<p>Nous allons maintenant g\u00e9n\u00e9rer la sortie de flamegraph en utilisant le script que nous avons cr\u00e9\u00e9 dans l&rsquo;\u00e9tape pr\u00e9c\u00e9dente (veiller a correctement pointer vers la commande flg correspondant \u00e0 votre script):<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nfgl &gt; out.svg\r\n<\/pre>\n<p>Cela produit la sortie <b>interactive<\/b> suivante:<\/p>\n<p><object data=\"http:\/\/france.paratools.com\/out.svg\" type=\"image\/svg+xml\"><\/object><\/p>\n<h1>Utilisation en contexte MPI<\/h1>\n<p>Si vous souhaitez utiliser perf en contexte MPI, vous devez faire attention \u00e0 g\u00e9n\u00e9rer des sorties diff\u00e9rentes. En effet, si vous ne passez pas d&rsquo;option, tous les processus MPI vont \u00e9crire dans le m\u00eame fichier \u00ab\u00a0perf.data\u00a0\u00bb. Il faut donc cr\u00e9er un wrapper qui passera \u00e0 \u00ab\u00a0perf record\u00a0\u00bb un nom diff\u00e9rent pour chaque processus MPI. Par exemple le script suivant :<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\n#!\/bin\/sh\r\n\r\nH=`hostname`\r\nP=$$\r\n\r\nperf record -o perf-${H}-${P}.data  $@\r\n<\/pre>\n<p>Le script s&rsquo;utilise de la mani\u00e8re suivante (consid\u00e9rant que le wrapper est dans le PATH et qu&rsquo;il s&rsquo;appelle <b>mpiperf<\/b>):<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nmpirun -np 4 mpiperf .\/program options\r\n<\/pre>\n<p>Avec ce script, de multiples fichiers perf-HOTE-PID.data seront g\u00e9n\u00e9r\u00e9s dans le dossier courant, permettant d&rsquo;instrumenter de multiples processus MPI.<\/p>\n<h1>Profilage \u00e0 l&rsquo;\u00e9chelle du syst\u00e8me<\/h1>\n<p>Parfois, il est int\u00e9ressant de profiler un noeud dans sa totalit\u00e9. Par exemple pour mesurer plusieurs applications \u00e0 la fois. La commande est tr\u00e8s simple mais requiert des droits suffisants pour l&rsquo;utilisateur faisant la mesure.<\/p>\n<p>La commande repose simplement sur l&rsquo;option \u00ab\u00a0-a\u00a0\u00bb par exemple:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nperf record -a --call-graph fp\r\n<\/pre>\n<p>Si la valeur de <i>\/proc\/sys\/kernel\/perf_event_paranoid<\/i> est incorrecte vous aurez ce message:<\/p>\n<blockquote><p>Error:<br \/>\nYou may not have permission to collect system-wide stats.<\/p>\n<p>Consider tweaking \/proc\/sys\/kernel\/perf_event_paranoid,<br \/>\nwhich controls use of the performance events system by<br \/>\nunprivileged users (without CAP_SYS_ADMIN).<\/p>\n<p>The current value is 1:<\/p>\n<p>-1: Allow use of (almost) all events by all users<br \/>\n&gt;= 0: Disallow raw tracepoint access by users without CAP_IOC_LOCK<br \/>\n&gt;= 1: Disallow CPU event access by users without CAP_SYS_ADMIN<br \/>\n&gt;= 2: Disallow kernel profiling by users without CAP_SYS_ADMIN<\/p><\/blockquote>\n<p>La mise \u00e0 -1 (en connaissance de cause) de ce fichier comme indiqu\u00e9 au d\u00e9but de ce tutoriel permettra de r\u00e9gler ce probl\u00e8me.<\/p>\n<h1>Surveillance Syst\u00e8me<\/h1>\n<p>Il est \u00e9galement possible d&rsquo;utiliser Perf pour afficher l&rsquo;\u00e9tat \u00ab\u00a0global\u00a0\u00bb du syst\u00e8me, \u00e9vitant ainsi l&rsquo;alternance, mesure puis affichage. La commande suivante permet d&rsquo;afficher les fonctions consommant du temps CPU \u00e0 l&rsquo;instant t:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nperf top\r\n<\/pre>\n<h1>Conclusion<\/h1>\n<p>N&rsquo;h\u00e9sitez pas a nous faire vos retours sur cette introduction \u00e0 Linux Perf. Notez qu&rsquo;\u00e0 ce point vous \u00eatre tr\u00e8s loin d&rsquo;avoir utilis\u00e9 toutes les fonctionnalit\u00e9s.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Dans ce tutorial, nous allons utiliser Linux-Perf pour collecter les donn\u00e9es de performance d&rsquo;une application parall\u00e8le. Notre but ici et de permettre simplement l&rsquo;identification des points\u00a0 chauds d&rsquo;un code donn\u00e9, le tout en \u00e9tant agnostique au runtime sous-jacent. \u00c0 la fin de ce module vous saurez: Collecter des donn\u00e9es de performance avec Linux-perf Analyser ces [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[4],"tags":[8,11,5,6,7],"_links":{"self":[{"href":"https:\/\/learningcenter.paratools.com\/index.php?rest_route=\/wp\/v2\/posts\/43"}],"collection":[{"href":"https:\/\/learningcenter.paratools.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/learningcenter.paratools.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/learningcenter.paratools.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/learningcenter.paratools.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=43"}],"version-history":[{"count":61,"href":"https:\/\/learningcenter.paratools.com\/index.php?rest_route=\/wp\/v2\/posts\/43\/revisions"}],"predecessor-version":[{"id":180,"href":"https:\/\/learningcenter.paratools.com\/index.php?rest_route=\/wp\/v2\/posts\/43\/revisions\/180"}],"wp:attachment":[{"href":"https:\/\/learningcenter.paratools.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=43"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/learningcenter.paratools.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=43"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/learningcenter.paratools.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=43"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}