On Fri, 11 Nov 2022 01:41:15 GMT, Jim Laskey <jlas...@openjdk.org> wrote:
>> Thanks, I think benchmarks like this are useful. The `interpolate()` case is >> not something I considered when I made my earlier comment. Please add any >> benchmarks to the patch as well, so that performance experiments can be >> reliably reproduced. >> >> I think what this benchmark mainly shows is the benefit of carriers in >> combination with the instance `interpolate()` method. I expect most custom >> string processors will interact with string template instances through the >> `fragments()` and `values()` methods, though (I don't think there is an >> alternative?). i.e. in the end, we still end up boxing everything into a >> couple of lists any ways. `interpolate()` also has another leg up in that it >> knows the shape of the template when the string template instance is >> constructed, and can use a specialized method handle to do the processing. >> >> If I change the benchmark to rely on the `fragments()` and `values()` >> accessors (which I think the majority/all of the custom processor will have >> to do), for instance by using `st -> >> StringTemplate.interpolate(st.fragments(), st.values())` as a custom >> processor, and I tweak `StringTemplateImplFactory::newStringTemplate` to use >> `List::copyOf` instead of the stream it uses now ([1]), then the list based >> implementation is slightly faster than the carriers based implementation on >> my machine: >> >> >> Benchmark Mode Cnt Score Error Units >> Carriers.carrier avgt 15 69.946 � 0.599 ns/op >> Carriers.carrier_inst avgt 15 15.014 � 0.106 ns/op >> Carriers.concat avgt 15 8.441 � 0.021 ns/op >> Carriers.format avgt 15 9.314 � 0.172 ns/op >> Carriers.lists avgt 15 61.131 � 0.401 ns/op >> Carriers.str avgt 15 8.547 � 0.145 ns/op >> >> >> It makes me wonder if carriers are worth it at this stage (hard to say... >> performance is usually a long string to pull), or if it's better to go >> all-in on custom linkage, which should give custom processors performance >> that is comparable with `STR` and `FMT`. >> >> Maybe the instance `interpolate()` method is an important enough use-case to >> add carriers though. I can't really say. >> >> I appreciate the fact that carriers will see use in future projects as well, >> but at face value, it doesn't seem like they add that much for string >> templates (rather, on the contrary in some cases it seems). >> >> [1]: http://cr.openjdk.java.net/~jvernee/bench.diff > > Something like a StringProcessorFactory could produce the same structures as > as interpolate without the boxing issues. > > There are generally two main types of processors (there are others but they > would require specialization anyway). The first type doesn't really care > about the construction of the string. It just wants to get the interpolation > and work with the result. A JSON processor might fall into that category. > > The second type wants to transform (MH filter args) the fragments or the > values or both and then get an interpolation (and maybe work with that > result). This is where the StringProcessorFactory would kick in and automate > the process and in the end get similar performance as interpolate. No lists > or boxing. A formatter processor might fall into that category. > > What I think you are really objecting to is the existence of StringTemplate > objects. Why not just BSM everything? The problem is that processors can be > swapped out and can have state. So you need a user model where the what > object (StringTemplate) is separate from the how object (TemplateProcessor). > > Try working through some examples and it will become clearer. I guess I'm not sure what you have in mind with `StringProcessorFactory`, but I think it's starting to become clearer. I expected it to return a method handle that took all the dynamic values as arguments (similar to the callsites return by the current BSMs), i.e. it would completely bypass `StringTemplate`, but it sounds like it will instead take just a `StringTemplate` instance as argument? In that case carriers make sense to me, as the accesses to the fragments and values would be funneled through the StringTemplate instance, and a StringProcessorFactory could generate 'sharp' accesses to those values (rather than going through `StringTemplate::fragments()` and `StringTemplate::values()`, which would box things into lists any ways). Thanks ------------- PR: https://git.openjdk.org/jdk/pull/10889