It' seems messages sent from Yandex Mail mobile application are not delivered, so I repeat it from web app.
--------------------------- Hello, Yes I’m willing to take this As I understand there is the code imported from 3rd party projects which shouldn’t be touched. I know only about jdk.internal.org.objectweb.* Are there any other similar places? Also what about the task to bind the changes to? I’m talking about this one and changes to java.lang.Class::methodToString. Sergei Tsypanov 22:03, 3 апреля 2019 г., Brian Goetz <brian.go...@oracle.com>: > I agree that getting rid of the append(concatenation) is a good move > regardless; that’s just wasteful movement. The rest of the patch seems > harmless. > > As to applying the refactor more broadly, there’s a risk of recreating the > “append(concatenation)” problem, where the concatenation is hidden inside the > call to repeat(). A loop over append() is likely to be more performant than > append(s.repeat()), even those the latter is more abstract and harder to get > wrong. > > If you’re willing to take the auto-refactor result and hand-edit it to > eliminate the cases where we’d create new append(concat) situations, I’d be > supportive of that as well. > >> On Mar 26, 2019, at 4:15 PM, Сергей Цыпанов <sergei.tsypa...@yandex.ru> >> wrote: >> >> Hello Peter, >> >> I was unaware of mentioned detail (thank you a lot for pointing that out, >> it made me read the whole JEP280 again) so I've rebenchmarked my changes >> compiled with -XDstringConcat=inline. >> >> 1) as of Class::getTypeName for Object[] it turned out, that String::repeat >> performs slightly better: >> >> Benchmark Mode Cnt Score Error Units >> >> getTypeName_patched avgt 25 36,676 ± 3,559 ns/op >> getTypeName avgt 25 39,083 ± 1,737 ns/op >> >> getTypeName_patched:·gc.alloc.rate.norm avgt 25 152,000 ± 0,001 B/op >> getTypeName:·gc.alloc.rate.norm avgt 25 152,000 ± 0,001 B/op >> >> But for Object[][] situation is the opposite: >> >> Mode Cnt Score >> Error Units >> >> getTypeName_patched avgt 50 47,045 ± 0,455 ns/op >> getTypeName avgt 50 40,536 ± 0,196 ns/op >> >> getTypeName_patched:·gc.alloc.rate.norm avgt 50 176,000 ± 0,001 B/op >> getTypeName:·gc.alloc.rate.norm avgt 50 152,000 ± 0,001 B/op >> >> 2) as of Class::methodToString patched version clearly wins: >> >> methodToString_1arg avgt 50 238,476 ± 1,641 ns/op >> methodToString_1arg_patched avgt 50 197,900 ± 5,824 ns/op >> >> methodToString_1arg:·gc.alloc.rate.norm avgt 50 1209,600 ± 6,401 B/op >> methodToString_1arg_patched:·gc.alloc.rate.norm avgt 50 936,000 ± 0,001 B/op >> >> methodToString_noArgs avgt 50 224,054 ± 1,840 ns/op >> methodToString_noArgs_patched avgt 50 78,195 ± 0,418 ns/op >> >> methodToString_noArgs:·gc.alloc.rate.norm avgt 50 1131,200 ± 7,839 B/op >> methodToString_noArgs_patched:·gc.alloc.rate.norm avgt 50 408,000 ± 0,001 >> B/op >> >> As Brian suggested I've separated the changes. The patch attached contains >> only the changes for Class::methodToString. They are obviously helpful as >> they rid concatenation as argument of StringBuilder::append call (obvious >> antipattern to me) and skip Stream creation for empty array. >> >> String::repeat obviously requires more investigation, it might turn out we >> don't need it in java.base in majority of use cases or in all of them. >> >> Regards, >> Sergei Tsypanov >> >> 21.03.2019, 00:56, "Peter Levart" <peter.lev...@gmail.com>: >>> Hi Sergei, >>> >>> I don't know if you are aware that the new invokedynamic based >>> translation of string concatenation expressions introduced in JDK 9 >>> (http://openjdk.java.net/jeps/280) only applies to code outside >>> java.base module. java.base module is still compiled with old-style >>> StringBuilder based translation of string concatenation expressions >>> because of bootstraping issues. >>> >>> If your benchmarks bellow are compiled with option >>> -XDstringConcat=inline to disable JEP280 translation (as java.base >>> module is), then it's OK. Else you are not benchmarking the right >>> translation of the code as you intend to change the code in java.base >>> module. >>> >>> Regards, Peter >>> >>> On 3/20/19 7:35 PM, Сергей Цыпанов wrote: >>>> I had a brief conversation with Brian Goetz which has left off the >>>> mailing list for some reason. Here's the text: >>>> --------------------------- >>>> Brian: >>>> >>>> These enhancements seem reasonable; these are exactly the cases that >>>> String::repeat was intended for. (This is a “is this a reasonable idea” >>>> review, not a code review.). >>>> Have you looked for other places where similar transformations could be >>>> done? >>>> >>>> --------------------------- >>>> Me: >>>> >>>> Hello, >>>> after I had realized that looped StringBuilder::append calls can >>>> sometimes be replaced with String::repeat I requested corresponding >>>> inspection in IDEA issue tracker. >>>> Using the inspection I’ve found 129 similar warnings in jdk13 repo. >>>> Some of them are very promising, e.g. BigDecimal:: toPlainString where >>>> currently we have >>>> >>>>> int trailingZeros = checkScaleNonZero((-(long)scale)); >>>>> StringBuilder buf; >>>>> if(intCompact!=INFLATED) { >>>>> buf = new StringBuilder(20+trailingZeros); >>>>> buf.append(intCompact); >>>>> } else { >>>>> String str = intVal.toString(); >>>>> buf = new StringBuilder(str.length()+trailingZeros); >>>>> buf.append(str); >>>>> } >>>>> for (int i = 0; i < trailingZeros; i++) { >>>>> buf.append('0'); >>>>> } >>>>> return buf.toString(); >>>> which in fact can be simplified to >>>> >>>>> int trailingZeros = checkScaleNonZero((-(long)scale)); >>>>> if(intCompact!=INFLATED) { >>>>> return intCompact + "0".repeat(trailingZeros); >>>>> } else { >>>>> return intVal.toString() + "0".repeat(trailingZeros); >>>>> } >>>> The second solution is not only shorter and more simple but it likely to >>>> be significantly faster and memory-saving. >>>> BTW, your reply to original message for some reason is missing from >>>> web-view. >>>> >>>> --------------------------- >>>> Brian: >>>> >>>> Cool. Note that replacing append() calls with repeat is not necessarily >>>> a win for anything other than code compactness; String::repeat will create >>>> a new string, which will then get appended to another StrinBuilder. So >>>> when used correctly (such as presized StringBuilders) appending in a loop >>>> is probably just as fast (look at the implementation of String::repeat.). >>>> >>>>> if(intCompact!=INFLATED) { >>>>> return intCompact + "0".repeat(trailingZeros); >>>>> } else { >>>>> return intVal.toString() + "0".repeat(trailingZeros); >>>>> } >>>> Which can be further simplified to >>>> >>>>> ((intCompact != INFLATED) ? intCompact : intVal.toString) + >>>>> “0”.repeat(trailingZeros); >>>> >>>> The second solution is not only shorter and more simple but it likely to >>>> be significantly faster and memory-saving. >>>> I like short and simple. I am questioning the “faster and memory >>>> saving.” That should be validated. >>>> >>>> --------------------------- >>>> Me: >>>> >>>> I think optimizations provided by JEP 280 allow compiler to optimize >>>> String concatenation executed with '+' by using StringBuilder of exact >>>> size (when the size of all components is known, like in our case). >>>> >>>> I've checked this with benchmark >>>> >>>>> @State(Scope.Thread) >>>>> @BenchmarkMode(Mode.AverageTime) >>>>> @OutputTimeUnit(TimeUnit.NANOSECONDS) >>>>> @Fork(jvmArgsAppend = {"-Xms2g", "-Xmx2g"}) >>>>> public class ConcatBenchmark { >>>>> >>>>> @Param({"1", "2", "5", "8"}) >>>>> private int trailingZeros; >>>>> >>>>> private final long intCompact = 1L; >>>>> >>>>> @Benchmark >>>>> public String stringBuilder() { >>>>> StringBuilder buf; >>>>> buf = new StringBuilder(20 + trailingZeros); >>>>> buf.append(intCompact); >>>>> for (int i = 0; i < trailingZeros; i++) { >>>>> buf.append('0'); >>>>> } >>>>> return buf.toString(); >>>>> } >>>>> @Benchmark >>>>> public String stringRepeat() { >>>>> return intCompact + "0".repeat(trailingZeros); >>>>> } >>>>> } >>>> Results: >>>> trailingZeros Mode Cnt Score >>>> Error Units >>>> stringBuilder 1 avgt 15 17,683 ± 0,664 ns/op >>>> stringRepeat 1 avgt 15 9,052 ± 0,042 ns/op >>>> >>>> stringBuilder 2 avgt 15 19,053 ± 1,206 ns/op >>>> stringRepeat 2 avgt 15 15,864 ± 1,331 ns/op >>>> >>>> stringBuilder 5 avgt 15 25,839 ± 2,256 ns/op >>>> stringRepeat 5 avgt 15 19,290 ± 1,685 ns/op >>>> >>>> stringBuilder 8 avgt 15 26,488 ± 0,371 ns/op >>>> stringRepeat 8 avgt 15 19,420 ± 1,593 ns/op >>>> >>>> stringBuilder:·gc.alloc.rate.norm 1 avgt 15 88,000 ± 0,001 B/op >>>> stringRepeat:·gc.alloc.rate.norm 1 avgt 15 48,000 ± 0,001 B/op >>>> >>>> stringBuilder:·gc.alloc.rate.norm 2 avgt 15 88,000 ± 0,001 B/op >>>> stringRepeat:·gc.alloc.rate.norm 2 avgt 15 72,000 ± 0,001 B/op >>>> >>>> stringBuilder:·gc.alloc.rate.norm 5 avgt 15 96,000 ± 0,001 B/op >>>> stringRepeat:·gc.alloc.rate.norm 5 avgt 15 72,000 ± 0,001 B/op >>>> >>>> stringBuilder:·gc.alloc.rate.norm 8 avgt 15 104,000 ± 0,001 B/op >>>> stringRepeat:·gc.alloc.rate.norm 8 avgt 15 80,000 ± 0,001 B/op >>>> >>>> I think this is a useful optimization, so we should use String::repeat >>>> where possible. >>>> >>>> --------------------------- >>>> Brian: >>>> >>>> My recommendation is to split your patch into two. The first is the >>>> straightforward “replace loop with repeat” refactoring, which can be >>>> mechanically generated by the IDE. Here, you should examine each site to >>>> ensure that the transform seems sensible given the context. The second can >>>> then be additional hand-refactoring opportunities exposed by the first. >>>> The benefit of splitting it this way is that reviewing the first is far >>>> easier when you can say all the changes are mechanical. >>>> >>>> (Somehow this fell off the list; feel free to bring it back.) >>>> >>>> 18.03.2019, 21:13, "Сергей Цыпанов" <sergei.tsypa...@yandex.ru>: >>>>> Hi, >>>>> >>>>> I have an enhancement proposal for java.lang.Class.methodToString and >>>>> java.lang.Class.getTypeName. >>>>> >>>>> First one is used when NoSuchMethodException is thrown from >>>>> Class::getMethod which is in turn widely used in Spring Framework and >>>>> often throws. >>>>> >>>>> In current implementation we have 2 major problems: >>>>> >>>>> - we create stream for the case when argTypes is not null but empty >>>>> (which happens e. g. when Class::getMethod is called without vararg and >>>>> throws) >>>>> - we have torn StringBuilder::append chain >>>>> >>>>> I’ve modified the method to skip creation of Stream for empty array and >>>>> used separate StringBuilder for each case. Latter allowed to rid SB >>>>> completely and use invokedynamic-based concatenation. >>>>> >>>>> I’ve compared both approaches for 2 cases: >>>>> >>>>> 1) argTypes is empty >>>>> 2) argTypes.length == 1 >>>>> >>>>> Benchmark Mode Cnt Score Error Units >>>>> >>>>> methodToString_noArgs avgt 25 170,986 ± 5,708 ns/op >>>>> methodToString_noArgs_patched avgt 25 26,883 ± 2,906 ns/op >>>>> >>>>> methodToString_1arg avgt 25 183,012 ± 0,701 ns/op >>>>> methodToString_1arg_patched avgt 25 112,784 ± 0,920 ns/op >>>>> >>>>> methodToString_noArgs:·gc.alloc.rate.norm avgt 25 881,600 ± 9,786 B/op >>>>> methodToString_noArgs_patched:·gc.alloc.rate.norm avgt 25 128,000 ± >>>>> 0,001 B/op >>>>> >>>>> methodToString_1arg:·gc.alloc.rate.norm avgt 25 960,000 ± 0,001 B/op >>>>> methodToString_1arg_patched:·gc.alloc.rate.norm avgt 25 552,000 ± 0,001 >>>>> B/op >>>>> >>>>> We have the same problem regarding misusage of StringBuilder in Class:: >>>>> getTypeName: >>>>> >>>>> StringBuilder sb = new StringBuilder(); >>>>> sb.append(cl.getName()); >>>>> for (int i = 0; i < dimensions; i++) { >>>>> sb.append("[]"); >>>>> } >>>>> return sb.toString(); >>>>> >>>>> I suggest to use String::repeat instead of the loop: this again allows >>>>> to get rid of StringBuilder and replace mentioned code with >>>>> >>>>> return cl.getName() + "[]".repeat(dimensions); >>>>> >>>>> Here are benchmark results executed for type Object[].class: >>>>> >>>>> Mode Cnt Score Error Units >>>>> getTypeName_patched avgt 25 16,037 ± 0,431 ns/op >>>>> getTypeName_patched:·gc.alloc.rate.norm avgt 25 64,000 ± 0,001 B/op >>>>> >>>>> getTypeName avgt 25 34,274 ± 1,432 ns/op >>>>> getTypeName:·gc.alloc.rate.norm avgt 25 152,000 ± 0,001 B/op >>>>> >>>>> Regards, >>>>> Sergei Tsypanov >> <klass.txt> -- Отправлено из мобильного приложения Яндекс.Почты