|
1 | 1 | = Measuring print loops |
| 2 | +:icons: font |
| 3 | +ifdef::env-github[] |
| 4 | +:tip-caption: :bulb: |
| 5 | +:note-caption: :information_source: |
| 6 | +:important-caption: :heavy_exclamation_mark: |
| 7 | +:caution-caption: :fire: |
| 8 | +:warning-caption: :warning: |
| 9 | +endif::[] |
2 | 10 |
|
3 | 11 | On February 23rd, 2020, the Twitter account https://twitter.com/java:[@java] tweeted out the following: |
4 | 12 |
|
@@ -117,55 +125,108 @@ Or via the command line: |
117 | 125 | $ ./mvnw clean package -Djava.version=8 |
118 | 126 | ---- |
119 | 127 |
|
120 | | -== Measurements |
121 | | -I ran all measurements with the following Java version: |
| 128 | +The benchmarks can then be run with: |
122 | 129 | [source, console] |
123 | 130 | ---- |
124 | | -$ java -version |
125 | | -openjdk version "13.0.1" 2019-10-15 |
126 | | -OpenJDK Runtime Environment AdoptOpenJDK (build 13.0.1+9) |
127 | | -OpenJDK 64-Bit Server VM AdoptOpenJDK (build 13.0.1+9, mixed mode, sharing) |
| 131 | +$ java -jar target/benchmarks.java |
128 | 132 | ---- |
129 | 133 |
|
130 | | -=== With the original names |
131 | | -The complete output of a measurement which I made with the original names (`{"Java", "Node", "JavaScript", "Rust", "Go"}`) can be found https://gist.github.com/blalasaadri/a6df6a01ebf61263d52acd330a18356b:[here]. |
132 | | -The final benchmark results are: |
133 | | -[source] |
134 | | ----- |
135 | | -Benchmark Mode Cnt Score Error Units |
136 | | -MyBenchmark.mapAndPrintWithStreams thrpt 25 5198235,071 ± 510816,392 ops/s |
137 | | -MyBenchmark.printInEnhancedForLoop thrpt 25 10696976,184 ± 999614,529 ops/s |
138 | | -MyBenchmark.printInOldSchoolForLoop thrpt 25 10436315,340 ± 1102141,921 ops/s |
139 | | ----- |
140 | | -So in this case, the throughput of the versions with for loops was about double that of the version with the stream. |
141 | | -The enhanced for loop was slightly more efficient. |
| 134 | +WARNING: Running these benchmarks takes a long time. The total completion time for one call for me was about 50 minutes. |
142 | 135 |
|
143 | | -=== With auto generated names |
| 136 | +== Measurements |
144 | 137 |
|
145 | | -Normally, you wouldn't run this kind of algorithm on just 5 names. |
146 | | -So, to make the whole thing a bit more realistic, I had the benchmark generate 1000 names: |
| 138 | +I ran all benchmarks with multiple Java versions. |
| 139 | +There are two variants (which is what the `listVariant` output refers to): |
147 | 140 |
|
| 141 | +FIVE_NAMES:: |
| 142 | + The original five names from the tweet: `{"Java", "Node", "JavaScript", "Rust", "Go"}` |
| 143 | +AUTO_GENERATED_NAMES:: |
| 144 | + Normally, you wouldn't run this kind of algorithm on just 5 names. |
| 145 | + So, to make the whole thing a bit more realistic, I had the benchmark generate 1000 names: |
| 146 | ++ |
148 | 147 | [source, java] |
149 | 148 | ---- |
150 | 149 | include::src/main/java/com/github/blalasaadri/MyBenchmark.java[tag=autogenerate_names, indent=0] |
151 | 150 | ---- |
152 | 151 | This name generation occurs within a function annotated with https://javadoc.io/doc/org.openjdk.jmh/jmh-core/latest/org/openjdk/jmh/annotations/Setup.html:[`@Setup(Leve.Trial)`]. |
153 | 152 | This means, that the array is generated before each trial and this generation will _not_ be included in the measurement itself. |
154 | 153 |
|
155 | | -The output of one measurement which I made can be found https://gist.github.com/blalasaadri/61bb7690a20aac496134ba014b860fee:[here]. |
156 | | -The final benchmark results are: |
| 154 | +=== With Java 8 |
| 155 | + |
| 156 | +.Java version information for Java 8 |
| 157 | +[source, console] |
| 158 | +---- |
| 159 | +$ java -version |
| 160 | +openjdk version "1.8.0_242" |
| 161 | +OpenJDK Runtime Environment (build 1.8.0_242-8u242-b08-0ubuntu3~19.10-b08) |
| 162 | +OpenJDK 64-Bit Server VM (build 25.242-b08, mixed mode) |
| 163 | +---- |
157 | 164 |
|
| 165 | +.Benchmark results |
158 | 166 | [source] |
159 | 167 | ---- |
160 | | -Benchmark Mode Cnt Score Error Units |
161 | | -MyBenchmark.mapAndPrintWithStreams thrpt 25 24634,932 ± 1804,697 ops/s |
162 | | -MyBenchmark.printInEnhancedForLoop thrpt 25 34491,687 ± 2478,776 ops/s |
163 | | -MyBenchmark.printInOldSchoolForLoop thrpt 25 32659,705 ± 2422,757 ops/s |
| 168 | +Benchmark (listVariant) Mode Cnt Score Error Units |
| 169 | +MyBenchmark.mapAndPrintWithStreams FIVE_NAMES thrpt 25 5207121,355 ± 276740,844 ops/s |
| 170 | +MyBenchmark.mapAndPrintWithStreams AUTO_GENERATED_NAMES thrpt 25 27035,503 ± 2851,299 ops/s |
| 171 | +MyBenchmark.printInEnhancedForLoop FIVE_NAMES thrpt 25 10380706,822 ± 786963,780 ops/s |
| 172 | +MyBenchmark.printInEnhancedForLoop AUTO_GENERATED_NAMES thrpt 25 38088,946 ± 348,914 ops/s |
| 173 | +MyBenchmark.printInOldSchoolForLoop FIVE_NAMES thrpt 25 10453896,992 ± 796088,166 ops/s |
| 174 | +MyBenchmark.printInOldSchoolForLoop AUTO_GENERATED_NAMES thrpt 25 38599,330 ± 358,688 ops/s |
164 | 175 | ---- |
165 | | -Again, the for loops did considerably better than the stream, with the enhanced for loop having about 1.40 times the throughput compared to the stream and the basic for loop having about 1.33 time the thoughput compared to the stream. |
| 176 | +For the original, shorter list, both for loops had about twice the throughput compared to the stream. |
| 177 | +With the much longer array of names, the enhanced for loop clocked in at about 1.41 times the throughput of the stream solution basic for loop managed about 1.43 times the throughput. |
| 178 | + |
| 179 | +The complete output can be found in https://gist.github.com/blalasaadri/f9c6de09275438f4f3817e3e3a773d20:[this gist]. |
| 180 | + |
| 181 | +//== With Java 11 |
| 182 | +//.Java version information for Java 11 |
| 183 | +//[source, console] |
| 184 | +//---- |
| 185 | +//$ java -version |
| 186 | +//openjdk version "11.0.6" 2020-01-14 |
| 187 | +//OpenJDK Runtime Environment (build 11.0.6+10-post-Ubuntu-1ubuntu119.10.1) |
| 188 | +//OpenJDK 64-Bit Server VM (build 11.0.6+10-post-Ubuntu-1ubuntu119.10.1, mixed mode, sharing) |
| 189 | +//---- |
| 190 | +// |
| 191 | +//.Benchmark results |
| 192 | +//[source] |
| 193 | +//---- |
| 194 | +//---- |
| 195 | +
|
| 196 | +//=== With Java 13 |
| 197 | +// |
| 198 | +//.Java version information for Java 13 |
| 199 | +//[source, console] |
| 200 | +//---- |
| 201 | +//$ java -version |
| 202 | +//openjdk version "13.0.1" 2019-10-15 |
| 203 | +//OpenJDK Runtime Environment AdoptOpenJDK (build 13.0.1+9) |
| 204 | +//OpenJDK 64-Bit Server VM AdoptOpenJDK (build 13.0.1+9, mixed mode, sharing) |
| 205 | +//---- |
| 206 | +// |
| 207 | +//.Benchmark results |
| 208 | +//[source] |
| 209 | +//---- |
| 210 | +//---- |
| 211 | +
|
| 212 | +//=== With Java 14 (early access) |
| 213 | +// |
| 214 | +//.Java version information for Java 14 (early access) |
| 215 | +//[source, console] |
| 216 | +//---- |
| 217 | +//$ java -version |
| 218 | +//openjdk version "14-ea" 2020-03-17 |
| 219 | +//OpenJDK Runtime Environment (build 14-ea+27-1339) |
| 220 | +//OpenJDK 64-Bit Server VM (build 14-ea+27-1339, mixed mode, sharing) |
| 221 | +//---- |
| 222 | +// |
| 223 | +//.Benchmark results |
| 224 | +//[source] |
| 225 | +//---- |
| 226 | +//---- |
166 | 227 |
|
167 | 228 | === Conclusions from those measurements |
168 | | -Both for loops were considerably faster than the stream solution suggested in the original tweet. |
| 229 | +Both for loops were considerably faster than the stream solution suggested in the original tweet (about twice the throughput for the short list and about 1.4 times the throughput for the much longer list). |
169 | 230 | In both cases, the enhanced for loop was slightly better than the basic for loop. |
170 | 231 |
|
171 | 232 | The exact measurements may vary depending on a number of factors, including but not limited to: |
|
0 commit comments