{"id":1395,"date":"2012-01-14T10:05:49","date_gmt":"2012-01-14T09:05:49","guid":{"rendered":"http:\/\/www.blaess.fr\/christophe\/?p=1395"},"modified":"2012-01-14T10:05:49","modified_gmt":"2012-01-14T09:05:49","slug":"parallelisation-de-compilations","status":"publish","type":"post","link":"https:\/\/www.blaess.fr\/christophe\/2012\/01\/14\/parallelisation-de-compilations\/","title":{"rendered":"Parall\u00e9lisation de compilations"},"content":{"rendered":"<p style=\"text-align: justify;\">(<a title=\"Parallelizing Compilations\" href=\"http:\/\/www.blaess.fr\/christophe\/2012\/01\/14\/parallelizing-compilations\/\">English translation here<\/a>)<\/p>\n<p style=\"text-align: justify;\">Il m&rsquo;arrive tr\u00e8s fr\u00e9quemment de compiler des noyaux Linux, souvent durant des sessions de formation ou des prestations d&rsquo;ing\u00e9nierie (principalement dans le domaine de l&#8217;embarqu\u00e9 ou le d\u00e9veloppement de drivers), et parfois \u00e0 titre exp\u00e9rimental ou par simple curiosit\u00e9 pour r\u00e9diger des articles ou mon prochain livre.<\/p>\n<p style=\"text-align: justify;\">La dur\u00e9e de compilation varie beaucoup en fonction de la quantit\u00e9 de code (de drivers, syst\u00e8mes de fichiers, protocoles, etc.) et de la puissance de la machine h\u00f4te. Sur un PC de milieu de gamme, la compilation d&rsquo;un kernel ajust\u00e9 pour un syst\u00e8me embarqu\u00e9 dure environ trois minutes. Sur une machine d&rsquo;entr\u00e9e de gamme (ou un peu ancienne), la compilation d&rsquo;un noyau g\u00e9n\u00e9rique pour PC (disposant donc de centaines de drivers sous forme de modules) peut durer une heure.<\/p>\n<p>\n<!--more-->\n<\/p>\n<p style=\"text-align: justify;\">Pour tirer parti du parall\u00e9lisme propos\u00e9 par les processeurs actuels (syst\u00e8mes multiprocesseurs, multicoeurs ou avec hyper-threading), la commande <code>make<\/code> nous permet de lancer simultan\u00e9ment plusieurs jobs. Ainsi<\/p>\n<pre>$ <strong>make -j 4<\/strong><\/pre>\n<p style=\"text-align: justify;\">s&rsquo;arrangera pour qu&rsquo;il y ait toujours quatre jobs de compilation actifs.<\/p>\n<p style=\"text-align: justify;\">J&rsquo;ai longtemps r\u00e9p\u00e9t\u00e9 que \u00ab\u00a0<em>si vous avez N processeurs (ou coeurs, ou CPU virtuels) disponibles, vous gagnerez du temps de compilation en lan\u00e7ant 2N jobs en parall\u00e8le<\/em>\u00ab\u00a0. Ceci repose sur l&rsquo;id\u00e9e que pour chaque processeur nous avons un job qui effectue de la compilation (en consommant du temps CPU) et tandis qu&rsquo;un autre job peut terminer de sauvegarder les r\u00e9sultats de la compilation pr\u00e9c\u00e9dente ou charger le fichier source du traitement suivant. Mais&#8230; est-ce vrai&nbsp;?<\/p>\n<h1>Script de test<\/h1>\n<p style=\"text-align: justify;\">Pour en avoir le coeur net, j&rsquo;ai \u00e9crit le petit script suivant, qui t\u00e9l\u00e9charge au besoin les sources d&rsquo;un noyau et les d\u00e9compresse, puis r\u00e9alise plusieurs compilations en d\u00e9marrant un nombre variable de jobs.<\/p>\n<p style=\"text-align: justify;\">Par exemple si on lance<\/p>\n<pre>$ <strong>.\/test-make-j.sh 3 5 8<\/strong><\/pre>\n<p style=\"text-align: justify;\">Il effectue trois compilations compl\u00e8tes&nbsp;: l&rsquo;une avec trois t\u00e2ches en parall\u00e8le, la suivante avec cinq jobs et la derni\u00e8re avec huit, les r\u00e9sultats \u00e9tant cumul\u00e9s dans un fichier de texte. Le script est le suivant.<\/p>\n<pre><a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-14\/test-make-j.sh\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-14\/test-make-j.sh\" target=\"_blank\"><strong>test-make-j.sh <\/strong><\/a>\n#! \/bin\/sh\n\nKERNEL_VERSION=\"linux-3.2\"\nKERNEL_URL_PATH=\"www.kernel.org\/pub\/linux\/kernel\/v3.0\/\"\nRESULT_FILE=\"compilation-timing.txt\"\n\nif [ \"$#\" -eq 0 ]\nthen\n  echo \"usage: $@ jobs_number...\" &gt;&amp; 2\n  exit 0\nfi\n\nif [ ! -d \"${KERNEL_VERSION}\" ]\nthen\n  if [ ! -f \"${KERNEL_VERSION}.tar.bz2\" ]\n  then\n    wget \"${KERNEL_URL_PATH}\/${KERNEL_VERSION}.tar.bz2\"\n    if [ $? -ne 0 ] || [ ! -f \"${KERNEL_VERSION}.tar.bz2\" ]\n    then\n      echo \"unable to obtain ${KERNEL_VERSION} archive\" &gt;&amp;2\n      exit 1\n    fi\n  fi\n  tar xjf \"${KERNEL_VERSION}.tar.bz2\"\n  if [ $? -ne 0 ]\n  then\n    echo \"Error while uncompressing kernel archive\" &gt;&amp;2\n    exit 1\n  fi\nfi\n\ncd \"${KERNEL_VERSION}\"\n\necho \"# Timings of ${KERNEL_VERSION} compilations\" &gt;&gt; \"${RESULT_FILE}\"\nnb_cpu=$(grep \"^processor\" \/proc\/cpuinfo | wc -l)\n\necho \"# Processors: ${nb_cpu}\" &gt;&gt; \"${RESULT_FILE}\"\naffinity=$(taskset -p $$ | sed -e 's\/^.*:\/\/') &gt;&gt; \"${RESULT_FILE}\"\n\necho \"# Affinity mask: ${affinity}\" &gt;&gt; \"${RESULT_FILE}\"\nfor nb in \"$@\"\ndo\n  echo \"# Compiling with $nb simultaneous jobs\" &gt;&gt; \"${RESULT_FILE}\"\n  <strong>make mrproper<\/strong>\n  <strong>make i386_defconfig<\/strong>\n  sync\n  sleep 10 # Let's all calm down\n  start=$(date \"+%s\")\n  <strong>make -j $nb<\/strong>\n  sync\n  end=$(date \"+%s\")\n  # This script will fail during february 2038 ;-)\n  echo \"$nb     $((end - start))\" &gt;&gt; \"${RESULT_FILE}\"\ndone<\/pre>\n<h1>R\u00e9sultats<\/h1>\n<p style=\"text-align: justify;\">Voici les r\u00e9sultats d&rsquo;une ex\u00e9cution sur un processeur Intel Q6600 Quad-Core (fichier <a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-14\/Intel-Q6600-1.txt\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-14\/Intel-Q6600-1.txt\" target=\"_blank\">Intel-Q6600-1.txt<\/a>)<\/p>\n<pre># Timings of linux-3.2 compilations\n# Processors: 4\n# Affinity mask:  f\n# Compiling with 1 simultaneous jobs\n1     675\n# Compiling with 2 simultaneous jobs\n2     346\n# Compiling with 3 simultaneous jobs\n3     241\n# Compiling with 4 simultaneous jobs\n4     197\n# Compiling with 5 simultaneous jobs\n5     198\n# Compiling with 6 simultaneous jobs\n6     194\n# Compiling with 7 simultaneous jobs\n7     195\n# Compiling with 8 simultaneous jobs\n8     196\n# Compiling with 9 simultaneous jobs\n9     197\n# Compiling with 10 simultaneous jobs\n10     198\n# Compiling with 11 simultaneous jobs\n11     198\n# Compiling with 12 simultaneous jobs\n12     198\n# Compiling with 13 simultaneous jobs\n13     200\n# Compiling with 14 simultaneous jobs\n14     201\n# Compiling with 15 simultaneous jobs\n15     201\n# Compiling with 16 simultaneous jobs\n16     200<\/pre>\n<p style=\"text-align: justify;\">Observons-les graphiquement avec cette petite ligne de commande pour Gnuplot. Horizontalement, nous voyons le nombre de jobs simultan\u00e9s et verticalement le temps de compilation en secondes.<\/p>\n<pre>$ <strong>echo \"set terminal png size 640,480 ; set output '.\/Intel-Q6600-1.png'; plot 'Intel-Q6600-1.txt' with linespoints\" | gnuplot<\/strong><\/pre>\n<p>&nbsp;<\/p>\n<div id=\"attachment_1402\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/01\/Intel-Q6600-1.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-1402\" class=\"size-medium wp-image-1402\" title=\"Intel-Q6600-1\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/01\/Intel-Q6600-1-300x225.png\" alt=\"Compilations parall\u00e8les sur quatre CPU\" width=\"300\" height=\"225\" \/><\/a><p id=\"caption-attachment-1402\" class=\"wp-caption-text\">Compilations parall\u00e8les sur quatre CPU<\/p><\/div>\n<p style=\"text-align: justify;\">Visiblement, les meilleurs r\u00e9sultats sont atteints (\u00e0 quelques fluctuations pr\u00e8s) d\u00e8s <code>make -j 4<\/code>. Essayons de confirmer ceci. Avant de lancer le script, nous le limitons sur deux processeurs avec la commande suivante qui fixe les jobs lanc\u00e9s \u00e0 partir du shell courant sur les processeurs 2 et 3.<\/p>\n<pre>$ <strong>taskset -pc 2-3 $$<\/strong><\/pre>\n<p style=\"text-align: justify;\">Voici le r\u00e9sultat (fichier <a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-14\/Intel-Q6600-2.txt\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-14\/Intel-Q6600-2.txt\" target=\"_blank\">Intel-QL6600-2.txt<\/a>).<\/p>\n<pre># Timings of linux-3.2 compilations\n# Processors: 4\n# Affinity mask:  c\n# Compiling with 1 simultaneous jobs\n1     684\n# Compiling with 2 simultaneous jobs\n2     360\n# Compiling with 3 simultaneous jobs\n3     362\n# Compiling with 4 simultaneous jobs\n4     366\n# Compiling with 8 simultaneous jobs\n8     370\n# Compiling with 16 simultaneous jobs\n16     376\n# Compiling with 32 simultaneous jobs\n32     377\n# Compiling with 64 simultaneous jobs\n64     378<\/pre>\n<div id=\"attachment_1405\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/01\/Intel-Q6600-21.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-1405\" class=\"size-medium wp-image-1405\" title=\"Intel-Q6600-2\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/01\/Intel-Q6600-21-300x225.png\" alt=\"Compilations parall\u00e8les sur deux CPU\" width=\"300\" height=\"225\" \/><\/a><p id=\"caption-attachment-1405\" class=\"wp-caption-text\">Compilations parall\u00e8les sur deux CPU<\/p><\/div>\n<p style=\"text-align: justify;\">Cette fois, il est visible que le minimum de temps est obtenu avec make -j 2. Si nous r\u00e9p\u00e9tons l&rsquo;exp\u00e9rience sur un seul CPU, on obtient les valeurs suivantes (fichier <a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-14\/Intel-Q6600-3.txt\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-14\/Intel-Q6600-3.txt\" target=\"_blank\">Intel-Q6600-3.txt<\/a>).<\/p>\n<pre># Timings of linux-3.2 compilations\n# Processors: 4\n# Affinity mask:  8\n# Compiling with 1 simultaneous jobs\n1     683\n# Compiling with 2 simultaneous jobs\n2     698\n# Compiling with 3 simultaneous jobs\n3     708\n# Compiling with 4 simultaneous jobs\n4     709\n# Compiling with 5 simultaneous jobs\n5     719\n# Compiling with 6 simultaneous jobs\n6     719\n# Compiling with 7 simultaneous jobs\n7     720\n# Compiling with 8 simultaneous jobs\n8     724<\/pre>\n<p style=\"text-align: justify;\">Ce qui se repr\u00e9sente sur le graphique suivant.<\/p>\n<div id=\"attachment_1406\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/01\/Intel-Q6600-3.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-1406\" class=\"size-medium wp-image-1406\" title=\"Intel-Q6600-3\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/01\/Intel-Q6600-3-300x225.png\" alt=\"Compilations parall\u00e8les sur un seul CPU\" width=\"300\" height=\"225\" \/><\/a><p id=\"caption-attachment-1406\" class=\"wp-caption-text\">Compilations parall\u00e8les sur un seul CPU<\/p><\/div>\n<p style=\"text-align: justify;\">Nous pouvons regrouper ces trois courbes sur un m\u00eame graphique pour mieux visualiser leurs \u00e9chelles (je n&rsquo;ai pas prolong\u00e9 la courbe de la compilation sur un seul CPU, mais on peut imaginer qu&rsquo;elle se poursuit avec une l\u00e9g\u00e8re croissance).<\/p>\n<div id=\"attachment_1448\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/01\/Intel-Q6600.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-1448\" class=\"size-medium wp-image-1448\" title=\"Intel-Q6600\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/01\/Intel-Q6600-300x225.png\" alt=\"Compilations parall\u00e8les sur processeur Q6600\" width=\"300\" height=\"225\" \/><\/a><p id=\"caption-attachment-1448\" class=\"wp-caption-text\">Compilations parall\u00e8les sur processeur Q6600<\/p><\/div>\n<p style=\"text-align: justify;\">Pour en avoir le coeur net, nous pouvons recommencer l&rsquo;exp\u00e9rience sur un autre processeur avec deux coeurs (AMD QL66). Les r\u00e9sultats sont les suivants (fichier <a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-14\/AMD-QL66-1.txt\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-14\/AMD-QL66-1.txt\" target=\"_blank\">AMD-QL66-1.txt<\/a>).<\/p>\n<pre># Timings of linux-3.2 compilations\n# Processors: 2\n# Affinity mask:  3\n# Compiling with 1 simultaneous jobs\n1     1113\n# Compiling with 2 simultaneous jobs\n2     844\n# Compiling with 3 simultaneous jobs\n3     875\n# Compiling with 4 simultaneous jobs\n4     863\n# Compiling with 5 simultaneous jobs\n5     840\n# Compiling with 6 simultaneous jobs\n6     844\n# Compiling with 7 simultaneous jobs\n7     844\n# Compiling with 8 simultaneous jobs\n8     851<\/pre>\n<div id=\"attachment_1407\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/01\/AMD-QL66-1.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-1407\" class=\"size-medium wp-image-1407 \" title=\"AMD-QL66-1\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/01\/AMD-QL66-1-300x225.png\" alt=\"Compilations parall\u00e8les sur deux CPU\" width=\"300\" height=\"225\" \/><\/a><p id=\"caption-attachment-1407\" class=\"wp-caption-text\">Compilations parall\u00e8les sur deux CPU<\/p><\/div>\n<p style=\"text-align: justify;\">Essayons une derni\u00e8re exp\u00e9rience, sur la m\u00eame machine (deux CPU), en d\u00e9sactivant deux \u00e9l\u00e9ments&nbsp;:<\/p>\n<ul>\n<li style=\"text-align: justify;\">la lecture anticip\u00e9e des blocs suivants du disque (qui permet d&rsquo;am\u00e9liorer les lectures localis\u00e9es) avec <code><strong>echo 0 &gt; \/sys\/block\/sda\/read_ahead_kb<\/strong><\/code><\/li>\n<\/ul>\n<ul>\n<li style=\"text-align: justify;\">l&rsquo;\u00e9criture diff\u00e9r\u00e9e (de 30 secondes environ) des blocs (qui \u00e9vite les acc\u00e8s r\u00e9p\u00e9titifs au disque en cas de modifications successives) avec <code><strong>mount \/ -o sync,remount<\/strong><\/code>.<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p style=\"text-align: justify;\">Cette fois les r\u00e9sultats sont tr\u00e8s diff\u00e9rents (fichier <a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-14\/AMD-QL66-2.txt\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-14\/AMD-QL66-2.txt\" target=\"_blank\">AMD-QL66-2.txt<\/a>). Les temps sont beaucoup plus longs que pr\u00e9c\u00e9demment car \u00e0 chaque \u00e9criture sur le disque, le processus attend que les donn\u00e9es soient transmises au p\u00e9riph\u00e9rique pour continuer son travail.<\/p>\n<pre> Timings of linux-3.2 compilations\n# Processors: 2\n# Affinity mask:  3\n# Compiling with 1 simultaneous jobs\n1     3487\n# Compiling with 2 simultaneous jobs\n2     2562\n# Compiling with 3 simultaneous jobs\n3     2198\n# Compiling with 4 simultaneous jobs\n4     1963\n# Compiling with 5 simultaneous jobs\n5     1779\n# Compiling with 6 simultaneous jobs\n6     1646\n# Compiling with 7 simultaneous jobs\n7     1636\n# Compiling with 8 simultaneous jobs\n8     1602\n# Compiling with 9 simultaneous jobs\n9     1738\n# Compiling with 10 simultaneous jobs\n10     1577<\/pre>\n<div id=\"attachment_1408\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/01\/AMD-QL66-2.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-1408\" class=\"size-medium wp-image-1408\" title=\"AMD-QL66-2\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/01\/AMD-QL66-2-300x225.png\" alt=\"Compilations parall\u00e8les sans optimisation disque\" width=\"300\" height=\"225\" \/><\/a><p id=\"caption-attachment-1408\" class=\"wp-caption-text\">Compilations parall\u00e8les (2 CPU) sans optimisation disque<\/p><\/div>\n<p style=\"text-align: justify;\">Ici, la courbe est plus proche de celle que j&rsquo;imaginais \u00e0 l&rsquo;origine. Le fait de placer plusieurs jobs par CPU permet de tirer parti des temps d&rsquo;attente li\u00e9s au disque pour avancer dans une autre compilation. Regroupons les deux courbes pour bien voir les dur\u00e9es respectives.<\/p>\n<div id=\"attachment_1449\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/01\/AMD-QL66.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-1449\" class=\"size-medium wp-image-1449\" title=\"Compilation parall\u00e8le sur QL66\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/01\/AMD-QL66-300x225.png\" alt=\"Compilation parall\u00e8le sur QL66\" width=\"300\" height=\"225\" \/><\/a><p id=\"caption-attachment-1449\" class=\"wp-caption-text\">Compilations parall\u00e8les sur QL66<\/p><\/div>\n<h1>Conclusion<\/h1>\n<p style=\"text-align: justify;\">Nous voyons qu&rsquo;avec la qualit\u00e9 de l&rsquo;ordonnanceur d&rsquo;entr\u00e9es-sorties (<em>IO Scheduler<\/em>) de Linux, et la gestion optimis\u00e9e des p\u00e9riph\u00e9riques blocs, les meilleurs temps de compilation sont obtenus d\u00e8s que l&rsquo;on lance <strong>un job par processeur<\/strong>.<\/p>\n<p style=\"text-align: justify;\">Je modifierai donc \u00e0 l&rsquo;avenir ma recommandation en \u00ab\u00a0<em>Si vous avez N processeurs disponibles, compilez votre noyau avec\u00a0 <\/em><code>make -j N<\/code><em>\u00a0 pour avoir le meilleur temps d&rsquo;ex\u00e9cution<\/em>\u00ab\u00a0.<\/p>\n<p style=\"text-align: justify;\">PS&nbsp;: si vous avez l&rsquo;occasion de faire fonctionner ce script sur des architectures diff\u00e9rentes (8 processeurs, 16 processeurs, etc.) je serai tr\u00e8s int\u00e9ress\u00e9 par vos r\u00e9sultats.<\/p>","protected":false},"excerpt":{"rendered":"<p>(English translation here) Il m&rsquo;arrive tr&egrave;s fr&eacute;quemment de compiler des noyaux Linux, souvent durant des sessions de formation ou des prestations d&rsquo;ing&eacute;nierie (principalement dans le domaine de l&rsquo;embarqu&eacute; ou le d&eacute;veloppement de drivers), et parfois &agrave; titre exp&eacute;rimental ou par simple curiosit&eacute; pour r&eacute;diger des articles ou mon prochain livre. La dur&eacute;e de compilation varie [&hellip;]<\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8,10],"tags":[],"class_list":["post-1395","post","type-post","status-publish","format-standard","hentry","category-linux-2","category-microprocesseur"],"_links":{"self":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/1395","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/comments?post=1395"}],"version-history":[{"count":0,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/1395\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/media?parent=1395"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/categories?post=1395"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/tags?post=1395"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}