schlosna opened a new pull request #352: URL: https://github.com/apache/httpcomponents-client/pull/352
While analyzing some JFR profiles from a service utilizing a high volume of async HTTP client requests, I noticed one of the top memory allocations of `java.text.DecimalFormatSymbols` coming from `org.apache.hc.client5.http.impl.ExecSupport#getNextExchangeId`, notably due to use of `String#format`. Given that this seems to be on a hot code path, we can optimize this code path. Backtrace: ``` sun.util.locale.provider.DecimalFormatSymbolsProviderImpl.getInstance(Locale) java.text.DecimalFormatSymbols.getInstance(Locale) java.util.Formatter.zero() java.util.Formatter$FormatSpecifier.getZero(Locale) java.util.Formatter$FormatSpecifier.localizedMagnitude(StringBuilder, CharSequence, int, Formatter$Flags, int, Locale) java.util.Formatter$FormatSpecifier.print(long, Locale) java.util.Formatter$FormatSpecifier.printInteger(Object, Locale) java.util.Formatter$FormatSpecifier.print(Object, Locale) java.util.Formatter.format(Locale, String, Object[]) java.util.Formatter.format(String, Object[]) java.lang.String.format(String, Object[]) org.apache.hc.client5.http.impl.ExecSupport.getNextExchangeId() org.apache.hc.client5.http.impl.classic.InternalHttpClient.doExecute(HttpHost, ClassicHttpRequest, HttpContext) org.apache.hc.client5.http.impl.classic.CloseableHttpClient.execute(ClassicHttpRequest, HttpContext) org.apache.hc.client5.http.impl.classic.CloseableHttpClient.execute(ClassicHttpRequest) ``` With a hand rolled a method to perform the same functionality of `String.format("ex-%010d", long)` we see a roughly 20x speed-up in execution time and ~16x reduction in allocations on a JMH microbenchmark for just this function (see https://github.com/schlosna/httpclient-format-performance ). This PR currently only optimizes the hot exchange ID code path and not the endpoint ID code paths that use similar formatting (see https://github.com/apache/httpcomponents-client/pull/249 ) Benchmarks all run on 16 core Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz. JDK 11.0.13, OpenJDK 64-Bit Server VM, 11.0.13+8-LTS ``` Benchmark Mode Cnt Score Error Units FormatBenchmarks.stringFormat avgt 5 674.730 ± 7.821 ns/op FormatBenchmarks.stringFormat:·gc.alloc.rate avgt 5 852.757 ± 9.814 MB/sec FormatBenchmarks.stringFormat:·gc.alloc.rate.norm avgt 5 704.000 ± 0.001 B/op FormatBenchmarks.stringFormat:·gc.churn.G1_Eden_Space avgt 5 862.955 ± 171.696 MB/sec FormatBenchmarks.stringFormat:·gc.churn.G1_Eden_Space.norm avgt 5 712.471 ± 146.197 B/op FormatBenchmarks.stringFormat:·gc.churn.G1_Old_Gen avgt 5 0.001 ± 0.002 MB/sec FormatBenchmarks.stringFormat:·gc.churn.G1_Old_Gen.norm avgt 5 0.001 ± 0.002 B/op FormatBenchmarks.stringFormat:·gc.count avgt 5 53.000 counts FormatBenchmarks.stringFormat:·gc.time avgt 5 33.000 ms FormatBenchmarks.zeroPad avgt 5 38.760 ± 1.082 ns/op FormatBenchmarks.zeroPad:·gc.alloc.rate avgt 5 1855.680 ± 51.458 MB/sec FormatBenchmarks.zeroPad:·gc.alloc.rate.norm avgt 5 88.000 ± 0.001 B/op FormatBenchmarks.zeroPad:·gc.churn.G1_Eden_Space avgt 5 1859.501 ± 202.606 MB/sec FormatBenchmarks.zeroPad:·gc.churn.G1_Eden_Space.norm avgt 5 88.186 ± 10.045 B/op FormatBenchmarks.zeroPad:·gc.churn.G1_Old_Gen avgt 5 0.004 ± 0.002 MB/sec FormatBenchmarks.zeroPad:·gc.churn.G1_Old_Gen.norm avgt 5 ≈ 10⁻⁴ B/op FormatBenchmarks.zeroPad:·gc.count avgt 5 79.000 counts FormatBenchmarks.zeroPad:·gc.time avgt 5 62.000 ms ``` JDK 15.0.5, OpenJDK 64-Bit Server VM, 15.0.5+3-MTS ``` Benchmark Mode Cnt Score Error Units FormatBenchmarks.stringFormat avgt 5 1081.263 ± 50.140 ns/op FormatBenchmarks.stringFormat:·gc.alloc.rate avgt 5 1094.601 ± 50.204 MB/sec FormatBenchmarks.stringFormat:·gc.alloc.rate.norm avgt 5 1448.105 ± 0.005 B/op FormatBenchmarks.stringFormat:·gc.churn.G1_Eden_Space avgt 5 1093.372 ± 0.707 MB/sec FormatBenchmarks.stringFormat:·gc.churn.G1_Eden_Space.norm avgt 5 1446.645 ± 67.105 B/op FormatBenchmarks.stringFormat:·gc.churn.G1_Survivor_Space avgt 5 0.004 ± 0.007 MB/sec FormatBenchmarks.stringFormat:·gc.churn.G1_Survivor_Space.norm avgt 5 0.006 ± 0.009 B/op FormatBenchmarks.stringFormat:·gc.count avgt 5 55.000 counts FormatBenchmarks.stringFormat:·gc.time avgt 5 51.000 ms FormatBenchmarks.zeroPad avgt 5 39.612 ± 1.489 ns/op FormatBenchmarks.zeroPad:·gc.alloc.rate avgt 5 1815.969 ± 68.124 MB/sec FormatBenchmarks.zeroPad:·gc.alloc.rate.norm avgt 5 88.006 ± 0.001 B/op FormatBenchmarks.zeroPad:·gc.churn.G1_Eden_Space avgt 5 1829.120 ± 209.669 MB/sec FormatBenchmarks.zeroPad:·gc.churn.G1_Eden_Space.norm avgt 5 88.641 ± 9.053 B/op FormatBenchmarks.zeroPad:·gc.churn.G1_Survivor_Space avgt 5 0.008 ± 0.002 MB/sec FormatBenchmarks.zeroPad:·gc.churn.G1_Survivor_Space.norm avgt 5 ≈ 10⁻³ B/op FormatBenchmarks.zeroPad:·gc.count avgt 5 92.000 counts FormatBenchmarks.zeroPad:·gc.time avgt 5 80.000 ms ``` JDK 17.0.1, OpenJDK 64-Bit Server VM, 17.0.1+12-LTS ``` Benchmark Mode Cnt Score Error Units FormatBenchmarks.stringFormat avgt 5 871.173 ± 11.990 ns/op FormatBenchmarks.stringFormat:·gc.alloc.rate avgt 5 1313.506 ± 18.053 MB/sec FormatBenchmarks.stringFormat:·gc.alloc.rate.norm avgt 5 1400.111 ± 0.011 B/op FormatBenchmarks.stringFormat:·gc.churn.G1_Eden_Space avgt 5 1314.209 ± 139.635 MB/sec FormatBenchmarks.stringFormat:·gc.churn.G1_Eden_Space.norm avgt 5 1400.917 ± 157.487 B/op FormatBenchmarks.stringFormat:·gc.churn.G1_Survivor_Space avgt 5 0.006 ± 0.008 MB/sec FormatBenchmarks.stringFormat:·gc.churn.G1_Survivor_Space.norm avgt 5 0.006 ± 0.009 B/op FormatBenchmarks.stringFormat:·gc.count avgt 5 81.000 counts FormatBenchmarks.stringFormat:·gc.time avgt 5 53.000 ms FormatBenchmarks.zeroPad avgt 5 41.057 ± 0.172 ns/op FormatBenchmarks.zeroPad:·gc.alloc.rate avgt 5 1751.849 ± 7.370 MB/sec FormatBenchmarks.zeroPad:·gc.alloc.rate.norm avgt 5 88.007 ± 0.001 B/op FormatBenchmarks.zeroPad:·gc.churn.G1_Eden_Space avgt 5 1752.274 ± 171.164 MB/sec FormatBenchmarks.zeroPad:·gc.churn.G1_Eden_Space.norm avgt 5 88.027 ± 8.268 B/op FormatBenchmarks.zeroPad:·gc.churn.G1_Survivor_Space avgt 5 0.009 ± 0.005 MB/sec FormatBenchmarks.zeroPad:·gc.churn.G1_Survivor_Space.norm avgt 5 ≈ 10⁻³ B/op FormatBenchmarks.zeroPad:·gc.count avgt 5 108.000 counts FormatBenchmarks.zeroPad:·gc.time avgt 5 69.000 ms ``` -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: dev-unsubscr...@hc.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@hc.apache.org For additional commands, e-mail: dev-h...@hc.apache.org