Tout le monde est un excellent enregistreur de vol, mais l'API JFR a été officiellement ajoutée à partir de Java 9. J'étais curieux, mais je ne pouvais pas l'essayer, mais ne serait-ce pas bien si je pouvais obtenir diverses informations de JFR cette fois, pas seulement l'heure d'exécution? Je pensais l'avoir fait en utilisant l'API JFR. Gist - koduki/TinyBenchmark.java
Comment l'utiliser, c'est comme ça.
public static void main(String[] args) throws IOException, ParseException {
Path path = Paths.get("test.jfr");
benchmarks(path, "ConcatString Benchmark", 3, (loop) -> {
System.err.println("benchmarking...");
benchmark(loop, "Concat all string by 'plus'", () -> ConcatString.fixedStringWithPlus(1_000), 1_000);
benchmark(loop, "Concat all string by 'plus'", () -> ConcatString.fixedStringWithPlus(100_000), 10_000);
});
printReport(makeReport(path));
}
La méthode des benchmarks
produit test.jfr
, le makeReport analyse JFR, et non seulement l'événement personnalisé créé cette fois-ci, mais aussi la valeur GC acquise en standard est résumée et sortie en LTSV.
Si JFR l'a, vous pouvez prendre n'importe quelle valeur, donc si vous voulez faire des E / S CPU ou fichier, vous êtes libre.
Résultat de l'exécution:
testcase:Concat all string by 'plus' loop:0 arguments:[1000] response(ms):113 gc_count:0 gc_total(ms):0 gc_max(ms):0 gc_avg(ms):0.000000
testcase:Concat all string by 'plus' loop:0 arguments:[10000] response(ms):20784 gc_count:237 gc_total(ms):250 gc_max(ms):12 gc_avg(ms):1.054852
testcase:Concat all string by 'plus' loop:1 arguments:[1000] response(ms):2 gc_count:0 gc_total(ms):0 gc_max(ms):0 gc_avg(ms):0.000000
testcase:Concat all string by 'plus' loop:1 arguments:[10000] response(ms):13782 gc_count:224 gc_total(ms):67 gc_max(ms):10 gc_avg(ms):0.299107
testcase:Concat all string by 'plus' loop:2 arguments:[1000] response(ms):0 gc_count:0 gc_total(ms):0 gc_max(ms):0 gc_avg(ms):0.000000
testcase:Concat all string by 'plus' loop:2 arguments:[10000] response(ms):12776 gc_count:225 gc_total(ms):34 gc_max(ms):2 gc_avg(ms):0.151111
Bien sûr, vous pouvez également le voir dans Mission Control. Cette fois, je l'ai ouvert avec JMC7. Il semble que cela ait beaucoup changé depuis 6 et il semble que le hotspot de performances soit analysé automatiquement dans une certaine mesure contrairement à 5.5 attaché à Java 8. Qu'est-ce que c'est incroyable.
Maintenant, continuons avec l'implémentation.
Tout d'abord, créez un événement personnalisé pour stocker les informations de référence.
@Label("Benchmark")
static class BenchmarkEvent extends Event {
@Label("Test Case")
String testcase;
@Label("Loop Count")
int loop;
@Label("Response")
long response;
@Label("Arguments")
String arguments;
}
Fondamentalement, il semble que cela puisse être géré en héritant de jdk.jfr.Event
et en ajoutant les champs nécessaires.
Il existe de nombreuses annotations autres que «Label», mais je n'ai pas encore pu les maintenir enfoncées. L'article ici est détaillé, mais le contenu spécifique ne peut être vu que dans javadoc et la source.
Ensuite, comment enregistrer dans un événement personnalisé. C'est aussi assez simple. Cliquez ici pour un exemple qui a été réellement utilisé.
BenchmarkEvent event = new BenchmarkEvent();
event.begin();
long s = System.nanoTime();
callback.run();
long e = System.nanoTime();
event.loop = loopCount;
event.testcase = testcase;
event.response = (e - s);
List<String> args = Arrays.stream(arguments).map(x -> x.toString()).collect(Collectors.toList());
event.arguments = "[" + String.join(",", args) + "]";
event.commit();
Comme vous pouvez le voir, le nouveau BenchmarkEvent
de l'événement personnalisé créé précédemment et s'exécute commence
au moment du début de l'événement.
Remplissez les champs avec les valeurs requises pour obtenir commit
. C'est facile à comprendre.
Il semble que la période entre le début et la validation soit enregistrée en tant que durée, donc cette fois, nous exécutons le traitement à évaluer pendant cette période.
La manière habituelle d'utiliser JFR est de spécifier des arguments pour les options java-agent et JVM, non? Je pensais que c'était la seule chose, mais récemment, il semble qu'il puisse être appelé normalement à partir du code Java. Après l'avoir créé correctement en tant qu'outil, il n'est pas facile de spécifier les options appropriées, mais il est très pratique que vous n'ayez pas à vous soucier de l'attacher depuis JMC lorsque vous souhaitez comparer le code en cours de développement directement à partir de l'EDI.
Configuration jfrConfig = Configuration.getConfiguration("default");
try (Recording recording = new Recording(jfrConfig)) {
recording.setName(name);
recording.start();
recording.enable(BenchmarkEvent.class);
for (int i = 0; i < loopCount; i++) {
callback.accept(i);
}
recording.stop();
recording.dump(path);
}
Comme vous pouvez le voir, ouvrez jdk.jfr.Recording
et il se présente sous la forme start / stop
et dump
.
Un point à noter est que si vous n'obtenez pas Configuration
et ne le spécifiez pas, seul l'événement spécifié par ʻenable` sera enregistré, vous devez donc le spécifier correctement si vous voulez des ressources CPU ou l'état de la mémoire.
Cette fonctionnalité que j'attendais depuis longtemps! Eh bien, juste parce que je ne pouvais pas rattraper le retard, au moins de Java 9, peut-être même 8 si non officiel. Quoi qu'il en soit, c'est une méthode pour analyser le JFR tant attendu avec PG. Je suis vraiment content parce que je voulais convertir JFR en CSV.
Utilisez jdk.jfr.consumer.RecordingFile
pour lire.
List<RecordedEvent> gcEvents = RecordingFile.readAllEvents(path).stream()
.filter((e) -> e.getEventType().getName().equals("jdk.G1GarbageCollection"))
.collect(Collectors.toList());
C'est une forme d'obtenir tous les événements inclus dans JFR avec readAllEvents
et de filtrer avec Stream API si nécessaire.
RecordedEvent contient plusieurs valeurs. Les éléments suivants peuvent-ils être utilisés souvent?
Comme il est identique au nom de base, l'explication détaillée est omise, mais vous pouvez obtenir la valeur en entrant le nom du champ dans getValue
. Veuillez noter qu'il ne s'agit pas d'un nom d'étiquette.
J'ai fait un micro-benchmark en utilisant l'API JFR. N'est-ce pas pratique car vous pouvez voir non seulement le temps d'exécution, mais également l'état de la ressource? Je pense.
De plus, c'est la première fois que je touche l'API JFR, et ça fait du bien. C'est facile à utiliser.
Sans parler des événements personnalisés, mais si vous utilisez bien l'API d'analyse, vous pouvez créer des outils de traçage distribués basés sur des valeurs JFR, en faire des applications Web et les analyser avec Kibana. À partir de Java 11, JMC peut utiliser JFR normalement avec OSS et OpenJDK, j'espère donc qu'il se développera davantage à l'avenir.
Cependant, je ne trouve aucune documentation officielle autre que Javadoc. Si quelqu'un sait, faites-le moi savoir> <
Alors bon piratage!
Recommended Posts