ããã«ã¡ã¯ãHabrïŒ
ããã¯ãJVMèšèªïŒjavaãkotlinãscalaãªã©ïŒã§ããã©ãŒãã³ã¹ãã¹ããè¡ãæ¹æ³ã«ã€ããŠã®å ¥éèšäºã§ãã ç¹å®ã®ã¢ã«ãŽãªãºã ã®äœ¿çšã«ããããã©ãŒãã³ã¹ã®å€åãæ°å€ã§ç€ºãå¿ èŠãããå Žåã«åœ¹ç«ã¡ãŸãã
ãã¹ãŠã®äŸã¯ãkotlinãšgradleãã«ãã·ã¹ãã çšã§ãã ãããžã§ã¯ãã®ãœãŒã¹ã³ãŒãã¯githubã§å ¥æã§ããŸã ã
æºåãã
Jmh
ãŸãã枬å®ã®äž»èŠéšåã§ããJMHã®äœ¿çšã«ã€ããŠèª¬æããŸãã Java Microbenchmark Harnessã¯ãå°ããªé¢æ°ïŒã€ãŸããGCãäžæåæ¢ãããšã©ã³ã¿ã€ã ãæ°åå¢å ãããã®ïŒã®ããã©ãŒãã³ã¹ããã¹ãããããã®ã©ã€ãã©ãªã®ã»ããã§ãã
ãã¹ããå®è¡ããåã«ãJMHã¯æ¬¡ã®çç±ã§ã³ãŒããåã³ã³ãã€ã«ããŸãã
- é¢æ°ã®ã©ã³ã¿ã€ã ãèšç®ããéã®ãšã©ãŒãæžããã«ã¯ããããNåå®è¡ããåèšã©ã³ã¿ã€ã ãèšç®ããŠããNã§å²ãå¿ èŠããããŸãã
- ãããè¡ãã«ã¯ãã«ãŒã圢åŒã§èµ·åãã©ããããå¿ èŠãªã¡ãœãããåŒã³åºãå¿ èŠããããŸãã ãã ãããã®å Žåããµã€ã¯ã«èªäœãšæž¬å®ãããé¢æ°ã®åŒã³åºãã¯ãé¢æ°ã®åäœæéã«åœ±é¿ããŸãã ãããã£ãŠãã«ãŒãã®ä»£ããã«ãå®è¡æã®ãªãã¬ã¯ã·ã§ã³ãŸãã¯ã¡ãœããçæãªãã§ãé¢æ°åŒã³åºãã³ãŒããçŽæ¥æ¿å ¥ãããŸãã
ãã€ãã³ãŒãã®å€æŽåŸããã¹ãŠã®å¿
èŠãªã³ã³ããŒãã³ãããã§ã«1ã€ã®jarãã¡ã€ã«ã«ããã¯ãããŠããããã java -jar benchmarks.jar
ã®åœ¢åŒã®ã³ãã³ãã§ãã¹ããéå§ã§ããŸãã
JMH Gradleãã©ã°ã€ã³
äžèšã®èª¬æãããããããã«ãã³ãŒãã®ããã©ãŒãã³ã¹ããã¹ãããã«ã¯ãã¯ã©ã¹ãã¹ã«å¿ èŠãªã©ã€ãã©ãªãè¿œå ããŠãJUnitã¹ã¿ã€ã«ã§ãã¹ããå®è¡ããã ãã§ã¯äžååã§ãã ãããã£ãŠãããžãã¹ãè¡ãããã«ãã¹ã¯ãªãããèšè¿°ããæ©èœãç解ããŠããªãå Žåãmaven / gradleãã©ã°ã€ã³ãªãã§ã¯å®è¡ã§ããŸããã æ°ãããããžã§ã¯ãã®å Žåãgradleã«ã¯å©ç¹ããããããéžæããŠãã ããã
JMHã«ã¯ã gradleã®åå ¬åŒãã©ã°ã€ã³jmh-gradle-pluginããããŸã ã ãããžã§ã¯ãã«è¿œå ããŸãã
buildscript { repositories { mavenCentral() maven { url "https://plugins.gradle.org/m2/" } } dependencies { classpath "me.champeau.gradle:jmh-gradle-plugin:$jmh_gradle_plugin_version" } } apply plugin: "me.champeau.gradle.jmh"
ãã©ã°ã€ã³ã¯èªåçã«æ°ãããœãŒã¹ã»ãããäœæããŸãïŒããã¯ãã³ã³ãã€ã«ããŠäžç·ã«å®è¡ããå¿ èŠããããã¡ã€ã«ãšãªãœãŒã¹ã®ã»ããã§ããã jmhãœãŒã¹ã»ããã¯èªåçã«ã¡ã€ã³ãåç §ããŸããã€ãŸããäœæ¥ã®çãã¢ã«ãŽãªãºã ãååŸããŸãã
- ãã€ããšåãå Žæã§ãæšæºã®ã¡ã€ã³ãœãŒã¹ã»ããã§å€æŽããã³ãŒããèšè¿°ããŸãã
- å¥ã®ãœãŒã¹ã»ããã§ãã¹ãã調æŽããã³ãŠã©ãŒã ã¢ããããã³ãŒããèšè¿°ããŸãã äžæžããããã®ã¯åœŒã®ãã€ãã³ãŒãã§ããããã§ã¯ããã©ã°ã€ã³ãå¿ èŠãªäŸåé¢ä¿ãè¿œå ãããã®äžã«æ³šéã®å®çŸ©ãªã©ããããŸãã
次ã®ãã£ã¬ã¯ããªéå±€ãååŸããŸãã
- src
- jmh / kotlin / <ããã±ãŒãžjavaå> / <ãã¹ããå®è¡ããã³ãŒãïŒããã³JMHå±æ§ã®æ³šéä»ãïŒ>
- main / kotlin / <ããã±ãŒãžjavaå> / <ãã¹ãçšã³ãŒã>
ãŸãã¯ãIntelliJ Ideaã§ã©ã®ããã«èŠãããïŒ
ãã®çµæããããžã§ã¯ããã»ããã¢ããããåŸã .\gradlew.bat jmh
ïŒãŸãã¯LinuxãMacãBSDã®å Žåã¯.\gradlew jmh
ãåŒã³åºãã ãã§ãã¹ããå®è¡ã§ããŸã.\gradlew.bat jmh
Windowsã®ãã©ã°ã€ã³ã«ã¯ãããã€ãã®èå³æ·±ãæ©èœããããŸãã
- JMHã¯ããã»ã¹ã®fork javaã䜿çšããŸãã Windowsã®å Žåããããç°¡åã«è¡ãããšã¯ã§ãããæ°ããããã»ã¹ã¯åãã¯ã©ã¹ãã¹ã§éå§ãããŸãã ãŸããjarãã¡ã€ã«ã®ãªã¹ãå šäœãã³ãã³ãã©ã€ã³çµç±ã§éä¿¡ãããŸããããµã€ãºã¯å¶éãããŠããŸãã ãã®çµæãGRADLE_USER_HOMEïŒgradleãã£ãã·ã¥ãå«ããã©ã«ããŒïŒããã¡ã€ã«æ§é ã®æ·±ãã«ããå Žåãforkã®jarãã¡ã€ã«ã®ãªã¹ãã¯éåžžã«å€§ãããªããWindowsã¯ãã®ãããªèšå€§ãªæ°ã®ã³ãã³ãã©ã€ã³åŒæ°ã§ããã»ã¹ãéå§ããããšãæåŠããŸãã ãããã£ãŠã JMHããã©ãŒã¯ãæåŠããå ŽåãGradleãã£ãã·ã¥ãçãååã®ãã©ã«ããŒã«ç§»åããã ãã§ãã ç°å¢å€æ°GRADLE_USER_HOMEã«cïŒ\ gradleã®ãããªãã®ãæžããŸãã
- 以åã®JMHããã»ã¹ããã¡ã€ã«ãããã¯ããå ŽåããããŸãïŒãã€ãã³ãŒãã®æžãæãããããè¡ãå¯èœæ§ããããŸãïŒã ãã®çµæããã³ãããŒã¯çšã®ãã¡ã€ã«ãæžã蟌ã¿ã®ããã«èª°ãã«ãã£ãŠéããããããåã³ã³ãã€ã«ãæ©èœããªãå ŽåããããŸãã ãã®åé¡ãä¿®æ£ããã«ã¯ãããŒã¢ã³gradleããã»ã¹ïŒã³ã³ãã€ã©ãé«éåããããã«æ¢ã«å®è¡ãããŠããïŒãåæ¢ããå¿
èŠããããŸãã
.\gradlew.bat --stop
- å®éšã®çŽåºŠãé«ããã«ã¯ããã¹ãçšã®ã€ã³ã¯ãªã¡ã³ã¿ã«ã¢ã»ã³ããªãäžæ¢ããããšããå§ãããŸãã ããããããã¹ãããåã«å¿
ãé»è©±ããŠãã ãã
.\gradlew.bat clean
ãã¹ãäž
äŸãšããŠã以åã«ç§ãèŠããã質åïŒä»¥åkotlinã®è°è«ã§å°ããããŸããïŒãåãäžããŸã-ã€ã³ã©ã€ã³æ§é ãuseã³ã³ã¹ãã©ã¯ãã§äœ¿çšãããã®ã¯ãªãã§ããïŒ
Javaã«ã¯ãã¿ãŒã³ããããŸãã ãªãœãŒã¹ã§è©ŠããŠã¿ãŠãã ãã ãããã«ããããããã¯å
ã§closeã¡ãœãããèªåçã«åŒã³åºãããšãã§ããŸããããã«ãæ¢ã«é£è¡äžã®äŸå€ããããã¯ããã«äŸå€ãåŠçããŠãå®å
šã§ãã .Netã®äžçããã®é¡äŒŒç©ã¯ã IDisposable
ã€ã³ã¿ãŒãã§ã€ã¹ã®äœ¿çšæ§é ã§ãã
ãµã³ãã«Javaã³ãŒãïŒ
try (BufferedReader reader = Files.newBufferedReader(file, charset)) { // try /* reader'*/ }
Kotlinã«ã¯ããããã«ç°ãªãæ§æãæã€å®å šãªã¢ããã°ããããŸãã
Files.newBufferedReader(file, charset)).use { reader -> /* reader'*/ }
ã€ãŸããããªããèŠãããšãã§ããããã«ïŒ
- 䜿çšã¯åãªãæ¡åŒµã¡ãœããã§ãããåå¥ã®èšèªæ§æã§ã¯ãããŸãã
- 䜿çšã¯ã€ã³ã©ã€ã³ã¡ãœããã§ããã€ãŸããåã¡ãœããã«åãã³ã³ã¹ãã©ã¯ããåã蟌ãŸããŠããããããã€ãã³ãŒãã®ãµã€ãºã倧ãããªããŸããã€ãŸããJITãã³ãŒããæé©åããããšã¯ããå°é£ã«ãªããŸãã ãããŠã ãã®çè«ã確èªããŸãã
ãããã£ãŠã2ã€ã®æ¹æ³ãäœæããå¿ èŠããããŸãã
- æåã®ãã®ã¯useã䜿çšããã ãã§ãkotlinã©ã€ãã©ãªã«å«ãŸããŠããŸã
- 2çªç®ã¯åãã¡ãœããã䜿çšããŸãããã€ã³ã©ã€ã³ã¯äœ¿çšããŸããã ãã®çµæãããŒãã®åŒã³åºãããšã«ãã©ã ãã®ãã©ã¡ãŒã¿ãŒãæã€ãªããžã§ã¯ããäœæãããŸãã
ããŸããŸãªæ©èœãå®è¡ããJMHå±æ§ãæã€ã³ãŒãïŒ
@BenchmarkMode(Mode.All) // @Warmup(iterations = 10) // @Measurement(iterations = 100, batchSize = 10) // , open class CompareInlineUseVsLambdaUse { @Benchmark fun inlineUse(blackhole: Blackhole) { NoopAutoCloseable(blackhole).use { blackhole.consume(1) } } @Benchmark fun lambdaUse(blackhole: Blackhole) { NoopAutoCloseable(blackhole).useNoInline { blackhole.consume(1) } } }
ãããã³ãŒãé€å»
Javaã³ã³ãã€ã©ãšJITã¯éåžžã«è³¢ããã³ã³ãã€ã«æãšå®è¡æã®äž¡æ¹ã§å€ãã®æé©åãè¡ãããŠããŸãã ããšãã°ã次ã®ã¡ãœããã¯1è¡ã«æããããããšãã§ããŸãïŒkotlinãšjavaã®äž¡æ¹ïŒïŒ
fun sum() : Unit { val a = 1 val b = 2 a + b; }
ãããŠæåŸã«ãã¡ãœããããã¹ãããŸãã
fun sum() : Unit { 3; }
ãã ããååãšããŠå¿ èŠãªããããã³ã³ãã€ã©ïŒãã€ãã³ãŒã+ JITïŒã¯æçµçã«ã¡ãœãããå®å šã«ç Žæ£ãããããçµæã¯ã©ã®ãããªæ¹æ³ã§ã䜿çšãããŸããã
ãããåé¿ããããã«ãJMHã«ã¯ç¹å¥ãªããã©ãã¯ããŒã«ãã¯ã©ã¹ããããŸã-ãã©ãã¯ããŒã«ã äžæ¹ã§ã¯äœããããããäžæ¹ã§ã¯JITã«çµæã®ãã©ã³ããã¹ããŒãããªãã¡ãœããããããŸãã
ãããŠãjavacãã³ã³ãã€ã«ããã»ã¹äžã«aãšbãè¿œå ããããšããªãããã«ãå€ãæ ŒçŽãããç¶æ ãªããžã§ã¯ããå®çŸ©ããå¿ èŠããããŸãã ãã®çµæããã¹ãèªäœã§ã¯ããã§ã«æºåããããªããžã§ã¯ãã䜿çšããŸãïŒã€ãŸããäœæã«æéã浪費ãããã³ã³ãã€ã©ãŒãæé©åãé©çšããããšãèš±å¯ããŸããïŒã
ãã®ãããé¢æ°ãé©åã«ãã¹ãããã«ã¯ã次ã®åœ¢åŒã§èšè¿°ããå¿ èŠããããŸãã
fun sum(blackhole: Blackhole) : Unit { val a = state.a // a val b = state.b val result = a + b; blackhole.consume(result) // JIT , - - }
ããã§ã¯ãããç¶æ ããaãšbãååŸããŸãããããã«ãããã³ã³ãã€ã©ãŒãåŒãããã«èšç®ã§ããªããªããŸãã ãããŠãçµæããã©ãã¯ããŒã«ã«éä¿¡ããŸãããããã«ãããJITãé¢æ°ã®æåŸã®éšåãæšãŠãããšãã§ããªããªããŸãã
ç§ã®æ©èœã«æ»ãïŒ
- ã»ãšãã©ã®å Žåãcloseã¡ãœãããåŒã³åºããšãã«ãã®åã«ãªããžã§ã¯ããäœæããããããã¹ãèªäœã§closeã¡ãœãããåŒã³åºãããã®ãªããžã§ã¯ããäœæããŸãã
- ã¡ãœããå ã§ãããŒãã«ã©ã ããäœæããããã«ãã©ãã¯ããŒã«ããé¢æ°ãåŒã³åºãå¿ èŠããããŸãïŒãããŠãJITãæœåšçã«äžèŠãªã³ãŒããã¹ããŒããã®ãé²ããŸãïŒã
è©Šéšçµæ
./gradle jmh
ãå®è¡ããŠãã2æéåŸ
ã€ãšãmac miniã§æ¬¡ã®çµæãåŸãããŸããã
# Run complete. Total time: 01:51:54 Benchmark Mode Cnt Score Error Units CompareInlineUseVsLambdaUse.inlineUse thrpt 1000 11689940,039 ± 21367,847 ops/s CompareInlineUseVsLambdaUse.lambdaUse thrpt 1000 11561748,220 ± 44580,699 ops/s CompareInlineUseVsLambdaUse.inlineUse avgt 1000 â 10â»â· s/op CompareInlineUseVsLambdaUse.lambdaUse avgt 1000 â 10â»â· s/op CompareInlineUseVsLambdaUse.inlineUse sample 21976631 â 10â»â· s/op CompareInlineUseVsLambdaUse.inlineUse:inlineUse·p0.00 sample â 10â»â· s/op CompareInlineUseVsLambdaUse.inlineUse:inlineUse·p0.50 sample â 10â»â· s/op CompareInlineUseVsLambdaUse.inlineUse:inlineUse·p0.90 sample â 10â»â· s/op CompareInlineUseVsLambdaUse.inlineUse:inlineUse·p0.95 sample â 10â»â· s/op CompareInlineUseVsLambdaUse.inlineUse:inlineUse·p0.99 sample â 10â»â· s/op CompareInlineUseVsLambdaUse.inlineUse:inlineUse·p0.999 sample â 10â»âµ s/op CompareInlineUseVsLambdaUse.inlineUse:inlineUse·p0.9999 sample â 10â»âµ s/op CompareInlineUseVsLambdaUse.inlineUse:inlineUse·p1.00 sample 0,005 s/op CompareInlineUseVsLambdaUse.lambdaUse sample 21772966 â 10â»â· s/op CompareInlineUseVsLambdaUse.lambdaUse:lambdaUse·p0.00 sample â 10â»âž s/op CompareInlineUseVsLambdaUse.lambdaUse:lambdaUse·p0.50 sample â 10â»â· s/op CompareInlineUseVsLambdaUse.lambdaUse:lambdaUse·p0.90 sample â 10â»â· s/op CompareInlineUseVsLambdaUse.lambdaUse:lambdaUse·p0.95 sample â 10â»â· s/op CompareInlineUseVsLambdaUse.lambdaUse:lambdaUse·p0.99 sample â 10â»â· s/op CompareInlineUseVsLambdaUse.lambdaUse:lambdaUse·p0.999 sample â 10â»âµ s/op CompareInlineUseVsLambdaUse.lambdaUse:lambdaUse·p0.9999 sample â 10â»âµ s/op CompareInlineUseVsLambdaUse.lambdaUse:lambdaUse·p1.00 sample 0,010 s/op CompareInlineUseVsLambdaUse.inlineUse ss 1000 â 10â»âµ s/op CompareInlineUseVsLambdaUse.lambdaUse ss 1000 â 10â»âµ s/op Benchmark result is saved to /Users/imanushin/git/use-performance-test/src/build/reports/jmh/results.txt
ãŸãã¯ãããŒãã«ãçãããå ŽåïŒ
Benchmark Mode Cnt Score Error Units inlineUse thrpt 1000 11689940,039 ± 21367,847 ops/s lambdaUse thrpt 1000 11561748,220 ± 44580,699 ops/s inlineUse avgt 1000 â 10â»â· s/op lambdaUse avgt 1000 â 10â»â· s/op inlineUse sample 21976631 â 10â»â· s/op lambdaUse sample 21772966 â 10â»â· s/op inlineUse ss 1000 â 10â»âµ s/op lambdaUse ss 1000 â 10â»âµ s/op
ãã®çµæã2ã€ã®æãéèŠãªã¡ããªãã¯ããããŸãã
- ã€ã³ã©ã€ã³æ¹åŒã¯ã1ç§ããã
11,6 * 10^6 ± 0,02 * 10^6
æäœã®çç£æ§ã瀺ããŸããã - LambdaããŒã¹ã®ã¡ãœããã¯ã1ç§ããã
11,5 * 10^6 ± 0,04 * 10^6
æäœã®ããã©ãŒãã³ã¹ã瀺ããŸããã - çµæãšããŠãã€ã³ã©ã€ã³æ¹åŒã¯ããé«éã§ãé床ãããå®å®ããŸãã lambdaUseã®ãšã©ãŒã®å¢å ã¯ãããããã¡ã¢ãªã䜿çšããããã¢ã¯ãã£ããªäœæ¥ã«é¢é£ããŠããå¯èœæ§ããããŸãã
- ç§ã¯ãã®ãã©ãŒã©ã ã§ééã£ãŠããŸãã-kotlinæšæºã©ã€ãã©ãªã«çŸåšã®ã¡ãœããå®è£ ãæ®ããæ¹ãè¯ãã§ãã
ãããã«
ãœãããŠã§ã¢ãéçºãããšããããã©ãŒãã³ã¹ãæ¯èŒãã2ã€ã®ããªãäžè¬çãªæ¹æ³ããããŸãã
- å®éšé¢æ°ã®Nåã®å埩ã«ãããµã€ã¯ã«ã®é床ã®æž¬å®ã
- ã2ãä¹ç®ãããããã·ããã䜿çšããæ¹ãéããšç¢ºä¿¡ããŠããŸããããããã°ã©ãã³ã°ããéããXMLã·ãªã¢ã«åã¯åžžã«æéã§ããããªã©ã®å²åŠçèæ ®äºé ãªã©ã
ãã ããæè¡ã«ç²Ÿéããå°é家ãªã誰ã§ãç¥ã£ãŠããããã«ããããã®ãªãã·ã§ã³ã¯ã©ã¡ãã誀ã£ãå€æãã¢ããªã±ãŒã·ã§ã³ãã¬ãŒããªã©ã«ã€ãªããããšããããããŸãããã®èšäºãè¯ãé«éãœãããŠã§ã¢ã®äœæã«åœ¹ç«ã€ããšãé¡ã£ãŠããŸãã
è±èš³ã¯ãã¡ã ã