{"id":1201,"date":"2021-03-02T13:06:12","date_gmt":"2021-03-02T12:06:12","guid":{"rendered":"https:\/\/www.loicmathieu.fr\/wordpress\/?p=1201"},"modified":"2021-03-04T13:35:46","modified_gmt":"2021-03-04T12:35:46","slug":"introduction-a-quickperf","status":"publish","type":"post","link":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/informatique\/introduction-a-quickperf\/","title":{"rendered":"Introduction \u00e0 Quickperf"},"content":{"rendered":"<p>QuickPerf est une biblioth\u00e8que de test pour Java permettant d&rsquo;\u00e9valuer et d&rsquo;am\u00e9liorer rapidement les performances de votre application.<\/p>\n<p>Le grand int\u00e9r\u00eat de Quickperf r\u00e9side dans le fait que cela s&rsquo;effecue via des tests unitaires, ce qui permet, apr\u00e8s avoir d\u00e9tect\u00e9 et corrig\u00e9 un probl\u00e8me de performance, d&rsquo;avoir des tests de non-r\u00e9gression pour que celui-ci ne revienne jamais ! Vous pouvez alors \u00e9valuer en continue les performances de votre application via votre environnement d&rsquo;int\u00e9gration continue !<\/p>\n<p>Quickperf peut \u00eatre utilis\u00e9 pour simplement mesurer des caract\u00e9ristiques de performance, ou pour asserter sur celle-ci via la d\u00e9finition d&rsquo;<em>expectation<\/em>.<\/p>\n<p>Quickperf n\u00e9cessite Java 7 minimum et fonctionne avec JUnit 4 ou 5 et TestNG. Les exemples de cet article sont r\u00e9alis\u00e9s en Java 11 via JUnit 5.<\/p>\n<p>Pour utiliser Quickperf vous devez ajouter la librairie correspondante \u00e0 votre framework de test, voici un exemple avec Maven pour JUnit 5.<\/p>\n<pre>\n\n    \n        \n            org.junit\n            junit-bom\n            5.7.0\n            pom\n            import\n        \n        \n            org.quickperf\n            quick-perf-bom\n            1.0.1\n            pom\n            import\n        \n    \n \n\n  \n    \n      org.junit.jupiter\n      junit-jupiter-engine\n      test\n    \n    \n       org.junit.platform\n       junit-platform-launcher\n       test\n    \n  \n<\/pre>\n<h2>Un premier exemple<\/h2>\n<p>Avant d&rsquo;entrer en d\u00e9tail dans les fonctionnalit\u00e9s de Quickperf, un petit exemple :<\/p>\n<pre>@QuickPerfTest\npublic class JvmAnnotationsJunit5Test {\n\n    @MeasureHeapAllocation\n    @Test\n    public void test_method_measuring_heap_allocation() {\n        \/\/ java.util.ArrayList: 24 bytes + Object[]: 16 + 100 x 4 = 416 =&gt; 440 bytes\n        ArrayList data = new ArrayList(100);\n    }\n\n    @ExpectNoHeapAllocation\n    @Test\n    public void should_not_allocate() {\n    }\n}<\/pre>\n<ul><li><code>@QuickPerfTest<\/code>: est utilis\u00e9 pour initialiser l&rsquo;extension Quickperf JUnit5 (optionnel)<\/li>\n\n<li><code>@MeasureHeapAllocation<\/code>: va mesurer les allocations m\u00e9moire faites par le test<\/li>\n\n<li><code>@ExpectNoHeapAllocation<\/code>: va cr\u00e9er une <em>expectation<\/em> comme quoi le test ne doit pas r\u00e9aliser d&rsquo;allocation m\u00e9moire. Si celle-ci est fausse, le test sera en \u00e9chec (assertion failure)<\/li>\n<\/ul>\n<p>Lancer ces tests vous donnera le r\u00e9sultat suivant :<\/p>\n<pre>[INFO] -------------------------------------------------------\n[INFO]  T E S T S\n[INFO] -------------------------------------------------------\n[INFO] Running org.quickperf.jvm.JvmAnnotationsJunit5Test\n[QUICK PERF] Measured heap allocation (test method thread): 440 bytes\n[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.203 s - in org.quickperf.jvm.JvmAnnotationsJunit5Test\n[INFO] \n[INFO] Results:\n[INFO] \n[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0\n[INFO] \n[INFO] ------------------------------------------------------------------------\n[INFO] BUILD SUCCESS\n[INFO] ------------------------------------------------------------------------\n<\/pre>\n<p>Build Success! Super!\nAu passage, vous remarquerez la mesure qu&rsquo;a prise Quickperf de l&rsquo;allocation m\u00e9moire du test <code>test_method_measuring_heap_allocation<\/code>:<\/p>\n<pre>[QUICK PERF] Measured heap allocation (test method thread): 440 bytes\n<\/pre>\n<p>Modifions maintenant le code pour ajouter une <em>expectation<\/em> pour le test <code>test_method_measuring_heap_allocation<\/code> comme quoi il doit allouer moins de 400 octets de m\u00e9moire.<\/p>\n<pre>\n@MeasureHeapAllocation\n@ExpectMaxHeapAllocation(value = 400, unit = AllocationUnit.BYTE)\n@Test\npublic void test_method_measuring_heap_allocation() {\n    \/\/ java.util.ArrayList: 24 bytes + Object[]: 16 + 100 x 4 = 416 =&gt; 440 bytes\n    ArrayList data = new ArrayList(100);\n}\n<\/pre>\n<p>Lancer ces tests modifi\u00e9s vous donnera :<\/p>\n<pre>[INFO] -------------------------------------------------------\n[INFO]  T E S T S\n[INFO] -------------------------------------------------------\n[INFO] Running org.quickperf.jvm.JvmAnnotationsJunit5Test\n[QUICK PERF] Measured heap allocation (test method thread): 440 bytes\n[ERROR] Tests run: 2, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 2.258 s &lt;&lt;&lt; FAILURE! - in org.quickperf.jvm.JvmAnnotationsJunit5Test\n[ERROR] test_method_measuring_heap_allocation  Time elapsed: 1.106 s  &lt;&lt;&lt; FAILURE!\njava.lang.AssertionError: \na performance property is not respected\n\n[PERF] Expected heap allocation (test method thread) to be less than 400 bytes but is 440 bytes.\n\n[INFO] \n[INFO] Results:\n[INFO] \n[ERROR] Failures: \n[ERROR]   JvmAnnotationsJunit5Test.test_method_measuring_heap_allocation a performance property is not respected\n\n[PERF] Expected heap allocation (test method thread) to be less than 400 bytes but is 440 bytes.\n\n[INFO] \n[ERROR] Tests run: 2, Failures: 1, Errors: 0, Skipped: 0\n[INFO] \n[INFO] ------------------------------------------------------------------------\n[INFO] BUILD FAILURE\n[INFO] ------------------------------------------------------------------------\n<\/pre>\n<p>Build Failure :(<\/p>\n<p>Mais avec une explication en toute lettre de la cause.<\/p>\n<pre>[PERF] Expected heap allocation (test method thread) to be less than 400 bytes but is 440 bytes.\n<\/pre>\n<p>Une des sp\u00e9cificit\u00e9s de Quickperf est de vous donner le plus d&rsquo;information possible sur la raison de l\u2019\u00e9chec du test, via des phrases compr\u00e9hensibles par un humain.<\/p>\n<h2>Les annotations c\u0153urs (core)<\/h2>\n<p>Les annotations c\u0153urs sont disponibles au sein de la librairie principale de Quickperf, elles offrent les fonctionnalit\u00e9s suivantes :<\/p>\n<ul><li><code>@MeasureExecutionTime<\/code> : mesure le temps d\u2019ex\u00e9cution de la m\u00e9thode de test.<\/li>\n\n<li><code>@ExpectMaxExecutionTime<\/code> : cr\u00e9er une <em>expectation<\/em> comme quoi le test ne doit s&rsquo;ex\u00e9cuter en plus d&rsquo;un certain temps.<\/li>\n<\/ul>\n<p>Il existe aussi un certain nombre d&rsquo;annotations permettant de configurer Quickperf, plus d&rsquo;information <a href=\"https:\/\/github.com\/quick-perf\/doc\/wiki\/core-annotations\" target=\"_blank\" rel=\"noopener noreferrer\">ici<\/a>.<\/p>\n<h2>Les annotations JVM<\/h2>\n<p>La plupart des annotations JVM sont inclues dans la librairie principale de Quickperf sauf les annotations li\u00e9es \u00e0 <a href=\"https:\/\/en.wikipedia.org\/wiki\/JDK_Flight_Recorder\" target=\"_blank\" rel=\"noopener noreferrer\">JFR &#8211; JDK Flight Recorder<\/a> qui n\u00e9cessitent l&rsquo;ajout de la librairie <code>org.quickperf:quick-perf-jfr-annotations<\/code>.<\/p>\n<p><strong>Attention : l&rsquo;utilisation d&rsquo;annotation JVM induit le d\u00e9marrage d&rsquo;une JVM par m\u00e9thode de test.<\/strong><\/p>\n<p>Les annotations JVM fournissent les fonctionnalit\u00e9s suivantes :<\/p>\n<ul><li>Configuration de la JVM qui ex\u00e9cutera le test via <code>@HeapSize<\/code> (pour configurer le Xmx et le Xms), <code>@Xms<\/code>, <code>@Xmx<\/code>, <code>@UseGC<\/code>, <code>@EnableGcLogging<\/code> et <code>@JvmOptions<\/code><\/li>\n\n<li>Mesure des allocations m\u00e9moire via <code>@MeasureHeapAllocation<\/code>, <code>@ExpectMaxHeapAllocation<\/code> et <code>@ExpectNoHeapAllocation<\/code>. Utilise la librairie <a href=\"https:\/\/github.com\/danielshaya\/ByteWatcher\" target=\"_blank\" rel=\"noopener\">ByteWatcher<\/a>.<\/li>\n\n<li>Mesure du resident set size du process de votre JVM via <code>@MeasureRSS<\/code> et <code>@ExpectMaxRSS<\/code>.<\/li>\n\n<li>Profilage de votre application via JFR.<\/li>\n<\/ul>\n<p>Petit zoom sur le profilage de votre application via JFR. L&rsquo;annotation <a>@ProfileJvm<\/code>code&gt;@ProfileJvm&lt;\/code<\/a> va lancer un enregistrement JFR pour l&rsquo;ex\u00e9cution de votre m\u00e9thode que vous pourrez ensuite ouvrir avec <a href=\"https:\/\/openjdk.java.net\/projects\/jmc\/\" target=\"_blank\" rel=\"noopener noreferrer\">JMC &#8211; JDK Mission Control<\/a>. Cette annotation va aussi afficher dans la console certaines m\u00e9triques globales de JFR.<\/p>\n<pre>------------------------------------------------------------------------------\n ALLOCATION (estimations)     |   GARBAGE COLLECTION           |  THROWABLE\n Total       : 20,1 MiB       |   Total pause     : 21,434 ms  |  Exception: 0\n Inside TLAB : 16,2 MiB       |   Longest GC pause: 21,434 ms  |  Error    : 0\n Outside TLAB: 3,95 MiB       |   Young: 1                     |  Throwable: 0\n Allocation rate: 255 MiB\/s   |   Old  : 0                     |\n------------------------------------------------------------------------------\n COMPILATION                  |   CODE CACHE\n Number : 0                   |   The number of full code cache events: 0\n Longest: 0                   |   \n------------------------------------------------------------------------------\n<\/pre>\n<p>Il est possible de d\u00e9finir des <em>expectations<\/em> quant \u00e0 ce profil via l&rsquo;annotation <a>@ExpectNoJvmIssue<\/code>code&gt;@ExpectNoJvmIssue&lt;\/code<\/a> qui va se baser sur les <a href=\"http:\/\/hirt.se\/blog\/?p=920\" target=\"_blank\" rel=\"noopener noreferrer\">r\u00e8gles JMC<\/a> pour mettre en \u00e9chec le test.<\/p>\n<pre>Rule: Primitive To Object Conversion\nSeverity: INFO\nScore: 73\nMessage: 78 % of the total allocation (15,1 MiB) is caused by conversion from primitive \ntypes to object types.\n\nThe most common object type that primitives are converted into is \n'java.lang.Integer', which causes 15,1 MiB to be allocated. The most common \ncall site is 'org.quickperf.jvm.IntegerAccumulator.accumulateInteger(int):26'.\n\n[...]\n<\/pre>\n<p>Plus d&rsquo;information sur les annotations JVM <a href=\"https:\/\/github.com\/quick-perf\/doc\/wiki\/JVM-annotations\" target=\"_blank\" rel=\"noopener noreferrer\">ici<\/a><\/p>\n<h2>Les annotations SQL<\/h2>\n<p>Pour utiliser les annotations SQL, il faut ajouter la librairie <code>org.quickperf:quick-perf-sql-annotations<\/code> (sauf si vous utilisez Spring qui a un support d\u00e9di\u00e9). En fonction de votre application, il faut ensuite configurer sa DataSource pour ajouter un proxy qui permettra \u00e0 Quickperf de tracer les requ\u00eates SQL. Plus d&rsquo;informations \u00e0 ce sujet dans la section suivante.<\/p>\n<p>Quickperf a \u00e9norm\u00e9ment d&rsquo;annotations permettant de v\u00e9rifier l&rsquo;ex\u00e9cution des requ\u00eates SQL, et de d\u00e9tecter les probl\u00e8mes les plus classiques : requ\u00eates dupliqu\u00e9es, n+1 select, batch, &#8230;<\/p>\n<p>Voici quelques unes des annotations les plus utilis\u00e9es :<\/p>\n<ul><li><code>@ExpectJdbcQueryExecution<\/code> et <code>@ExpectMaxQueryExecutionTime<\/code> : <em>expectation<\/em> quant \u00e0 la dur\u00e9e d&rsquo;ex\u00e9cution d&rsquo;une requ\u00eate SQL, la premi\u00e8re attend une dur\u00e9e pr\u00e9cise, la deuxi\u00e8me sera en \u00e9chec si la dur\u00e9e sp\u00e9cifi\u00e9e est atteinte (la plupart des annotations SQL viennent par couple selon ce m\u00eame sch\u00e9ma).<\/li>\n\n<li><code>@ExpectSelectedColumn<\/code> et <code>@ExpectMaxSelectedColumn<\/code> : <em>expectation<\/em> quant au nombre de colonnes s\u00e9lectionn\u00e9es<\/li>\n\n<li><code>@ExpectSelect<\/code> et <code>@ExpectMaxSelect<\/code> : expectation quant au nombre de select g\u00e9n\u00e9r\u00e9s<\/li>\n\n<li><code>@ExpectJdbcBatching<\/code> : expectation quant \u00e0 l&rsquo;utilisation de batch JDBC<\/li>\n<\/ul>\n<p>Petit zoom sur une annotation un peu particuli\u00e8re : <a>@DisableSameSelectTypesWithDifferentParamValues<\/code>code&gt;@DisableSameSelectTypesWithDifferentParamValues&lt;\/code<\/a>, celle-ci permet de d\u00e9tecter les probl\u00e8mes de <strong>n+1 select\/strong&gt; avec JPA \/ Hibernate.<\/strong><\/p>\n<p>Ce probl\u00e8me bien connu arrive quand deux entit\u00e9s ont une relation parent fils, et que le chargement de l&rsquo;entit\u00e9 parente implique une requ\u00eate select pour la charger plus n select pour charger ses enfants. C&rsquo;est un anti-pattern bien connu qui se r\u00e9sout g\u00e9n\u00e9ralement en r\u00e9alisant un <strong>JOIN FETCH<\/strong> JPA.<\/p>\n<p>Quickperf peut d\u00e9tecter cela gr\u00e2ce \u00e0 l&rsquo;annotation <a>@DisableSameSelectTypesWithDifferentParamValues<\/code>code&gt;@DisableSameSelectTypesWithDifferentParamValues&lt;\/code<\/a> qui va mettre votre test en \u00e9chec si plusieurs select identiques sont ex\u00e9cut\u00e9s avec des param\u00e8tres diff\u00e9rents. Et s&rsquo;il d\u00e9tecte la pr\u00e9sence d&rsquo;Hibernate, Quickperf va m\u00eame vous donner des conseils quant \u00e0 la r\u00e9solution du probl\u00e8me !<\/p>\n<p>Imaginons les entit\u00e9s <code>Player<\/code> et <code>Team<\/code> suivantes :<\/p>\n<pre>@Entity\npublic class Player implements Serializable {\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.SEQUENCE)\n    private Long id;\n\n    private String firstName;\n\n    private String lastName;\n\n    @ManyToOne(targetEntity = Team.class)\n    @JoinColumn(name = \"team_id\")\n    private Team team;\n\n    \/\/ getter and setters ...\n}\n\n@Entity\npublic class Team implements Serializable {\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.SEQUENCE)\n    private Long id;\n\n    private String name;\n\n   \/\/ getter and setters ...\n}\n<\/pre>\n<p>Et le test suivant :<\/p>\n<pre>    @DisableSameSelectTypesWithDifferentParamValues\n    @Test\n    public void should_find_all_players() {\n\n        TypedQuery fromPlayer\n                = entityManager.createQuery(\"FROM Player\", Player.class);\n\n        List players = fromPlayer.getResultList();\n\n        assertThat(players).hasSize(2);\n\n    }\n<\/pre>\n<p>Le chargement de la classe <code>Player<\/code> va entra\u00eener n+1 requ\u00eates SQL qui seront d\u00e9tect\u00e9es par Quickperf qui vous donnera alors le message d&rsquo;erreur suivant en sugg\u00e9rant un probl\u00e8me de n+1 et des solutions possibles :<\/p>\n<pre>ERROR] Failures: \n[ERROR]   HibernateJUnit5Test.should_find_all_players a performance property is not respected\n\n[PERF] Same SELECT types with different parameter values\n\n\ud83d\udca3 You may have even more select statements with production data.\nBe careful with the cost of JDBC server roundtrips: https:\/\/blog.jooq.org\/2017\/12\/18\/the-cost-of-jdbc-server-roundtrips\/\n\n\ud83d\udca1 Perhaps you are facing an N+1 select issue\n    * With Hibernate, you may fix it by using JOIN FETCH\n                                           or LEFT JOIN FETCH\n                                           or FetchType.LAZY\n                                           or ...\n      Some examples: https:\/\/stackoverflow.com\/questions\/32453989\/what-is-the-solution-for-the-n1-issue-in-jpa-and-hibernate\";\n                     https:\/\/stackoverflow.com\/questions\/52850442\/how-to-get-rid-of-n1-with-jpa-criteria-api-in-hibernate\/52945771?stw=2#52945771\n                     https:\/\/thoughts-on-java.org\/jpa-21-entity-graph-part-1-named-entity\/\n\n[...]\n<\/pre>\n<h2>Int\u00e9gration dans les frameworks<\/h2>\n<p>Comme \u00e9voqu\u00e9 dans la section pr\u00e9c\u00e9dente, Quickperf n\u00e9cessite un proxy de votre DataSource pour pouvoir d\u00e9tecter les probl\u00e8mes SQL. En fonction des frameworks que vous utilisez, il vous faudra donc mettre en place ce proxy.<\/p>\n<p>Ceci consiste en quelques lignes de code qui vont d\u00e9finir un wrapper au dessus de votre DataSource:<\/p>\n<pre>\npublic DataSource wrapDatasource(DataSource dataSource){\n    ProxyDataSource proxyDataSource = QuickPerfSqlDataSourceBuilder.aDataSourceBuilder()\n            .buildProxy(dataSource);\n    return proxyDataSource;\n}\n<\/pre>\n<p>Le repository <a href=\"https:\/\/github.com\/quick-perf\/quickperf-examples\/\" target=\"_blank\" rel=\"noopener\">quickperf-examples<\/a> contient de nombreux exemples de mise en place de ce proxy pour les frameworks les plus courants (Spring, Hibernate, Micronaut, &#8230;).<\/p>\n<p>Si vous utilisez Spring, la configuration est simplifi\u00e9e, il n&rsquo;est pas n\u00e9cessaire d&rsquo;ajouter la librairie <code>org.quickperf:quick-perf-sql-annotations<\/code>, \u00e0 la place, vous devez ajouter une librairie d\u00e9di\u00e9e et tout se fait automatiquement. Par exemple, pour Spring Boot 2, vous devez ajouter le starter <code>quick-perf-springboot2-sql-starter<\/code>.<\/p>\n<pre>\n\n    org.quickperf\n    quick-perf-springboot2-sql-starter\n    test\n\n<\/pre>\n<p>Plus d&rsquo;information sur le support des annotations SQL avec Spring <a href=\"https:\/\/github.com\/quick-perf\/doc\/wiki\/Spring#sql-annotations\" target=\"_blank\" rel=\"noopener\">ici<\/a>.<\/p>\n<p>Quickperf ne se contente pas de d\u00e9tecter les probl\u00e8mes de performance, il va aussi donner des conseils sur les mani\u00e8res de les r\u00e9soudre en listant les causes les plus courantes. Pour ceci il va d\u00e9tecter les frameworks utilis\u00e9s par votre application (Hibernate, Spring Boot, &#8230;) et personnaliser les conseils donn\u00e9s en cons\u00e9quence.<\/p>\n<p>En fonction des frameworks d\u00e9tect\u00e9s, Quickperf va aussi sugg\u00e9rer des solutions aux probl\u00e8mes d&rsquo;utilisation de Quickperf lui-m\u00eame.<\/p>\n<p>Par exemple, en cas de probl\u00e8me de n+1 avec une application qui utilise Spring Data JPA, Quickperf va vous donner une aide \u00e0 comment le r\u00e9gler sp\u00e9cifiquement avec Spring Data JPA (les conseils pour Hibernate ont \u00e9t\u00e9 retir\u00e9s de l&rsquo;exemple pour am\u00e9liorer sa lisibilit\u00e9).<\/p>\n<pre>[PERF] You may think that  select statement was sent to the database\n       But there are in fact ...\n\n\ud83d\udca3 You may have even more select statements with production data.\nBe careful with the cost of JDBC roundtrips: https:\/\/blog.jooq.org\/2017\/12\/18\/the-cost-of-jdbc-server-roundtrips\/\n\n\ud83d\udca1 Perhaps you are facing an N+1 select issue\n    * With Hibernate [...]\n\n    * With Spring Data JPA, you may fix it by adding @EntityGraph(attributePaths = { \"...\" })\n      on repository method: https:\/\/docs.spring.io\/spring-data\/jpa\/docs\/current\/reference\/html\/#jpa.entity-graph\n<\/pre>\n<h2>Conclusion<\/h2>\n<p>Quickperf est un outil qui vous permet d&rsquo;ajouter de la non-r\u00e9gression continue des performances gr\u00e2ce \u00e0 son int\u00e9gration via les frameworks de test (JUnit, TestNG).<\/p>\n<p>Il permet de d\u00e9tecter les probl\u00e8mes de performance les plus courants en Java (allocation m\u00e9moire, requ\u00eatage, &#8230;), de profiler votre application via un test, et plus encore. Une fois ces probl\u00e8mes d\u00e9tect\u00e9s et corrig\u00e9s gr\u00e2ce aux conseils qu&rsquo;il prodigue, votre test deviendra le garant de la non-r\u00e9gression des performances de votre application.<\/p>\n<p>Quickperf a \u00e9t\u00e9 utilis\u00e9 avec succ\u00e8s pour mesur\u00e9 la consommation de m\u00e9moire de Maven entre les versions 3.6.1 et 3.6.2. Suite \u00e0 \u00e7a un bench a \u00e9t\u00e9 cr\u00e9\u00e9 qui permet de contr\u00f4ler en continue les allocations m\u00e9moire de Maven. C&rsquo;est un bel exemple d&rsquo;utilisation de Quickperf sur un projet complexe et du gain qu&rsquo;il a apport\u00e9.<\/p>","protected":false},"excerpt":{"rendered":"<p>QuickPerf est une biblioth\u00e8que de test pour Java permettant d&rsquo;\u00e9valuer et d&rsquo;am\u00e9liorer rapidement les performances de votre application. Le grand int\u00e9r\u00eat de Quickperf r\u00e9side dans le fait que cela s&rsquo;effecue via des tests unitaires, ce qui permet, apr\u00e8s avoir d\u00e9tect\u00e9 et corrig\u00e9 un probl\u00e8me de performance, d&rsquo;avoir des tests de non-r\u00e9gression pour que celui-ci ne revienne jamais ! Vous pouvez alors \u00e9valuer en continue les performances de votre application via votre environnement d&rsquo;int\u00e9gration continue ! Quickperf peut \u00eatre utilis\u00e9 pour&#8230;<p class=\"read-more\"><a class=\"btn btn-default\" href=\"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/informatique\/introduction-a-quickperf\/\">Lire la suite<span class=\"screen-reader-text\"> Lire la suite<\/span><\/a><\/p><\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"activitypub_content_warning":"","activitypub_content_visibility":"","activitypub_max_image_attachments":4,"activitypub_interaction_policy_quote":"anyone","activitypub_status":"","footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[9],"tags":[11,159,190],"class_list":["post-1201","post","type-post","status-publish","format-standard","hentry","category-informatique","tag-java","tag-performance","tag-quickperf"],"aioseo_notices":[],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"jetpack-related-posts":[{"id":1258,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/informatique\/profiler-une-application-java-dans-un-conteneur-deploye-dans-kubernetes-avec-jfr-java-flight-recorder\/","url_meta":{"origin":1201,"position":0},"title":"Profiler une application Java dans un conteneur d\u00e9ploy\u00e9 dans kubernetes avec JFR &#8211; Java Flight Recorder","author":"admin","date":"lundi 12 avril 2021","format":false,"excerpt":"La plupart des clients chez lesquels j'interviens aujourd'hui utilisent Kubernetes pour d\u00e9ployer leurs applications. Bien que Kubernetes soit un super outil, si on a besoin de ce type d'outil (qui est une discussion dans laquelle je ne rentrerais pas ici), il peut apporter une certaine complexit\u00e9 quant aux moyens de\u2026","rel":"","context":"Dans &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1041,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/informatique\/introduction-a-jmh-java-microbenchmark-harness\/","url_meta":{"origin":1201,"position":1},"title":"Introduction \u00e0 JMH &#8211; Java Microbenchmark Harness","author":"admin","date":"mercredi 29 avril 2020","format":false,"excerpt":"Dans mon pr\u00e9c\u00e9dent article For vs Stream, j'ai utilis\u00e9 JMH \u2013 The Java Microbenchmark Harness, un outil pour r\u00e9aliser des microbenchmarks de mani\u00e8re facile, et surtout, pertinente. Cet article \u00e0 pour but de vous pr\u00e9senter l'outil et son utilisation. Mais tout d'abord : c'est quoi un microbenchmark ? Microbenchmark Benchmark\u2026","rel":"","context":"Dans &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1153,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/informatique\/profiler-une-image-native-graalvm-avec-perf\/","url_meta":{"origin":1201,"position":2},"title":"Profiler une image native GraalVM avec perf","author":"admin","date":"lundi 16 novembre 2020","format":false,"excerpt":"L'outil GraalVM native-image permet de g\u00e9n\u00e9rer un ex\u00e9cutable natif (ou image native) depuis votre application Java. Cet ex\u00e9cutable natif va d\u00e9marrer tr\u00e8s rapidement et avoir une empreinte m\u00e9moire beaucoup plus faible qu'une application Java traditionnelle; au prix de performances en pic r\u00e9duites et d'un temps de cr\u00e9ation de ce package\u2026","rel":"","context":"Dans &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/category\/informatique\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/flamegraph-2.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/flamegraph-2.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/flamegraph-2.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/flamegraph-2.png?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":1090,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/informatique\/quarkus-jlink-et-application-class-data-sharing-appcds\/","url_meta":{"origin":1201,"position":3},"title":"Quarkus, jlink et Application Class Data Sharing (AppCDS)","author":"admin","date":"vendredi 29 mai 2020","format":false,"excerpt":"Quarkus est optimis\u00e9 pour d\u00e9marrer rapidement et avoir une empreinte m\u00e9moire tr\u00e8s faible. Ceci est vrai en d\u00e9ployant dans une JVM standard mais encore plus en d\u00e9ployant notre application comme un ex\u00e9cutable natif via GraalVM. Quarkus facilite grandement la cr\u00e9ation d\u2019ex\u00e9cutable natif, gr\u00e2ce \u00e0 \u00e7a, une application Quarkus d\u00e9marre en\u2026","rel":"","context":"Dans &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/category\/informatique\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/quarkus_metrics_graphic_bootmem_wide-1024x473.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/quarkus_metrics_graphic_bootmem_wide-1024x473.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/loicmathieu.fr\/wordpress\/wp-content\/uploads\/quarkus_metrics_graphic_bootmem_wide-1024x473.png?resize=525%2C300&ssl=1 1.5x"},"classes":[]},{"id":1375,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/informatique\/java-18-quoi-de-neuf\/","url_meta":{"origin":1201,"position":4},"title":"Java 18 : quoi de neuf ?","author":"admin","date":"mardi  4 janvier 2022","format":false,"excerpt":"Maintenant que Java 18 est features complete (Rampdown Phase One au jour d\u2019\u00e9criture de l\u2019article), c\u2019est le moment de faire le tour des fonctionnalit\u00e9s qu\u2019apporte cette nouvelle version, \u00e0 nous, les d\u00e9veloppeurs. Cet article fait partie d\u2019une suite d\u2019article sur les nouveaut\u00e9s des derni\u00e8res versions de Java, pour ceux qui\u2026","rel":"","context":"Dans &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1068,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/informatique\/j-ai-teste-java-google-cloud-functions-aplha\/","url_meta":{"origin":1201,"position":5},"title":"J&rsquo;ai test\u00e9 Java Google Cloud Functions Alpha","author":"admin","date":"mercredi  6 mai 2020","format":false,"excerpt":"J'ai test\u00e9 les Java Google Cloud Functions en Alpha. Jusqu'ici, les Cloud Functions de Google n'\u00e9taient impl\u00e9mentables qu'en NodeJs, Go ou Python. Mais Google est en train de pr\u00e9parer l'ouverture d'un runtime Java (8 et 11), que j'ai pu tester en alpha release priv\u00e9e (pour s'inscrire, c'est ici). Apr\u00e8s inscription\u2026","rel":"","context":"Dans &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/posts\/1201","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/comments?post=1201"}],"version-history":[{"count":0,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/posts\/1201\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/media?parent=1201"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/categories?post=1201"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/fr\/wp-json\/wp\/v2\/tags?post=1201"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}